2017-06-09 11:51:25 +02:00

17844 lines
1.5 MiB
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(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":115}],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":102}],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":104}],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":114,"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":114,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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":115,"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){
(function (global){
/*
* 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 adapterFactory = require('./adapter_factory.js');
module.exports = adapterFactory({window: global.window});
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./adapter_factory.js":92}],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';
// Shimming starts here.
module.exports = function(dependencies) {
var window = dependencies && dependencies.window;
// Utils.
var utils = require('./utils');
var logging = utils.log;
var browserDetails = utils.detectBrowser(window);
// Export to the adapter global object visible in the browser.
var adapter = {
browserDetails: browserDetails,
extractVersion: utils.extractVersion,
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 adapter;
}
logging('adapter.js shimming chrome.');
// Export to the adapter global object visible in the browser.
adapter.browserShim = chromeShim;
chromeShim.shimGetUserMedia(window);
chromeShim.shimMediaStream(window);
utils.shimCreateObjectURL(window);
chromeShim.shimSourceObject(window);
chromeShim.shimPeerConnection(window);
chromeShim.shimOnTrack(window);
chromeShim.shimGetSendersWithDtmf(window);
break;
case 'firefox':
if (!firefoxShim || !firefoxShim.shimPeerConnection) {
logging('Firefox shim is not included in this adapter release.');
return adapter;
}
logging('adapter.js shimming firefox.');
// Export to the adapter global object visible in the browser.
adapter.browserShim = firefoxShim;
firefoxShim.shimGetUserMedia(window);
utils.shimCreateObjectURL(window);
firefoxShim.shimSourceObject(window);
firefoxShim.shimPeerConnection(window);
firefoxShim.shimOnTrack(window);
break;
case 'edge':
if (!edgeShim || !edgeShim.shimPeerConnection) {
logging('MS edge shim is not included in this adapter release.');
return adapter;
}
logging('adapter.js shimming edge.');
// Export to the adapter global object visible in the browser.
adapter.browserShim = edgeShim;
edgeShim.shimGetUserMedia(window);
utils.shimCreateObjectURL(window);
edgeShim.shimPeerConnection(window);
edgeShim.shimReplaceTrack(window);
break;
case 'safari':
if (!safariShim) {
logging('Safari shim is not included in this adapter release.');
return adapter;
}
logging('adapter.js shimming safari.');
// Export to the adapter global object visible in the browser.
adapter.browserShim = safariShim;
safariShim.shimCallbacksAPI(window);
safariShim.shimAddStream(window);
safariShim.shimOnAddStream(window);
safariShim.shimGetUserMedia(window);
break;
default:
logging('Unsupported browser!');
break;
}
return adapter;
};
},{"./chrome/chrome_shim":93,"./edge/edge_shim":95,"./firefox/firefox_shim":98,"./safari/safari_shim":100,"./utils":101}],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 utils = require('../utils.js');
var logging = utils.log;
var chromeShim = {
shimMediaStream: function(window) {
window.MediaStream = window.MediaStream || window.webkitMediaStream;
},
shimOnTrack: function(window) {
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 receiver;
if (window.RTCPeerConnection.prototype.getReceivers) {
receiver = self.getReceivers().find(function(r) {
return r.track.id === te.track.id;
});
} else {
receiver = {track: te.track};
}
var event = new Event('track');
event.track = te.track;
event.receiver = receiver;
event.streams = [e.stream];
self.dispatchEvent(event);
});
e.stream.getTracks().forEach(function(track) {
var receiver;
if (window.RTCPeerConnection.prototype.getReceivers) {
receiver = self.getReceivers().find(function(r) {
return r.track.id === track.id;
});
} else {
receiver = {track: track};
}
var event = new Event('track');
event.track = track;
event.receiver = receiver;
event.streams = [e.stream];
this.dispatchEvent(event);
}.bind(this));
}.bind(this));
}
});
}
},
shimGetSendersWithDtmf: function(window) {
if (typeof window === 'object' && window.RTCPeerConnection &&
!('getSenders' in window.RTCPeerConnection.prototype) &&
'createDTMFSender' in window.RTCPeerConnection.prototype) {
window.RTCPeerConnection.prototype.getSenders = function() {
return this._senders || [];
};
var origAddStream = window.RTCPeerConnection.prototype.addStream;
var origRemoveStream = window.RTCPeerConnection.prototype.removeStream;
if (!window.RTCPeerConnection.prototype.addTrack) {
window.RTCPeerConnection.prototype.addTrack = function(track, stream) {
var pc = this;
if (pc.signalingState === 'closed') {
throw new DOMException(
'The RTCPeerConnection\'s signalingState is \'closed\'.',
'InvalidStateError');
}
var streams = [].slice.call(arguments, 1);
if (streams.length !== 1 ||
!streams[0].getTracks().find(function(t) {
return t === track;
})) {
// this is not fully correct but all we can manage without
// [[associated MediaStreams]] internal slot.
throw new DOMException(
'The adapter.js addTrack polyfill only supports a single ' +
' stream which is associated with the specified track.',
'NotSupportedError');
}
pc._senders = pc._senders || [];
var alreadyExists = pc._senders.find(function(t) {
return t.track === track;
});
if (alreadyExists) {
throw new DOMException('Track already exists.',
'InvalidAccessError');
}
pc._streams = pc._streams || {};
var oldStream = pc._streams[stream.id];
if (oldStream) {
oldStream.addTrack(track);
pc.removeStream(oldStream);
pc.addStream(oldStream);
} else {
var newStream = new window.MediaStream([track]);
pc._streams[stream.id] = newStream;
pc.addStream(newStream);
}
var sender = {
track: track,
get dtmf() {
if (this._dtmf === undefined) {
if (track.kind === 'audio') {
this._dtmf = pc.createDTMFSender(track);
} else {
this._dtmf = null;
}
}
return this._dtmf;
}
};
pc._senders.push(sender);
return sender;
};
}
window.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;
}
});
});
};
window.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(window) {
var URL = window && window.URL;
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(window) {
var browserDetails = utils.detectBrowser(window);
// 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 window.webkitRTCPeerConnection(pcConfig, pcConstraints);
};
window.RTCPeerConnection.prototype =
window.webkitRTCPeerConnection.prototype;
// wrap static methods. Currently just generateCertificate.
if (window.webkitRTCPeerConnection.generateCertificate) {
Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
get: function() {
return window.webkitRTCPeerConnection.generateCertificate;
}
});
}
} else {
// migrate from non-spec RTCIceServer.url to RTCIceServer.urls
var OrigPeerConnection = window.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 = window.RTCPeerConnection.prototype.getStats;
window.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 = window.RTCPeerConnection.prototype[method];
window.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 = window.RTCPeerConnection.prototype[method];
window.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 = window.RTCPeerConnection.prototype[method];
window.RTCPeerConnection.prototype[method] = function() {
arguments[0] = new ((method === 'addIceCandidate') ?
window.RTCIceCandidate :
window.RTCSessionDescription)(arguments[0]);
return nativeMethod.apply(this, arguments);
};
});
// support for addIceCandidate(null or undefined)
var nativeAddIceCandidate =
window.RTCPeerConnection.prototype.addIceCandidate;
window.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":101,"./getusermedia":94}],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 utils = require('../utils.js');
var logging = utils.log;
// Expose public methods.
module.exports = function(window) {
var browserDetails = utils.detectBrowser(window);
var navigator = window && window.navigator;
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 && typeof constraints.audio === 'object') {
var remap = function(obj, a, b) {
if (a in obj && !(b in obj)) {
obj[b] = obj[a];
delete obj[a];
}
};
constraints = JSON.parse(JSON.stringify(constraints));
remap(constraints.audio, 'autoGainControl', 'googAutoGainControl');
remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression');
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',
InvalidStateError: 'NotReadableError',
DevicesNotFoundError: 'NotFoundError',
ConstraintNotSatisfiedError: 'OverconstrainedError',
TrackStartError: 'NotReadableError',
MediaDeviceFailedDueToShutdown: 'NotReadableError',
MediaDeviceKillSwitchOn: 'NotReadableError'
}[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 window.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":101}],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';
var utils = require('../utils');
var shimRTCPeerConnection = require('./rtcpeerconnection_shim');
module.exports = {
shimGetUserMedia: require('./getusermedia'),
shimPeerConnection: function(window) {
var browserDetails = utils.detectBrowser(window);
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(
window.MediaStreamTrack.prototype, 'enabled');
Object.defineProperty(window.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(window, browserDetails.version);
},
shimReplaceTrack: function(window) {
// ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614
if (window.RTCRtpSender &&
!('replaceTrack' in window.RTCRtpSender.prototype)) {
window.RTCRtpSender.prototype.replaceTrack =
window.RTCRtpSender.prototype.setTrack;
}
}
};
},{"../utils":101,"./getusermedia":96,"./rtcpeerconnection_shim":97}],96:[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(window) {
var navigator = window && window.navigator;
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));
});
};
};
},{}],97:[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;
});
}
// Determines the intersection of local and remote capabilities.
function getCommonCapabilities(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;
}
// is action=setLocalDescription with type allowed in signalingState
function isActionAllowedInSignalingState(action, type, signalingState) {
return {
offer: {
setLocalDescription: ['stable', 'have-local-offer'],
setRemoteDescription: ['stable', 'have-remote-offer']
},
answer: {
setLocalDescription: ['have-remote-offer', 'have-local-pranswer'],
setRemoteDescription: ['have-local-offer', 'have-remote-pranswer']
}
}[type][action].indexOf(signalingState) !== -1;
}
module.exports = function(window, 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.needNegotiation = false;
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 window.RTCSessionDescription({
type: '',
sdp: ''
});
this.remoteDescription = new window.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;
};
// internal helper to create a transceiver object.
// (whih is not yet the same as the WebRTC 1.0 transceiver)
RTCPeerConnection.prototype._createTransceiver = function(kind) {
var hasBundleTransport = this.transceivers.length > 0;
var transceiver = {
track: null,
iceGatherer: null,
iceTransport: null,
dtlsTransport: null,
localCapabilities: null,
remoteCapabilities: null,
rtpSender: null,
rtpReceiver: null,
kind: kind,
mid: null,
sendEncodingParameters: null,
recvEncodingParameters: null,
stream: null,
wantReceive: true
};
if (this.usingBundle && hasBundleTransport) {
transceiver.iceTransport = this.transceivers[0].iceTransport;
transceiver.dtlsTransport = this.transceivers[0].dtlsTransport;
} else {
var transports = this._createIceAndDtlsTransports();
transceiver.iceTransport = transports.iceTransport;
transceiver.dtlsTransport = transports.dtlsTransport;
}
this.transceivers.push(transceiver);
return transceiver;
};
RTCPeerConnection.prototype.addTrack = function(track, stream) {
var transceiver;
for (var i = 0; i < this.transceivers.length; i++) {
if (!this.transceivers[i].track &&
this.transceivers[i].kind === track.kind) {
transceiver = this.transceivers[i];
}
}
if (!transceiver) {
transceiver = this._createTransceiver(track.kind);
}
transceiver.track = track;
transceiver.stream = stream;
transceiver.rtpSender = new window.RTCRtpSender(track,
transceiver.dtlsTransport);
this._maybeFireNegotiationNeeded();
return transceiver.rtpSender;
};
RTCPeerConnection.prototype.addStream = function(stream) {
var self = this;
if (edgeVersion >= 15025) {
this.localStreams.push(stream);
stream.getTracks().forEach(function(track) {
self.addTrack(track, 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;
});
});
clonedStream.getTracks().forEach(function(track) {
self.addTrack(track, clonedStream);
});
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;
});
};
// Create ICE gatherer and hook it up.
RTCPeerConnection.prototype._createIceGatherer = function(mid,
sdpMLineIndex) {
var self = this;
var iceGatherer = new window.RTCIceGatherer(self.iceOptions);
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 = 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;
}
};
return iceGatherer;
};
// Create ICE transport and DTLS transport.
RTCPeerConnection.prototype._createIceAndDtlsTransports = function() {
var self = this;
var iceTransport = new window.RTCIceTransport(null);
iceTransport.onicestatechange = function() {
self._updateConnectionState();
};
var dtlsTransport = new window.RTCDtlsTransport(iceTransport);
dtlsTransport.ondtlsstatechange = function() {
self._updateConnectionState();
};
dtlsTransport.onerror = function() {
// onerror does not set state to failed by itself.
Object.defineProperty(dtlsTransport, 'state',
{value: 'failed', writable: true});
self._updateConnectionState();
};
return {
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 = 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;
if (!isActionAllowedInSignalingState('setLocalDescription',
description.type, this.signalingState)) {
var e = new Error('Can not set local ' + description.type +
' in state ' + this.signalingState);
e.name = 'InvalidStateError';
if (arguments.length > 2 && typeof arguments[2] === 'function') {
window.setTimeout(arguments[2], 0, e);
}
return Promise.reject(e);
}
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 = SDPUtils.isRejected(mediaSection);
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 = 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;
if (!isActionAllowedInSignalingState('setRemoteDescription',
description.type, this.signalingState)) {
var e = new Error('Can not set remote ' + description.type +
' in state ' + this.signalingState);
e.name = 'InvalidStateError';
if (arguments.length > 2 && typeof arguments[2] === 'function') {
window.setTimeout(arguments[2], 0, e);
}
return Promise.reject(e);
}
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;
this.usingBundle = usingBundle;
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 kind = SDPUtils.getKind(mediaSection);
var rejected = SDPUtils.isRejected(mediaSection);
var protocol = lines[0].substr(2).split(' ')[2];
var direction = SDPUtils.getDirection(mediaSection, sessionpart);
var remoteMsid = SDPUtils.parseMsid(mediaSection);
var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier();
// Reject datachannels which are not implemented yet.
if (kind === 'application' && protocol === 'DTLS/SCTP') {
self.transceivers[sdpMLineIndex] = {
mid: mid,
isDatachannel: true
};
return;
}
var transceiver;
var iceGatherer;
var iceTransport;
var dtlsTransport;
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' || cand.component === 1;
});
// Check if we can use BUNDLE and dispose transports.
if ((description.type === 'offer' || description.type === 'answer') &&
!rejected && usingBundle && sdpMLineIndex > 0 &&
self.transceivers[sdpMLineIndex]) {
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);
}
}
if (description.type === 'offer' && !rejected) {
transceiver = self.transceivers[sdpMLineIndex] ||
self._createTransceiver(kind);
transceiver.mid = mid;
if (!transceiver.iceGatherer) {
transceiver.iceGatherer = usingBundle && sdpMLineIndex > 0 ?
self.transceivers[0].iceGatherer :
self._createIceGatherer(mid, sdpMLineIndex);
}
if (isComplete && (!usingBundle || sdpMLineIndex === 0)) {
transceiver.iceTransport.setRemoteCandidates(cands);
}
localCapabilities = window.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 window.RTCRtpReceiver(transceiver.dtlsTransport,
kind);
track = rtpReceiver.track;
// FIXME: does not work with Plan B.
if (remoteMsid) {
if (!streams[remoteMsid.stream]) {
streams[remoteMsid.stream] = new window.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 window.MediaStream();
}
streams.default.addTrack(track);
receiverList.push([track, rtpReceiver, streams.default]);
}
}
transceiver.localCapabilities = localCapabilities;
transceiver.remoteCapabilities = remoteCapabilities;
transceiver.rtpReceiver = rtpReceiver;
transceiver.rtcpParameters = rtcpParameters;
transceiver.sendEncodingParameters = sendEncodingParameters;
transceiver.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) {
transceiver = self.transceivers[sdpMLineIndex];
iceGatherer = transceiver.iceGatherer;
iceTransport = transceiver.iceTransport;
dtlsTransport = transceiver.dtlsTransport;
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;
if (remoteMsid) {
if (!streams[remoteMsid.stream]) {
streams[remoteMsid.stream] = new window.MediaStream();
}
streams[remoteMsid.stream].addTrack(track);
receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]);
} else {
if (!streams.default) {
streams.default = new window.MediaStream();
}
streams.default.addTrack(track);
receiverList.push([track, rtpReceiver, streams.default]);
}
} else {
// FIXME: actually the receiver should be created later.
delete transceiver.rtpReceiver;
}
}
});
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);
}
});
}
});
// check whether addIceCandidate({}) was called within four seconds after
// setRemoteDescription.
window.setTimeout(function() {
if (!(self && self.transceivers)) {
return;
}
self.transceivers.forEach(function(transceiver) {
if (transceiver.iceTransport &&
transceiver.iceTransport.state === 'new' &&
transceiver.iceTransport.getRemoteCandidates().length > 0) {
console.warn('Timeout for addRemoteCandidate. Consider sending ' +
'an end-of-candidates notification');
transceiver.iceTransport.addRemoteCandidate({});
}
});
}, 4000);
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() {
var self = this;
if (this.signalingState !== 'stable' || this.needNegotiation === true) {
return;
}
this.needNegotiation = true;
window.setTimeout(function() {
if (self.needNegotiation === false) {
return;
}
self.needNegotiation = false;
var event = new Event('negotiationneeded');
self.dispatchEvent(event);
if (self.onnegotiationneeded !== null) {
self.onnegotiationneeded(event);
}
}, 0);
};
// 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,
disconnected: 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 numAudioTracks = this.transceivers.filter(function(t) {
return t.kind === 'audio';
}).length;
var numVideoTracks = this.transceivers.filter(function(t) {
return t.kind === 'video';
}).length;
// 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) {
if (offerOptions.offerToReceiveAudio === true) {
numAudioTracks = 1;
} else if (offerOptions.offerToReceiveAudio === false) {
numAudioTracks = 0;
} else {
numAudioTracks = offerOptions.offerToReceiveAudio;
}
}
if (offerOptions.offerToReceiveVideo !== undefined) {
if (offerOptions.offerToReceiveVideo === true) {
numVideoTracks = 1;
} else if (offerOptions.offerToReceiveVideo === false) {
numVideoTracks = 0;
} else {
numVideoTracks = offerOptions.offerToReceiveVideo;
}
}
}
this.transceivers.forEach(function(transceiver) {
if (transceiver.kind === 'audio') {
numAudioTracks--;
if (numAudioTracks < 0) {
transceiver.wantReceive = false;
}
} else if (transceiver.kind === 'video') {
numVideoTracks--;
if (numVideoTracks < 0) {
transceiver.wantReceive = false;
}
}
});
// Create M-lines for recvonly streams.
while (numAudioTracks > 0 || numVideoTracks > 0) {
if (numAudioTracks > 0) {
this._createTransceiver('audio');
numAudioTracks--;
}
if (numVideoTracks > 0) {
this._createTransceiver('video');
numVideoTracks--;
}
}
// reorder tracks
var transceivers = sortTracks(this.transceivers);
var sdp = SDPUtils.writeSessionBoilerplate();
transceivers.forEach(function(transceiver, sdpMLineIndex) {
// For each track, create an ice gatherer, ice transport,
// dtls transport, potentially rtpsender and rtpreceiver.
var track = transceiver.track;
var kind = transceiver.kind;
var mid = SDPUtils.generateIdentifier();
transceiver.mid = mid;
if (!transceiver.iceGatherer) {
transceiver.iceGatherer = self.usingBundle && sdpMLineIndex > 0 ?
transceivers[0].iceGatherer :
self._createIceGatherer(mid, sdpMLineIndex);
}
var localCapabilities = window.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';
}
});
// 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
};
}
}
if (transceiver.wantReceive) {
transceiver.rtpReceiver = new window.RTCRtpReceiver(
transceiver.dtlsTransport,
kind
);
}
transceiver.localCapabilities = localCapabilities;
transceiver.sendEncodingParameters = sendEncodingParameters;
});
// 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';
transceivers.forEach(function(transceiver, sdpMLineIndex) {
sdp += SDPUtils.writeMediaSection(transceiver,
transceiver.localCapabilities, 'offer', transceiver.stream);
sdp += 'a=rtcp-rsize\r\n';
});
this._pendingOffer = transceivers;
var desc = new window.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 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, sdpMLineIndex) {
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;
}
// FIXME: look at direction.
if (transceiver.stream) {
var localTrack;
if (transceiver.kind === 'audio') {
localTrack = transceiver.stream.getAudioTracks()[0];
} else if (transceiver.kind === 'video') {
localTrack = transceiver.stream.getVideoTracks()[0];
}
if (localTrack) {
// add RTX
if (edgeVersion >= 15019 && transceiver.kind === 'video') {
transceiver.sendEncodingParameters[0].rtx = {
ssrc: (2 * sdpMLineIndex + 2) * 1001 + 1
};
}
}
}
// Calculate intersection of capabilities.
var commonCapabilities = 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', transceiver.stream);
if (transceiver.rtcpParameters &&
transceiver.rtcpParameters.reducedSize) {
sdp += 'a=rtcp-rsize\r\n';
}
});
var desc = new window.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 &&
!(cand.component === '1' || 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}],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 utils = require('../utils');
var firefoxShim = {
shimOnTrack: function(window) {
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(window) {
// 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(window) {
var browserDetails = utils.detectBrowser(window);
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 window.mozRTCPeerConnection(pcConfig, pcConstraints);
};
window.RTCPeerConnection.prototype =
window.mozRTCPeerConnection.prototype;
// wrap static methods. Currently just generateCertificate.
if (window.mozRTCPeerConnection.generateCertificate) {
Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
get: function() {
return window.mozRTCPeerConnection.generateCertificate;
}
});
}
window.RTCSessionDescription = window.mozRTCSessionDescription;
window.RTCIceCandidate = window.mozRTCIceCandidate;
}
// shim away need for obsolete RTCIceCandidate/RTCSessionDescription.
['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
.forEach(function(method) {
var nativeMethod = window.RTCPeerConnection.prototype[method];
window.RTCPeerConnection.prototype[method] = function() {
arguments[0] = new ((method === 'addIceCandidate') ?
window.RTCIceCandidate :
window.RTCSessionDescription)(arguments[0]);
return nativeMethod.apply(this, arguments);
};
});
// support for addIceCandidate(null or undefined)
var nativeAddIceCandidate =
window.RTCPeerConnection.prototype.addIceCandidate;
window.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 = window.RTCPeerConnection.prototype.getStats;
window.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":101,"./getusermedia":99}],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.
*/
/* eslint-env node */
'use strict';
var utils = require('../utils');
var logging = utils.log;
// Expose public methods.
module.exports = function(window) {
var browserDetails = utils.detectBrowser(window);
var navigator = window && window.navigator;
var MediaStreamTrack = window && window.MediaStreamTrack;
var shimError_ = function(e) {
return {
name: {
InternalError: 'NotReadableError',
NotSupportedError: 'TypeError',
PermissionDeniedError: 'NotAllowedError',
SecurityError: '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));
});
};
}
if (!(browserDetails.version > 55 &&
'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) {
var remap = function(obj, a, b) {
if (a in obj && !(b in obj)) {
obj[b] = obj[a];
delete obj[a];
}
};
var nativeGetUserMedia = navigator.mediaDevices.getUserMedia.
bind(navigator.mediaDevices);
navigator.mediaDevices.getUserMedia = function(c) {
if (typeof c === 'object' && typeof c.audio === 'object') {
c = JSON.parse(JSON.stringify(c));
remap(c.audio, 'autoGainControl', 'mozAutoGainControl');
remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression');
}
return nativeGetUserMedia(c);
};
if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) {
var nativeGetSettings = MediaStreamTrack.prototype.getSettings;
MediaStreamTrack.prototype.getSettings = function() {
var obj = nativeGetSettings.apply(this, arguments);
remap(obj, 'mozAutoGainControl', 'autoGainControl');
remap(obj, 'mozNoiseSuppression', 'noiseSuppression');
return obj;
};
}
if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) {
var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints;
MediaStreamTrack.prototype.applyConstraints = function(c) {
if (this.kind === 'audio' && typeof c === 'object') {
c = JSON.parse(JSON.stringify(c));
remap(c, 'autoGainControl', 'mozAutoGainControl');
remap(c, 'noiseSuppression', 'mozNoiseSuppression');
}
return nativeApplyConstraints.apply(this, [c]);
};
}
}
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":101}],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.
*/
'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() { },
shimAddStream: function(window) {
if (typeof window === 'object' && window.RTCPeerConnection &&
!('addStream' in window.RTCPeerConnection.prototype)) {
window.RTCPeerConnection.prototype.addStream = function(stream) {
var self = this;
stream.getTracks().forEach(function(track) {
self.addTrack(track, stream);
});
};
}
},
shimOnAddStream: function(window) {
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));
}
});
}
},
shimCallbacksAPI: function(window) {
if (typeof window !== 'object' || !window.RTCPeerConnection) {
return;
}
var prototype = window.RTCPeerConnection.prototype;
var createOffer = prototype.createOffer;
var createAnswer = prototype.createAnswer;
var setLocalDescription = prototype.setLocalDescription;
var setRemoteDescription = prototype.setRemoteDescription;
var addIceCandidate = prototype.addIceCandidate;
prototype.createOffer = function(successCallback, failureCallback) {
var options = (arguments.length >= 2) ? arguments[2] : arguments[0];
var promise = createOffer.apply(this, [options]);
if (!failureCallback) {
return promise;
}
promise.then(successCallback, failureCallback);
return Promise.resolve();
};
prototype.createAnswer = function(successCallback, failureCallback) {
var options = (arguments.length >= 2) ? arguments[2] : arguments[0];
var promise = createAnswer.apply(this, [options]);
if (!failureCallback) {
return promise;
}
promise.then(successCallback, failureCallback);
return Promise.resolve();
};
var withCallback = function(description, successCallback, failureCallback) {
var promise = setLocalDescription.apply(this, [description]);
if (!failureCallback) {
return promise;
}
promise.then(successCallback, failureCallback);
return Promise.resolve();
};
prototype.setLocalDescription = withCallback;
withCallback = function(description, successCallback, failureCallback) {
var promise = setRemoteDescription.apply(this, [description]);
if (!failureCallback) {
return promise;
}
promise.then(successCallback, failureCallback);
return Promise.resolve();
};
prototype.setRemoteDescription = withCallback;
withCallback = function(candidate, successCallback, failureCallback) {
var promise = addIceCandidate.apply(this, [candidate]);
if (!failureCallback) {
return promise;
}
promise.then(successCallback, failureCallback);
return Promise.resolve();
};
prototype.addIceCandidate = withCallback;
},
shimGetUserMedia: function(window) {
var navigator = window && window.navigator;
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 = {
shimCallbacksAPI: safariShim.shimCallbacksAPI,
shimAddStream: safariShim.shimAddStream,
shimOnAddStream: safariShim.shimOnAddStream,
shimGetUserMedia: safariShim.shimGetUserMedia
// TODO
// shimPeerConnection: safariShim.shimPeerConnection
};
},{}],101:[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(window) {
var navigator = window && window.navigator;
// 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(window) {
var URL = window && window.URL;
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 = window.HTMLMediaElement.prototype.setAttribute;
window.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,
extractVersion: utils.extractVersion,
shimCreateObjectURL: utils.shimCreateObjectURL,
detectBrowser: utils.detectBrowser.bind(utils)
};
},{}],102:[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);
},{}],103:[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));
},{}],104:[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;
},{}],105:[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":106}],106:[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(wsUri) {
this.wsUri = wsUri;
this.openVidu = new OpenViduInternal_1.OpenViduInternal(wsUri);
}
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":111,"./Publisher":107,"./Session":108,"webrtc-adapter":91}],107:[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
}]);
});
}
}
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":103}],108:[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-removed-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();
}
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) {
var realEventName = '';
switch (eventName) {
case 'streamCreated':
realEventName = 'stream-added';
break;
case 'streamDestroyed':
realEventName = 'stream-removed';
break;
}
if (realEventName != '') {
this.session.addEventListener(realEventName, function (event) {
callback(event);
});
}
else {
this.session.addEventListener(eventName, function (event) {
callback(event);
});
}
};
Session.prototype.once = function (eventName, callback) {
var realEventName = '';
switch (eventName) {
case 'streamCreated':
realEventName = 'stream-added';
break;
case 'streamDestroyed':
realEventName = 'stream-removed';
break;
}
if (realEventName != '') {
this.session.addOnceEventListener(realEventName, function (event) {
callback(event);
});
}
else {
this.session.addOnceEventListener(eventName, function (event) {
callback(event);
});
}
};
Session.prototype.off = function (eventName, eventHandler) {
var realEventName = '';
switch (eventName) {
case 'streamCreated':
realEventName = 'stream-added';
break;
case 'streamDestroyed':
realEventName = 'stream-removed';
break;
}
if (realEventName != '') {
this.session.removeListener(realEventName, eventHandler);
}
else {
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("stream-added", function (streamEvent) {
callback(streamEvent.stream);
});
};
Session.prototype.onStreamDestroyed = function (callback) {
this.session.addEventListener("stream-removed", 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":109,"wolfy87-eventemitter":103}],109:[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":103}],110:[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":113}],111:[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(wsUri) {
this.wsUri = wsUri;
this.remoteStreams = [];
if (this.wsUri.charAt(wsUri.length - 1) != '/') {
this.wsUri += '/';
}
this.checkNgrokUri();
this.wsUri += 'room';
}
OpenViduInternal.prototype.checkNgrokUri = function () {
if (this.wsUri.indexOf(".ngrok.io") !== -1) {
// OpenVidu server URL referes to a ngrok IP: secure wss protocol and delete port of URL
this.wsUri = this.wsUri.replace("ws://", "wss://");
var regex = /\.ngrok\.io:\d+/;
this.wsUri = this.wsUri.replace(regex, ".ngrok.io");
}
else if (this.wsUri.indexOf("localhost") !== -1) {
// OpenVidu server URL referes to localhost IP
}
};
/* 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.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":112,"./Stream":113,"kurento-jsonrpc":14}],112:[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);
}
/* 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('stream-added', [{ 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('stream-added', [{ 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('stream-removed', [{
stream: streams[key],
preventDefault: function () { _this.ee.removeEvent('stream-removed-default'); }
}]);
this.ee.emitEvent('stream-removed-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":110,"wolfy87-eventemitter":103}],113:[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":103}],114:[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;
}
},{}],115:[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; };
},{}]},{},[105])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Vzci9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvYnJvd3Nlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvZGVidWcuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvZnJlZWljZS9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9mcmVlaWNlL3N0dW4uanNvbiIsIi4uLy4uL25vZGVfbW9kdWxlcy9mcmVlaWNlL3R1cm4uanNvbiIsIi4uLy4uL25vZGVfbW9kdWxlcy9oYXJrL2hhcmsuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvaW5oZXJpdHMvaW5oZXJpdHNfYnJvd3Nlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9qc29uMy9saWIvanNvbjMuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMva3VyZW50by1qc29ucnBjL2xpYi9NYXBwZXIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMva3VyZW50by1qc29ucnBjL2xpYi9jbGllbnRzL2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2t1cmVudG8tanNvbnJwYy9saWIvY2xpZW50cy9qc29ucnBjY2xpZW50LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2t1cmVudG8tanNvbnJwYy9saWIvY2xpZW50cy90cmFuc3BvcnRzL2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2t1cmVudG8tanNvbnJwYy9saWIvY2xpZW50cy90cmFuc3BvcnRzL3dlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb24uanMiLCIuLi8uLi9ub2RlX21vZHVsZXMva3VyZW50by1qc29ucnBjL2xpYi9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9rdXJlbnRvLWpzb25ycGMvbGliL3BhY2tlcnMvSnNvblJQQy5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9rdXJlbnRvLWpzb25ycGMvbGliL3BhY2tlcnMvWG1sUlBDLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2t1cmVudG8tanNvbnJwYy9saWIvcGFja2Vycy9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9rdXJlbnRvLXV0aWxzL2xpYi9XZWJSdGNQZWVyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2t1cmVudG8tdXRpbHMvbGliL2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL21lcmdlL21lcmdlLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL21zL2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL25vcm1hbGljZS9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9yZXF1aXJlcy1wb3J0L2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC10cmFuc2Zvcm0vbGliL2dyYW1tYXIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc2RwLXRyYW5zZm9ybS9saWIvaW5kZXguanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc2RwLXRyYW5zZm9ybS9saWIvcGFyc2VyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC10cmFuc2Zvcm0vbGliL3dyaXRlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNsYXRvci9saWIvYXJyYXktZXF1YWxzLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC10cmFuc2xhdG9yL2xpYi9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNsYXRvci9saWIvaW50ZXJvcC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNsYXRvci9saWIvdHJhbnNmb3JtLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC9zZHAuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvZW50cnkuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvZXZlbnQvY2xvc2UuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvZXZlbnQvZW1pdHRlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9ldmVudC9ldmVudC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9ldmVudC9ldmVudHRhcmdldC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9ldmVudC90cmFucy1tZXNzYWdlLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL2ZhY2FkZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9pZnJhbWUtYm9vdHN0cmFwLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL2luZm8tYWpheC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9pbmZvLWlmcmFtZS1yZWNlaXZlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9pbmZvLWlmcmFtZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9pbmZvLXJlY2VpdmVyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL2xvY2F0aW9uLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL21haW4uanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvc2hpbXMuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0LWxpc3QuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L2Jyb3dzZXIvYWJzdHJhY3QteGhyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9icm93c2VyL2V2ZW50c291cmNlLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9icm93c2VyL3dlYnNvY2tldC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi90cmFuc3BvcnQvZXZlbnRzb3VyY2UuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L2h0bWxmaWxlLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9pZnJhbWUuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L2pzb25wLXBvbGxpbmcuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L2xpYi9hamF4LWJhc2VkLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9saWIvYnVmZmVyZWQtc2VuZGVyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9saWIvaWZyYW1lLXdyYXAuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L2xpYi9wb2xsaW5nLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9saWIvc2VuZGVyLXJlY2VpdmVyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9yZWNlaXZlci9ldmVudHNvdXJjZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi90cmFuc3BvcnQvcmVjZWl2ZXIvaHRtbGZpbGUuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3JlY2VpdmVyL2pzb25wLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9yZWNlaXZlci94aHIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3NlbmRlci9qc29ucC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi90cmFuc3BvcnQvc2VuZGVyL3hkci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi90cmFuc3BvcnQvc2VuZGVyL3hoci1jb3JzLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9zZW5kZXIveGhyLWZha2UuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3NlbmRlci94aHItbG9jYWwuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3dlYnNvY2tldC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi90cmFuc3BvcnQveGRyLXBvbGxpbmcuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3hkci1zdHJlYW1pbmcuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3hoci1wb2xsaW5nLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC94aHItc3RyZWFtaW5nLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3V0aWxzL2Jyb3dzZXItY3J5cHRvLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3V0aWxzL2Jyb3dzZXIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdXRpbHMvZXNjYXBlLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3V0aWxzL2V2ZW50LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3V0aWxzL2lmcmFtZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi91dGlscy9sb2cuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdXRpbHMvb2JqZWN0LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3V0aWxzL3JhbmRvbS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi91dGlscy90cmFuc3BvcnQuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdXRpbHMvdXJsLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3ZlcnNpb24uanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvdWEtcGFyc2VyLWpzL3NyYy91YS1wYXJzZXIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvdXJsLXBhcnNlL2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3VybC1wYXJzZS9ub2RlX21vZHVsZXMvcXVlcnlzdHJpbmdpZnkvaW5kZXguanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvdXVpZC9ybmctYnJvd3Nlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy91dWlkL3V1aWQuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL2FkYXB0ZXJfY29yZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93ZWJydGMtYWRhcHRlci9zcmMvanMvYWRhcHRlcl9mYWN0b3J5LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dlYnJ0Yy1hZGFwdGVyL3NyYy9qcy9jaHJvbWUvY2hyb21lX3NoaW0uanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL2Nocm9tZS9nZXR1c2VybWVkaWEuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL2VkZ2UvZWRnZV9zaGltLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dlYnJ0Yy1hZGFwdGVyL3NyYy9qcy9lZGdlL2dldHVzZXJtZWRpYS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93ZWJydGMtYWRhcHRlci9zcmMvanMvZWRnZS9ydGNwZWVyY29ubmVjdGlvbl9zaGltLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dlYnJ0Yy1hZGFwdGVyL3NyYy9qcy9maXJlZm94L2ZpcmVmb3hfc2hpbS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93ZWJydGMtYWRhcHRlci9zcmMvanMvZmlyZWZveC9nZXR1c2VybWVkaWEuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL3NhZmFyaS9zYWZhcmlfc2hpbS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93ZWJydGMtYWRhcHRlci9zcmMvanMvdXRpbHMuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2lsZGVtaXR0ZXIvd2lsZGVtaXR0ZXIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd29sZnk4Ny1ldmVudGVtaXR0ZXIvRXZlbnRFbWl0dGVyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dzL2xpYi9icm93c2VyLmpzIiwiTWFpbi50cyIsIk9wZW5WaWR1LnRzIiwiUHVibGlzaGVyLnRzIiwiU2Vzc2lvbi50cyIsIlN1YnNjcmliZXIudHMiLCIuLi9PcGVuVmlkdUludGVybmFsL0Nvbm5lY3Rpb24udHMiLCIuLi9PcGVuVmlkdUludGVybmFsL09wZW5WaWR1SW50ZXJuYWwudHMiLCIuLi9PcGVuVmlkdUludGVybmFsL1Nlc3Npb25JbnRlcm5hbC50cyIsIi4uL09wZW5WaWR1SW50ZXJuYWwvU3RyZWFtLnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vdXNyL2xpYi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvZXZlbnRzL2V2ZW50cy5qcyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Vzci9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL3Byb2Nlc3MvYnJvd3Nlci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN6TEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEJBO0FBQ0E7O0FDREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ3ZCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN0NEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcnpCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNiQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6d0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDalFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ24zQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQzlsQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ1ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQzNCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUN0R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDakNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ3JFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDekZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUM3WEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDak1BO0FBQ0E7Ozs7O0FDREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ3pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUM3SUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUNsQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDdkZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ2pDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUN6REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDN0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQy9EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUN2RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDdkxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDdEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ25HQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDdkdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNsR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ3pDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ3pFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQzNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ2xCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ2xEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUMvQ0E7QUFDQTs7QUNEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDbjVCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN2WkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ3hFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNoQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ3ZMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDYkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzEyQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdE1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9JQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDM0NBLHVDQUFzQztBQUV0Qyx1RkFBdUY7QUFDdkYsd0NBQXdDO0FBRXhDLGlFQUFpRTtBQUNqRSxFQUFFLENBQUEsQ0FBQyxNQUFNLENBQUMsQ0FBQSxDQUFDO0lBQ1AsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLG1CQUFRLENBQUM7QUFDbEMs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RUFBRSxDQUFBO2dCQUM5QixDQUFDLENBQUMsQ0FBQTtZQUNOLENBQUM7UUFDTCxDQUFDO1FBRUQsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7WUFDbkIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUM1QixDQUFDO1FBRUQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsWUFBWSxHQUFHLElBQUksQ0FBQyxFQUFFLEdBQUcsWUFBWSxDQUFDLENBQUM7SUFDdEUsQ0FBQztJQUNMLGFBQUM7QUFBRCxDQXZsQkEsQUF1bEJDLElBQUE7QUF2bEJZLHdCQUFNOzs7QUNqRG5CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5U0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIvKipcbiAqIFRoaXMgaXMgdGhlIHdlYiBicm93c2VyIGltcGxlbWVudGF0aW9uIG9mIGBkZWJ1ZygpYC5cbiAqXG4gKiBFeHBvc2UgYGRlYnVnKClgIGFzIHRoZSBtb2R1bGUuXG4gKi9cblxuZXhwb3J0cyA9IG1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9kZWJ1ZycpO1xuZXhwb3J0cy5sb2cgPSBsb2c7XG5leHBvcnRzLmZvcm1hdEFyZ3MgPSBmb3JtYXRBcmdzO1xuZXhwb3J0cy5zYXZlID0gc2F2ZTtcbmV4cG9ydHMubG9hZCA9IGxvYWQ7XG5leHBvcnRzLnVzZUNvbG9ycyA9IHVzZUNvbG9ycztcbmV4cG9ydHMuc3RvcmFnZSA9ICd1bmRlZmluZWQnICE9IHR5cGVvZiBjaHJvbWVcbiAgICAgICAgICAgICAgICYmICd1bmRlZmluZWQnICE9IHR5cGVvZiBjaHJvbWUuc3RvcmFnZVxuICAgICAgICAgICAgICAgICAgPyBjaHJvbWUuc3RvcmFnZS5sb2NhbFxuICAgICAgICAgICAgICAgICAgOiBsb2NhbHN0b3JhZ2UoKTtcblxuLyoqXG4gKiBDb2xvcnMuXG4gKi9cblxuZXhwb3J0cy5jb2xvcnMgPSBbXG4gICdsaWdodHNlYWdyZWVuJyxcbiAgJ2ZvcmVzdGdyZWVuJyxcbiAgJ2dvbGRlbnJvZCcsXG4gICdkb2RnZXJibHVlJyxcbiAgJ2RhcmtvcmNoaWQnLFxuICAnY3JpbXNvbidcbl07XG5cbi8qKlxuICogQ3VycmVudGx5IG9ubHkgV2ViS2l0LWJhc2VkIFdlYiBJbnNwZWN0b3JzLCBGaXJlZm94ID49IHYzMSxcbiAqIGFuZCB0aGUgRmlyZWJ1ZyBleHRlbnNpb24gKGFueSBGaXJlZm94IHZlcnNpb24pIGFyZSBrbm93blxuICogdG8gc3VwcG9ydCBcIiVjXCIgQ1NTIGN1c3RvbWl6YXRpb25zLlxuICpcbiAqIFRPRE86IGFkZCBhIGBsb2NhbFN0b3JhZ2VgIHZhcmlhYmxlIHRvIGV4cGxpY2l0bHkgZW5hYmxlL2Rpc2FibGUgY29sb3JzXG4gKi9cblxuZnVuY3Rpb24gdXNlQ29sb3JzKCkge1xuICAvLyBOQjogSW4gYW4gRWxlY3Ryb24gcHJlbG9hZCBzY3JpcHQsIGRvY3VtZW50IHdpbGwgYmUgZGVmaW5lZCBidXQgbm90IGZ1bGx5XG4gIC8vIGluaXRpYWxpemVkLiBTaW5jZSB3ZSBrbm93IHdlJ3JlIGluIENocm9tZSwgd2UnbGwganVzdCBkZXRlY3QgdGhpcyBjYXNlXG4gIC8vIGV4cGxpY2l0bHlcbiAgaWYgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHdpbmRvdy5wcm9jZXNzICYmIHdpbmRvdy5wcm9jZXNzLnR5cGUgPT09ICdyZW5kZXJlcicpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8vIGlzIHdlYmtpdD8gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMTY0NTk2MDYvMzc2NzczXG4gIC8vIGRvY3VtZW50IGlzIHVuZGVmaW5lZCBpbiByZWFjdC1uYXRpdmU6IGh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9vay9yZWFjdC1uYXRpdmUvcHVsbC8xNjMyXG4gIHJldHVybiAodHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQgJiYgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlICYmIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZS5XZWJraXRBcHBlYXJhbmNlKSB8fFxuICAgIC8vIGlzIGZpcmVidWc/IGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzM5ODEyMC8zNzY3NzNcbiAgICAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LmNvbnNvbGUgJiYgKHdpbmRvdy5jb25zb2xlLmZpcmVidWcgfHwgKHdpbmRvdy5jb25zb2xlLmV4Y2VwdGlvbiAmJiB3aW5kb3cuY29uc29sZS50YWJsZSkpKSB8fFxuICAgIC8vIGlzIGZpcmVmb3ggPj0gdjMxP1xuICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvVG9vbHMvV2ViX0NvbnNvbGUjU3R5bGluZ19tZXNzYWdlc1xuICAgICh0eXBlb2YgbmF2aWdhdG9yICE9PSAndW5kZWZpbmVkJyAmJiBuYXZpZ2F0b3IudXNlckFnZW50ICYmIG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5tYXRjaCgvZmlyZWZveFxcLyhcXGQrKS8pICYmIHBhcnNlSW50KFJlZ0V4cC4kMSwgMTApID49IDMxKSB8fFxuICAgIC8vIGRvdWJsZSBjaGVjayB3ZWJraXQgaW4gdXNlckFnZW50IGp1c3QgaW4gY2FzZSB3ZSBhcmUgaW4gYSB3b3JrZXJcbiAgICAodHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudCAmJiBuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCkubWF0Y2goL2FwcGxld2Via2l0XFwvKFxcZCspLykpO1xufVxuXG4vKipcbiAqIE1hcCAlaiB0byBgSlNPTi5zdHJpbmdpZnkoKWAsIHNpbmNlIG5vIFdlYiBJbnNwZWN0b3JzIGRvIHRoYXQgYnkgZGVmYXVsdC5cbiAqL1xuXG5leHBvcnRzLmZvcm1hdHRlcnMuaiA9IGZ1bmN0aW9uKHYpIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodik7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIHJldHVybiAnW1VuZXhwZWN0ZWRKU09OUGFyc2VFcnJvcl06ICcgKyBlcnIubWVzc2FnZTtcbiAgfVxufTtcblxuXG4vKipcbiAqIENvbG9yaXplIGxvZyBhcmd1bWVudHMgaWYgZW5hYmxlZC5cbiAqXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbmZ1bmN0aW9uIGZvcm1hdEFyZ3MoYXJncykge1xuICB2YXIgdXNlQ29sb3JzID0gdGhpcy51c2VDb2xvcnM7XG5cbiAgYXJnc1swXSA9ICh1c2VDb2xvcnMgPyAnJWMnIDogJycpXG4gICAgKyB0aGlzLm5hbWVzcGFjZVxuICAgICsgKHVzZUNvbG9ycyA/ICcgJWMnIDogJyAnKVxuICAgICsgYXJnc1swXVxuICAgICsgKHVzZUNvbG9ycyA/ICclYyAnIDogJyAnKVxuICAgICsgJysnICsgZXhwb3J0cy5odW1hbml6ZSh0aGlzLmRpZmYpO1xuXG4gIGlmICghdXNlQ29sb3JzKSByZXR1cm47XG5cbiAgdmFyIGMgPSAnY29sb3I6ICcgKyB0aGlzLmNvbG9yO1xuICBhcmdzLnNwbGljZSgxLCAwLCBjLCAnY29sb3I6IGluaGVyaXQnKVxuXG4gIC8vIHRoZSBmaW5hbCBcIiVjXCIgaXMgc29tZXdoYXQgdHJpY2t5LCBiZWNhdXNlIHRoZXJlIGNvdWxkIGJlIG90aGVyXG4gIC8vIGFyZ3VtZW50cyBwYXNzZWQgZWl0aGVyIGJlZm9yZSBvciBhZnRlciB0aGUgJWMsIHNvIHdlIG5lZWQgdG9cbiAgLy8gZmlndXJlIG91dCB0aGUgY29ycmVjdCBpbmRleCB0byBpbnNlcnQgdGhlIENTUyBpbnRvXG4gIHZhciBpbmRleCA9IDA7XG4gIHZhciBsYXN0QyA9IDA7XG4gIGFyZ3NbMF0ucmVwbGFjZSgvJVthLXpBLVolXS9nLCBmdW5jdGlvbihtYXRjaCkge1xuICAgIGlmICgnJSUnID09PSBtYXRjaCkgcmV0dXJuO1xuICAgIGluZGV4Kys7XG4gICAgaWYgKCclYycgPT09IG1hdGNoKSB7XG4gICAgICAvLyB3ZSBvbmx5IGFyZSBpbnRlcmVzdGVkIGluIHRoZSAqbGFzdCogJWNcbiAgICAgIC8vICh0aGUgdXNlciBtYXkgaGF2ZSBwcm92aWRlZCB0aGVpciBvd24pXG4gICAgICBsYXN0QyA9IGluZGV4O1xuICAgIH1cbiAgfSk7XG5cbiAgYXJncy5zcGxpY2UobGFzdEMsIDAsIGMpO1xufVxuXG4vKipcbiAqIEludm9rZXMgYGNvbnNvbGUubG9nKClgIHdoZW4gYXZhaWxhYmxlLlxuICogTm8tb3Agd2hlbiBgY29uc29sZS5sb2dgIGlzIG5vdCBhIFwiZnVuY3Rpb25cIi5cbiAqXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbmZ1bmN0aW9uIGxvZygpIHtcbiAgLy8gdGhpcyBoYWNrZXJ5IGlzIHJlcXVpcmVkIGZvciBJRTgvOSwgd2hlcmVcbiAgLy8gdGhlIGBjb25zb2xlLmxvZ2AgZnVuY3Rpb24gZG9lc24ndCBoYXZlICdhcHBseSdcbiAgcmV0dXJuICdvYmplY3QnID09PSB0eXBlb2YgY29uc29sZVxuICAgICYmIGNvbnNvbGUubG9nXG4gICAgJiYgRnVuY3Rpb24ucHJvdG90eXBlLmFwcGx5LmNhbGwoY29uc29sZS5sb2csIGNvbnNvbGUsIGFyZ3VtZW50cyk7XG59XG5cbi8qKlxuICogU2F2ZSBgbmFtZXNwYWNlc2AuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWVzcGFjZXNcbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIHNhdmUobmFtZXNwYWNlcykge1xuICB0cnkge1xuICAgIGlmIChudWxsID09IG5hbWVzcGFjZXMpIHtcbiAgICAgIGV4cG9ydHMuc3RvcmFnZS5yZW1vdmVJdGVtKCdkZWJ1ZycpO1xuICAgIH0gZWxzZSB7XG4gICAgICBleHBvcnRzLnN0b3JhZ2UuZGVidWcgPSBuYW1lc3BhY2VzO1xuICAgIH1cbiAgfSBjYXRjaChlKSB7fVxufVxuXG4vKipcbiAqIExvYWQgYG5hbWVzcGFjZXNgLlxuICpcbiAqIEByZXR1cm4ge1N0cmluZ30gcmV0dXJucyB0aGUgcHJldmlvdXNseSBwZXJzaXN0ZWQgZGVidWcgbW9kZXNcbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIGxvYWQoKSB7XG4gIHZhciByO1xuICB0cnkge1xuICAgIHIgPSBleHBvcnRzLnN0b3JhZ2UuZGVidWc7XG4gIH0gY2F0Y2goZSkge31cblxuICAvLyBJZiBkZWJ1ZyBpc24ndCBzZXQgaW4gTFMsIGFuZCB3ZSdyZSBpbiBFbGVjdHJvbiwgdHJ5IHRvIGxvYWQgJERFQlVHXG4gIGlmICghciAmJiB0eXBlb2YgcHJvY2VzcyAhPT0gJ3VuZGVmaW5lZCcgJiYgJ2VudicgaW4gcHJvY2Vzcykge1xuICAgIHIgPSBwcm9jZXNzLmVudi5ERUJVRztcbiAgfVxuXG4gIHJldHVybiByO1xufVxuXG4vKipcbiAqIEVuYWJsZSBuYW1lc3BhY2VzIGxpc3RlZCBpbiBgbG9jYWxTdG9yYWdlLmRlYnVnYCBpbml0aWFsbHkuXG4gKi9cblxuZXhwb3J0cy5lbmFibGUobG9hZCgpKTtcblxuLyoqXG4gKiBMb2NhbHN0b3JhZ2UgYXR0ZW1wdHMgdG8gcmV0dXJuIHRoZSBsb2NhbHN0b3JhZ2UuXG4gKlxuICogVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSBzYWZhcmkgdGhyb3dzXG4gKiB3aGVuIGEgdXNlciBkaXNhYmxlcyBjb29raWVzL2xvY2Fsc3RvcmFnZVxuICogYW5kIHlvdSBhdHRlbXB0IHRvIGFjY2VzcyBpdC5cbiAqXG4gKiBAcmV0dXJuIHtMb2NhbFN0b3JhZ2V9XG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuXG5mdW5jdGlvbiBsb2NhbHN0b3JhZ2UoKSB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIHdpbmRvdy5sb2NhbFN0b3JhZ2U7XG4gIH0gY2F0Y2ggKGUpIHt9XG59XG4iLCJcbi8qKlxuICogVGhpcyBpcyB0aGUgY29tbW9uIGxvZ2ljIGZvciBib3RoIHRoZSBOb2RlLmpzIGFuZCB3ZWIgYnJvd3NlclxuICogaW1wbGVtZW50YXRpb25zIG9mIGBkZWJ1ZygpYC5cbiAqXG4gKiBFeHBvc2UgYGRlYnVnKClgIGFzIHRoZSBtb2R1bGUuXG4gKi9cblxuZXhwb3J0cyA9IG1vZHVsZS5leHBvcnRzID0gY3JlYXRlRGVidWcuZGVidWcgPSBjcmVhdGVEZWJ1Z1snZGVmYXVsdCddID0gY3JlYXRlRGVidWc7XG5leHBvcnRzLmNvZXJjZSA9IGNvZXJjZTtcbmV4cG9ydHMuZGlzYWJsZSA9IGRpc2FibGU7XG5leHBvcnRzLmVuYWJsZSA9IGVuYWJsZTtcbmV4cG9ydHMuZW5hYmxlZCA9IGVuYWJsZWQ7XG5leHBvcnRzLmh1bWFuaXplID0gcmVxdWlyZSgnbXMnKTtcblxuLyoqXG4gKiBUaGUgY3VycmVudGx5IGFjdGl2ZSBkZWJ1ZyBtb2RlIG5hbWVzLCBhbmQgbmFtZXMgdG8gc2tpcC5cbiAqL1xuXG5leHBvcnRzLm5hbWVzID0gW107XG5leHBvcnRzLnNraXBzID0gW107XG5cbi8qKlxuICogTWFwIG9mIHNwZWNpYWwgXCIlblwiIGhhbmRsaW5nIGZ1bmN0aW9ucywgZm9yIHRoZSBkZWJ1ZyBcImZvcm1hdFwiIGFyZ3VtZW50LlxuICpcbiAqIFZhbGlkIGtleSBuYW1lcyBhcmUgYSBzaW5nbGUsIGxvd2VyIG9yIHVwcGVyLWNhc2UgbGV0dGVyLCBpLmUuIFwiblwiIGFuZCBcIk5cIi5cbiAqL1xuXG5leHBvcnRzLmZvcm1hdHRlcnMgPSB7fTtcblxuLyoqXG4gKiBQcmV2aW91cyBsb2cgdGltZXN0YW1wLlxuICovXG5cbnZhciBwcmV2VGltZTtcblxuLyoqXG4gKiBTZWxlY3QgYSBjb2xvci5cbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lc3BhY2VcbiAqIEByZXR1cm4ge051bWJlcn1cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIHNlbGVjdENvbG9yKG5hbWVzcGFjZSkge1xuICB2YXIgaGFzaCA9IDAsIGk7XG5cbiAgZm9yIChpIGluIG5hbWVzcGFjZSkge1xuICAgIGhhc2ggID0gKChoYXNoIDw8IDUpIC0gaGFzaCkgKyBuYW1lc3BhY2UuY2hhckNvZGVBdChpKTtcbiAgICBoYXNoIHw9IDA7IC8vIENvbnZlcnQgdG8gMzJiaXQgaW50ZWdlclxuICB9XG5cbiAgcmV0dXJuIGV4cG9ydHMuY29sb3JzW01hdGguYWJzKGhhc2gpICUgZXhwb3J0cy5jb2xvcnMubGVuZ3RoXTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBkZWJ1Z2dlciB3aXRoIHRoZSBnaXZlbiBgbmFtZXNwYWNlYC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZXNwYWNlXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqIEBhcGkgcHVibGljXG4gKi9cblxuZnVuY3Rpb24gY3JlYXRlRGVidWcobmFtZXNwYWNlKSB7XG5cbiAgZnVuY3Rpb24gZGVidWcoKSB7XG4gICAgLy8gZGlzYWJsZWQ/XG4gICAgaWYgKCFkZWJ1Zy5lbmFibGVkKSByZXR1cm47XG5cbiAgICB2YXIgc2VsZiA9IGRlYnVnO1xuXG4gICAgLy8gc2V0IGBkaWZmYCB0aW1lc3RhbXBcbiAgICB2YXIgY3VyciA9ICtuZXcgRGF0ZSgpO1xuICAgIHZhciBtcyA9IGN1cnIgLSAocHJldlRpbWUgfHwgY3Vycik7XG4gICAgc2VsZi5kaWZmID0gbXM7XG4gICAgc2VsZi5wcmV2ID0gcHJldlRpbWU7XG4gICAgc2VsZi5jdXJyID0gY3VycjtcbiAgICBwcmV2VGltZSA9IGN1cnI7XG5cbiAgICAvLyB0dXJuIHRoZSBgYXJndW1lbnRzYCBpbnRvIGEgcHJvcGVyIEFycmF5XG4gICAgdmFyIGFyZ3MgPSBuZXcgQXJyYXkoYXJndW1lbnRzLmxlbmd0aCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBhcmdzW2ldID0gYXJndW1lbnRzW2ldO1xuICAgIH1cblxuICAgIGFyZ3NbMF0gPSBleHBvcnRzLmNvZXJjZShhcmdzWzBdKTtcblxuICAgIGlmICgnc3RyaW5nJyAhPT0gdHlwZW9mIGFyZ3NbMF0pIHtcbiAgICAgIC8vIGFueXRoaW5nIGVsc2UgbGV0J3MgaW5zcGVjdCB3aXRoICVPXG4gICAgICBhcmdzLnVuc2hpZnQoJyVPJyk7XG4gICAgfVxuXG4gICAgLy8gYXBwbHkgYW55IGBmb3JtYXR0ZXJzYCB0cmFuc2Zvcm1hdGlvbnNcbiAgICB2YXIgaW5kZXggPSAwO1xuICAgIGFyZ3NbMF0gPSBhcmdzWzBdLnJlcGxhY2UoLyUoW2EtekEtWiVdKS9nLCBmdW5jdGlvbihtYXRjaCwgZm9ybWF0KSB7XG4gICAgICAvLyBpZiB3ZSBlbmNvdW50ZXIgYW4gZXNjYXBlZCAlIHRoZW4gZG9uJ3QgaW5jcmVhc2UgdGhlIGFycmF5IGluZGV4XG4gICAgICBpZiAobWF0Y2ggPT09ICclJScpIHJldHVybiBtYXRjaDtcbiAgICAgIGluZGV4Kys7XG4gICAgICB2YXIgZm9ybWF0dGVyID0gZXhwb3J0cy5mb3JtYXR0ZXJzW2Zvcm1hdF07XG4gICAgICBpZiAoJ2Z1bmN0aW9uJyA9PT0gdHlwZW9mIGZvcm1hdHRlcikge1xuICAgICAgICB2YXIgdmFsID0gYXJnc1tpbmRleF07XG4gICAgICAgIG1hdGNoID0gZm9ybWF0dGVyLmNhbGwoc2VsZiwgdmFsKTtcblxuICAgICAgICAvLyBub3cgd2UgbmVlZCB0byByZW1vdmUgYGFyZ3NbaW5kZXhdYCBzaW5jZSBpdCdzIGlubGluZWQgaW4gdGhlIGBmb3JtYXRgXG4gICAgICAgIGFyZ3Muc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgaW5kZXgtLTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBtYXRjaDtcbiAgICB9KTtcblxuICAgIC8vIGFwcGx5IGVudi1zcGVjaWZpYyBmb3JtYXR0aW5nIChjb2xvcnMsIGV0Yy4pXG4gICAgZXhwb3J0cy5mb3JtYXRBcmdzLmNhbGwoc2VsZiwgYXJncyk7XG5cbiAgICB2YXIgbG9nRm4gPSBkZWJ1Zy5sb2cgfHwgZXhwb3J0cy5sb2cgfHwgY29uc29sZS5sb2cuYmluZChjb25zb2xlKTtcbiAgICBsb2dGbi5hcHBseShzZWxmLCBhcmdzKTtcbiAgfVxuXG4gIGRlYnVnLm5hbWVzcGFjZSA9IG5hbWVzcGFjZTtcbiAgZGVidWcuZW5hYmxlZCA9IGV4cG9ydHMuZW5hYmxlZChuYW1lc3BhY2UpO1xuICBkZWJ1Zy51c2VDb2xvcnMgPSBleHBvcnRzLnVzZUNvbG9ycygpO1xuICBkZWJ1Zy5jb2xvciA9IHNlbGVjdENvbG9yKG5hbWVzcGFjZSk7XG5cbiAgLy8gZW52LXNwZWNpZmljIGluaXRpYWxpemF0aW9uIGxvZ2ljIGZvciBkZWJ1ZyBpbnN0YW5jZXNcbiAgaWYgKCdmdW5jdGlvbicgPT09IHR5cGVvZiBleHBvcnRzLmluaXQpIHtcbiAgICBleHBvcnRzLmluaXQoZGVidWcpO1xuICB9XG5cbiAgcmV0dXJuIGRlYnVnO1xufVxuXG4vKipcbiAqIEVuYWJsZXMgYSBkZWJ1ZyBtb2RlIGJ5IG5hbWVzcGFjZXMuIFRoaXMgY2FuIGluY2x1ZGUgbW9kZXNcbiAqIHNlcGFyYXRlZCBieSBhIGNvbG9uIGFuZCB3aWxkY2FyZHMuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWVzcGFjZXNcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuZnVuY3Rpb24gZW5hYmxlKG5hbWVzcGFjZXMpIHtcbiAgZXhwb3J0cy5zYXZlKG5hbWVzcGFjZXMpO1xuXG4gIGV4cG9ydHMubmFtZXMgPSBbXTtcbiAgZXhwb3J0cy5za2lwcyA9IFtdO1xuXG4gIHZhciBzcGxpdCA9ICh0eXBlb2YgbmFtZXNwYWNlcyA9PT0gJ3N0cmluZycgPyBuYW1lc3BhY2VzIDogJycpLnNwbGl0KC9bXFxzLF0rLyk7XG4gIHZhciBsZW4gPSBzcGxpdC5sZW5ndGg7XG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgIGlmICghc3BsaXRbaV0pIGNvbnRpbnVlOyAvLyBpZ25vcmUgZW1wdHkgc3RyaW5nc1xuICAgIG5hbWVzcGFjZXMgPSBzcGxpdFtpXS5yZXBsYWNlKC9cXCovZywgJy4qPycpO1xuICAgIGlmIChuYW1lc3BhY2VzWzBdID09PSAnLScpIHtcbiAgICAgIGV4cG9ydHMuc2tpcHMucHVzaChuZXcgUmVnRXhwKCdeJyArIG5hbWVzcGFjZXMuc3Vic3RyKDEpICsgJyQnKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGV4cG9ydHMubmFtZXMucHVzaChuZXcgUmVnRXhwKCdeJyArIG5hbWVzcGFjZXMgKyAnJCcpKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBEaXNhYmxlIGRlYnVnIG91dHB1dC5cbiAqXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbmZ1bmN0aW9uIGRpc2FibGUoKSB7XG4gIGV4cG9ydHMuZW5hYmxlKCcnKTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgdGhlIGdpdmVuIG1vZGUgbmFtZSBpcyBlbmFibGVkLCBmYWxzZSBvdGhlcndpc2UuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWVcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbmZ1bmN0aW9uIGVuYWJsZWQobmFtZSkge1xuICB2YXIgaSwgbGVuO1xuICBmb3IgKGkgPSAwLCBsZW4gPSBleHBvcnRzLnNraXBzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgaWYgKGV4cG9ydHMuc2tpcHNbaV0udGVzdChuYW1lKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuICBmb3IgKGkgPSAwLCBsZW4gPSBleHBvcnRzLm5hbWVzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgaWYgKGV4cG9ydHMubmFtZXNbaV0udGVzdChuYW1lKSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBDb2VyY2UgYHZhbGAuXG4gKlxuICogQHBhcmFtIHtNaXhlZH0gdmFsXG4gKiBAcmV0dXJuIHtNaXhlZH1cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIGNvZXJjZSh2YWwpIHtcbiAgaWYgKHZhbCBpbnN0YW5jZW9mIEVycm9yKSByZXR1cm4gdmFsLnN0YWNrIHx8IHZhbC5tZXNzYWdlO1xuICByZXR1cm4gdmFsO1xufVxuIiwiLyoganNoaW50IG5vZGU6IHRydWUgKi9cbid1c2Ugc3RyaWN0JztcblxudmFyIG5vcm1hbGljZSA9IHJlcXVpcmUoJ25vcm1hbGljZScpO1xuXG4vKipcbiAgIyBmcmVlaWNlXG5cbiAgVGhlIGBmcmVlaWNlYCBtb2R1bGUgaXMgYSBzaW1wbGUgd2F5IG9mIGdldHRpbmcgcmFuZG9tIFNUVU4gb3IgVFVSTiBzZXJ2ZXJcbiAgZm9yIHlvdXIgV2ViUlRDIGFwcGxpY2F0aW9uLiAgVGhlIGxpc3Qgb2Ygc2VydmVycyAoanVzdCBTVFVOIGF0IHRoaXMgc3RhZ2UpXG4gIHdlcmUgc291cmNlZCBmcm9tIHRoaXMgW2dpc3RdKGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL3p6aXVuaS8zNzQxOTMzKS5cblxuICAjIyBFeGFtcGxlIFVzZVxuXG4gIFRoZSBmb2xsb3dpbmcgZGVtb25zdHJhdGVzIGhvdyB5b3UgY2FuIHVzZSBgZnJlZWljZWAgd2l0aFxuICBbcnRjLXF1aWNrY29ubmVjdF0oaHR0cHM6Ly9naXRodWIuY29tL3J0Yy1pby9ydGMtcXVpY2tjb25uZWN0KTpcblxuICA8PDwgZXhhbXBsZXMvcXVpY2tjb25uZWN0LmpzXG5cbiAgQXMgdGhlIGBmcmVlaWNlYCBtb2R1bGUgZ2VuZXJhdGVzIGljZSBzZXJ2ZXJzIGluIGEgbGlzdCBjb21wbGlhbnQgd2l0aCB0aGVcbiAgV2ViUlRDIHNwZWMgeW91IHdpbGwgYmUgYWJsZSB0byB1c2UgaXQgd2l0aCByYXcgYFJUQ1BlZXJDb25uZWN0aW9uYFxuICBjb25zdHJ1Y3RvcnMgYW5kIG90aGVyIFdlYlJUQyBsaWJyYXJpZXMuXG5cbiAgIyMgSGV5LCBkb24ndCB1c2UgbXkgU1RVTi9UVVJOIHNlcnZlciFcblxuICBJZiBmb3Igc29tZSByZWFzb24geW91ciBmcmVlIFNUVU4gb3IgVFVSTiBzZXJ2ZXIgZW5kcyB1cCBpbiB0aGVcbiAgbGlzdCBvZiBzZXJ2ZXJzIChbc3R1bl0oaHR0cHM6Ly9naXRodWIuY29tL0RhbW9uT2VobG1hbi9mcmVlaWNlL2Jsb2IvbWFzdGVyL3N0dW4uanNvbikgb3JcbiAgW3R1cm5dKGh0dHBzOi8vZ2l0aHViLmNvbS9EYW1vbk9laGxtYW4vZnJlZWljZS9ibG9iL21hc3Rlci90dXJuLmpzb24pKVxuICB0aGF0IGlzIHVzZWQgaW4gdGhpcyBtb2R1bGUsIHlvdSBjYW4gZmVlbFxuICBmcmVlIHRvIG9wZW4gYW4gaXNzdWUgb24gdGhpcyByZXBvc2l0b3J5IGFuZCB0aG9zZSBzZXJ2ZXJzIHdpbGwgYmUgcmVtb3ZlZFxuICB3aXRoaW4gMjQgaG91cnMgKG9yIHNvb25lcikuICBUaGlzIGlzIHRoZSBxdWlja2VzdCBhbmQgcHJvYmFibHkgdGhlIG1vc3RcbiAgcG9saXRlIHdheSB0byBoYXZlIHNvbWV0aGluZyByZW1vdmVkIChhbmQgcHJvdmlkZXMgdXMgc29tZSB2aXNpYmlsaXR5XG4gIGlmIHNvbWVvbmUgb3BlbnMgYSBwdWxsIHJlcXVlc3QgcmVxdWVzdGluZyB0aGF0IGEgc2VydmVyIGlzIGFkZGVkKS5cblxuICAjIyBQbGVhc2UgYWRkIG15IHNlcnZlciFcblxuICBJZiB5b3UgaGF2ZSBhIHNlcnZlciB0aGF0IHlvdSB3aXNoIHRvIGFkZCB0byB0aGUgbGlzdCwgdGhhdCdzIGF3ZXNvbWUhIEknbVxuICBzdXJlIEkgc3BlYWsgb24gYmVoYWxmIG9mIGEgd2hvbGUgcGlsZSBvZiBXZWJSVEMgZGV2ZWxvcGVycyB3aG8gc2F5IHRoYW5rcy5cbiAgVG8gZ2V0IGl0IGludG8gdGhlIGxpc3QsIGZlZWwgZnJlZSB0byBlaXRoZXIgb3BlbiBhIHB1bGwgcmVxdWVzdCBvciBpZiB5b3VcbiAgZmluZCB0aGF0IHByb2Nlc3MgYSBiaXQgZGF1bnRpbmcgdGhlbiBqdXN0IGNyZWF0ZSBhbiBpc3N1ZSByZXF1ZXN0aW5nXG4gIHRoZSBhZGRpdGlvbiBvZiB0aGUgc2VydmVyIChtYWtlIHN1cmUgeW91IHByb3ZpZGUgYWxsIHRoZSBkZXRhaWxzLCBhbmQgaWZcbiAgeW91IGhhdmUgYSBUZXJtcyBvZiBTZXJ2aWNlIHRoZW4gaW5jbHVkaW5nIHRoYXQgaW4gdGhlIFBSL2lzc3VlIHdvdWxkIGJlXG4gIGF3ZXNvbWUpLlxuXG4gICMjIEkga25vdyBvZiBhIGZyZWUgc2VydmVyLCBjYW4gSSBhZGQgaXQ/XG5cbiAgU3VyZSwgaWYgeW91IGRvIHlvdXIgaG9tZXdvcmsgYW5kIG1ha2Ugc3VyZSBpdCBpcyBvayB0byB1c2UgKEknbSBjdXJyZW50bHlcbiAgaW4gdGhlIHByb2Nlc3Mgb2YgcmV2aWV3aW5nIHRoZSB0ZXJtcyBvZiB0aG9zZSBTVFVOIHNlcnZlcnMgaW5jbHVkZWQgZnJvbVxuICB0aGUgb3JpZ2luYWwgbGlzdCkuICBJZiBpdCdzIG9rIHRvIGdvLCB0aGVuIHBsZWFzZSBzZWUgdGhlIHByZXZpb3VzIGVudHJ5XG4gIGZvciBob3cgdG8gYWRkIGl0LlxuXG4gICMjIEN1cnJlbnQgTGlzdCBvZiBTZXJ2ZXJzXG5cbiAgKiBjdXJyZW50IGFzIGF0IHRoZSB0aW1lIG9mIGxhc3QgYFJFQURNRS5tZGAgZmlsZSBnZW5lcmF0aW9uXG5cbiAgIyMjIFNUVU5cblxuICA8PDwgc3R1bi5qc29uXG5cbiAgIyMjIFRVUk5cblxuICA8PDwgdHVybi5qc29uXG5cbioqL1xuXG52YXIgZnJlZWljZSA9IG1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24ob3B0cykge1xuICAvLyBpZiBhIGxpc3Qgb2Ygc2VydmVycyBoYXMgYmVlbiBwcm92aWRlZCwgdGhlbiB1c2UgaXQgaW5zdGVhZCBvZiBkZWZhdWx0c1xuICB2YXIgc2VydmVycyA9IHtcbiAgICBzdHVuOiAob3B0cyB8fCB7fSkuc3R1biB8fCByZXF1aXJlKCcuL3N0dW4uanNvbicpLFxuICAgIHR1cm46IChvcHRzIHx8IHt9KS50dXJuIHx8IHJlcXVpcmUoJy4vdHVybi5qc29uJylcbiAgfTtcblxuICB2YXIgc3R1bkNvdW50ID0gKG9wdHMgfHwge30pLnN0dW5Db3VudCB8fCAyO1xuICB2YXIgdHVybkNvdW50ID0gKG9wdHMgfHwge30pLnR1cm5Db3VudCB8fCAwO1xuICB2YXIgc2VsZWN0ZWQ7XG5cbiAgZnVuY3Rpb24gZ2V0U2VydmVycyh0eXBlLCBjb3VudCkge1xuICAgIHZhciBvdXQgPSBbXTtcbiAgICB2YXIgaW5wdXQgPSBbXS5jb25jYXQoc2VydmVyc1t0eXBlXSk7XG4gICAgdmFyIGlkeDtcblxuICAgIHdoaWxlIChpbnB1dC5sZW5ndGggJiYgb3V0Lmxlbmd0aCA8IGNvdW50KSB7XG4gICAgICBpZHggPSAoTWF0aC5yYW5kb20oKSAqIGlucHV0Lmxlbmd0aCkgfCAwO1xuICAgICAgb3V0ID0gb3V0LmNvbmNhdChpbnB1dC5zcGxpY2UoaWR4LCAxKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG91dC5tYXAoZnVuY3Rpb24odXJsKSB7XG4gICAgICAgIC8vSWYgaXQncyBhIG5vdCBhIHN0cmluZywgZG9uJ3QgdHJ5IHRvIFwibm9ybWFsaWNlXCIgaXQgb3RoZXJ3aXNlIHVzaW5nIHR5cGU6dXJsIHdpbGwgc2NyZXcgaXQgdXBcbiAgICAgICAgaWYgKCh0eXBlb2YgdXJsICE9PSAnc3RyaW5nJykgJiYgKCEgKHVybCBpbnN0YW5jZW9mIFN0cmluZykpKSB7XG4gICAgICAgICAgICByZXR1cm4gdXJsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGljZSh0eXBlICsgJzonICsgdXJsKTtcbiAgICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLy8gYWRkIHN0dW4gc2VydmVyc1xuICBzZWxlY3RlZCA9IFtdLmNvbmNhdChnZXRTZXJ2ZXJzKCdzdHVuJywgc3R1bkNvdW50KSk7XG5cbiAgaWYgKHR1cm5Db3VudCkge1xuICAgIHNlbGVjdGVkID0gc2VsZWN0ZWQuY29uY2F0KGdldFNlcnZlcnMoJ3R1cm4nLCB0dXJuQ291bnQpKTtcbiAgfVxuXG4gIHJldHVybiBzZWxlY3RlZDtcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz1bXG4gIFwic3R1bi5sLmdvb2dsZS5jb206MTkzMDJcIixcbiAgXCJzdHVuMS5sLmdvb2dsZS5jb206MTkzMDJcIixcbiAgXCJzdHVuMi5sLmdvb2dsZS5jb206MTkzMDJcIixcbiAgXCJzdHVuMy5sLmdvb2dsZS5jb206MTkzMDJcIixcbiAgXCJzdHVuNC5sLmdvb2dsZS5jb206MTkzMDJcIixcbiAgXCJzdHVuLmVraWdhLm5ldFwiLFxuICBcInN0dW4uaWRlYXNpcC5jb21cIixcbiAgXCJzdHVuLnNjaGx1bmQuZGVcIixcbiAgXCJzdHVuLnN0dW5wcm90b2NvbC5vcmc6MzQ3OFwiLFxuICBcInN0dW4udm9pcGFyb3VuZC5jb21cIixcbiAgXCJzdHVuLnZvaXBidXN0ZXIuY29tXCIsXG4gIFwic3R1bi52b2lwc3R1bnQuY29tXCIsXG4gIFwic3R1bi52b3hncmF0aWEub3JnXCIsXG4gIFwic3R1bi5zZXJ2aWNlcy5tb3ppbGxhLmNvbVwiXG5dXG4iLCJtb2R1bGUuZXhwb3J0cz1bXVxuIiwidmFyIFdpbGRFbWl0dGVyID0gcmVxdWlyZSgnd2lsZGVtaXR0ZXInKTtcblxuZnVuY3Rpb24gZ2V0TWF4Vm9sdW1lIChhbmFseXNlciwgZmZ0Qmlucykge1xuICB2YXIgbWF4Vm9sdW1lID0gLUluZmluaXR5O1xuICBhbmFseXNlci5nZXRGbG9hdEZyZXF1ZW5jeURhdGEoZmZ0Qmlucyk7XG5cbiAgZm9yKHZhciBpPTQsIGlpPWZmdEJpbnMubGVuZ3RoOyBpIDwgaWk7IGkrKykge1xuICAgIGlmIChmZnRCaW5zW2ldID4gbWF4Vm9sdW1lICYmIGZmdEJpbnNbaV0gPCAwKSB7XG4gICAgICBtYXhWb2x1bWUgPSBmZnRCaW5zW2ldO1xuICAgIH1cbiAgfTtcblxuICByZXR1cm4gbWF4Vm9sdW1lO1xufVxuXG5cbnZhciBhdWRpb0NvbnRleHRUeXBlID0gd2luZG93LkF1ZGlvQ29udGV4dCB8fCB3aW5kb3cud2Via2l0QXVkaW9Db250ZXh0O1xuLy8gdXNlIGEgc2luZ2xlIGF1ZGlvIGNvbnRleHQgZHVlIHRvIGhhcmR3YXJlIGxpbWl0c1xudmFyIGF1ZGlvQ29udGV4dCA9IG51bGw7XG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKHN0cmVhbSwgb3B0aW9ucykge1xuICB2YXIgaGFya2VyID0gbmV3IFdpbGRFbWl0dGVyKCk7XG5cblxuICAvLyBtYWtlIGl0IG5vdCBicmVhayBpbiBub24tc3VwcG9ydGVkIGJyb3dzZXJzXG4gIGlmICghYXVkaW9Db250ZXh0VHlwZSkgcmV0dXJuIGhhcmtlcjtcblxuICAvL0NvbmZpZ1xuICB2YXIgb3B0aW9ucyA9IG9wdGlvbnMgfHwge30sXG4gICAgICBzbW9vdGhpbmcgPSAob3B0aW9ucy5zbW9vdGhpbmcgfHwgMC4xKSxcbiAgICAgIGludGVydmFsID0gKG9wdGlvbnMuaW50ZXJ2YWwgfHwgNTApLFxuICAgICAgdGhyZXNob2xkID0gb3B0aW9ucy50aHJlc2hvbGQsXG4gICAgICBwbGF5ID0gb3B0aW9ucy5wbGF5LFxuICAgICAgaGlzdG9yeSA9IG9wdGlvbnMuaGlzdG9yeSB8fCAxMCxcbiAgICAgIHJ1bm5pbmcgPSB0cnVlO1xuXG4gIC8vU2V0dXAgQXVkaW8gQ29udGV4dFxuICBpZiAoIWF1ZGlvQ29udGV4dCkge1xuICAgIGF1ZGlvQ29udGV4dCA9IG5ldyBhdWRpb0NvbnRleHRUeXBlKCk7XG4gIH1cbiAgdmFyIHNvdXJjZU5vZGUsIGZmdEJpbnMsIGFuYWx5c2VyO1xuXG4gIGFuYWx5c2VyID0gYXVkaW9Db250ZXh0LmNyZWF0ZUFuYWx5c2VyKCk7XG4gIGFuYWx5c2VyLmZmdFNpemUgPSA1MTI7XG4gIGFuYWx5c2VyLnNtb290aGluZ1RpbWVDb25zdGFudCA9IHNtb290aGluZztcbiAgZmZ0QmlucyA9IG5ldyBGbG9hdDMyQXJyYXkoYW5hbHlzZXIuZmZ0U2l6ZSk7XG5cbiAgaWYgKHN0cmVhbS5qcXVlcnkpIHN0cmVhbSA9IHN0cmVhbVswXTtcbiAgaWYgKHN0cmVhbSBpbnN0YW5jZW9mIEhUTUxBdWRpb0VsZW1lbnQgfHwgc3RyZWFtIGluc3RhbmNlb2YgSFRNTFZpZGVvRWxlbWVudCkge1xuICAgIC8vQXVkaW8gVGFnXG4gICAgc291cmNlTm9kZSA9IGF1ZGlvQ29udGV4dC5jcmVhdGVNZWRpYUVsZW1lbnRTb3VyY2Uoc3RyZWFtKTtcbiAgICBpZiAodHlwZW9mIHBsYXkgPT09ICd1bmRlZmluZWQnKSBwbGF5ID0gdHJ1ZTtcbiAgICB0aHJlc2hvbGQgPSB0aHJlc2hvbGQgfHwgLTUwO1xuICB9IGVsc2Uge1xuICAgIC8vV2ViUlRDIFN0cmVhbVxuICAgIHNvdXJjZU5vZGUgPSBhdWRpb0NvbnRleHQuY3JlYXRlTWVkaWFTdHJlYW1Tb3VyY2Uoc3RyZWFtKTtcbiAgICB0aHJlc2hvbGQgPSB0aHJlc2hvbGQgfHwgLTUwO1xuICB9XG5cbiAgc291cmNlTm9kZS5jb25uZWN0KGFuYWx5c2VyKTtcbiAgaWYgKHBsYXkpIGFuYWx5c2VyLmNvbm5lY3QoYXVkaW9Db250ZXh0LmRlc3RpbmF0aW9uKTtcblxuICBoYXJrZXIuc3BlYWtpbmcgPSBmYWxzZTtcblxuICBoYXJrZXIuc2V0VGhyZXNob2xkID0gZnVuY3Rpb24odCkge1xuICAgIHRocmVzaG9sZCA9IHQ7XG4gIH07XG5cbiAgaGFya2VyLnNldEludGVydmFsID0gZnVuY3Rpb24oaSkge1xuICAgIGludGVydmFsID0gaTtcbiAgfTtcbiAgXG4gIGhhcmtlci5zdG9wID0gZnVuY3Rpb24oKSB7XG4gICAgcnVubmluZyA9IGZhbHNlO1xuICAgIGhhcmtlci5lbWl0KCd2b2x1bWVfY2hhbmdlJywgLTEwMCwgdGhyZXNob2xkKTtcbiAgICBpZiAoaGFya2VyLnNwZWFraW5nKSB7XG4gICAgICBoYXJrZXIuc3BlYWtpbmcgPSBmYWxzZTtcbiAgICAgIGhhcmtlci5lbWl0KCdzdG9wcGVkX3NwZWFraW5nJyk7XG4gICAgfVxuICB9O1xuICBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5ID0gW107XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgaGlzdG9yeTsgaSsrKSB7XG4gICAgICBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5LnB1c2goMCk7XG4gIH1cblxuICAvLyBQb2xsIHRoZSBhbmFseXNlciBub2RlIHRvIGRldGVybWluZSBpZiBzcGVha2luZ1xuICAvLyBhbmQgZW1pdCBldmVudHMgaWYgY2hhbmdlZFxuICB2YXIgbG9vcGVyID0gZnVuY3Rpb24oKSB7XG4gICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICBcbiAgICAgIC8vY2hlY2sgaWYgc3RvcCBoYXMgYmVlbiBjYWxsZWRcbiAgICAgIGlmKCFydW5uaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgdmFyIGN1cnJlbnRWb2x1bWUgPSBnZXRNYXhWb2x1bWUoYW5hbHlzZXIsIGZmdEJpbnMpO1xuXG4gICAgICBoYXJrZXIuZW1pdCgndm9sdW1lX2NoYW5nZScsIGN1cnJlbnRWb2x1bWUsIHRocmVzaG9sZCk7XG5cbiAgICAgIHZhciBoaXN0b3J5ID0gMDtcbiAgICAgIGlmIChjdXJyZW50Vm9sdW1lID4gdGhyZXNob2xkICYmICFoYXJrZXIuc3BlYWtpbmcpIHtcbiAgICAgICAgLy8gdHJpZ2dlciBxdWlja2x5LCBzaG9ydCBoaXN0b3J5XG4gICAgICAgIGZvciAodmFyIGkgPSBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5Lmxlbmd0aCAtIDM7IGkgPCBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgaGlzdG9yeSArPSBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5W2ldO1xuICAgICAgICB9XG4gICAgICAgIGlmIChoaXN0b3J5ID49IDIpIHtcbiAgICAgICAgICBoYXJrZXIuc3BlYWtpbmcgPSB0cnVlO1xuICAgICAgICAgIGhhcmtlci5lbWl0KCdzcGVha2luZycpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGN1cnJlbnRWb2x1bWUgPCB0aHJlc2hvbGQgJiYgaGFya2VyLnNwZWFraW5nKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaGFya2VyLnNwZWFraW5nSGlzdG9yeS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIGhpc3RvcnkgKz0gaGFya2VyLnNwZWFraW5nSGlzdG9yeVtpXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaGlzdG9yeSA9PSAwKSB7XG4gICAgICAgICAgaGFya2VyLnNwZWFraW5nID0gZmFsc2U7XG4gICAgICAgICAgaGFya2VyLmVtaXQoJ3N0b3BwZWRfc3BlYWtpbmcnKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaGFya2VyLnNwZWFraW5nSGlzdG9yeS5zaGlmdCgpO1xuICAgICAgaGFya2VyLnNwZWFraW5nSGlzdG9yeS5wdXNoKDAgKyAoY3VycmVudFZvbHVtZSA+IHRocmVzaG9sZCkpO1xuXG4gICAgICBsb29wZXIoKTtcbiAgICB9LCBpbnRlcnZhbCk7XG4gIH07XG4gIGxvb3BlcigpO1xuXG5cbiAgcmV0dXJuIGhhcmtlcjtcbn1cbiIsImlmICh0eXBlb2YgT2JqZWN0LmNyZWF0ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAvLyBpbXBsZW1lbnRhdGlvbiBmcm9tIHN0YW5kYXJkIG5vZGUuanMgJ3V0aWwnIG1vZHVsZVxuICBtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGluaGVyaXRzKGN0b3IsIHN1cGVyQ3Rvcikge1xuICAgIGN0b3Iuc3VwZXJfID0gc3VwZXJDdG9yXG4gICAgY3Rvci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHN1cGVyQ3Rvci5wcm90b3R5cGUsIHtcbiAgICAgIGNvbnN0cnVjdG9yOiB7XG4gICAgICAgIHZhbHVlOiBjdG9yLFxuICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgICAgfVxuICAgIH0pO1xuICB9O1xufSBlbHNlIHtcbiAgLy8gb2xkIHNjaG9vbCBzaGltIGZvciBvbGQgYnJvd3NlcnNcbiAgbW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBpbmhlcml0cyhjdG9yLCBzdXBlckN0b3IpIHtcbiAgICBjdG9yLnN1cGVyXyA9IHN1cGVyQ3RvclxuICAgIHZhciBUZW1wQ3RvciA9IGZ1bmN0aW9uICgpIHt9XG4gICAgVGVtcEN0b3IucHJvdG90eXBlID0gc3VwZXJDdG9yLnByb3RvdHlwZVxuICAgIGN0b3IucHJvdG90eXBlID0gbmV3IFRlbXBDdG9yKClcbiAgICBjdG9yLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IGN0b3JcbiAgfVxufVxuIiwiLyohIEpTT04gdjMuMy4yIHwgaHR0cDovL2Jlc3RpZWpzLmdpdGh1Yi5pby9qc29uMyB8IENvcHlyaWdodCAyMDEyLTIwMTQsIEtpdCBDYW1icmlkZ2UgfCBodHRwOi8va2l0Lm1pdC1saWNlbnNlLm9yZyAqL1xuOyhmdW5jdGlvbiAoKSB7XG4gIC8vIERldGVjdCB0aGUgYGRlZmluZWAgZnVuY3Rpb24gZXhwb3NlZCBieSBhc3luY2hyb25vdXMgbW9kdWxlIGxvYWRlcnMuIFRoZVxuICAvLyBzdHJpY3QgYGRlZmluZWAgY2hlY2sgaXMgbmVjZXNzYXJ5IGZvciBjb21wYXRpYmlsaXR5IHdpdGggYHIuanNgLlxuICB2YXIgaXNMb2FkZXIgPSB0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgZGVmaW5lLmFtZDtcblxuICAvLyBBIHNldCBvZiB0eXBlcyB1c2VkIHRvIGRpc3Rpbmd1aXNoIG9iamVjdHMgZnJvbSBwcmltaXRpdmVzLlxuICB2YXIgb2JqZWN0VHlwZXMgPSB7XG4gICAgXCJmdW5jdGlvblwiOiB0cnVlLFxuICAgIFwib2JqZWN0XCI6IHRydWVcbiAgfTtcblxuICAvLyBEZXRlY3QgdGhlIGBleHBvcnRzYCBvYmplY3QgZXhwb3NlZCBieSBDb21tb25KUyBpbXBsZW1lbnRhdGlvbnMuXG4gIHZhciBmcmVlRXhwb3J0cyA9IG9iamVjdFR5cGVzW3R5cGVvZiBleHBvcnRzXSAmJiBleHBvcnRzICYmICFleHBvcnRzLm5vZGVUeXBlICYmIGV4cG9ydHM7XG5cbiAgLy8gVXNlIHRoZSBgZ2xvYmFsYCBvYmplY3QgZXhwb3NlZCBieSBOb2RlIChpbmNsdWRpbmcgQnJvd3NlcmlmeSB2aWFcbiAgLy8gYGluc2VydC1tb2R1bGUtZ2xvYmFsc2ApLCBOYXJ3aGFsLCBhbmQgUmluZ28gYXMgdGhlIGRlZmF1bHQgY29udGV4dCxcbiAgLy8gYW5kIHRoZSBgd2luZG93YCBvYmplY3QgaW4gYnJvd3NlcnMuIFJoaW5vIGV4cG9ydHMgYSBgZ2xvYmFsYCBmdW5jdGlvblxuICAvLyBpbnN0ZWFkLlxuICB2YXIgcm9vdCA9IG9iamVjdFR5cGVzW3R5cGVvZiB3aW5kb3ddICYmIHdpbmRvdyB8fCB0aGlzLFxuICAgICAgZnJlZUdsb2JhbCA9IGZyZWVFeHBvcnRzICYmIG9iamVjdFR5cGVzW3R5cGVvZiBtb2R1bGVdICYmIG1vZHVsZSAmJiAhbW9kdWxlLm5vZGVUeXBlICYmIHR5cGVvZiBnbG9iYWwgPT0gXCJvYmplY3RcIiAmJiBnbG9iYWw7XG5cbiAgaWYgKGZyZWVHbG9iYWwgJiYgKGZyZWVHbG9iYWxbXCJnbG9iYWxcIl0gPT09IGZyZWVHbG9iYWwgfHwgZnJlZUdsb2JhbFtcIndpbmRvd1wiXSA9PT0gZnJlZUdsb2JhbCB8fCBmcmVlR2xvYmFsW1wic2VsZlwiXSA9PT0gZnJlZUdsb2JhbCkpIHtcbiAgICByb290ID0gZnJlZUdsb2JhbDtcbiAgfVxuXG4gIC8vIFB1YmxpYzogSW5pdGlhbGl6ZXMgSlNPTiAzIHVzaW5nIHRoZSBnaXZlbiBgY29udGV4dGAgb2JqZWN0LCBhdHRhY2hpbmcgdGhlXG4gIC8vIGBzdHJpbmdpZnlgIGFuZCBgcGFyc2VgIGZ1bmN0aW9ucyB0byB0aGUgc3BlY2lmaWVkIGBleHBvcnRzYCBvYmplY3QuXG4gIGZ1bmN0aW9uIHJ1bkluQ29udGV4dChjb250ZXh0LCBleHBvcnRzKSB7XG4gICAgY29udGV4dCB8fCAoY29udGV4dCA9IHJvb3RbXCJPYmplY3RcIl0oKSk7XG4gICAgZXhwb3J0cyB8fCAoZXhwb3J0cyA9IHJvb3RbXCJPYmplY3RcIl0oKSk7XG5cbiAgICAvLyBOYXRpdmUgY29uc3RydWN0b3IgYWxpYXNlcy5cbiAgICB2YXIgTnVtYmVyID0gY29udGV4dFtcIk51bWJlclwiXSB8fCByb290W1wiTnVtYmVyXCJdLFxuICAgICAgICBTdHJpbmcgPSBjb250ZXh0W1wiU3RyaW5nXCJdIHx8IHJvb3RbXCJTdHJpbmdcIl0sXG4gICAgICAgIE9iamVjdCA9IGNvbnRleHRbXCJPYmplY3RcIl0gfHwgcm9vdFtcIk9iamVjdFwiXSxcbiAgICAgICAgRGF0ZSA9IGNvbnRleHRbXCJEYXRlXCJdIHx8IHJvb3RbXCJEYXRlXCJdLFxuICAgICAgICBTeW50YXhFcnJvciA9IGNvbnRleHRbXCJTeW50YXhFcnJvclwiXSB8fCByb290W1wiU3ludGF4RXJyb3JcIl0sXG4gICAgICAgIFR5cGVFcnJvciA9IGNvbnRleHRbXCJUeXBlRXJyb3JcIl0gfHwgcm9vdFtcIlR5cGVFcnJvclwiXSxcbiAgICAgICAgTWF0aCA9IGNvbnRleHRbXCJNYXRoXCJdIHx8IHJvb3RbXCJNYXRoXCJdLFxuICAgICAgICBuYXRpdmVKU09OID0gY29udGV4dFtcIkpTT05cIl0gfHwgcm9vdFtcIkpTT05cIl07XG5cbiAgICAvLyBEZWxlZ2F0ZSB0byB0aGUgbmF0aXZlIGBzdHJpbmdpZnlgIGFuZCBgcGFyc2VgIGltcGxlbWVudGF0aW9ucy5cbiAgICBpZiAodHlwZW9mIG5hdGl2ZUpTT04gPT0gXCJvYmplY3RcIiAmJiBuYXRpdmVKU09OKSB7XG4gICAgICBleHBvcnRzLnN0cmluZ2lmeSA9IG5hdGl2ZUpTT04uc3RyaW5naWZ5O1xuICAgICAgZXhwb3J0cy5wYXJzZSA9IG5hdGl2ZUpTT04ucGFyc2U7XG4gICAgfVxuXG4gICAgLy8gQ29udmVuaWVuY2UgYWxpYXNlcy5cbiAgICB2YXIgb2JqZWN0UHJvdG8gPSBPYmplY3QucHJvdG90eXBlLFxuICAgICAgICBnZXRDbGFzcyA9IG9iamVjdFByb3RvLnRvU3RyaW5nLFxuICAgICAgICBpc1Byb3BlcnR5LCBmb3JFYWNoLCB1bmRlZjtcblxuICAgIC8vIFRlc3QgdGhlIGBEYXRlI2dldFVUQypgIG1ldGhvZHMuIEJhc2VkIG9uIHdvcmsgYnkgQFlhZmZsZS5cbiAgICB2YXIgaXNFeHRlbmRlZCA9IG5ldyBEYXRlKC0zNTA5ODI3MzM0NTczMjkyKTtcbiAgICB0cnkge1xuICAgICAgLy8gVGhlIGBnZXRVVENGdWxsWWVhcmAsIGBNb250aGAsIGFuZCBgRGF0ZWAgbWV0aG9kcyByZXR1cm4gbm9uc2Vuc2ljYWxcbiAgICAgIC8vIHJlc3VsdHMgZm9yIGNlcnRhaW4gZGF0ZXMgaW4gT3BlcmEgPj0gMTAuNTMuXG4gICAgICBpc0V4dGVuZGVkID0gaXNFeHRlbmRlZC5nZXRVVENGdWxsWWVhcigpID09IC0xMDkyNTIgJiYgaXNFeHRlbmRlZC5nZXRVVENNb250aCgpID09PSAwICYmIGlzRXh0ZW5kZWQuZ2V0VVRDRGF0ZSgpID09PSAxICYmXG4gICAgICAgIC8vIFNhZmFyaSA8IDIuMC4yIHN0b3JlcyB0aGUgaW50ZXJuYWwgbWlsbGlzZWNvbmQgdGltZSB2YWx1ZSBjb3JyZWN0bHksXG4gICAgICAgIC8vIGJ1dCBjbGlwcyB0aGUgdmFsdWVzIHJldHVybmVkIGJ5IHRoZSBkYXRlIG1ldGhvZHMgdG8gdGhlIHJhbmdlIG9mXG4gICAgICAgIC8vIHNpZ25lZCAzMi1iaXQgaW50ZWdlcnMgKFstMiAqKiAzMSwgMiAqKiAzMSAtIDFdKS5cbiAgICAgICAgaXNFeHRlbmRlZC5nZXRVVENIb3VycygpID09IDEwICYmIGlzRXh0ZW5kZWQuZ2V0VVRDTWludXRlcygpID09IDM3ICYmIGlzRXh0ZW5kZWQuZ2V0VVRDU2Vjb25kcygpID09IDYgJiYgaXNFeHRlbmRlZC5nZXRVVENNaWxsaXNlY29uZHMoKSA9PSA3MDg7XG4gICAgfSBjYXRjaCAoZXhjZXB0aW9uKSB7fVxuXG4gICAgLy8gSW50ZXJuYWw6IERldGVybWluZXMgd2hldGhlciB0aGUgbmF0aXZlIGBKU09OLnN0cmluZ2lmeWAgYW5kIGBwYXJzZWBcbiAgICAvLyBpbXBsZW1lbnRhdGlvbnMgYXJlIHNwZWMtY29tcGxpYW50LiBCYXNlZCBvbiB3b3JrIGJ5IEtlbiBTbnlkZXIuXG4gICAgZnVuY3Rpb24gaGFzKG5hbWUpIHtcbiAgICAgIGlmIChoYXNbbmFtZV0gIT09IHVuZGVmKSB7XG4gICAgICAgIC8vIFJldHVybiBjYWNoZWQgZmVhdHVyZSB0ZXN0IHJlc3VsdC5cbiAgICAgICAgcmV0dXJuIGhhc1tuYW1lXTtcbiAgICAgIH1cbiAgICAgIHZhciBpc1N1cHBvcnRlZDtcbiAgICAgIGlmIChuYW1lID09IFwiYnVnLXN0cmluZy1jaGFyLWluZGV4XCIpIHtcbiAgICAgICAgLy8gSUUgPD0gNyBkb2Vzbid0IHN1cHBvcnQgYWNjZXNzaW5nIHN0cmluZyBjaGFyYWN0ZXJzIHVzaW5nIHNxdWFyZVxuICAgICAgICAvLyBicmFja2V0IG5vdGF0aW9uLiBJRSA4IG9ubHkgc3VwcG9ydHMgdGhpcyBmb3IgcHJpbWl0aXZlcy5cbiAgICAgICAgaXNTdXBwb3J0ZWQgPSBcImFcIlswXSAhPSBcImFcIjtcbiAgICAgIH0gZWxzZSBpZiAobmFtZSA9PSBcImpzb25cIikge1xuICAgICAgICAvLyBJbmRpY2F0ZXMgd2hldGhlciBib3RoIGBKU09OLnN0cmluZ2lmeWAgYW5kIGBKU09OLnBhcnNlYCBhcmVcbiAgICAgICAgLy8gc3VwcG9ydGVkLlxuICAgICAgICBpc1N1cHBvcnRlZCA9IGhhcyhcImpzb24tc3RyaW5naWZ5XCIpICYmIGhhcyhcImpzb24tcGFyc2VcIik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgdmFsdWUsIHNlcmlhbGl6ZWQgPSAne1wiYVwiOlsxLHRydWUsZmFsc2UsbnVsbCxcIlxcXFx1MDAwMFxcXFxiXFxcXG5cXFxcZlxcXFxyXFxcXHRcIl19JztcbiAgICAgICAgLy8gVGVzdCBgSlNPTi5zdHJpbmdpZnlgLlxuICAgICAgICBpZiAobmFtZSA9PSBcImpzb24tc3RyaW5naWZ5XCIpIHtcbiAgICAgICAgICB2YXIgc3RyaW5naWZ5ID0gZXhwb3J0cy5zdHJpbmdpZnksIHN0cmluZ2lmeVN1cHBvcnRlZCA9IHR5cGVvZiBzdHJpbmdpZnkgPT0gXCJmdW5jdGlvblwiICYmIGlzRXh0ZW5kZWQ7XG4gICAgICAgICAgaWYgKHN0cmluZ2lmeVN1cHBvcnRlZCkge1xuICAgICAgICAgICAgLy8gQSB0ZXN0IGZ1bmN0aW9uIG9iamVjdCB3aXRoIGEgY3VzdG9tIGB0b0pTT05gIG1ldGhvZC5cbiAgICAgICAgICAgICh2YWx1ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgICAgICB9KS50b0pTT04gPSB2YWx1ZTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIHN0cmluZ2lmeVN1cHBvcnRlZCA9XG4gICAgICAgICAgICAgICAgLy8gRmlyZWZveCAzLjFiMSBhbmQgYjIgc2VyaWFsaXplIHN0cmluZywgbnVtYmVyLCBhbmQgYm9vbGVhblxuICAgICAgICAgICAgICAgIC8vIHByaW1pdGl2ZXMgYXMgb2JqZWN0IGxpdGVyYWxzLlxuICAgICAgICAgICAgICAgIHN0cmluZ2lmeSgwKSA9PT0gXCIwXCIgJiZcbiAgICAgICAgICAgICAgICAvLyBGRiAzLjFiMSwgYjIsIGFuZCBKU09OIDIgc2VyaWFsaXplIHdyYXBwZWQgcHJpbWl0aXZlcyBhcyBvYmplY3RcbiAgICAgICAgICAgICAgICAvLyBsaXRlcmFscy5cbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkobmV3IE51bWJlcigpKSA9PT0gXCIwXCIgJiZcbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkobmV3IFN0cmluZygpKSA9PSAnXCJcIicgJiZcbiAgICAgICAgICAgICAgICAvLyBGRiAzLjFiMSwgMiB0aHJvdyBhbiBlcnJvciBpZiB0aGUgdmFsdWUgaXMgYG51bGxgLCBgdW5kZWZpbmVkYCwgb3JcbiAgICAgICAgICAgICAgICAvLyBkb2VzIG5vdCBkZWZpbmUgYSBjYW5vbmljYWwgSlNPTiByZXByZXNlbnRhdGlvbiAodGhpcyBhcHBsaWVzIHRvXG4gICAgICAgICAgICAgICAgLy8gb2JqZWN0cyB3aXRoIGB0b0pTT05gIHByb3BlcnRpZXMgYXMgd2VsbCwgKnVubGVzcyogdGhleSBhcmUgbmVzdGVkXG4gICAgICAgICAgICAgICAgLy8gd2l0aGluIGFuIG9iamVjdCBvciBhcnJheSkuXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KGdldENsYXNzKSA9PT0gdW5kZWYgJiZcbiAgICAgICAgICAgICAgICAvLyBJRSA4IHNlcmlhbGl6ZXMgYHVuZGVmaW5lZGAgYXMgYFwidW5kZWZpbmVkXCJgLiBTYWZhcmkgPD0gNS4xLjcgYW5kXG4gICAgICAgICAgICAgICAgLy8gRkYgMy4xYjMgcGFzcyB0aGlzIHRlc3QuXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KHVuZGVmKSA9PT0gdW5kZWYgJiZcbiAgICAgICAgICAgICAgICAvLyBTYWZhcmkgPD0gNS4xLjcgYW5kIEZGIDMuMWIzIHRocm93IGBFcnJvcmBzIGFuZCBgVHlwZUVycm9yYHMsXG4gICAgICAgICAgICAgICAgLy8gcmVzcGVjdGl2ZWx5LCBpZiB0aGUgdmFsdWUgaXMgb21pdHRlZCBlbnRpcmVseS5cbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkoKSA9PT0gdW5kZWYgJiZcbiAgICAgICAgICAgICAgICAvLyBGRiAzLjFiMSwgMiB0aHJvdyBhbiBlcnJvciBpZiB0aGUgZ2l2ZW4gdmFsdWUgaXMgbm90IGEgbnVtYmVyLFxuICAgICAgICAgICAgICAgIC8vIHN0cmluZywgYXJyYXksIG9iamVjdCwgQm9vbGVhbiwgb3IgYG51bGxgIGxpdGVyYWwuIFRoaXMgYXBwbGllcyB0b1xuICAgICAgICAgICAgICAgIC8vIG9iamVjdHMgd2l0aCBjdXN0b20gYHRvSlNPTmAgbWV0aG9kcyBhcyB3ZWxsLCB1bmxlc3MgdGhleSBhcmUgbmVzdGVkXG4gICAgICAgICAgICAgICAgLy8gaW5zaWRlIG9iamVjdCBvciBhcnJheSBsaXRlcmFscy4gWVVJIDMuMC4wYjEgaWdub3JlcyBjdXN0b20gYHRvSlNPTmBcbiAgICAgICAgICAgICAgICAvLyBtZXRob2RzIGVudGlyZWx5LlxuICAgICAgICAgICAgICAgIHN0cmluZ2lmeSh2YWx1ZSkgPT09IFwiMVwiICYmXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KFt2YWx1ZV0pID09IFwiWzFdXCIgJiZcbiAgICAgICAgICAgICAgICAvLyBQcm90b3R5cGUgPD0gMS42LjEgc2VyaWFsaXplcyBgW3VuZGVmaW5lZF1gIGFzIGBcIltdXCJgIGluc3RlYWQgb2ZcbiAgICAgICAgICAgICAgICAvLyBgXCJbbnVsbF1cImAuXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KFt1bmRlZl0pID09IFwiW251bGxdXCIgJiZcbiAgICAgICAgICAgICAgICAvLyBZVUkgMy4wLjBiMSBmYWlscyB0byBzZXJpYWxpemUgYG51bGxgIGxpdGVyYWxzLlxuICAgICAgICAgICAgICAgIHN0cmluZ2lmeShudWxsKSA9PSBcIm51bGxcIiAmJlxuICAgICAgICAgICAgICAgIC8vIEZGIDMuMWIxLCAyIGhhbHRzIHNlcmlhbGl6YXRpb24gaWYgYW4gYXJyYXkgY29udGFpbnMgYSBmdW5jdGlvbjpcbiAgICAgICAgICAgICAgICAvLyBgWzEsIHRydWUsIGdldENsYXNzLCAxXWAgc2VyaWFsaXplcyBhcyBcIlsxLHRydWUsXSxcIi4gRkYgMy4xYjNcbiAgICAgICAgICAgICAgICAvLyBlbGlkZXMgbm9uLUpTT04gdmFsdWVzIGZyb20gb2JqZWN0cyBhbmQgYXJyYXlzLCB1bmxlc3MgdGhleVxuICAgICAgICAgICAgICAgIC8vIGRlZmluZSBjdXN0b20gYHRvSlNPTmAgbWV0aG9kcy5cbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkoW3VuZGVmLCBnZXRDbGFzcywgbnVsbF0pID09IFwiW251bGwsbnVsbCxudWxsXVwiICYmXG4gICAgICAgICAgICAgICAgLy8gU2ltcGxlIHNlcmlhbGl6YXRpb24gdGVzdC4gRkYgMy4xYjEgdXNlcyBVbmljb2RlIGVzY2FwZSBzZXF1ZW5jZXNcbiAgICAgICAgICAgICAgICAvLyB3aGVyZSBjaGFyYWN0ZXIgZXNjYXBlIGNvZGVzIGFyZSBleHBlY3RlZCAoZS5nLiwgYFxcYmAgPT4gYFxcdTAwMDhgKS5cbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkoeyBcImFcIjogW3ZhbHVlLCB0cnVlLCBmYWxzZSwgbnVsbCwgXCJcXHgwMFxcYlxcblxcZlxcclxcdFwiXSB9KSA9PSBzZXJpYWxpemVkICYmXG4gICAgICAgICAgICAgICAgLy8gRkYgMy4xYjEgYW5kIGIyIGlnbm9yZSB0aGUgYGZpbHRlcmAgYW5kIGB3aWR0aGAgYXJndW1lbnRzLlxuICAgICAgICAgICAgICAgIHN0cmluZ2lmeShudWxsLCB2YWx1ZSkgPT09IFwiMVwiICYmXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KFsxLCAyXSwgbnVsbCwgMSkgPT0gXCJbXFxuIDEsXFxuIDJcXG5dXCIgJiZcbiAgICAgICAgICAgICAgICAvLyBKU09OIDIsIFByb3RvdHlwZSA8PSAxLjcsIGFuZCBvbGRlciBXZWJLaXQgYnVpbGRzIGluY29ycmVjdGx5XG4gICAgICAgICAgICAgICAgLy8gc2VyaWFsaXplIGV4dGVuZGVkIHllYXJzLlxuICAgICAgICAgICAgICAgIHN0cmluZ2lmeShuZXcgRGF0ZSgtOC42NGUxNSkpID09ICdcIi0yNzE4MjEtMDQtMjBUMDA6MDA6MDAuMDAwWlwiJyAmJlxuICAgICAgICAgICAgICAgIC8vIFRoZSBtaWxsaXNlY29uZHMgYXJlIG9wdGlvbmFsIGluIEVTIDUsIGJ1dCByZXF1aXJlZCBpbiA1LjEuXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KG5ldyBEYXRlKDguNjRlMTUpKSA9PSAnXCIrMjc1NzYwLTA5LTEzVDAwOjAwOjAwLjAwMFpcIicgJiZcbiAgICAgICAgICAgICAgICAvLyBGaXJlZm94IDw9IDExLjAgaW5jb3JyZWN0bHkgc2VyaWFsaXplcyB5ZWFycyBwcmlvciB0byAwIGFzIG5lZ2F0aXZlXG4gICAgICAgICAgICAgICAgLy8gZm91ci1kaWdpdCB5ZWFycyBpbnN0ZWFkIG9mIHNpeC1kaWdpdCB5ZWFycy4gQ3JlZGl0czogQFlhZmZsZS5cbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkobmV3IERhdGUoLTYyMTk4NzU1MmU1KSkgPT0gJ1wiLTAwMDAwMS0wMS0wMVQwMDowMDowMC4wMDBaXCInICYmXG4gICAgICAgICAgICAgICAgLy8gU2FmYXJpIDw9IDUuMS41IGFuZCBPcGVyYSA+PSAxMC41MyBpbmNvcnJlY3RseSBzZXJpYWxpemUgbWlsbGlzZWNvbmRcbiAgICAgICAgICAgICAgICAvLyB2YWx1ZXMgbGVzcyB0aGFuIDEwMDAuIENyZWRpdHM6IEBZYWZmbGUuXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KG5ldyBEYXRlKC0xKSkgPT0gJ1wiMTk2OS0xMi0zMVQyMzo1OTo1OS45OTlaXCInO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXhjZXB0aW9uKSB7XG4gICAgICAgICAgICAgIHN0cmluZ2lmeVN1cHBvcnRlZCA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpc1N1cHBvcnRlZCA9IHN0cmluZ2lmeVN1cHBvcnRlZDtcbiAgICAgICAgfVxuICAgICAgICAvLyBUZXN0IGBKU09OLnBhcnNlYC5cbiAgICAgICAgaWYgKG5hbWUgPT0gXCJqc29uLXBhcnNlXCIpIHtcbiAgICAgICAgICB2YXIgcGFyc2UgPSBleHBvcnRzLnBhcnNlO1xuICAgICAgICAgIGlmICh0eXBlb2YgcGFyc2UgPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAvLyBGRiAzLjFiMSwgYjIgd2lsbCB0aHJvdyBhbiBleGNlcHRpb24gaWYgYSBiYXJlIGxpdGVyYWwgaXMgcHJvdmlkZWQuXG4gICAgICAgICAgICAgIC8vIENvbmZvcm1pbmcgaW1wbGVtZW50YXRpb25zIHNob3VsZCBhbHNvIGNvZXJjZSB0aGUgaW5pdGlhbCBhcmd1bWVudCB0b1xuICAgICAgICAgICAgICAvLyBhIHN0cmluZyBwcmlvciB0byBwYXJzaW5nLlxuICAgICAgICAgICAgICBpZiAocGFyc2UoXCIwXCIpID09PSAwICYmICFwYXJzZShmYWxzZSkpIHtcbiAgICAgICAgICAgICAgICAvLyBTaW1wbGUgcGFyc2luZyB0ZXN0LlxuICAgICAgICAgICAgICAgIHZhbHVlID0gcGFyc2Uoc2VyaWFsaXplZCk7XG4gICAgICAgICAgICAgICAgdmFyIHBhcnNlU3VwcG9ydGVkID0gdmFsdWVbXCJhXCJdLmxlbmd0aCA9PSA1ICYmIHZhbHVlW1wiYVwiXVswXSA9PT0gMTtcbiAgICAgICAgICAgICAgICBpZiAocGFyc2VTdXBwb3J0ZWQpIHtcbiAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFNhZmFyaSA8PSA1LjEuMiBhbmQgRkYgMy4xYjEgYWxsb3cgdW5lc2NhcGVkIHRhYnMgaW4gc3RyaW5ncy5cbiAgICAgICAgICAgICAgICAgICAgcGFyc2VTdXBwb3J0ZWQgPSAhcGFyc2UoJ1wiXFx0XCInKTtcbiAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGV4Y2VwdGlvbikge31cbiAgICAgICAgICAgICAgICAgIGlmIChwYXJzZVN1cHBvcnRlZCkge1xuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIEZGIDQuMCBhbmQgNC4wLjEgYWxsb3cgbGVhZGluZyBgK2Agc2lnbnMgYW5kIGxlYWRpbmdcbiAgICAgICAgICAgICAgICAgICAgICAvLyBkZWNpbWFsIHBvaW50cy4gRkYgNC4wLCA0LjAuMSwgYW5kIElFIDktMTAgYWxzbyBhbGxvd1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGNlcnRhaW4gb2N0YWwgbGl0ZXJhbHMuXG4gICAgICAgICAgICAgICAgICAgICAgcGFyc2VTdXBwb3J0ZWQgPSBwYXJzZShcIjAxXCIpICE9PSAxO1xuICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChleGNlcHRpb24pIHt9XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBpZiAocGFyc2VTdXBwb3J0ZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBGRiA0LjAsIDQuMC4xLCBhbmQgUmhpbm8gMS43UjMtUjQgYWxsb3cgdHJhaWxpbmcgZGVjaW1hbFxuICAgICAgICAgICAgICAgICAgICAgIC8vIHBvaW50cy4gVGhlc2UgZW52aXJvbm1lbnRzLCBhbG9uZyB3aXRoIEZGIDMuMWIxIGFuZCAyLFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGFsc28gYWxsb3cgdHJhaWxpbmcgY29tbWFzIGluIEpTT04gb2JqZWN0cyBhbmQgYXJyYXlzLlxuICAgICAgICAgICAgICAgICAgICAgIHBhcnNlU3VwcG9ydGVkID0gcGFyc2UoXCIxLlwiKSAhPT0gMTtcbiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZXhjZXB0aW9uKSB7fVxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCAoZXhjZXB0aW9uKSB7XG4gICAgICAgICAgICAgIHBhcnNlU3VwcG9ydGVkID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGlzU3VwcG9ydGVkID0gcGFyc2VTdXBwb3J0ZWQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBoYXNbbmFtZV0gPSAhIWlzU3VwcG9ydGVkO1xuICAgIH1cblxuICAgIGlmICghaGFzKFwianNvblwiKSkge1xuICAgICAgLy8gQ29tbW9uIGBbW0NsYXNzXV1gIG5hbWUgYWxpYXNlcy5cbiAgICAgIHZhciBmdW5jdGlvbkNsYXNzID0gXCJbb2JqZWN0IEZ1bmN0aW9uXVwiLFxuICAgICAgICAgIGRhdGVDbGFzcyA9IFwiW29iamVjdCBEYXRlXVwiLFxuICAgICAgICAgIG51bWJlckNsYXNzID0gXCJbb2JqZWN0IE51bWJlcl1cIixcbiAgICAgICAgICBzdHJpbmdDbGFzcyA9IFwiW29iamVjdCBTdHJpbmddXCIsXG4gICAgICAgICAgYXJyYXlDbGFzcyA9IFwiW29iamVjdCBBcnJheV1cIixcbiAgICAgICAgICBib29sZWFuQ2xhc3MgPSBcIltvYmplY3QgQm9vbGVhbl1cIjtcblxuICAgICAgLy8gRGV0ZWN0IGluY29tcGxldGUgc3VwcG9ydCBmb3IgYWNjZXNzaW5nIHN0cmluZyBjaGFyYWN0ZXJzIGJ5IGluZGV4LlxuICAgICAgdmFyIGNoYXJJbmRleEJ1Z2d5ID0gaGFzKFwiYnVnLXN0cmluZy1jaGFyLWluZGV4XCIpO1xuXG4gICAgICAvLyBEZWZpbmUgYWRkaXRpb25hbCB1dGlsaXR5IG1ldGhvZHMgaWYgdGhlIGBEYXRlYCBtZXRob2RzIGFyZSBidWdneS5cbiAgICAgIGlmICghaXNFeHRlbmRlZCkge1xuICAgICAgICB2YXIgZmxvb3IgPSBNYXRoLmZsb29yO1xuICAgICAgICAvLyBBIG1hcHBpbmcgYmV0d2VlbiB0aGUgbW9udGhzIG9mIHRoZSB5ZWFyIGFuZCB0aGUgbnVtYmVyIG9mIGRheXMgYmV0d2VlblxuICAgICAgICAvLyBKYW51YXJ5IDFzdCBhbmQgdGhlIGZpcnN0IG9mIHRoZSByZXNwZWN0aXZlIG1vbnRoLlxuICAgICAgICB2YXIgTW9udGhzID0gWzAsIDMxLCA1OSwgOTAsIDEyMCwgMTUxLCAxODEsIDIxMiwgMjQzLCAyNzMsIDMwNCwgMzM0XTtcbiAgICAgICAgLy8gSW50ZXJuYWw6IENhbGN1bGF0ZXMgdGhlIG51bWJlciBvZiBkYXlzIGJldHdlZW4gdGhlIFVuaXggZXBvY2ggYW5kIHRoZVxuICAgICAgICAvLyBmaXJzdCBkYXkgb2YgdGhlIGdpdmVuIG1vbnRoLlxuICAgICAgICB2YXIgZ2V0RGF5ID0gZnVuY3Rpb24gKHllYXIsIG1vbnRoKSB7XG4gICAgICAgICAgcmV0dXJuIE1vbnRoc1ttb250aF0gKyAzNjUgKiAoeWVhciAtIDE5NzApICsgZmxvb3IoKHllYXIgLSAxOTY5ICsgKG1vbnRoID0gKyhtb250aCA+IDEpKSkgLyA0KSAtIGZsb29yKCh5ZWFyIC0gMTkwMSArIG1vbnRoKSAvIDEwMCkgKyBmbG9vcigoeWVhciAtIDE2MDEgKyBtb250aCkgLyA0MDApO1xuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICAvLyBJbnRlcm5hbDogRGV0ZXJtaW5lcyBpZiBhIHByb3BlcnR5IGlzIGEgZGlyZWN0IHByb3BlcnR5IG9mIHRoZSBnaXZlblxuICAgICAgLy8gb2JqZWN0LiBEZWxlZ2F0ZXMgdG8gdGhlIG5hdGl2ZSBgT2JqZWN0I2hhc093blByb3BlcnR5YCBtZXRob2QuXG4gICAgICBpZiAoIShpc1Byb3BlcnR5ID0gb2JqZWN0UHJvdG8uaGFzT3duUHJvcGVydHkpKSB7XG4gICAgICAgIGlzUHJvcGVydHkgPSBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICB2YXIgbWVtYmVycyA9IHt9LCBjb25zdHJ1Y3RvcjtcbiAgICAgICAgICBpZiAoKG1lbWJlcnMuX19wcm90b19fID0gbnVsbCwgbWVtYmVycy5fX3Byb3RvX18gPSB7XG4gICAgICAgICAgICAvLyBUaGUgKnByb3RvKiBwcm9wZXJ0eSBjYW5ub3QgYmUgc2V0IG11bHRpcGxlIHRpbWVzIGluIHJlY2VudFxuICAgICAgICAgICAgLy8gdmVyc2lvbnMgb2YgRmlyZWZveCBhbmQgU2VhTW9ua2V5LlxuICAgICAgICAgICAgXCJ0b1N0cmluZ1wiOiAxXG4gICAgICAgICAgfSwgbWVtYmVycykudG9TdHJpbmcgIT0gZ2V0Q2xhc3MpIHtcbiAgICAgICAgICAgIC8vIFNhZmFyaSA8PSAyLjAuMyBkb2Vzbid0IGltcGxlbWVudCBgT2JqZWN0I2hhc093blByb3BlcnR5YCwgYnV0XG4gICAgICAgICAgICAvLyBzdXBwb3J0cyB0aGUgbXV0YWJsZSAqcHJvdG8qIHByb3BlcnR5LlxuICAgICAgICAgICAgaXNQcm9wZXJ0eSA9IGZ1bmN0aW9uIChwcm9wZXJ0eSkge1xuICAgICAgICAgICAgICAvLyBDYXB0dXJlIGFuZCBicmVhayB0aGUgb2JqZWN0J3MgcHJvdG90eXBlIGNoYWluIChzZWUgc2VjdGlvbiA4LjYuMlxuICAgICAgICAgICAgICAvLyBvZiB0aGUgRVMgNS4xIHNwZWMpLiBUaGUgcGFyZW50aGVzaXplZCBleHByZXNzaW9uIHByZXZlbnRzIGFuXG4gICAgICAgICAgICAgIC8vIHVuc2FmZSB0cmFuc2Zvcm1hdGlvbiBieSB0aGUgQ2xvc3VyZSBDb21waWxlci5cbiAgICAgICAgICAgICAgdmFyIG9yaWdpbmFsID0gdGhpcy5fX3Byb3RvX18sIHJlc3VsdCA9IHByb3BlcnR5IGluICh0aGlzLl9fcHJvdG9fXyA9IG51bGwsIHRoaXMpO1xuICAgICAgICAgICAgICAvLyBSZXN0b3JlIHRoZSBvcmlnaW5hbCBwcm90b3R5cGUgY2hhaW4uXG4gICAgICAgICAgICAgIHRoaXMuX19wcm90b19fID0gb3JpZ2luYWw7XG4gICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBDYXB0dXJlIGEgcmVmZXJlbmNlIHRvIHRoZSB0b3AtbGV2ZWwgYE9iamVjdGAgY29uc3RydWN0b3IuXG4gICAgICAgICAgICBjb25zdHJ1Y3RvciA9IG1lbWJlcnMuY29uc3RydWN0b3I7XG4gICAgICAgICAgICAvLyBVc2UgdGhlIGBjb25zdHJ1Y3RvcmAgcHJvcGVydHkgdG8gc2ltdWxhdGUgYE9iamVjdCNoYXNPd25Qcm9wZXJ0eWAgaW5cbiAgICAgICAgICAgIC8vIG90aGVyIGVudmlyb25tZW50cy5cbiAgICAgICAgICAgIGlzUHJvcGVydHkgPSBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgICAgdmFyIHBhcmVudCA9ICh0aGlzLmNvbnN0cnVjdG9yIHx8IGNvbnN0cnVjdG9yKS5wcm90b3R5cGU7XG4gICAgICAgICAgICAgIHJldHVybiBwcm9wZXJ0eSBpbiB0aGlzICYmICEocHJvcGVydHkgaW4gcGFyZW50ICYmIHRoaXNbcHJvcGVydHldID09PSBwYXJlbnRbcHJvcGVydHldKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuICAgICAgICAgIG1lbWJlcnMgPSBudWxsO1xuICAgICAgICAgIHJldHVybiBpc1Byb3BlcnR5LmNhbGwodGhpcywgcHJvcGVydHkpO1xuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICAvLyBJbnRlcm5hbDogTm9ybWFsaXplcyB0aGUgYGZvci4uLmluYCBpdGVyYXRpb24gYWxnb3JpdGhtIGFjcm9zc1xuICAgICAgLy8gZW52aXJvbm1lbnRzLiBFYWNoIGVudW1lcmF0ZWQga2V5IGlzIHlpZWxkZWQgdG8gYSBgY2FsbGJhY2tgIGZ1bmN0aW9uLlxuICAgICAgZm9yRWFjaCA9IGZ1bmN0aW9uIChvYmplY3QsIGNhbGxiYWNrKSB7XG4gICAgICAgIHZhciBzaXplID0gMCwgUHJvcGVydGllcywgbWVtYmVycywgcHJvcGVydHk7XG5cbiAgICAgICAgLy8gVGVzdHMgZm9yIGJ1Z3MgaW4gdGhlIGN1cnJlbnQgZW52aXJvbm1lbnQncyBgZm9yLi4uaW5gIGFsZ29yaXRobS4gVGhlXG4gICAgICAgIC8vIGB2YWx1ZU9mYCBwcm9wZXJ0eSBpbmhlcml0cyB0aGUgbm9uLWVudW1lcmFibGUgZmxhZyBmcm9tXG4gICAgICAgIC8vIGBPYmplY3QucHJvdG90eXBlYCBpbiBvbGRlciB2ZXJzaW9ucyBvZiBJRSwgTmV0c2NhcGUsIGFuZCBNb3ppbGxhLlxuICAgICAgICAoUHJvcGVydGllcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICB0aGlzLnZhbHVlT2YgPSAwO1xuICAgICAgICB9KS5wcm90b3R5cGUudmFsdWVPZiA9IDA7XG5cbiAgICAgICAgLy8gSXRlcmF0ZSBvdmVyIGEgbmV3IGluc3RhbmNlIG9mIHRoZSBgUHJvcGVydGllc2AgY2xhc3MuXG4gICAgICAgIG1lbWJlcnMgPSBuZXcgUHJvcGVydGllcygpO1xuICAgICAgICBmb3IgKHByb3BlcnR5IGluIG1lbWJlcnMpIHtcbiAgICAgICAgICAvLyBJZ25vcmUgYWxsIHByb3BlcnRpZXMgaW5oZXJpdGVkIGZyb20gYE9iamVjdC5wcm90b3R5cGVgLlxuICAgICAgICAgIGlmIChpc1Byb3BlcnR5LmNhbGwobWVtYmVycywgcHJvcGVydHkpKSB7XG4gICAgICAgICAgICBzaXplKys7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIFByb3BlcnRpZXMgPSBtZW1iZXJzID0gbnVsbDtcblxuICAgICAgICAvLyBOb3JtYWxpemUgdGhlIGl0ZXJhdGlvbiBhbGdvcml0aG0uXG4gICAgICAgIGlmICghc2l6ZSkge1xuICAgICAgICAgIC8vIEEgbGlzdCBvZiBub24tZW51bWVyYWJsZSBwcm9wZXJ0aWVzIGluaGVyaXRlZCBmcm9tIGBPYmplY3QucHJvdG90eXBlYC5cbiAgICAgICAgICBtZW1iZXJzID0gW1widmFsdWVPZlwiLCBcInRvU3RyaW5nXCIsIFwidG9Mb2NhbGVTdHJpbmdcIiwgXCJwcm9wZXJ0eUlzRW51bWVyYWJsZVwiLCBcImlzUHJvdG90eXBlT2ZcIiwgXCJoYXNPd25Qcm9wZXJ0eVwiLCBcImNvbnN0cnVjdG9yXCJdO1xuICAgICAgICAgIC8vIElFIDw9IDgsIE1vemlsbGEgMS4wLCBhbmQgTmV0c2NhcGUgNi4yIGlnbm9yZSBzaGFkb3dlZCBub24tZW51bWVyYWJsZVxuICAgICAgICAgIC8vIHByb3BlcnRpZXMuXG4gICAgICAgICAgZm9yRWFjaCA9IGZ1bmN0aW9uIChvYmplY3QsIGNhbGxiYWNrKSB7XG4gICAgICAgICAgICB2YXIgaXNGdW5jdGlvbiA9IGdldENsYXNzLmNhbGwob2JqZWN0KSA9PSBmdW5jdGlvbkNsYXNzLCBwcm9wZXJ0eSwgbGVuZ3RoO1xuICAgICAgICAgICAgdmFyIGhhc1Byb3BlcnR5ID0gIWlzRnVuY3Rpb24gJiYgdHlwZW9mIG9iamVjdC5jb25zdHJ1Y3RvciAhPSBcImZ1bmN0aW9uXCIgJiYgb2JqZWN0VHlwZXNbdHlwZW9mIG9iamVjdC5oYXNPd25Qcm9wZXJ0eV0gJiYgb2JqZWN0Lmhhc093blByb3BlcnR5IHx8IGlzUHJvcGVydHk7XG4gICAgICAgICAgICBmb3IgKHByb3BlcnR5IGluIG9iamVjdCkge1xuICAgICAgICAgICAgICAvLyBHZWNrbyA8PSAxLjAgZW51bWVyYXRlcyB0aGUgYHByb3RvdHlwZWAgcHJvcGVydHkgb2YgZnVuY3Rpb25zIHVuZGVyXG4gICAgICAgICAgICAgIC8vIGNlcnRhaW4gY29uZGl0aW9uczsgSUUgZG9lcyBub3QuXG4gICAgICAgICAgICAgIGlmICghKGlzRnVuY3Rpb24gJiYgcHJvcGVydHkgPT0gXCJwcm90b3R5cGVcIikgJiYgaGFzUHJvcGVydHkuY2FsbChvYmplY3QsIHByb3BlcnR5KSkge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKHByb3BlcnR5KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gTWFudWFsbHkgaW52b2tlIHRoZSBjYWxsYmFjayBmb3IgZWFjaCBub24tZW51bWVyYWJsZSBwcm9wZXJ0eS5cbiAgICAgICAgICAgIGZvciAobGVuZ3RoID0gbWVtYmVycy5sZW5ndGg7IHByb3BlcnR5ID0gbWVtYmVyc1stLWxlbmd0aF07IGhhc1Byb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSkgJiYgY2FsbGJhY2socHJvcGVydHkpKTtcbiAgICAgICAgICB9O1xuICAgICAgICB9IGVsc2UgaWYgKHNpemUgPT0gMikge1xuICAgICAgICAgIC8vIFNhZmFyaSA8PSAyLjAuNCBlbnVtZXJhdGVzIHNoYWRvd2VkIHByb3BlcnRpZXMgdHdpY2UuXG4gICAgICAgICAgZm9yRWFjaCA9IGZ1bmN0aW9uIChvYmplY3QsIGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAvLyBDcmVhdGUgYSBzZXQgb2YgaXRlcmF0ZWQgcHJvcGVydGllcy5cbiAgICAgICAgICAgIHZhciBtZW1iZXJzID0ge30sIGlzRnVuY3Rpb24gPSBnZXRDbGFzcy5jYWxsKG9iamVjdCkgPT0gZnVuY3Rpb25DbGFzcywgcHJvcGVydHk7XG4gICAgICAgICAgICBmb3IgKHByb3BlcnR5IGluIG9iamVjdCkge1xuICAgICAgICAgICAgICAvLyBTdG9yZSBlYWNoIHByb3BlcnR5IG5hbWUgdG8gcHJldmVudCBkb3VibGUgZW51bWVyYXRpb24uIFRoZVxuICAgICAgICAgICAgICAvLyBgcHJvdG90eXBlYCBwcm9wZXJ0eSBvZiBmdW5jdGlvbnMgaXMgbm90IGVudW1lcmF0ZWQgZHVlIHRvIGNyb3NzLVxuICAgICAgICAgICAgICAvLyBlbnZpcm9ubWVudCBpbmNvbnNpc3RlbmNpZXMuXG4gICAgICAgICAgICAgIGlmICghKGlzRnVuY3Rpb24gJiYgcHJvcGVydHkgPT0gXCJwcm90b3R5cGVcIikgJiYgIWlzUHJvcGVydHkuY2FsbChtZW1iZXJzLCBwcm9wZXJ0eSkgJiYgKG1lbWJlcnNbcHJvcGVydHldID0gMSkgJiYgaXNQcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2socHJvcGVydHkpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBObyBidWdzIGRldGVjdGVkOyB1c2UgdGhlIHN0YW5kYXJkIGBmb3IuLi5pbmAgYWxnb3JpdGhtLlxuICAgICAgICAgIGZvckVhY2ggPSBmdW5jdGlvbiAob2JqZWN0LCBjYWxsYmFjaykge1xuICAgICAgICAgICAgdmFyIGlzRnVuY3Rpb24gPSBnZXRDbGFzcy5jYWxsKG9iamVjdCkgPT0gZnVuY3Rpb25DbGFzcywgcHJvcGVydHksIGlzQ29uc3RydWN0b3I7XG4gICAgICAgICAgICBmb3IgKHByb3BlcnR5IGluIG9iamVjdCkge1xuICAgICAgICAgICAgICBpZiAoIShpc0Z1bmN0aW9uICYmIHByb3BlcnR5ID09IFwicHJvdG90eXBlXCIpICYmIGlzUHJvcGVydHkuY2FsbChvYmplY3QsIHByb3BlcnR5KSAmJiAhKGlzQ29uc3RydWN0b3IgPSBwcm9wZXJ0eSA9PT0gXCJjb25zdHJ1Y3RvclwiKSkge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKHByb3BlcnR5KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gTWFudWFsbHkgaW52b2tlIHRoZSBjYWxsYmFjayBmb3IgdGhlIGBjb25zdHJ1Y3RvcmAgcHJvcGVydHkgZHVlIHRvXG4gICAgICAgICAgICAvLyBjcm9zcy1lbnZpcm9ubWVudCBpbmNvbnNpc3RlbmNpZXMuXG4gICAgICAgICAgICBpZiAoaXNDb25zdHJ1Y3RvciB8fCBpc1Byb3BlcnR5LmNhbGwob2JqZWN0LCAocHJvcGVydHkgPSBcImNvbnN0cnVjdG9yXCIpKSkge1xuICAgICAgICAgICAgICBjYWxsYmFjayhwcm9wZXJ0eSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZm9yRWFjaChvYmplY3QsIGNhbGxiYWNrKTtcbiAgICAgIH07XG5cbiAgICAgIC8vIFB1YmxpYzogU2VyaWFsaXplcyBhIEphdmFTY3JpcHQgYHZhbHVlYCBhcyBhIEpTT04gc3RyaW5nLiBUaGUgb3B0aW9uYWxcbiAgICAgIC8vIGBmaWx0ZXJgIGFyZ3VtZW50IG1heSBzcGVjaWZ5IGVpdGhlciBhIGZ1bmN0aW9uIHRoYXQgYWx0ZXJzIGhvdyBvYmplY3QgYW5kXG4gICAgICAvLyBhcnJheSBtZW1iZXJzIGFyZSBzZXJpYWxpemVkLCBvciBhbiBhcnJheSBvZiBzdHJpbmdzIGFuZCBudW1iZXJzIHRoYXRcbiAgICAgIC8vIGluZGljYXRlcyB3aGljaCBwcm9wZXJ0aWVzIHNob3VsZCBiZSBzZXJpYWxpemVkLiBUaGUgb3B0aW9uYWwgYHdpZHRoYFxuICAgICAgLy8gYXJndW1lbnQgbWF5IGJlIGVpdGhlciBhIHN0cmluZyBvciBudW1iZXIgdGhhdCBzcGVjaWZpZXMgdGhlIGluZGVudGF0aW9uXG4gICAgICAvLyBsZXZlbCBvZiB0aGUgb3V0cHV0LlxuICAgICAgaWYgKCFoYXMoXCJqc29uLXN0cmluZ2lmeVwiKSkge1xuICAgICAgICAvLyBJbnRlcm5hbDogQSBtYXAgb2YgY29udHJvbCBjaGFyYWN0ZXJzIGFuZCB0aGVpciBlc2NhcGVkIGVxdWl2YWxlbnRzLlxuICAgICAgICB2YXIgRXNjYXBlcyA9IHtcbiAgICAgICAgICA5MjogXCJcXFxcXFxcXFwiLFxuICAgICAgICAgIDM0OiAnXFxcXFwiJyxcbiAgICAgICAgICA4OiBcIlxcXFxiXCIsXG4gICAgICAgICAgMTI6IFwiXFxcXGZcIixcbiAgICAgICAgICAxMDogXCJcXFxcblwiLFxuICAgICAgICAgIDEzOiBcIlxcXFxyXCIsXG4gICAgICAgICAgOTogXCJcXFxcdFwiXG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gSW50ZXJuYWw6IENvbnZlcnRzIGB2YWx1ZWAgaW50byBhIHplcm8tcGFkZGVkIHN0cmluZyBzdWNoIHRoYXQgaXRzXG4gICAgICAgIC8vIGxlbmd0aCBpcyBhdCBsZWFzdCBlcXVhbCB0byBgd2lkdGhgLiBUaGUgYHdpZHRoYCBtdXN0IGJlIDw9IDYuXG4gICAgICAgIHZhciBsZWFkaW5nWmVyb2VzID0gXCIwMDAwMDBcIjtcbiAgICAgICAgdmFyIHRvUGFkZGVkU3RyaW5nID0gZnVuY3Rpb24gKHdpZHRoLCB2YWx1ZSkge1xuICAgICAgICAgIC8vIFRoZSBgfHwgMGAgZXhwcmVzc2lvbiBpcyBuZWNlc3NhcnkgdG8gd29yayBhcm91bmQgYSBidWcgaW5cbiAgICAgICAgICAvLyBPcGVyYSA8PSA3LjU0dTIgd2hlcmUgYDAgPT0gLTBgLCBidXQgYFN0cmluZygtMCkgIT09IFwiMFwiYC5cbiAgICAgICAgICByZXR1cm4gKGxlYWRpbmdaZXJvZXMgKyAodmFsdWUgfHwgMCkpLnNsaWNlKC13aWR0aCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gSW50ZXJuYWw6IERvdWJsZS1xdW90ZXMgYSBzdHJpbmcgYHZhbHVlYCwgcmVwbGFjaW5nIGFsbCBBU0NJSSBjb250cm9sXG4gICAgICAgIC8vIGNoYXJhY3RlcnMgKGNoYXJhY3RlcnMgd2l0aCBjb2RlIHVuaXQgdmFsdWVzIGJldHdlZW4gMCBhbmQgMzEpIHdpdGhcbiAgICAgICAgLy8gdGhlaXIgZXNjYXBlZCBlcXVpdmFsZW50cy4gVGhpcyBpcyBhbiBpbXBsZW1lbnRhdGlvbiBvZiB0aGVcbiAgICAgICAgLy8gYFF1b3RlKHZhbHVlKWAgb3BlcmF0aW9uIGRlZmluZWQgaW4gRVMgNS4xIHNlY3Rpb24gMTUuMTIuMy5cbiAgICAgICAgdmFyIHVuaWNvZGVQcmVmaXggPSBcIlxcXFx1MDBcIjtcbiAgICAgICAgdmFyIHF1b3RlID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgdmFyIHJlc3VsdCA9ICdcIicsIGluZGV4ID0gMCwgbGVuZ3RoID0gdmFsdWUubGVuZ3RoLCB1c2VDaGFySW5kZXggPSAhY2hhckluZGV4QnVnZ3kgfHwgbGVuZ3RoID4gMTA7XG4gICAgICAgICAgdmFyIHN5bWJvbHMgPSB1c2VDaGFySW5kZXggJiYgKGNoYXJJbmRleEJ1Z2d5ID8gdmFsdWUuc3BsaXQoXCJcIikgOiB2YWx1ZSk7XG4gICAgICAgICAgZm9yICg7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgICAgICAgICB2YXIgY2hhckNvZGUgPSB2YWx1ZS5jaGFyQ29kZUF0KGluZGV4KTtcbiAgICAgICAgICAgIC8vIElmIHRoZSBjaGFyYWN0ZXIgaXMgYSBjb250cm9sIGNoYXJhY3RlciwgYXBwZW5kIGl0cyBVbmljb2RlIG9yXG4gICAgICAgICAgICAvLyBzaG9ydGhhbmQgZXNjYXBlIHNlcXVlbmNlOyBvdGhlcndpc2UsIGFwcGVuZCB0aGUgY2hhcmFjdGVyIGFzLWlzLlxuICAgICAgICAgICAgc3dpdGNoIChjaGFyQ29kZSkge1xuICAgICAgICAgICAgICBjYXNlIDg6IGNhc2UgOTogY2FzZSAxMDogY2FzZSAxMjogY2FzZSAxMzogY2FzZSAzNDogY2FzZSA5MjpcbiAgICAgICAgICAgICAgICByZXN1bHQgKz0gRXNjYXBlc1tjaGFyQ29kZV07XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgaWYgKGNoYXJDb2RlIDwgMzIpIHtcbiAgICAgICAgICAgICAgICAgIHJlc3VsdCArPSB1bmljb2RlUHJlZml4ICsgdG9QYWRkZWRTdHJpbmcoMiwgY2hhckNvZGUudG9TdHJpbmcoMTYpKTtcbiAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXN1bHQgKz0gdXNlQ2hhckluZGV4ID8gc3ltYm9sc1tpbmRleF0gOiB2YWx1ZS5jaGFyQXQoaW5kZXgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gcmVzdWx0ICsgJ1wiJztcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBJbnRlcm5hbDogUmVjdXJzaXZlbHkgc2VyaWFsaXplcyBhbiBvYmplY3QuIEltcGxlbWVudHMgdGhlXG4gICAgICAgIC8vIGBTdHIoa2V5LCBob2xkZXIpYCwgYEpPKHZhbHVlKWAsIGFuZCBgSkEodmFsdWUpYCBvcGVyYXRpb25zLlxuICAgICAgICB2YXIgc2VyaWFsaXplID0gZnVuY3Rpb24gKHByb3BlcnR5LCBvYmplY3QsIGNhbGxiYWNrLCBwcm9wZXJ0aWVzLCB3aGl0ZXNwYWNlLCBpbmRlbnRhdGlvbiwgc3RhY2spIHtcbiAgICAgICAgICB2YXIgdmFsdWUsIGNsYXNzTmFtZSwgeWVhciwgbW9udGgsIGRhdGUsIHRpbWUsIGhvdXJzLCBtaW51dGVzLCBzZWNvbmRzLCBtaWxsaXNlY29uZHMsIHJlc3VsdHMsIGVsZW1lbnQsIGluZGV4LCBsZW5ndGgsIHByZWZpeCwgcmVzdWx0O1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBOZWNlc3NhcnkgZm9yIGhvc3Qgb2JqZWN0IHN1cHBvcnQuXG4gICAgICAgICAgICB2YWx1ZSA9IG9iamVjdFtwcm9wZXJ0eV07XG4gICAgICAgICAgfSBjYXRjaCAoZXhjZXB0aW9uKSB7fVxuICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT0gXCJvYmplY3RcIiAmJiB2YWx1ZSkge1xuICAgICAgICAgICAgY2xhc3NOYW1lID0gZ2V0Q2xhc3MuY2FsbCh2YWx1ZSk7XG4gICAgICAgICAgICBpZiAoY2xhc3NOYW1lID09IGRhdGVDbGFzcyAmJiAhaXNQcm9wZXJ0eS5jYWxsKHZhbHVlLCBcInRvSlNPTlwiKSkge1xuICAgICAgICAgICAgICBpZiAodmFsdWUgPiAtMSAvIDAgJiYgdmFsdWUgPCAxIC8gMCkge1xuICAgICAgICAgICAgICAgIC8vIERhdGVzIGFyZSBzZXJpYWxpemVkIGFjY29yZGluZyB0byB0aGUgYERhdGUjdG9KU09OYCBtZXRob2RcbiAgICAgICAgICAgICAgICAvLyBzcGVjaWZpZWQgaW4gRVMgNS4xIHNlY3Rpb24gMTUuOS41LjQ0LiBTZWUgc2VjdGlvbiAxNS45LjEuMTVcbiAgICAgICAgICAgICAgICAvLyBmb3IgdGhlIElTTyA4NjAxIGRhdGUgdGltZSBzdHJpbmcgZm9ybWF0LlxuICAgICAgICAgICAgICAgIGlmIChnZXREYXkpIHtcbiAgICAgICAgICAgICAgICAgIC8vIE1hbnVhbGx5IGNvbXB1dGUgdGhlIHllYXIsIG1vbnRoLCBkYXRlLCBob3VycywgbWludXRlcyxcbiAgICAgICAgICAgICAgICAgIC8vIHNlY29uZHMsIGFuZCBtaWxsaXNlY29uZHMgaWYgdGhlIGBnZXRVVEMqYCBtZXRob2RzIGFyZVxuICAgICAgICAgICAgICAgICAgLy8gYnVnZ3kuIEFkYXB0ZWQgZnJvbSBAWWFmZmxlJ3MgYGRhdGUtc2hpbWAgcHJvamVjdC5cbiAgICAgICAgICAgICAgICAgIGRhdGUgPSBmbG9vcih2YWx1ZSAvIDg2NGU1KTtcbiAgICAgICAgICAgICAgICAgIGZvciAoeWVhciA9IGZsb29yKGRhdGUgLyAzNjUuMjQyNSkgKyAxOTcwIC0gMTsgZ2V0RGF5KHllYXIgKyAxLCAwKSA8PSBkYXRlOyB5ZWFyKyspO1xuICAgICAgICAgICAgICAgICAgZm9yIChtb250aCA9IGZsb29yKChkYXRlIC0gZ2V0RGF5KHllYXIsIDApKSAvIDMwLjQyKTsgZ2V0RGF5KHllYXIsIG1vbnRoICsgMSkgPD0gZGF0ZTsgbW9udGgrKyk7XG4gICAgICAgICAgICAgICAgICBkYXRlID0gMSArIGRhdGUgLSBnZXREYXkoeWVhciwgbW9udGgpO1xuICAgICAgICAgICAgICAgICAgLy8gVGhlIGB0aW1lYCB2YWx1ZSBzcGVjaWZpZXMgdGhlIHRpbWUgd2l0aGluIHRoZSBkYXkgKHNlZSBFU1xuICAgICAgICAgICAgICAgICAgLy8gNS4xIHNlY3Rpb24gMTUuOS4xLjIpLiBUaGUgZm9ybXVsYSBgKEEgJSBCICsgQikgJSBCYCBpcyB1c2VkXG4gICAgICAgICAgICAgICAgICAvLyB0byBjb21wdXRlIGBBIG1vZHVsbyBCYCwgYXMgdGhlIGAlYCBvcGVyYXRvciBkb2VzIG5vdFxuICAgICAgICAgICAgICAgICAgLy8gY29ycmVzcG9uZCB0byB0aGUgYG1vZHVsb2Agb3BlcmF0aW9uIGZvciBuZWdhdGl2ZSBudW1iZXJzLlxuICAgICAgICAgICAgICAgICAgdGltZSA9ICh2YWx1ZSAlIDg2NGU1ICsgODY0ZTUpICUgODY0ZTU7XG4gICAgICAgICAgICAgICAgICAvLyBUaGUgaG91cnMsIG1pbnV0ZXMsIHNlY29uZHMsIGFuZCBtaWxsaXNlY29uZHMgYXJlIG9idGFpbmVkIGJ5XG4gICAgICAgICAgICAgICAgICAvLyBkZWNvbXBvc2luZyB0aGUgdGltZSB3aXRoaW4gdGhlIGRheS4gU2VlIHNlY3Rpb24gMTUuOS4xLjEwLlxuICAgICAgICAgICAgICAgICAgaG91cnMgPSBmbG9vcih0aW1lIC8gMzZlNSkgJSAyNDtcbiAgICAgICAgICAgICAgICAgIG1pbnV0ZXMgPSBmbG9vcih0aW1lIC8gNmU0KSAlIDYwO1xuICAgICAgICAgICAgICAgICAgc2Vjb25kcyA9IGZsb29yKHRpbWUgLyAxZTMpICUgNjA7XG4gICAgICAgICAgICAgICAgICBtaWxsaXNlY29uZHMgPSB0aW1lICUgMWUzO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICB5ZWFyID0gdmFsdWUuZ2V0VVRDRnVsbFllYXIoKTtcbiAgICAgICAgICAgICAgICAgIG1vbnRoID0gdmFsdWUuZ2V0VVRDTW9udGgoKTtcbiAgICAgICAgICAgICAgICAgIGRhdGUgPSB2YWx1ZS5nZXRVVENEYXRlKCk7XG4gICAgICAgICAgICAgICAgICBob3VycyA9IHZhbHVlLmdldFVUQ0hvdXJzKCk7XG4gICAgICAgICAgICAgICAgICBtaW51dGVzID0gdmFsdWUuZ2V0VVRDTWludXRlcygpO1xuICAgICAgICAgICAgICAgICAgc2Vjb25kcyA9IHZhbHVlLmdldFVUQ1NlY29uZHMoKTtcbiAgICAgICAgICAgICAgICAgIG1pbGxpc2Vjb25kcyA9IHZhbHVlLmdldFVUQ01pbGxpc2Vjb25kcygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBTZXJpYWxpemUgZXh0ZW5kZWQgeWVhcnMgY29ycmVjdGx5LlxuICAgICAgICAgICAgICAgIHZhbHVlID0gKHllYXIgPD0gMCB8fCB5ZWFyID49IDFlNCA/ICh5ZWFyIDwgMCA/IFwiLVwiIDogXCIrXCIpICsgdG9QYWRkZWRTdHJpbmcoNiwgeWVhciA8IDAgPyAteWVhciA6IHllYXIpIDogdG9QYWRkZWRTdHJpbmcoNCwgeWVhcikpICtcbiAgICAgICAgICAgICAgICAgIFwiLVwiICsgdG9QYWRkZWRTdHJpbmcoMiwgbW9udGggKyAxKSArIFwiLVwiICsgdG9QYWRkZWRTdHJpbmcoMiwgZGF0ZSkgK1xuICAgICAgICAgICAgICAgICAgLy8gTW9udGhzLCBkYXRlcywgaG91cnMsIG1pbnV0ZXMsIGFuZCBzZWNvbmRzIHNob3VsZCBoYXZlIHR3b1xuICAgICAgICAgICAgICAgICAgLy8gZGlnaXRzOyBtaWxsaXNlY29uZHMgc2hvdWxkIGhhdmUgdGhyZWUuXG4gICAgICAgICAgICAgICAgICBcIlRcIiArIHRvUGFkZGVkU3RyaW5nKDIsIGhvdXJzKSArIFwiOlwiICsgdG9QYWRkZWRTdHJpbmcoMiwgbWludXRlcykgKyBcIjpcIiArIHRvUGFkZGVkU3RyaW5nKDIsIHNlY29uZHMpICtcbiAgICAgICAgICAgICAgICAgIC8vIE1pbGxpc2Vjb25kcyBhcmUgb3B0aW9uYWwgaW4gRVMgNS4wLCBidXQgcmVxdWlyZWQgaW4gNS4xLlxuICAgICAgICAgICAgICAgICAgXCIuXCIgKyB0b1BhZGRlZFN0cmluZygzLCBtaWxsaXNlY29uZHMpICsgXCJaXCI7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdmFsdWUgPSBudWxsO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiB2YWx1ZS50b0pTT04gPT0gXCJmdW5jdGlvblwiICYmICgoY2xhc3NOYW1lICE9IG51bWJlckNsYXNzICYmIGNsYXNzTmFtZSAhPSBzdHJpbmdDbGFzcyAmJiBjbGFzc05hbWUgIT0gYXJyYXlDbGFzcykgfHwgaXNQcm9wZXJ0eS5jYWxsKHZhbHVlLCBcInRvSlNPTlwiKSkpIHtcbiAgICAgICAgICAgICAgLy8gUHJvdG90eXBlIDw9IDEuNi4xIGFkZHMgbm9uLXN0YW5kYXJkIGB0b0pTT05gIG1ldGhvZHMgdG8gdGhlXG4gICAgICAgICAgICAgIC8vIGBOdW1iZXJgLCBgU3RyaW5nYCwgYERhdGVgLCBhbmQgYEFycmF5YCBwcm90b3R5cGVzLiBKU09OIDNcbiAgICAgICAgICAgICAgLy8gaWdub3JlcyBhbGwgYHRvSlNPTmAgbWV0aG9kcyBvbiB0aGVzZSBvYmplY3RzIHVubGVzcyB0aGV5IGFyZVxuICAgICAgICAgICAgICAvLyBkZWZpbmVkIGRpcmVjdGx5IG9uIGFuIGluc3RhbmNlLlxuICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnRvSlNPTihwcm9wZXJ0eSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgICAgLy8gSWYgYSByZXBsYWNlbWVudCBmdW5jdGlvbiB3YXMgcHJvdmlkZWQsIGNhbGwgaXQgdG8gb2J0YWluIHRoZSB2YWx1ZVxuICAgICAgICAgICAgLy8gZm9yIHNlcmlhbGl6YXRpb24uXG4gICAgICAgICAgICB2YWx1ZSA9IGNhbGxiYWNrLmNhbGwob2JqZWN0LCBwcm9wZXJ0eSwgdmFsdWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAodmFsdWUgPT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiBcIm51bGxcIjtcbiAgICAgICAgICB9XG4gICAgICAgICAgY2xhc3NOYW1lID0gZ2V0Q2xhc3MuY2FsbCh2YWx1ZSk7XG4gICAgICAgICAgaWYgKGNsYXNzTmFtZSA9PSBib29sZWFuQ2xhc3MpIHtcbiAgICAgICAgICAgIC8vIEJvb2xlYW5zIGFyZSByZXByZXNlbnRlZCBsaXRlcmFsbHkuXG4gICAgICAgICAgICByZXR1cm4gXCJcIiArIHZhbHVlO1xuICAgICAgICAgIH0gZWxzZSBpZiAoY2xhc3NOYW1lID09IG51bWJlckNsYXNzKSB7XG4gICAgICAgICAgICAvLyBKU09OIG51bWJlcnMgbXVzdCBiZSBmaW5pdGUuIGBJbmZpbml0eWAgYW5kIGBOYU5gIGFyZSBzZXJpYWxpemVkIGFzXG4gICAgICAgICAgICAvLyBgXCJudWxsXCJgLlxuICAgICAgICAgICAgcmV0dXJuIHZhbHVlID4gLTEgLyAwICYmIHZhbHVlIDwgMSAvIDAgPyBcIlwiICsgdmFsdWUgOiBcIm51bGxcIjtcbiAgICAgICAgICB9IGVsc2UgaWYgKGNsYXNzTmFtZSA9PSBzdHJpbmdDbGFzcykge1xuICAgICAgICAgICAgLy8gU3RyaW5ncyBhcmUgZG91YmxlLXF1b3RlZCBhbmQgZXNjYXBlZC5cbiAgICAgICAgICAgIHJldHVybiBxdW90ZShcIlwiICsgdmFsdWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBSZWN1cnNpdmVseSBzZXJpYWxpemUgb2JqZWN0cyBhbmQgYXJyYXlzLlxuICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgLy8gQ2hlY2sgZm9yIGN5Y2xpYyBzdHJ1Y3R1cmVzLiBUaGlzIGlzIGEgbGluZWFyIHNlYXJjaDsgcGVyZm9ybWFuY2VcbiAgICAgICAgICAgIC8vIGlzIGludmVyc2VseSBwcm9wb3J0aW9uYWwgdG8gdGhlIG51bWJlciBvZiB1bmlxdWUgbmVzdGVkIG9iamVjdHMuXG4gICAgICAgICAgICBmb3IgKGxlbmd0aCA9IHN0YWNrLmxlbmd0aDsgbGVuZ3RoLS07KSB7XG4gICAgICAgICAgICAgIGlmIChzdGFja1tsZW5ndGhdID09PSB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIC8vIEN5Y2xpYyBzdHJ1Y3R1cmVzIGNhbm5vdCBiZSBzZXJpYWxpemVkIGJ5IGBKU09OLnN0cmluZ2lmeWAuXG4gICAgICAgICAgICAgICAgdGhyb3cgVHlwZUVycm9yKCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEFkZCB0aGUgb2JqZWN0IHRvIHRoZSBzdGFjayBvZiB0cmF2ZXJzZWQgb2JqZWN0cy5cbiAgICAgICAgICAgIHN0YWNrLnB1c2godmFsdWUpO1xuICAgICAgICAgICAgcmVzdWx0cyA9IFtdO1xuICAgICAgICAgICAgLy8gU2F2ZSB0aGUgY3VycmVudCBpbmRlbnRhdGlvbiBsZXZlbCBhbmQgaW5kZW50IG9uZSBhZGRpdGlvbmFsIGxldmVsLlxuICAgICAgICAgICAgcHJlZml4ID0gaW5kZW50YXRpb247XG4gICAgICAgICAgICBpbmRlbnRhdGlvbiArPSB3aGl0ZXNwYWNlO1xuICAgICAgICAgICAgaWYgKGNsYXNzTmFtZSA9PSBhcnJheUNsYXNzKSB7XG4gICAgICAgICAgICAgIC8vIFJlY3Vyc2l2ZWx5IHNlcmlhbGl6ZSBhcnJheSBlbGVtZW50cy5cbiAgICAgICAgICAgICAgZm9yIChpbmRleCA9IDAsIGxlbmd0aCA9IHZhbHVlLmxlbmd0aDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KyspIHtcbiAgICAgICAgICAgICAgICBlbGVtZW50ID0gc2VyaWFsaXplKGluZGV4LCB2YWx1ZSwgY2FsbGJhY2ssIHByb3BlcnRpZXMsIHdoaXRlc3BhY2UsIGluZGVudGF0aW9uLCBzdGFjayk7XG4gICAgICAgICAgICAgICAgcmVzdWx0cy5wdXNoKGVsZW1lbnQgPT09IHVuZGVmID8gXCJudWxsXCIgOiBlbGVtZW50KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXN1bHQgPSByZXN1bHRzLmxlbmd0aCA/ICh3aGl0ZXNwYWNlID8gXCJbXFxuXCIgKyBpbmRlbnRhdGlvbiArIHJlc3VsdHMuam9pbihcIixcXG5cIiArIGluZGVudGF0aW9uKSArIFwiXFxuXCIgKyBwcmVmaXggKyBcIl1cIiA6IChcIltcIiArIHJlc3VsdHMuam9pbihcIixcIikgKyBcIl1cIikpIDogXCJbXVwiO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgLy8gUmVjdXJzaXZlbHkgc2VyaWFsaXplIG9iamVjdCBtZW1iZXJzLiBNZW1iZXJzIGFyZSBzZWxlY3RlZCBmcm9tXG4gICAgICAgICAgICAgIC8vIGVpdGhlciBhIHVzZXItc3BlY2lmaWVkIGxpc3Qgb2YgcHJvcGVydHkgbmFtZXMsIG9yIHRoZSBvYmplY3RcbiAgICAgICAgICAgICAgLy8gaXRzZWxmLlxuICAgICAgICAgICAgICBmb3JFYWNoKHByb3BlcnRpZXMgfHwgdmFsdWUsIGZ1bmN0aW9uIChwcm9wZXJ0eSkge1xuICAgICAgICAgICAgICAgIHZhciBlbGVtZW50ID0gc2VyaWFsaXplKHByb3BlcnR5LCB2YWx1ZSwgY2FsbGJhY2ssIHByb3BlcnRpZXMsIHdoaXRlc3BhY2UsIGluZGVudGF0aW9uLCBzdGFjayk7XG4gICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQgIT09IHVuZGVmKSB7XG4gICAgICAgICAgICAgICAgICAvLyBBY2NvcmRpbmcgdG8gRVMgNS4xIHNlY3Rpb24gMTUuMTIuMzogXCJJZiBgZ2FwYCB7d2hpdGVzcGFjZX1cbiAgICAgICAgICAgICAgICAgIC8vIGlzIG5vdCB0aGUgZW1wdHkgc3RyaW5nLCBsZXQgYG1lbWJlcmAge3F1b3RlKHByb3BlcnR5KSArIFwiOlwifVxuICAgICAgICAgICAgICAgICAgLy8gYmUgdGhlIGNvbmNhdGVuYXRpb24gb2YgYG1lbWJlcmAgYW5kIHRoZSBgc3BhY2VgIGNoYXJhY3Rlci5cIlxuICAgICAgICAgICAgICAgICAgLy8gVGhlIFwiYHNwYWNlYCBjaGFyYWN0ZXJcIiByZWZlcnMgdG8gdGhlIGxpdGVyYWwgc3BhY2VcbiAgICAgICAgICAgICAgICAgIC8vIGNoYXJhY3Rlciwgbm90IHRoZSBgc3BhY2VgIHt3aWR0aH0gYXJndW1lbnQgcHJvdmlkZWQgdG9cbiAgICAgICAgICAgICAgICAgIC8vIGBKU09OLnN0cmluZ2lmeWAuXG4gICAgICAgICAgICAgICAgICByZXN1bHRzLnB1c2gocXVvdGUocHJvcGVydHkpICsgXCI6XCIgKyAod2hpdGVzcGFjZSA/IFwiIFwiIDogXCJcIikgKyBlbGVtZW50KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICByZXN1bHQgPSByZXN1bHRzLmxlbmd0aCA/ICh3aGl0ZXNwYWNlID8gXCJ7XFxuXCIgKyBpbmRlbnRhdGlvbiArIHJlc3VsdHMuam9pbihcIixcXG5cIiArIGluZGVudGF0aW9uKSArIFwiXFxuXCIgKyBwcmVmaXggKyBcIn1cIiA6IChcIntcIiArIHJlc3VsdHMuam9pbihcIixcIikgKyBcIn1cIikpIDogXCJ7fVwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gUmVtb3ZlIHRoZSBvYmplY3QgZnJvbSB0aGUgdHJhdmVyc2VkIG9iamVjdCBzdGFjay5cbiAgICAgICAgICAgIHN0YWNrLnBvcCgpO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gUHVibGljOiBgSlNPTi5zdHJpbmdpZnlgLiBTZWUgRVMgNS4xIHNlY3Rpb24gMTUuMTIuMy5cbiAgICAgICAgZXhwb3J0cy5zdHJpbmdpZnkgPSBmdW5jdGlvbiAoc291cmNlLCBmaWx0ZXIsIHdpZHRoKSB7XG4gICAgICAgICAgdmFyIHdoaXRlc3BhY2UsIGNhbGxiYWNrLCBwcm9wZXJ0aWVzLCBjbGFzc05hbWU7XG4gICAgICAgICAgaWYgKG9iamVjdFR5cGVzW3R5cGVvZiBmaWx0ZXJdICYmIGZpbHRlcikge1xuICAgICAgICAgICAgaWYgKChjbGFzc05hbWUgPSBnZXRDbGFzcy5jYWxsKGZpbHRlcikpID09IGZ1bmN0aW9uQ2xhc3MpIHtcbiAgICAgICAgICAgICAgY2FsbGJhY2sgPSBmaWx0ZXI7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGNsYXNzTmFtZSA9PSBhcnJheUNsYXNzKSB7XG4gICAgICAgICAgICAgIC8vIENvbnZlcnQgdGhlIHByb3BlcnR5IG5hbWVzIGFycmF5IGludG8gYSBtYWtlc2hpZnQgc2V0LlxuICAgICAgICAgICAgICBwcm9wZXJ0aWVzID0ge307XG4gICAgICAgICAgICAgIGZvciAodmFyIGluZGV4ID0gMCwgbGVuZ3RoID0gZmlsdGVyLmxlbmd0aCwgdmFsdWU7IGluZGV4IDwgbGVuZ3RoOyB2YWx1ZSA9IGZpbHRlcltpbmRleCsrXSwgKChjbGFzc05hbWUgPSBnZXRDbGFzcy5jYWxsKHZhbHVlKSksIGNsYXNzTmFtZSA9PSBzdHJpbmdDbGFzcyB8fCBjbGFzc05hbWUgPT0gbnVtYmVyQ2xhc3MpICYmIChwcm9wZXJ0aWVzW3ZhbHVlXSA9IDEpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHdpZHRoKSB7XG4gICAgICAgICAgICBpZiAoKGNsYXNzTmFtZSA9IGdldENsYXNzLmNhbGwod2lkdGgpKSA9PSBudW1iZXJDbGFzcykge1xuICAgICAgICAgICAgICAvLyBDb252ZXJ0IHRoZSBgd2lkdGhgIHRvIGFuIGludGVnZXIgYW5kIGNyZWF0ZSBhIHN0cmluZyBjb250YWluaW5nXG4gICAgICAgICAgICAgIC8vIGB3aWR0aGAgbnVtYmVyIG9mIHNwYWNlIGNoYXJhY3RlcnMuXG4gICAgICAgICAgICAgIGlmICgod2lkdGggLT0gd2lkdGggJSAxKSA+IDApIHtcbiAgICAgICAgICAgICAgICBmb3IgKHdoaXRlc3BhY2UgPSBcIlwiLCB3aWR0aCA+IDEwICYmICh3aWR0aCA9IDEwKTsgd2hpdGVzcGFjZS5sZW5ndGggPCB3aWR0aDsgd2hpdGVzcGFjZSArPSBcIiBcIik7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAoY2xhc3NOYW1lID09IHN0cmluZ0NsYXNzKSB7XG4gICAgICAgICAgICAgIHdoaXRlc3BhY2UgPSB3aWR0aC5sZW5ndGggPD0gMTAgPyB3aWR0aCA6IHdpZHRoLnNsaWNlKDAsIDEwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gT3BlcmEgPD0gNy41NHUyIGRpc2NhcmRzIHRoZSB2YWx1ZXMgYXNzb2NpYXRlZCB3aXRoIGVtcHR5IHN0cmluZyBrZXlzXG4gICAgICAgICAgLy8gKGBcIlwiYCkgb25seSBpZiB0aGV5IGFyZSB1c2VkIGRpcmVjdGx5IHdpdGhpbiBhbiBvYmplY3QgbWVtYmVyIGxpc3RcbiAgICAgICAgICAvLyAoZS5nLiwgYCEoXCJcIiBpbiB7IFwiXCI6IDF9KWApLlxuICAgICAgICAgIHJldHVybiBzZXJpYWxpemUoXCJcIiwgKHZhbHVlID0ge30sIHZhbHVlW1wiXCJdID0gc291cmNlLCB2YWx1ZSksIGNhbGxiYWNrLCBwcm9wZXJ0aWVzLCB3aGl0ZXNwYWNlLCBcIlwiLCBbXSk7XG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIC8vIFB1YmxpYzogUGFyc2VzIGEgSlNPTiBzb3VyY2Ugc3RyaW5nLlxuICAgICAgaWYgKCFoYXMoXCJqc29uLXBhcnNlXCIpKSB7XG4gICAgICAgIHZhciBmcm9tQ2hhckNvZGUgPSBTdHJpbmcuZnJvbUNoYXJDb2RlO1xuXG4gICAgICAgIC8vIEludGVybmFsOiBBIG1hcCBvZiBlc2NhcGVkIGNvbnRyb2wgY2hhcmFjdGVycyBhbmQgdGhlaXIgdW5lc2NhcGVkXG4gICAgICAgIC8vIGVxdWl2YWxlbnRzLlxuICAgICAgICB2YXIgVW5lc2NhcGVzID0ge1xuICAgICAgICAgIDkyOiBcIlxcXFxcIixcbiAgICAgICAgICAzNDogJ1wiJyxcbiAgICAgICAgICA0NzogXCIvXCIsXG4gICAgICAgICAgOTg6IFwiXFxiXCIsXG4gICAgICAgICAgMTE2OiBcIlxcdFwiLFxuICAgICAgICAgIDExMDogXCJcXG5cIixcbiAgICAgICAgICAxMDI6IFwiXFxmXCIsXG4gICAgICAgICAgMTE0OiBcIlxcclwiXG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gSW50ZXJuYWw6IFN0b3JlcyB0aGUgcGFyc2VyIHN0YXRlLlxuICAgICAgICB2YXIgSW5kZXgsIFNvdXJjZTtcblxuICAgICAgICAvLyBJbnRlcm5hbDogUmVzZXRzIHRoZSBwYXJzZXIgc3RhdGUgYW5kIHRocm93cyBhIGBTeW50YXhFcnJvcmAuXG4gICAgICAgIHZhciBhYm9ydCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBJbmRleCA9IFNvdXJjZSA9IG51bGw7XG4gICAgICAgICAgdGhyb3cgU3ludGF4RXJyb3IoKTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBJbnRlcm5hbDogUmV0dXJucyB0aGUgbmV4dCB0b2tlbiwgb3IgYFwiJFwiYCBpZiB0aGUgcGFyc2VyIGhhcyByZWFjaGVkXG4gICAgICAgIC8vIHRoZSBlbmQgb2YgdGhlIHNvdXJjZSBzdHJpbmcuIEEgdG9rZW4gbWF5IGJlIGEgc3RyaW5nLCBudW1iZXIsIGBudWxsYFxuICAgICAgICAvLyBsaXRlcmFsLCBvciBCb29sZWFuIGxpdGVyYWwuXG4gICAgICAgIHZhciBsZXggPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgdmFyIHNvdXJjZSA9IFNvdXJjZSwgbGVuZ3RoID0gc291cmNlLmxlbmd0aCwgdmFsdWUsIGJlZ2luLCBwb3NpdGlvbiwgaXNTaWduZWQsIGNoYXJDb2RlO1xuICAgICAgICAgIHdoaWxlIChJbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgICAgY2hhckNvZGUgPSBzb3VyY2UuY2hhckNvZGVBdChJbmRleCk7XG4gICAgICAgICAgICBzd2l0Y2ggKGNoYXJDb2RlKSB7XG4gICAgICAgICAgICAgIGNhc2UgOTogY2FzZSAxMDogY2FzZSAxMzogY2FzZSAzMjpcbiAgICAgICAgICAgICAgICAvLyBTa2lwIHdoaXRlc3BhY2UgdG9rZW5zLCBpbmNsdWRpbmcgdGFicywgY2FycmlhZ2UgcmV0dXJucywgbGluZVxuICAgICAgICAgICAgICAgIC8vIGZlZWRzLCBhbmQgc3BhY2UgY2hhcmFjdGVycy5cbiAgICAgICAgICAgICAgICBJbmRleCsrO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICBjYXNlIDEyMzogY2FzZSAxMjU6IGNhc2UgOTE6IGNhc2UgOTM6IGNhc2UgNTg6IGNhc2UgNDQ6XG4gICAgICAgICAgICAgICAgLy8gUGFyc2UgYSBwdW5jdHVhdG9yIHRva2VuIChge2AsIGB9YCwgYFtgLCBgXWAsIGA6YCwgb3IgYCxgKSBhdFxuICAgICAgICAgICAgICAgIC8vIHRoZSBjdXJyZW50IHBvc2l0aW9uLlxuICAgICAgICAgICAgICAgIHZhbHVlID0gY2hhckluZGV4QnVnZ3kgPyBzb3VyY2UuY2hhckF0KEluZGV4KSA6IHNvdXJjZVtJbmRleF07XG4gICAgICAgICAgICAgICAgSW5kZXgrKztcbiAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgICAgICAgIGNhc2UgMzQ6XG4gICAgICAgICAgICAgICAgLy8gYFwiYCBkZWxpbWl0cyBhIEpTT04gc3RyaW5nOyBhZHZhbmNlIHRvIHRoZSBuZXh0IGNoYXJhY3RlciBhbmRcbiAgICAgICAgICAgICAgICAvLyBiZWdpbiBwYXJzaW5nIHRoZSBzdHJpbmcuIFN0cmluZyB0b2tlbnMgYXJlIHByZWZpeGVkIHdpdGggdGhlXG4gICAgICAgICAgICAgICAgLy8gc2VudGluZWwgYEBgIGNoYXJhY3RlciB0byBkaXN0aW5ndWlzaCB0aGVtIGZyb20gcHVuY3R1YXRvcnMgYW5kXG4gICAgICAgICAgICAgICAgLy8gZW5kLW9mLXN0cmluZyB0b2tlbnMuXG4gICAgICAgICAgICAgICAgZm9yICh2YWx1ZSA9IFwiQFwiLCBJbmRleCsrOyBJbmRleCA8IGxlbmd0aDspIHtcbiAgICAgICAgICAgICAgICAgIGNoYXJDb2RlID0gc291cmNlLmNoYXJDb2RlQXQoSW5kZXgpO1xuICAgICAgICAgICAgICAgICAgaWYgKGNoYXJDb2RlIDwgMzIpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gVW5lc2NhcGVkIEFTQ0lJIGNvbnRyb2wgY2hhcmFjdGVycyAodGhvc2Ugd2l0aCBhIGNvZGUgdW5pdFxuICAgICAgICAgICAgICAgICAgICAvLyBsZXNzIHRoYW4gdGhlIHNwYWNlIGNoYXJhY3RlcikgYXJlIG5vdCBwZXJtaXR0ZWQuXG4gICAgICAgICAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGNoYXJDb2RlID09IDkyKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEEgcmV2ZXJzZSBzb2xpZHVzIChgXFxgKSBtYXJrcyB0aGUgYmVnaW5uaW5nIG9mIGFuIGVzY2FwZWRcbiAgICAgICAgICAgICAgICAgICAgLy8gY29udHJvbCBjaGFyYWN0ZXIgKGluY2x1ZGluZyBgXCJgLCBgXFxgLCBhbmQgYC9gKSBvciBVbmljb2RlXG4gICAgICAgICAgICAgICAgICAgIC8vIGVzY2FwZSBzZXF1ZW5jZS5cbiAgICAgICAgICAgICAgICAgICAgY2hhckNvZGUgPSBzb3VyY2UuY2hhckNvZGVBdCgrK0luZGV4KTtcbiAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChjaGFyQ29kZSkge1xuICAgICAgICAgICAgICAgICAgICAgIGNhc2UgOTI6IGNhc2UgMzQ6IGNhc2UgNDc6IGNhc2UgOTg6IGNhc2UgMTE2OiBjYXNlIDExMDogY2FzZSAxMDI6IGNhc2UgMTE0OlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmV2aXZlIGVzY2FwZWQgY29udHJvbCBjaGFyYWN0ZXJzLlxuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgKz0gVW5lc2NhcGVzW2NoYXJDb2RlXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIEluZGV4Kys7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICBjYXNlIDExNzpcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGBcXHVgIG1hcmtzIHRoZSBiZWdpbm5pbmcgb2YgYSBVbmljb2RlIGVzY2FwZSBzZXF1ZW5jZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFkdmFuY2UgdG8gdGhlIGZpcnN0IGNoYXJhY3RlciBhbmQgdmFsaWRhdGUgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBmb3VyLWRpZ2l0IGNvZGUgcG9pbnQuXG4gICAgICAgICAgICAgICAgICAgICAgICBiZWdpbiA9ICsrSW5kZXg7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKHBvc2l0aW9uID0gSW5kZXggKyA0OyBJbmRleCA8IHBvc2l0aW9uOyBJbmRleCsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNoYXJDb2RlID0gc291cmNlLmNoYXJDb2RlQXQoSW5kZXgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBIHZhbGlkIHNlcXVlbmNlIGNvbXByaXNlcyBmb3VyIGhleGRpZ2l0cyAoY2FzZS1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW5zZW5zaXRpdmUpIHRoYXQgZm9ybSBhIHNpbmdsZSBoZXhhZGVjaW1hbCB2YWx1ZS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEoY2hhckNvZGUgPj0gNDggJiYgY2hhckNvZGUgPD0gNTcgfHwgY2hhckNvZGUgPj0gOTcgJiYgY2hhckNvZGUgPD0gMTAyIHx8IGNoYXJDb2RlID49IDY1ICYmIGNoYXJDb2RlIDw9IDcwKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEludmFsaWQgVW5pY29kZSBlc2NhcGUgc2VxdWVuY2UuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmV2aXZlIHRoZSBlc2NhcGVkIGNoYXJhY3Rlci5cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlICs9IGZyb21DaGFyQ29kZShcIjB4XCIgKyBzb3VyY2Uuc2xpY2UoYmVnaW4sIEluZGV4KSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSW52YWxpZCBlc2NhcGUgc2VxdWVuY2UuXG4gICAgICAgICAgICAgICAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY2hhckNvZGUgPT0gMzQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBBbiB1bmVzY2FwZWQgZG91YmxlLXF1b3RlIGNoYXJhY3RlciBtYXJrcyB0aGUgZW5kIG9mIHRoZVxuICAgICAgICAgICAgICAgICAgICAgIC8vIHN0cmluZy5cbiAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjaGFyQ29kZSA9IHNvdXJjZS5jaGFyQ29kZUF0KEluZGV4KTtcbiAgICAgICAgICAgICAgICAgICAgYmVnaW4gPSBJbmRleDtcbiAgICAgICAgICAgICAgICAgICAgLy8gT3B0aW1pemUgZm9yIHRoZSBjb21tb24gY2FzZSB3aGVyZSBhIHN0cmluZyBpcyB2YWxpZC5cbiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKGNoYXJDb2RlID49IDMyICYmIGNoYXJDb2RlICE9IDkyICYmIGNoYXJDb2RlICE9IDM0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgY2hhckNvZGUgPSBzb3VyY2UuY2hhckNvZGVBdCgrK0luZGV4KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvLyBBcHBlbmQgdGhlIHN0cmluZyBhcy1pcy5cbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgKz0gc291cmNlLnNsaWNlKGJlZ2luLCBJbmRleCk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChzb3VyY2UuY2hhckNvZGVBdChJbmRleCkgPT0gMzQpIHtcbiAgICAgICAgICAgICAgICAgIC8vIEFkdmFuY2UgdG8gdGhlIG5leHQgY2hhcmFjdGVyIGFuZCByZXR1cm4gdGhlIHJldml2ZWQgc3RyaW5nLlxuICAgICAgICAgICAgICAgICAgSW5kZXgrKztcbiAgICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gVW50ZXJtaW5hdGVkIHN0cmluZy5cbiAgICAgICAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIC8vIFBhcnNlIG51bWJlcnMgYW5kIGxpdGVyYWxzLlxuICAgICAgICAgICAgICAgIGJlZ2luID0gSW5kZXg7XG4gICAgICAgICAgICAgICAgLy8gQWR2YW5jZSBwYXN0IHRoZSBuZWdhdGl2ZSBzaWduLCBpZiBvbmUgaXMgc3BlY2lmaWVkLlxuICAgICAgICAgICAgICAgIGlmIChjaGFyQ29kZSA9PSA0NSkge1xuICAgICAgICAgICAgICAgICAgaXNTaWduZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgY2hhckNvZGUgPSBzb3VyY2UuY2hhckNvZGVBdCgrK0luZGV4KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gUGFyc2UgYW4gaW50ZWdlciBvciBmbG9hdGluZy1wb2ludCB2YWx1ZS5cbiAgICAgICAgICAgICAgICBpZiAoY2hhckNvZGUgPj0gNDggJiYgY2hhckNvZGUgPD0gNTcpIHtcbiAgICAgICAgICAgICAgICAgIC8vIExlYWRpbmcgemVyb2VzIGFyZSBpbnRlcnByZXRlZCBhcyBvY3RhbCBsaXRlcmFscy5cbiAgICAgICAgICAgICAgICAgIGlmIChjaGFyQ29kZSA9PSA0OCAmJiAoKGNoYXJDb2RlID0gc291cmNlLmNoYXJDb2RlQXQoSW5kZXggKyAxKSksIGNoYXJDb2RlID49IDQ4ICYmIGNoYXJDb2RlIDw9IDU3KSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBJbGxlZ2FsIG9jdGFsIGxpdGVyYWwuXG4gICAgICAgICAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBpc1NpZ25lZCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgLy8gUGFyc2UgdGhlIGludGVnZXIgY29tcG9uZW50LlxuICAgICAgICAgICAgICAgICAgZm9yICg7IEluZGV4IDwgbGVuZ3RoICYmICgoY2hhckNvZGUgPSBzb3VyY2UuY2hhckNvZGVBdChJbmRleCkpLCBjaGFyQ29kZSA+PSA0OCAmJiBjaGFyQ29kZSA8PSA1Nyk7IEluZGV4KyspO1xuICAgICAgICAgICAgICAgICAgLy8gRmxvYXRzIGNhbm5vdCBjb250YWluIGEgbGVhZGluZyBkZWNpbWFsIHBvaW50OyBob3dldmVyLCB0aGlzXG4gICAgICAgICAgICAgICAgICAvLyBjYXNlIGlzIGFscmVhZHkgYWNjb3VudGVkIGZvciBieSB0aGUgcGFyc2VyLlxuICAgICAgICAgICAgICAgICAgaWYgKHNvdXJjZS5jaGFyQ29kZUF0KEluZGV4KSA9PSA0Nikge1xuICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICsrSW5kZXg7XG4gICAgICAgICAgICAgICAgICAgIC8vIFBhcnNlIHRoZSBkZWNpbWFsIGNvbXBvbmVudC5cbiAgICAgICAgICAgICAgICAgICAgZm9yICg7IHBvc2l0aW9uIDwgbGVuZ3RoICYmICgoY2hhckNvZGUgPSBzb3VyY2UuY2hhckNvZGVBdChwb3NpdGlvbikpLCBjaGFyQ29kZSA+PSA0OCAmJiBjaGFyQ29kZSA8PSA1Nyk7IHBvc2l0aW9uKyspO1xuICAgICAgICAgICAgICAgICAgICBpZiAocG9zaXRpb24gPT0gSW5kZXgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBJbGxlZ2FsIHRyYWlsaW5nIGRlY2ltYWwuXG4gICAgICAgICAgICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBJbmRleCA9IHBvc2l0aW9uO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgLy8gUGFyc2UgZXhwb25lbnRzLiBUaGUgYGVgIGRlbm90aW5nIHRoZSBleHBvbmVudCBpc1xuICAgICAgICAgICAgICAgICAgLy8gY2FzZS1pbnNlbnNpdGl2ZS5cbiAgICAgICAgICAgICAgICAgIGNoYXJDb2RlID0gc291cmNlLmNoYXJDb2RlQXQoSW5kZXgpO1xuICAgICAgICAgICAgICAgICAgaWYgKGNoYXJDb2RlID09IDEwMSB8fCBjaGFyQ29kZSA9PSA2OSkge1xuICAgICAgICAgICAgICAgICAgICBjaGFyQ29kZSA9IHNvdXJjZS5jaGFyQ29kZUF0KCsrSW5kZXgpO1xuICAgICAgICAgICAgICAgICAgICAvLyBTa2lwIHBhc3QgdGhlIHNpZ24gZm9sbG93aW5nIHRoZSBleHBvbmVudCwgaWYgb25lIGlzXG4gICAgICAgICAgICAgICAgICAgIC8vIHNwZWNpZmllZC5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGNoYXJDb2RlID09IDQzIHx8IGNoYXJDb2RlID09IDQ1KSB7XG4gICAgICAgICAgICAgICAgICAgICAgSW5kZXgrKztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvLyBQYXJzZSB0aGUgZXhwb25lbnRpYWwgY29tcG9uZW50LlxuICAgICAgICAgICAgICAgICAgICBmb3IgKHBvc2l0aW9uID0gSW5kZXg7IHBvc2l0aW9uIDwgbGVuZ3RoICYmICgoY2hhckNvZGUgPSBzb3VyY2UuY2hhckNvZGVBdChwb3NpdGlvbikpLCBjaGFyQ29kZSA+PSA0OCAmJiBjaGFyQ29kZSA8PSA1Nyk7IHBvc2l0aW9uKyspO1xuICAgICAgICAgICAgICAgICAgICBpZiAocG9zaXRpb24gPT0gSW5kZXgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBJbGxlZ2FsIGVtcHR5IGV4cG9uZW50LlxuICAgICAgICAgICAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgSW5kZXggPSBwb3NpdGlvbjtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIC8vIENvZXJjZSB0aGUgcGFyc2VkIHZhbHVlIHRvIGEgSmF2YVNjcmlwdCBudW1iZXIuXG4gICAgICAgICAgICAgICAgICByZXR1cm4gK3NvdXJjZS5zbGljZShiZWdpbiwgSW5kZXgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBBIG5lZ2F0aXZlIHNpZ24gbWF5IG9ubHkgcHJlY2VkZSBudW1iZXJzLlxuICAgICAgICAgICAgICAgIGlmIChpc1NpZ25lZCkge1xuICAgICAgICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gYHRydWVgLCBgZmFsc2VgLCBhbmQgYG51bGxgIGxpdGVyYWxzLlxuICAgICAgICAgICAgICAgIGlmIChzb3VyY2Uuc2xpY2UoSW5kZXgsIEluZGV4ICsgNCkgPT0gXCJ0cnVlXCIpIHtcbiAgICAgICAgICAgICAgICAgIEluZGV4ICs9IDQ7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHNvdXJjZS5zbGljZShJbmRleCwgSW5kZXggKyA1KSA9PSBcImZhbHNlXCIpIHtcbiAgICAgICAgICAgICAgICAgIEluZGV4ICs9IDU7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChzb3VyY2Uuc2xpY2UoSW5kZXgsIEluZGV4ICsgNCkgPT0gXCJudWxsXCIpIHtcbiAgICAgICAgICAgICAgICAgIEluZGV4ICs9IDQ7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gVW5yZWNvZ25pemVkIHRva2VuLlxuICAgICAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIFJldHVybiB0aGUgc2VudGluZWwgYCRgIGNoYXJhY3RlciBpZiB0aGUgcGFyc2VyIGhhcyByZWFjaGVkIHRoZSBlbmRcbiAgICAgICAgICAvLyBvZiB0aGUgc291cmNlIHN0cmluZy5cbiAgICAgICAgICByZXR1cm4gXCIkXCI7XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gSW50ZXJuYWw6IFBhcnNlcyBhIEpTT04gYHZhbHVlYCB0b2tlbi5cbiAgICAgICAgdmFyIGdldCA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgIHZhciByZXN1bHRzLCBoYXNNZW1iZXJzO1xuICAgICAgICAgIGlmICh2YWx1ZSA9PSBcIiRcIikge1xuICAgICAgICAgICAgLy8gVW5leHBlY3RlZCBlbmQgb2YgaW5wdXQuXG4gICAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIGlmICgoY2hhckluZGV4QnVnZ3kgPyB2YWx1ZS5jaGFyQXQoMCkgOiB2YWx1ZVswXSkgPT0gXCJAXCIpIHtcbiAgICAgICAgICAgICAgLy8gUmVtb3ZlIHRoZSBzZW50aW5lbCBgQGAgY2hhcmFjdGVyLlxuICAgICAgICAgICAgICByZXR1cm4gdmFsdWUuc2xpY2UoMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBQYXJzZSBvYmplY3QgYW5kIGFycmF5IGxpdGVyYWxzLlxuICAgICAgICAgICAgaWYgKHZhbHVlID09IFwiW1wiKSB7XG4gICAgICAgICAgICAgIC8vIFBhcnNlcyBhIEpTT04gYXJyYXksIHJldHVybmluZyBhIG5ldyBKYXZhU2NyaXB0IGFycmF5LlxuICAgICAgICAgICAgICByZXN1bHRzID0gW107XG4gICAgICAgICAgICAgIGZvciAoOzsgaGFzTWVtYmVycyB8fCAoaGFzTWVtYmVycyA9IHRydWUpKSB7XG4gICAgICAgICAgICAgICAgdmFsdWUgPSBsZXgoKTtcbiAgICAgICAgICAgICAgICAvLyBBIGNsb3Npbmcgc3F1YXJlIGJyYWNrZXQgbWFya3MgdGhlIGVuZCBvZiB0aGUgYXJyYXkgbGl0ZXJhbC5cbiAgICAgICAgICAgICAgICBpZiAodmFsdWUgPT0gXCJdXCIpIHtcbiAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBJZiB0aGUgYXJyYXkgbGl0ZXJhbCBjb250YWlucyBlbGVtZW50cywgdGhlIGN1cnJlbnQgdG9rZW5cbiAgICAgICAgICAgICAgICAvLyBzaG91bGQgYmUgYSBjb21tYSBzZXBhcmF0aW5nIHRoZSBwcmV2aW91cyBlbGVtZW50IGZyb20gdGhlXG4gICAgICAgICAgICAgICAgLy8gbmV4dC5cbiAgICAgICAgICAgICAgICBpZiAoaGFzTWVtYmVycykge1xuICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlID09IFwiLFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gbGV4KCk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh2YWx1ZSA9PSBcIl1cIikge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIFVuZXhwZWN0ZWQgdHJhaWxpbmcgYCxgIGluIGFycmF5IGxpdGVyYWwuXG4gICAgICAgICAgICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQSBgLGAgbXVzdCBzZXBhcmF0ZSBlYWNoIGFycmF5IGVsZW1lbnQuXG4gICAgICAgICAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIEVsaXNpb25zIGFuZCBsZWFkaW5nIGNvbW1hcyBhcmUgbm90IHBlcm1pdHRlZC5cbiAgICAgICAgICAgICAgICBpZiAodmFsdWUgPT0gXCIsXCIpIHtcbiAgICAgICAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJlc3VsdHMucHVzaChnZXQodmFsdWUpKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0cztcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWUgPT0gXCJ7XCIpIHtcbiAgICAgICAgICAgICAgLy8gUGFyc2VzIGEgSlNPTiBvYmplY3QsIHJldHVybmluZyBhIG5ldyBKYXZhU2NyaXB0IG9iamVjdC5cbiAgICAgICAgICAgICAgcmVzdWx0cyA9IHt9O1xuICAgICAgICAgICAgICBmb3IgKDs7IGhhc01lbWJlcnMgfHwgKGhhc01lbWJlcnMgPSB0cnVlKSkge1xuICAgICAgICAgICAgICAgIHZhbHVlID0gbGV4KCk7XG4gICAgICAgICAgICAgICAgLy8gQSBjbG9zaW5nIGN1cmx5IGJyYWNlIG1hcmtzIHRoZSBlbmQgb2YgdGhlIG9iamVjdCBsaXRlcmFsLlxuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSA9PSBcIn1cIikge1xuICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIElmIHRoZSBvYmplY3QgbGl0ZXJhbCBjb250YWlucyBtZW1iZXJzLCB0aGUgY3VycmVudCB0b2tlblxuICAgICAgICAgICAgICAgIC8vIHNob3VsZCBiZSBhIGNvbW1hIHNlcGFyYXRvci5cbiAgICAgICAgICAgICAgICBpZiAoaGFzTWVtYmVycykge1xuICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlID09IFwiLFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gbGV4KCk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh2YWx1ZSA9PSBcIn1cIikge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIFVuZXhwZWN0ZWQgdHJhaWxpbmcgYCxgIGluIG9iamVjdCBsaXRlcmFsLlxuICAgICAgICAgICAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEEgYCxgIG11c3Qgc2VwYXJhdGUgZWFjaCBvYmplY3QgbWVtYmVyLlxuICAgICAgICAgICAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBMZWFkaW5nIGNvbW1hcyBhcmUgbm90IHBlcm1pdHRlZCwgb2JqZWN0IHByb3BlcnR5IG5hbWVzIG11c3QgYmVcbiAgICAgICAgICAgICAgICAvLyBkb3VibGUtcXVvdGVkIHN0cmluZ3MsIGFuZCBhIGA6YCBtdXN0IHNlcGFyYXRlIGVhY2ggcHJvcGVydHlcbiAgICAgICAgICAgICAgICAvLyBuYW1lIGFuZCB2YWx1ZS5cbiAgICAgICAgICAgICAgICBpZiAodmFsdWUgPT0gXCIsXCIgfHwgdHlwZW9mIHZhbHVlICE9IFwic3RyaW5nXCIgfHwgKGNoYXJJbmRleEJ1Z2d5ID8gdmFsdWUuY2hhckF0KDApIDogdmFsdWVbMF0pICE9IFwiQFwiIHx8IGxleCgpICE9IFwiOlwiKSB7XG4gICAgICAgICAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXN1bHRzW3ZhbHVlLnNsaWNlKDEpXSA9IGdldChsZXgoKSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdHM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBVbmV4cGVjdGVkIHRva2VuIGVuY291bnRlcmVkLlxuICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIEludGVybmFsOiBVcGRhdGVzIGEgdHJhdmVyc2VkIG9iamVjdCBtZW1iZXIuXG4gICAgICAgIHZhciB1cGRhdGUgPSBmdW5jdGlvbiAoc291cmNlLCBwcm9wZXJ0eSwgY2FsbGJhY2spIHtcbiAgICAgICAgICB2YXIgZWxlbWVudCA9IHdhbGsoc291cmNlLCBwcm9wZXJ0eSwgY2FsbGJhY2spO1xuICAgICAgICAgIGlmIChlbGVtZW50ID09PSB1bmRlZikge1xuICAgICAgICAgICAgZGVsZXRlIHNvdXJjZVtwcm9wZXJ0eV07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHNvdXJjZVtwcm9wZXJ0eV0gPSBlbGVtZW50O1xuICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICAvLyBJbnRlcm5hbDogUmVjdXJzaXZlbHkgdHJhdmVyc2VzIGEgcGFyc2VkIEpTT04gb2JqZWN0LCBpbnZva2luZyB0aGVcbiAgICAgICAgLy8gYGNhbGxiYWNrYCBmdW5jdGlvbiBmb3IgZWFjaCB2YWx1ZS4gVGhpcyBpcyBhbiBpbXBsZW1lbnRhdGlvbiBvZiB0aGVcbiAgICAgICAgLy8gYFdhbGsoaG9sZGVyLCBuYW1lKWAgb3BlcmF0aW9uIGRlZmluZWQgaW4gRVMgNS4xIHNlY3Rpb24gMTUuMTIuMi5cbiAgICAgICAgdmFyIHdhbGsgPSBmdW5jdGlvbiAoc291cmNlLCBwcm9wZXJ0eSwgY2FsbGJhY2spIHtcbiAgICAgICAgICB2YXIgdmFsdWUgPSBzb3VyY2VbcHJvcGVydHldLCBsZW5ndGg7XG4gICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PSBcIm9iamVjdFwiICYmIHZhbHVlKSB7XG4gICAgICAgICAgICAvLyBgZm9yRWFjaGAgY2FuJ3QgYmUgdXNlZCB0byB0cmF2ZXJzZSBhbiBhcnJheSBpbiBPcGVyYSA8PSA4LjU0XG4gICAgICAgICAgICAvLyBiZWNhdXNlIGl0cyBgT2JqZWN0I2hhc093blByb3BlcnR5YCBpbXBsZW1lbnRhdGlvbiByZXR1cm5zIGBmYWxzZWBcbiAgICAgICAgICAgIC8vIGZvciBhcnJheSBpbmRpY2VzIChlLmcuLCBgIVsxLCAyLCAzXS5oYXNPd25Qcm9wZXJ0eShcIjBcIilgKS5cbiAgICAgICAgICAgIGlmIChnZXRDbGFzcy5jYWxsKHZhbHVlKSA9PSBhcnJheUNsYXNzKSB7XG4gICAgICAgICAgICAgIGZvciAobGVuZ3RoID0gdmFsdWUubGVuZ3RoOyBsZW5ndGgtLTspIHtcbiAgICAgICAgICAgICAgICB1cGRhdGUodmFsdWUsIGxlbmd0aCwgY2FsbGJhY2spO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBmb3JFYWNoKHZhbHVlLCBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgICAgICB1cGRhdGUodmFsdWUsIHByb3BlcnR5LCBjYWxsYmFjayk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2suY2FsbChzb3VyY2UsIHByb3BlcnR5LCB2YWx1ZSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gUHVibGljOiBgSlNPTi5wYXJzZWAuIFNlZSBFUyA1LjEgc2VjdGlvbiAxNS4xMi4yLlxuICAgICAgICBleHBvcnRzLnBhcnNlID0gZnVuY3Rpb24gKHNvdXJjZSwgY2FsbGJhY2spIHtcbiAgICAgICAgICB2YXIgcmVzdWx0LCB2YWx1ZTtcbiAgICAgICAgICBJbmRleCA9IDA7XG4gICAgICAgICAgU291cmNlID0gXCJcIiArIHNvdXJjZTtcbiAgICAgICAgICByZXN1bHQgPSBnZXQobGV4KCkpO1xuICAgICAgICAgIC8vIElmIGEgSlNPTiBzdHJpbmcgY29udGFpbnMgbXVsdGlwbGUgdG9rZW5zLCBpdCBpcyBpbnZhbGlkLlxuICAgICAgICAgIGlmIChsZXgoKSAhPSBcIiRcIikge1xuICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gUmVzZXQgdGhlIHBhcnNlciBzdGF0ZS5cbiAgICAgICAgICBJbmRleCA9IFNvdXJjZSA9IG51bGw7XG4gICAgICAgICAgcmV0dXJuIGNhbGxiYWNrICYmIGdldENsYXNzLmNhbGwoY2FsbGJhY2spID09IGZ1bmN0aW9uQ2xhc3MgPyB3YWxrKCh2YWx1ZSA9IHt9LCB2YWx1ZVtcIlwiXSA9IHJlc3VsdCwgdmFsdWUpLCBcIlwiLCBjYWxsYmFjaykgOiByZXN1bHQ7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfVxuXG4gICAgZXhwb3J0c1tcInJ1bkluQ29udGV4dFwiXSA9IHJ1bkluQ29udGV4dDtcbiAgICByZXR1cm4gZXhwb3J0cztcbiAgfVxuXG4gIGlmIChmcmVlRXhwb3J0cyAmJiAhaXNMb2FkZXIpIHtcbiAgICAvLyBFeHBvcnQgZm9yIENvbW1vbkpTIGVudmlyb25tZW50cy5cbiAgICBydW5JbkNvbnRleHQocm9vdCwgZnJlZUV4cG9ydHMpO1xuICB9IGVsc2Uge1xuICAgIC8vIEV4cG9ydCBmb3Igd2ViIGJyb3dzZXJzIGFuZCBKYXZhU2NyaXB0IGVuZ2luZXMuXG4gICAgdmFyIG5hdGl2ZUpTT04gPSByb290LkpTT04sXG4gICAgICAgIHByZXZpb3VzSlNPTiA9IHJvb3RbXCJKU09OM1wiXSxcbiAgICAgICAgaXNSZXN0b3JlZCA9IGZhbHNlO1xuXG4gICAgdmFyIEpTT04zID0gcnVuSW5Db250ZXh0KHJvb3QsIChyb290W1wiSlNPTjNcIl0gPSB7XG4gICAgICAvLyBQdWJsaWM6IFJlc3RvcmVzIHRoZSBvcmlnaW5hbCB2YWx1ZSBvZiB0aGUgZ2xvYmFsIGBKU09OYCBvYmplY3QgYW5kXG4gICAgICAvLyByZXR1cm5zIGEgcmVmZXJlbmNlIHRvIHRoZSBgSlNPTjNgIG9iamVjdC5cbiAgICAgIFwibm9Db25mbGljdFwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghaXNSZXN0b3JlZCkge1xuICAgICAgICAgIGlzUmVzdG9yZWQgPSB0cnVlO1xuICAgICAgICAgIHJvb3QuSlNPTiA9IG5hdGl2ZUpTT047XG4gICAgICAgICAgcm9vdFtcIkpTT04zXCJdID0gcHJldmlvdXNKU09OO1xuICAgICAgICAgIG5hdGl2ZUpTT04gPSBwcmV2aW91c0pTT04gPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBKU09OMztcbiAgICAgIH1cbiAgICB9KSk7XG5cbiAgICByb290LkpTT04gPSB7XG4gICAgICBcInBhcnNlXCI6IEpTT04zLnBhcnNlLFxuICAgICAgXCJzdHJpbmdpZnlcIjogSlNPTjMuc3RyaW5naWZ5XG4gICAgfTtcbiAgfVxuXG4gIC8vIEV4cG9ydCBmb3IgYXN5bmNocm9ub3VzIG1vZHVsZSBsb2FkZXJzLlxuICBpZiAoaXNMb2FkZXIpIHtcbiAgICBkZWZpbmUoZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIEpTT04zO1xuICAgIH0pO1xuICB9XG59KS5jYWxsKHRoaXMpO1xuIiwiZnVuY3Rpb24gTWFwcGVyKClcbntcbiAgdmFyIHNvdXJjZXMgPSB7fTtcblxuXG4gIHRoaXMuZm9yRWFjaCA9IGZ1bmN0aW9uKGNhbGxiYWNrKVxuICB7XG4gICAgZm9yKHZhciBrZXkgaW4gc291cmNlcylcbiAgICB7XG4gICAgICB2YXIgc291cmNlID0gc291cmNlc1trZXldO1xuXG4gICAgICBmb3IodmFyIGtleTIgaW4gc291cmNlKVxuICAgICAgICBjYWxsYmFjayhzb3VyY2Vba2V5Ml0pO1xuICAgIH07XG4gIH07XG5cbiAgdGhpcy5nZXQgPSBmdW5jdGlvbihpZCwgc291cmNlKVxuICB7XG4gICAgdmFyIGlkcyA9IHNvdXJjZXNbc291cmNlXTtcbiAgICBpZihpZHMgPT0gdW5kZWZpbmVkKVxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcblxuICAgIHJldHVybiBpZHNbaWRdO1xuICB9O1xuXG4gIHRoaXMucmVtb3ZlID0gZnVuY3Rpb24oaWQsIHNvdXJjZSlcbiAge1xuICAgIHZhciBpZHMgPSBzb3VyY2VzW3NvdXJjZV07XG4gICAgaWYoaWRzID09IHVuZGVmaW5lZClcbiAgICAgIHJldHVybjtcblxuICAgIGRlbGV0ZSBpZHNbaWRdO1xuXG4gICAgLy8gQ2hlY2sgaXQncyBlbXB0eVxuICAgIGZvcih2YXIgaSBpbiBpZHMpe3JldHVybiBmYWxzZX1cblxuICAgIGRlbGV0ZSBzb3VyY2VzW3NvdXJjZV07XG4gIH07XG5cbiAgdGhpcy5zZXQgPSBmdW5jdGlvbih2YWx1ZSwgaWQsIHNvdXJjZSlcbiAge1xuICAgIGlmKHZhbHVlID09IHVuZGVmaW5lZClcbiAgICAgIHJldHVybiB0aGlzLnJlbW92ZShpZCwgc291cmNlKTtcblxuICAgIHZhciBpZHMgPSBzb3VyY2VzW3NvdXJjZV07XG4gICAgaWYoaWRzID09IHVuZGVmaW5lZClcbiAgICAgIHNvdXJjZXNbc291cmNlXSA9IGlkcyA9IHt9O1xuXG4gICAgaWRzW2lkXSA9IHZhbHVlO1xuICB9O1xufTtcblxuXG5NYXBwZXIucHJvdG90eXBlLnBvcCA9IGZ1bmN0aW9uKGlkLCBzb3VyY2UpXG57XG4gIHZhciB2YWx1ZSA9IHRoaXMuZ2V0KGlkLCBzb3VyY2UpO1xuICBpZih2YWx1ZSA9PSB1bmRlZmluZWQpXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcblxuICB0aGlzLnJlbW92ZShpZCwgc291cmNlKTtcblxuICByZXR1cm4gdmFsdWU7XG59O1xuXG5cbm1vZHVsZS5leHBvcnRzID0gTWFwcGVyO1xuIiwiLypcbiAqIChDKSBDb3B5cmlnaHQgMjAxNCBLdXJlbnRvIChodHRwOi8va3VyZW50by5vcmcvKVxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICovXG5cbnZhciBKc29uUnBjQ2xpZW50ICA9IHJlcXVpcmUoJy4vanNvbnJwY2NsaWVudCcpO1xuXG5cbmV4cG9ydHMuSnNvblJwY0NsaWVudCAgPSBKc29uUnBjQ2xpZW50OyIsIi8qXG4gKiAoQykgQ29weXJpZ2h0IDIwMTQgS3VyZW50byAoaHR0cDovL2t1cmVudG8ub3JnLylcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICpcbiAqL1xuXG52YXIgUnBjQnVpbGRlciA9IHJlcXVpcmUoJy4uLy4uJyk7XG52YXIgV2ViU29ja2V0V2l0aFJlY29ubmVjdGlvbiA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0cy93ZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uJyk7XG5cbkRhdGUubm93ID0gRGF0ZS5ub3cgfHwgZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuICtuZXcgRGF0ZTtcbn07XG5cbnZhciBQSU5HX0lOVEVSVkFMID0gNTAwMDtcblxudmFyIFJFQ09OTkVDVElORyA9ICdSRUNPTk5FQ1RJTkcnO1xudmFyIENPTk5FQ1RFRCA9ICdDT05ORUNURUQnO1xudmFyIERJU0NPTk5FQ1RFRCA9ICdESVNDT05ORUNURUQnO1xuXG52YXIgUkVDT05ORUNUSU5HID0gXCJSRUNPTk5FQ1RJTkdcIjtcbnZhciBDT05ORUNURUQgPSBcIkNPTk5FQ1RFRFwiO1xudmFyIERJU0NPTk5FQ1RFRCA9IFwiRElTQ09OTkVDVEVEXCI7XG5cblxuLyoqXG4gKlxuICogaGVhcnRiZWF0OiBpbnRlcnZhbCBpbiBtcyBmb3IgZWFjaCBoZWFydGJlYXQgbWVzc2FnZSxcbiAqIHNlbmRDbG9zZU1lc3NhZ2UgOiB0cnVlIC8gZmFsc2UsIGJlZm9yZSBjbG9zaW5nIHRoZSBjb25uZWN0aW9uLCBpdCBzZW5kcyBhIGNsb3NlU2Vzc2lvbiBtZXNzYWdlXG4gKiA8cHJlPlxuICogd3MgOiB7XG4gKiBcdHVyaSA6IFVSSSB0byBjb25udGVjdCB0byxcbiAqICB1c2VTb2NrSlMgOiB0cnVlICh1c2UgU29ja0pTKSAvIGZhbHNlICh1c2UgV2ViU29ja2V0KSBieSBkZWZhdWx0LFxuICogXHRvbmNvbm5lY3RlZCA6IGNhbGxiYWNrIG1ldGhvZCB0byBpbnZva2Ugd2hlbiBjb25uZWN0aW9uIGlzIHN1Y2Nlc3NmdWwsXG4gKiBcdG9uZGlzY29ubmVjdCA6IGNhbGxiYWNrIG1ldGhvZCB0byBpbnZva2Ugd2hlbiB0aGUgY29ubmVjdGlvbiBpcyBsb3N0LFxuICogXHRvbnJlY29ubmVjdGluZyA6IGNhbGxiYWNrIG1ldGhvZCB0byBpbnZva2Ugd2hlbiB0aGUgY2xpZW50IGlzIHJlY29ubmVjdGluZyxcbiAqIFx0b25yZWNvbm5lY3RlZCA6IGNhbGxiYWNrIG1ldGhvZCB0byBpbnZva2Ugd2hlbiB0aGUgY2xpZW50IHN1Y2Nlc2Z1bGx5IHJlY29ubmVjdHMsXG4gKiB9LFxuICogcnBjIDoge1xuICogXHRyZXF1ZXN0VGltZW91dCA6IHRpbWVvdXQgZm9yIGEgcmVxdWVzdCxcbiAqIFx0c2Vzc2lvblN0YXR1c0NoYW5nZWQ6IGNhbGxiYWNrIG1ldGhvZCBmb3IgY2hhbmdlcyBpbiBzZXNzaW9uIHN0YXR1cyxcbiAqIFx0bWVkaWFSZW5lZ290aWF0aW9uOiBtZWRpYVJlbmVnb3RpYXRpb25cbiAqIH1cbiAqIDwvcHJlPlxuICovXG5mdW5jdGlvbiBKc29uUnBjQ2xpZW50KGNvbmZpZ3VyYXRpb24pIHtcblxuICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgIHZhciB3c0NvbmZpZyA9IGNvbmZpZ3VyYXRpb24ud3M7XG5cbiAgICB2YXIgbm90UmVjb25uZWN0SWZOdW1MZXNzVGhhbiA9IC0xO1xuXG4gICAgdmFyIHBpbmdOZXh0TnVtID0gMDtcbiAgICB2YXIgZW5hYmxlZFBpbmdzID0gdHJ1ZTtcbiAgICB2YXIgcGluZ1BvbmdTdGFydGVkID0gZmFsc2U7XG4gICAgdmFyIHBpbmdJbnRlcnZhbDtcblxuICAgIHZhciBzdGF0dXMgPSBESVNDT05ORUNURUQ7XG5cbiAgICB2YXIgb25yZWNvbm5lY3RpbmcgPSB3c0NvbmZpZy5vbnJlY29ubmVjdGluZztcbiAgICB2YXIgb25yZWNvbm5lY3RlZCA9IHdzQ29uZmlnLm9ucmVjb25uZWN0ZWQ7XG4gICAgdmFyIG9uY29ubmVjdGVkID0gd3NDb25maWcub25jb25uZWN0ZWQ7XG5cbiAgICBjb25maWd1cmF0aW9uLnJwYy5wdWxsID0gZnVuY3Rpb24ocGFyYW1zLCByZXF1ZXN0KSB7XG4gICAgICAgIHJlcXVlc3QucmVwbHkobnVsbCwgXCJwdXNoXCIpO1xuICAgIH1cblxuICAgIHdzQ29uZmlnLm9ucmVjb25uZWN0aW5nID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiLS0tLS0tLS0tIE9OUkVDT05ORUNUSU5HIC0tLS0tLS0tLS0tXCIpO1xuICAgICAgICBpZiAoc3RhdHVzID09PSBSRUNPTk5FQ1RJTkcpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJXZWJzb2NrZXQgYWxyZWFkeSBpbiBSRUNPTk5FQ1RJTkcgc3RhdGUgd2hlbiByZWNlaXZpbmcgYSBuZXcgT05SRUNPTk5FQ1RJTkcgbWVzc2FnZS4gSWdub3JpbmcgaXRcIik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBzdGF0dXMgPSBSRUNPTk5FQ1RJTkc7XG4gICAgICAgIGlmIChvbnJlY29ubmVjdGluZykge1xuICAgICAgICAgICAgb25yZWNvbm5lY3RpbmcoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHdzQ29uZmlnLm9ucmVjb25uZWN0ZWQgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCItLS0tLS0tLS0gT05SRUNPTk5FQ1RFRCAtLS0tLS0tLS0tLVwiKTtcbiAgICAgICAgaWYgKHN0YXR1cyA9PT0gQ09OTkVDVEVEKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiV2Vic29ja2V0IGFscmVhZHkgaW4gQ09OTkVDVEVEIHN0YXRlIHdoZW4gcmVjZWl2aW5nIGEgbmV3IE9OUkVDT05ORUNURUQgbWVzc2FnZS4gSWdub3JpbmcgaXRcIik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgc3RhdHVzID0gQ09OTkVDVEVEO1xuXG4gICAgICAgIGVuYWJsZWRQaW5ncyA9IHRydWU7XG4gICAgICAgIHVwZGF0ZU5vdFJlY29ubmVjdElmTGVzc1RoYW4oKTtcbiAgICAgICAgdXNlUGluZygpO1xuXG4gICAgICAgIGlmIChvbnJlY29ubmVjdGVkKSB7XG4gICAgICAgICAgICBvbnJlY29ubmVjdGVkKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB3c0NvbmZpZy5vbmNvbm5lY3RlZCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBjb25zb2xlLmxvZyhcIi0tLS0tLS0tLSBPTkNPTk5FQ1RFRCAtLS0tLS0tLS0tLVwiKTtcbiAgICAgICAgaWYgKHN0YXR1cyA9PT0gQ09OTkVDVEVEKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiV2Vic29ja2V0IGFscmVhZHkgaW4gQ09OTkVDVEVEIHN0YXRlIHdoZW4gcmVjZWl2aW5nIGEgbmV3IE9OQ09OTkVDVEVEIG1lc3NhZ2UuIElnbm9yaW5nIGl0XCIpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHN0YXR1cyA9IENPTk5FQ1RFRDtcblxuICAgICAgICBlbmFibGVkUGluZ3MgPSB0cnVlO1xuICAgICAgICB1c2VQaW5nKCk7XG5cbiAgICAgICAgaWYgKG9uY29ubmVjdGVkKSB7XG4gICAgICAgICAgICBvbmNvbm5lY3RlZCgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdmFyIHdzID0gbmV3IFdlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb24od3NDb25maWcpO1xuXG4gICAgY29uc29sZS5sb2coJ0Nvbm5lY3Rpbmcgd2Vic29ja2V0IHRvIFVSSTogJyArIHdzQ29uZmlnLnVyaSk7XG5cbiAgICB2YXIgcnBjQnVpbGRlck9wdGlvbnMgPSB7XG4gICAgICAgIHJlcXVlc3RfdGltZW91dDogY29uZmlndXJhdGlvbi5ycGMucmVxdWVzdFRpbWVvdXRcbiAgICB9O1xuXG4gICAgdmFyIHJwYyA9IG5ldyBScGNCdWlsZGVyKFJwY0J1aWxkZXIucGFja2Vycy5Kc29uUlBDLCBycGNCdWlsZGVyT3B0aW9ucywgd3MsXG4gICAgICAgIGZ1bmN0aW9uKHJlcXVlc3QpIHtcblxuICAgICAgICAgICAgY29uc29sZS5sb2coJ1JlY2VpdmVkIHJlcXVlc3Q6ICcgKyBKU09OLnN0cmluZ2lmeShyZXF1ZXN0KSk7XG5cbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdmFyIGZ1bmMgPSBjb25maWd1cmF0aW9uLnJwY1tyZXF1ZXN0Lm1ldGhvZF07XG5cbiAgICAgICAgICAgICAgICBpZiAoZnVuYyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJNZXRob2QgXCIgKyByZXF1ZXN0Lm1ldGhvZCArIFwiIG5vdCByZWdpc3RlcmVkIGluIGNsaWVudFwiKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBmdW5jKHJlcXVlc3QucGFyYW1zLCByZXF1ZXN0KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdFeGNlcHRpb24gcHJvY2Vzc2luZyByZXF1ZXN0OiAnICsgSlNPTi5zdHJpbmdpZnkocmVxdWVzdCkpO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICB0aGlzLnNlbmQgPSBmdW5jdGlvbihtZXRob2QsIHBhcmFtcywgY2FsbGJhY2spIHtcbiAgICAgICAgaWYgKG1ldGhvZCAhPT0gJ3BpbmcnKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygnUmVxdWVzdDogbWV0aG9kOicgKyBtZXRob2QgKyBcIiBwYXJhbXM6XCIgKyBKU09OLnN0cmluZ2lmeShwYXJhbXMpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciByZXF1ZXN0VGltZSA9IERhdGUubm93KCk7XG5cbiAgICAgICAgcnBjLmVuY29kZShtZXRob2QsIHBhcmFtcywgZnVuY3Rpb24oZXJyb3IsIHJlc3VsdCkge1xuICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVSUk9SOlwiICsgZXJyb3IubWVzc2FnZSArIFwiIGluIFJlcXVlc3Q6IG1ldGhvZDpcIiArIG1ldGhvZCArIFwiIHBhcmFtczpcIiArIEpTT04uc3RyaW5naWZ5KHBhcmFtcykpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyb3IuZGF0YSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVSUk9SIERBVEE6XCIgKyBKU09OLnN0cmluZ2lmeShlcnJvci5kYXRhKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7fVxuICAgICAgICAgICAgICAgIGVycm9yLnJlcXVlc3RUaW1lID0gcmVxdWVzdFRpbWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICBpZiAocmVzdWx0ICE9IHVuZGVmaW5lZCAmJiByZXN1bHQudmFsdWUgIT09ICdwb25nJykge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnUmVzcG9uc2U6ICcgKyBKU09OLnN0cmluZ2lmeShyZXN1bHQpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soZXJyb3IsIHJlc3VsdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHVwZGF0ZU5vdFJlY29ubmVjdElmTGVzc1RoYW4oKSB7XG4gICAgICAgIG5vdFJlY29ubmVjdElmTnVtTGVzc1RoYW4gPSBwaW5nTmV4dE51bTtcbiAgICAgICAgY29uc29sZS5sb2coXCJub3RSZWNvbm5lY3RJZk51bUxlc3NUaGFuID0gXCIgKyBub3RSZWNvbm5lY3RJZk51bUxlc3NUaGFuKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzZW5kUGluZygpIHtcbiAgICAgICAgaWYgKGVuYWJsZWRQaW5ncykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9IG51bGw7XG5cbiAgICAgICAgICAgIGlmIChwaW5nTmV4dE51bSA9PSAwIHx8IHBpbmdOZXh0TnVtID09IG5vdFJlY29ubmVjdElmTnVtTGVzc1RoYW4pIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgICAgIGludGVydmFsOiBQSU5HX0lOVEVSVkFMXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcGluZ05leHROdW0rKztcblxuICAgICAgICAgICAgc2VsZi5zZW5kKCdwaW5nJywgcGFyYW1zLCAoZnVuY3Rpb24ocGluZ051bSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbihlcnJvciwgcmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBpbmdOdW0gPiBub3RSZWNvbm5lY3RJZk51bUxlc3NUaGFuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5hYmxlZFBpbmdzID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBkYXRlTm90UmVjb25uZWN0SWZMZXNzVGhhbigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiRFNTIGRpZCBub3QgcmVzcG9uZCB0byBwaW5nIG1lc3NhZ2UgXCIgKyBwaW5nTnVtICsgXCIuIFJlY29ubmVjdGluZy4uLiBcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd3MucmVjb25uZWN0V3MoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pKHBpbmdOZXh0TnVtKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIlRyeWluZyB0byBzZW5kIHBpbmcsIGJ1dCBwaW5nIGlzIG5vdCBlbmFibGVkXCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLypcbiAgICAqIElmIGNvbmZpZ3VyYXRpb24uaGVhcmJlYXQgaGFzIGFueSB2YWx1ZSwgdGhlIHBpbmctcG9uZyB3aWxsIHdvcmsgd2l0aCB0aGUgaW50ZXJ2YWxcbiAgICAqIG9mIGNvbmZpZ3VyYXRpb24uaGVhcmJlYXRcbiAgICAqL1xuICAgIGZ1bmN0aW9uIHVzZVBpbmcoKSB7XG4gICAgICAgIGlmICghcGluZ1BvbmdTdGFydGVkKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIlN0YXJ0aW5nIHBpbmcgKGlmIGNvbmZpZ3VyZWQpXCIpXG4gICAgICAgICAgICBwaW5nUG9uZ1N0YXJ0ZWQgPSB0cnVlO1xuXG4gICAgICAgICAgICBpZiAoY29uZmlndXJhdGlvbi5oZWFydGJlYXQgIT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcGluZ0ludGVydmFsID0gc2V0SW50ZXJ2YWwoc2VuZFBpbmcsIGNvbmZpZ3VyYXRpb24uaGVhcnRiZWF0KTtcbiAgICAgICAgICAgICAgICBzZW5kUGluZygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBjb25zb2xlLmxvZyhcIkNsb3NpbmcganNvblJwY0NsaWVudCBleHBsaWNpdGVseSBieSBjbGllbnRcIik7XG5cbiAgICAgICAgaWYgKHBpbmdJbnRlcnZhbCAhPSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwocGluZ0ludGVydmFsKTtcbiAgICAgICAgfVxuICAgICAgICBwaW5nUG9uZ1N0YXJ0ZWQgPSBmYWxzZTtcbiAgICAgICAgZW5hYmxlZFBpbmdzID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKGNvbmZpZ3VyYXRpb24uc2VuZENsb3NlTWVzc2FnZSkge1xuICAgICAgICAgICAgdGhpcy5zZW5kKCdjbG9zZVNlc3Npb24nLCBudWxsLCBmdW5jdGlvbihlcnJvciwgcmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBzZW5kaW5nIGNsb3NlIG1lc3NhZ2U6IFwiICsgSlNPTi5zdHJpbmdpZnkoZXJyb3IpKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB3cy5jbG9zZSgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG5cdFx0XHR3cy5jbG9zZSgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gVGhpcyBtZXRob2QgaXMgb25seSBmb3IgdGVzdGluZ1xuICAgIHRoaXMuZm9yY2VDbG9zZSA9IGZ1bmN0aW9uKG1pbGxpcykge1xuICAgICAgICB3cy5mb3JjZUNsb3NlKG1pbGxpcyk7XG4gICAgfVxuXG4gICAgdGhpcy5yZWNvbm5lY3QgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgd3MucmVjb25uZWN0V3MoKTtcbiAgICB9XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBKc29uUnBjQ2xpZW50O1xuIiwiLypcbiAqIChDKSBDb3B5cmlnaHQgMjAxNCBLdXJlbnRvIChodHRwOi8va3VyZW50by5vcmcvKVxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICovXG5cbnZhciBXZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uICA9IHJlcXVpcmUoJy4vd2ViU29ja2V0V2l0aFJlY29ubmVjdGlvbicpO1xuXG5cbmV4cG9ydHMuV2ViU29ja2V0V2l0aFJlY29ubmVjdGlvbiAgPSBXZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uOyIsIi8qXG4gKiAoQykgQ29weXJpZ2h0IDIwMTMtMjAxNSBLdXJlbnRvIChodHRwOi8va3VyZW50by5vcmcvKVxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBXZWJTb2NrZXQgPSByZXF1aXJlKCd3cycpO1xudmFyIFNvY2tKUyA9IHJlcXVpcmUoJ3NvY2tqcy1jbGllbnQnKTtcblxudmFyIE1BWF9SRVRSSUVTID0gMjAwMDsgLy8gRm9yZXZlci4uLlxudmFyIFJFVFJZX1RJTUVfTVMgPSAzMDAwOyAvLyBGSVhNRTogSW1wbGVtZW50IGV4cG9uZW50aWFsIHdhaXQgdGltZXMuLi5cbnZhciBQSU5HX0lOVEVSVkFMID0gNTAwMDtcbnZhciBQSU5HX01TRyA9IEpTT04uc3RyaW5naWZ5KHtcbiAgICAnbWV0aG9kJzogJ3BpbmcnXG59KTtcblxudmFyIENPTk5FQ1RJTkcgPSAwO1xudmFyIE9QRU4gPSAxO1xudmFyIENMT1NJTkcgPSAyO1xudmFyIENMT1NFRCA9IDM7XG5cbi8qXG5jb25maWcgPSB7XG5cdFx0dXJpIDogd3NVcmksXG5cdFx0dXNlU29ja0pTIDogdHJ1ZSAodXNlIFNvY2tKUykgLyBmYWxzZSAodXNlIFdlYlNvY2tldCkgYnkgZGVmYXVsdCxcblx0XHRvbmNvbm5lY3RlZCA6IGNhbGxiYWNrIG1ldGhvZCB0byBpbnZva2Ugd2hlbiBjb25uZWN0aW9uIGlzIHN1Y2Nlc3NmdWwsXG5cdFx0b25kaXNjb25uZWN0IDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIHRoZSBjb25uZWN0aW9uIGlzIGxvc3QsXG5cdFx0b25yZWNvbm5lY3RpbmcgOiBjYWxsYmFjayBtZXRob2QgdG8gaW52b2tlIHdoZW4gdGhlIGNsaWVudCBpcyByZWNvbm5lY3RpbmcsXG5cdFx0b25yZWNvbm5lY3RlZCA6IGNhbGxiYWNrIG1ldGhvZCB0byBpbnZva2Ugd2hlbiB0aGUgY2xpZW50IHN1Y2Nlc2Z1bGx5IHJlY29ubmVjdHMsXG5cdH07XG4qL1xuZnVuY3Rpb24gV2ViU29ja2V0V2l0aFJlY29ubmVjdGlvbihjb25maWcpIHtcblxuICAgIHZhciBjbG9zaW5nID0gZmFsc2U7XG4gICAgdmFyIHJlZ2lzdGVyTWVzc2FnZUhhbmRsZXI7XG4gICAgdmFyIHdzVXJpID0gY29uZmlnLnVyaTtcbiAgICB2YXIgdXNlU29ja0pTID0gY29uZmlnLnVzZVNvY2tKUztcbiAgICB2YXIgcmVjb25uZWN0aW5nID0gZmFsc2U7XG5cbiAgICB2YXIgZm9yY2luZ0Rpc2Nvbm5lY3Rpb24gPSBmYWxzZTtcblxuICAgIHZhciB3cztcblxuICAgIGlmICh1c2VTb2NrSlMpIHtcbiAgICAgICAgd3MgPSBuZXcgU29ja0pTKHdzVXJpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB3cyA9IG5ldyBXZWJTb2NrZXQod3NVcmkpO1xuICAgIH1cblxuICAgIHdzLm9ub3BlbiA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBsb2dDb25uZWN0ZWQod3MsIHdzVXJpKTtcbiAgICAgICAgY29uZmlnLm9uY29ubmVjdGVkKCk7XG4gICAgfTtcblxuICAgIHdzLm9uZXJyb3IgPSBmdW5jdGlvbihldnQpIHtcbiAgICAgICAgY29uZmlnLm9uY29ubmVjdGVkKGV2dC5kYXRhKTtcbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gbG9nQ29ubmVjdGVkKHdzLCB3c1VyaSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coXCJXZWJTb2NrZXQgY29ubmVjdGVkIHRvIFwiICsgd3NVcmkpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdmFyIHJlY29ubmVjdGlvbk9uQ2xvc2UgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKHdzLnJlYWR5U3RhdGUgPT09IENMT1NFRCkge1xuICAgICAgICAgICAgaWYgKGNsb3NpbmcpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIkNvbm5lY3Rpb24gQ2xvc2VkIGJ5IHVzZXJcIik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiQ29ubmVjdGlvbiBjbG9zZWQgdW5leHBlY3RlY2x5LiBSZWNvbm5lY3RpbmcuLi5cIik7XG4gICAgICAgICAgICAgICAgcmVjb25uZWN0SW5OZXdVcmkoTUFYX1JFVFJJRVMsIDEpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS5sb2coXCJDbG9zZSBjYWxsYmFjayBmcm9tIHByZXZpb3VzIHdlYnNvY2tldC4gSWdub3JpbmcgaXRcIik7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgd3Mub25jbG9zZSA9IHJlY29ubmVjdGlvbk9uQ2xvc2U7XG5cbiAgICBmdW5jdGlvbiByZWNvbm5lY3RJbk5ld1VyaShtYXhSZXRyaWVzLCBudW1SZXRyaWVzKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwicmVjb25uZWN0SW5OZXdVcmlcIik7XG5cbiAgICAgICAgaWYgKG51bVJldHJpZXMgPT09IDEpIHtcbiAgICAgICAgICAgIGlmIChyZWNvbm5lY3RpbmcpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlXG4gICAgICAgICAgICAgICAgICAgIC53YXJuKFwiVHJ5aW5nIHRvIHJlY29ubmVjdCB3aGVuIHJlY29ubmVjdGluZy4uLiBJZ25vcmluZyB0aGlzIHJlY29ubmVjdGlvbi5cIilcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlY29ubmVjdGluZyA9IHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChjb25maWcub25yZWNvbm5lY3RpbmcpIHtcbiAgICAgICAgICAgICAgICBjb25maWcub25yZWNvbm5lY3RpbmcoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChmb3JjaW5nRGlzY29ubmVjdGlvbikge1xuICAgICAgICAgICAgcmVjb25uZWN0KG1heFJldHJpZXMsIG51bVJldHJpZXMsIHdzVXJpKTtcblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKGNvbmZpZy5uZXdXc1VyaU9uUmVjb25uZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgY29uZmlnLm5ld1dzVXJpT25SZWNvbm5lY3Rpb24oZnVuY3Rpb24oZXJyb3IsIG5ld1dzVXJpKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY29ubmVjdEluTmV3VXJpKG1heFJldHJpZXMsIG51bVJldHJpZXMgKyAxKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sIFJFVFJZX1RJTUVfTVMpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVjb25uZWN0KG1heFJldHJpZXMsIG51bVJldHJpZXMsIG5ld1dzVXJpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlY29ubmVjdChtYXhSZXRyaWVzLCBudW1SZXRyaWVzLCB3c1VyaSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUT0RPIFRlc3QgcmV0cmllcy4gSG93IHRvIGZvcmNlIG5vdCBjb25uZWN0aW9uP1xuICAgIGZ1bmN0aW9uIHJlY29ubmVjdChtYXhSZXRyaWVzLCBudW1SZXRyaWVzLCByZWNvbm5lY3RXc1VyaSkge1xuXG4gICAgICAgIGNvbnNvbGUubG9nKFwiVHJ5aW5nIHRvIHJlY29ubmVjdCBcIiArIG51bVJldHJpZXMgKyBcIiB0aW1lc1wiKTtcblxuICAgICAgICB2YXIgbmV3V3M7XG4gICAgICAgIGlmICh1c2VTb2NrSlMpIHtcbiAgICAgICAgICAgIG5ld1dzID0gbmV3IFNvY2tKUyh3c1VyaSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBuZXdXcyA9IG5ldyBXZWJTb2NrZXQod3NVcmkpO1xuICAgICAgICB9XG5cbiAgICAgICAgbmV3V3Mub25vcGVuID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIlJlY29ubmVjdGVkIGluIFwiICsgbnVtUmV0cmllcyArIFwiIHJldHJpZXMuLi5cIik7XG4gICAgICAgICAgICBsb2dDb25uZWN0ZWQobmV3V3MsIHJlY29ubmVjdFdzVXJpKTtcbiAgICAgICAgICAgIHJlY29ubmVjdGluZyA9IGZhbHNlO1xuICAgICAgICAgICAgcmVnaXN0ZXJNZXNzYWdlSGFuZGxlcigpO1xuICAgICAgICAgICAgaWYgKGNvbmZpZy5vbnJlY29ubmVjdGVkKCkpIHtcbiAgICAgICAgICAgICAgICBjb25maWcub25yZWNvbm5lY3RlZCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBuZXdXcy5vbmNsb3NlID0gcmVjb25uZWN0aW9uT25DbG9zZTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb25FcnJvck9yQ2xvc2UgPSBmdW5jdGlvbihlcnJvcikge1xuICAgICAgICAgICAgY29uc29sZS5sb2coXCJSZWNvbm5lY3Rpb24gZXJyb3I6IFwiLCBlcnJvcik7XG5cbiAgICAgICAgICAgIGlmIChudW1SZXRyaWVzID09PSBtYXhSZXRyaWVzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGNvbmZpZy5vbmRpc2Nvbm5lY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uZmlnLm9uZGlzY29ubmVjdCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVjb25uZWN0SW5OZXdVcmkobWF4UmV0cmllcywgbnVtUmV0cmllcyArIDEpO1xuICAgICAgICAgICAgICAgIH0sIFJFVFJZX1RJTUVfTVMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIG5ld1dzLm9uZXJyb3IgPSBvbkVycm9yT3JDbG9zZTtcblxuICAgICAgICB3cyA9IG5ld1dzO1xuICAgIH1cblxuICAgIHRoaXMuY2xvc2UgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgY2xvc2luZyA9IHRydWU7XG4gICAgICAgIHdzLmNsb3NlKCk7XG4gICAgfTtcblxuXG4gICAgLy8gVGhpcyBtZXRob2QgaXMgb25seSBmb3IgdGVzdGluZ1xuICAgIHRoaXMuZm9yY2VDbG9zZSA9IGZ1bmN0aW9uKG1pbGxpcykge1xuICAgICAgICBjb25zb2xlLmxvZyhcIlRlc3Rpbmc6IEZvcmNlIFdlYlNvY2tldCBjbG9zZVwiKTtcblxuICAgICAgICBpZiAobWlsbGlzKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIlRlc3Rpbmc6IENoYW5nZSB3c1VyaSBmb3IgXCIgKyBtaWxsaXMgKyBcIiBtaWxsaXMgdG8gc2ltdWxhdGUgbmV0IGZhaWx1cmVcIik7XG4gICAgICAgICAgICB2YXIgZ29vZFdzVXJpID0gd3NVcmk7XG4gICAgICAgICAgICB3c1VyaSA9IFwid3NzOi8vMjEuMjM0LjEyLjM0LjQ6NDQzL1wiO1xuXG4gICAgICAgICAgICBmb3JjaW5nRGlzY29ubmVjdGlvbiA9IHRydWU7XG5cbiAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJUZXN0aW5nOiBSZWNvdmVyIGdvb2Qgd3NVcmkgXCIgKyBnb29kV3NVcmkpO1xuICAgICAgICAgICAgICAgIHdzVXJpID0gZ29vZFdzVXJpO1xuXG4gICAgICAgICAgICAgICAgZm9yY2luZ0Rpc2Nvbm5lY3Rpb24gPSBmYWxzZTtcblxuICAgICAgICAgICAgfSwgbWlsbGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHdzLmNsb3NlKCk7XG4gICAgfTtcblxuICAgIHRoaXMucmVjb25uZWN0V3MgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJyZWNvbm5lY3RXc1wiKTtcbiAgICAgICAgcmVjb25uZWN0SW5OZXdVcmkoTUFYX1JFVFJJRVMsIDEsIHdzVXJpKTtcbiAgICB9O1xuXG4gICAgdGhpcy5zZW5kID0gZnVuY3Rpb24obWVzc2FnZSkge1xuICAgICAgICB3cy5zZW5kKG1lc3NhZ2UpO1xuICAgIH07XG5cbiAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXIgPSBmdW5jdGlvbih0eXBlLCBjYWxsYmFjaykge1xuICAgICAgICByZWdpc3Rlck1lc3NhZ2VIYW5kbGVyID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB3cy5hZGRFdmVudExpc3RlbmVyKHR5cGUsIGNhbGxiYWNrKTtcbiAgICAgICAgfTtcblxuICAgICAgICByZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKCk7XG4gICAgfTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBXZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uOyIsIi8qXG4gKiAoQykgQ29weXJpZ2h0IDIwMTQgS3VyZW50byAoaHR0cDovL2t1cmVudG8ub3JnLylcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICpcbiAqL1xuXG5cbnZhciBkZWZpbmVQcm9wZXJ0eV9JRTggPSBmYWxzZVxuaWYoT2JqZWN0LmRlZmluZVByb3BlcnR5KVxue1xuICB0cnlcbiAge1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh7fSwgXCJ4XCIsIHt9KTtcbiAgfVxuICBjYXRjaChlKVxuICB7XG4gICAgZGVmaW5lUHJvcGVydHlfSUU4ID0gdHJ1ZVxuICB9XG59XG5cbi8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0Z1bmN0aW9uL2JpbmRcbmlmICghRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQpIHtcbiAgRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQgPSBmdW5jdGlvbihvVGhpcykge1xuICAgIGlmICh0eXBlb2YgdGhpcyAhPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgLy8gY2xvc2VzdCB0aGluZyBwb3NzaWJsZSB0byB0aGUgRUNNQVNjcmlwdCA1XG4gICAgICAvLyBpbnRlcm5hbCBJc0NhbGxhYmxlIGZ1bmN0aW9uXG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdGdW5jdGlvbi5wcm90b3R5cGUuYmluZCAtIHdoYXQgaXMgdHJ5aW5nIHRvIGJlIGJvdW5kIGlzIG5vdCBjYWxsYWJsZScpO1xuICAgIH1cblxuICAgIHZhciBhQXJncyAgID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSxcbiAgICAgICAgZlRvQmluZCA9IHRoaXMsXG4gICAgICAgIGZOT1AgICAgPSBmdW5jdGlvbigpIHt9LFxuICAgICAgICBmQm91bmQgID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgcmV0dXJuIGZUb0JpbmQuYXBwbHkodGhpcyBpbnN0YW5jZW9mIGZOT1AgJiYgb1RoaXNcbiAgICAgICAgICAgICAgICAgPyB0aGlzXG4gICAgICAgICAgICAgICAgIDogb1RoaXMsXG4gICAgICAgICAgICAgICAgIGFBcmdzLmNvbmNhdChBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH07XG5cbiAgICBmTk9QLnByb3RvdHlwZSA9IHRoaXMucHJvdG90eXBlO1xuICAgIGZCb3VuZC5wcm90b3R5cGUgPSBuZXcgZk5PUCgpO1xuXG4gICAgcmV0dXJuIGZCb3VuZDtcbiAgfTtcbn1cblxuXG52YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpO1xuXG52YXIgcGFja2VycyA9IHJlcXVpcmUoJy4vcGFja2VycycpO1xudmFyIE1hcHBlciA9IHJlcXVpcmUoJy4vTWFwcGVyJyk7XG5cblxudmFyIEJBU0VfVElNRU9VVCA9IDUwMDA7XG5cblxuZnVuY3Rpb24gdW5pZnlSZXNwb25zZU1ldGhvZHMocmVzcG9uc2VNZXRob2RzKVxue1xuICBpZighcmVzcG9uc2VNZXRob2RzKSByZXR1cm4ge307XG5cbiAgZm9yKHZhciBrZXkgaW4gcmVzcG9uc2VNZXRob2RzKVxuICB7XG4gICAgdmFyIHZhbHVlID0gcmVzcG9uc2VNZXRob2RzW2tleV07XG5cbiAgICBpZih0eXBlb2YgdmFsdWUgPT0gJ3N0cmluZycpXG4gICAgICByZXNwb25zZU1ldGhvZHNba2V5XSA9XG4gICAgICB7XG4gICAgICAgIHJlc3BvbnNlOiB2YWx1ZVxuICAgICAgfVxuICB9O1xuXG4gIHJldHVybiByZXNwb25zZU1ldGhvZHM7XG59O1xuXG5mdW5jdGlvbiB1bmlmeVRyYW5zcG9ydCh0cmFuc3BvcnQpXG57XG4gIGlmKCF0cmFuc3BvcnQpIHJldHVybjtcblxuICAvLyBUcmFuc3BvcnQgYXMgYSBmdW5jdGlvblxuICBpZih0cmFuc3BvcnQgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAgICByZXR1cm4ge3NlbmQ6IHRyYW5zcG9ydH07XG5cbiAgLy8gV2ViU29ja2V0ICYgRGF0YUNoYW5uZWxcbiAgaWYodHJhbnNwb3J0LnNlbmQgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAgICByZXR1cm4gdHJhbnNwb3J0O1xuXG4gIC8vIE1lc3NhZ2UgQVBJIChJbnRlci13aW5kb3cgJiBXZWJXb3JrZXIpXG4gIGlmKHRyYW5zcG9ydC5wb3N0TWVzc2FnZSBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICB7XG4gICAgdHJhbnNwb3J0LnNlbmQgPSB0cmFuc3BvcnQucG9zdE1lc3NhZ2U7XG4gICAgcmV0dXJuIHRyYW5zcG9ydDtcbiAgfVxuXG4gIC8vIFN0cmVhbSBBUElcbiAgaWYodHJhbnNwb3J0LndyaXRlIGluc3RhbmNlb2YgRnVuY3Rpb24pXG4gIHtcbiAgICB0cmFuc3BvcnQuc2VuZCA9IHRyYW5zcG9ydC53cml0ZTtcbiAgICByZXR1cm4gdHJhbnNwb3J0O1xuICB9XG5cbiAgLy8gVHJhbnNwb3J0cyB0aGF0IG9ubHkgY2FuIHJlY2VpdmUgbWVzc2FnZXMsIGJ1dCBub3Qgc2VuZFxuICBpZih0cmFuc3BvcnQub25tZXNzYWdlICE9PSB1bmRlZmluZWQpIHJldHVybjtcbiAgaWYodHJhbnNwb3J0LnBhdXNlIGluc3RhbmNlb2YgRnVuY3Rpb24pIHJldHVybjtcblxuICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJUcmFuc3BvcnQgaXMgbm90IGEgZnVuY3Rpb24gbm9yIGEgdmFsaWQgb2JqZWN0XCIpO1xufTtcblxuXG4vKipcbiAqIFJlcHJlc2VudGF0aW9uIG9mIGEgUlBDIG5vdGlmaWNhdGlvblxuICpcbiAqIEBjbGFzc1xuICpcbiAqIEBjb25zdHJ1Y3RvclxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXRob2QgLW1ldGhvZCBvZiB0aGUgbm90aWZpY2F0aW9uXG4gKiBAcGFyYW0gcGFyYW1zIC0gcGFyYW1ldGVycyBvZiB0aGUgbm90aWZpY2F0aW9uXG4gKi9cbmZ1bmN0aW9uIFJwY05vdGlmaWNhdGlvbihtZXRob2QsIHBhcmFtcylcbntcbiAgaWYoZGVmaW5lUHJvcGVydHlfSUU4KVxuICB7XG4gICAgdGhpcy5tZXRob2QgPSBtZXRob2RcbiAgICB0aGlzLnBhcmFtcyA9IHBhcmFtc1xuICB9XG4gIGVsc2VcbiAge1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnbWV0aG9kJywge3ZhbHVlOiBtZXRob2QsIGVudW1lcmFibGU6IHRydWV9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ3BhcmFtcycsIHt2YWx1ZTogcGFyYW1zLCBlbnVtZXJhYmxlOiB0cnVlfSk7XG4gIH1cbn07XG5cblxuLyoqXG4gKiBAY2xhc3NcbiAqXG4gKiBAY29uc3RydWN0b3JcbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gcGFja2VyXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IFtvcHRpb25zXVxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBbdHJhbnNwb3J0XVxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IFtvblJlcXVlc3RdXG4gKi9cbmZ1bmN0aW9uIFJwY0J1aWxkZXIocGFja2VyLCBvcHRpb25zLCB0cmFuc3BvcnQsIG9uUmVxdWVzdClcbntcbiAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gIGlmKCFwYWNrZXIpXG4gICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKCdQYWNrZXIgaXMgbm90IGRlZmluZWQnKTtcblxuICBpZighcGFja2VyLnBhY2sgfHwgIXBhY2tlci51bnBhY2spXG4gICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKCdQYWNrZXIgaXMgaW52YWxpZCcpO1xuXG4gIHZhciByZXNwb25zZU1ldGhvZHMgPSB1bmlmeVJlc3BvbnNlTWV0aG9kcyhwYWNrZXIucmVzcG9uc2VNZXRob2RzKTtcblxuXG4gIGlmKG9wdGlvbnMgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAge1xuICAgIGlmKHRyYW5zcG9ydCAhPSB1bmRlZmluZWQpXG4gICAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJUaGVyZSBjYW4ndCBiZSBwYXJhbWV0ZXJzIGFmdGVyIG9uUmVxdWVzdFwiKTtcblxuICAgIG9uUmVxdWVzdCA9IG9wdGlvbnM7XG4gICAgdHJhbnNwb3J0ID0gdW5kZWZpbmVkO1xuICAgIG9wdGlvbnMgICA9IHVuZGVmaW5lZDtcbiAgfTtcblxuICBpZihvcHRpb25zICYmIG9wdGlvbnMuc2VuZCBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICB7XG4gICAgaWYodHJhbnNwb3J0ICYmICEodHJhbnNwb3J0IGluc3RhbmNlb2YgRnVuY3Rpb24pKVxuICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiT25seSBhIGZ1bmN0aW9uIGNhbiBiZSBhZnRlciB0cmFuc3BvcnRcIik7XG5cbiAgICBvblJlcXVlc3QgPSB0cmFuc3BvcnQ7XG4gICAgdHJhbnNwb3J0ID0gb3B0aW9ucztcbiAgICBvcHRpb25zICAgPSB1bmRlZmluZWQ7XG4gIH07XG5cbiAgaWYodHJhbnNwb3J0IGluc3RhbmNlb2YgRnVuY3Rpb24pXG4gIHtcbiAgICBpZihvblJlcXVlc3QgIT0gdW5kZWZpbmVkKVxuICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlcmUgY2FuJ3QgYmUgcGFyYW1ldGVycyBhZnRlciBvblJlcXVlc3RcIik7XG5cbiAgICBvblJlcXVlc3QgPSB0cmFuc3BvcnQ7XG4gICAgdHJhbnNwb3J0ID0gdW5kZWZpbmVkO1xuICB9O1xuXG4gIGlmKHRyYW5zcG9ydCAmJiB0cmFuc3BvcnQuc2VuZCBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICAgIGlmKG9uUmVxdWVzdCAmJiAhKG9uUmVxdWVzdCBpbnN0YW5jZW9mIEZ1bmN0aW9uKSlcbiAgICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIk9ubHkgYSBmdW5jdGlvbiBjYW4gYmUgYWZ0ZXIgdHJhbnNwb3J0XCIpO1xuXG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG5cbiAgRXZlbnRFbWl0dGVyLmNhbGwodGhpcyk7XG5cbiAgaWYob25SZXF1ZXN0KVxuICAgIHRoaXMub24oJ3JlcXVlc3QnLCBvblJlcXVlc3QpO1xuXG5cbiAgaWYoZGVmaW5lUHJvcGVydHlfSUU4KVxuICAgIHRoaXMucGVlcklEID0gb3B0aW9ucy5wZWVySURcbiAgZWxzZVxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAncGVlcklEJywge3ZhbHVlOiBvcHRpb25zLnBlZXJJRH0pO1xuXG4gIHZhciBtYXhfcmV0cmllcyA9IG9wdGlvbnMubWF4X3JldHJpZXMgfHwgMDtcblxuXG4gIGZ1bmN0aW9uIHRyYW5zcG9ydE1lc3NhZ2UoZXZlbnQpXG4gIHtcbiAgICBzZWxmLmRlY29kZShldmVudC5kYXRhIHx8IGV2ZW50KTtcbiAgfTtcblxuICB0aGlzLmdldFRyYW5zcG9ydCA9IGZ1bmN0aW9uKClcbiAge1xuICAgIHJldHVybiB0cmFuc3BvcnQ7XG4gIH1cbiAgdGhpcy5zZXRUcmFuc3BvcnQgPSBmdW5jdGlvbih2YWx1ZSlcbiAge1xuICAgIC8vIFJlbW92ZSBsaXN0ZW5lciBmcm9tIG9sZCB0cmFuc3BvcnRcbiAgICBpZih0cmFuc3BvcnQpXG4gICAge1xuICAgICAgLy8gVzNDIHRyYW5zcG9ydHNcbiAgICAgIGlmKHRyYW5zcG9ydC5yZW1vdmVFdmVudExpc3RlbmVyKVxuICAgICAgICB0cmFuc3BvcnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIHRyYW5zcG9ydE1lc3NhZ2UpO1xuXG4gICAgICAvLyBOb2RlLmpzIFN0cmVhbXMgQVBJXG4gICAgICBlbHNlIGlmKHRyYW5zcG9ydC5yZW1vdmVMaXN0ZW5lcilcbiAgICAgICAgdHJhbnNwb3J0LnJlbW92ZUxpc3RlbmVyKCdkYXRhJywgdHJhbnNwb3J0TWVzc2FnZSk7XG4gICAgfTtcblxuICAgIC8vIFNldCBsaXN0ZW5lciBvbiBuZXcgdHJhbnNwb3J0XG4gICAgaWYodmFsdWUpXG4gICAge1xuICAgICAgLy8gVzNDIHRyYW5zcG9ydHNcbiAgICAgIGlmKHZhbHVlLmFkZEV2ZW50TGlzdGVuZXIpXG4gICAgICAgIHZhbHVlLmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCB0cmFuc3BvcnRNZXNzYWdlKTtcblxuICAgICAgLy8gTm9kZS5qcyBTdHJlYW1zIEFQSVxuICAgICAgZWxzZSBpZih2YWx1ZS5hZGRMaXN0ZW5lcilcbiAgICAgICAgdmFsdWUuYWRkTGlzdGVuZXIoJ2RhdGEnLCB0cmFuc3BvcnRNZXNzYWdlKTtcbiAgICB9O1xuXG4gICAgdHJhbnNwb3J0ID0gdW5pZnlUcmFuc3BvcnQodmFsdWUpO1xuICB9XG5cbiAgaWYoIWRlZmluZVByb3BlcnR5X0lFOClcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ3RyYW5zcG9ydCcsXG4gICAge1xuICAgICAgZ2V0OiB0aGlzLmdldFRyYW5zcG9ydC5iaW5kKHRoaXMpLFxuICAgICAgc2V0OiB0aGlzLnNldFRyYW5zcG9ydC5iaW5kKHRoaXMpXG4gICAgfSlcblxuICB0aGlzLnNldFRyYW5zcG9ydCh0cmFuc3BvcnQpO1xuXG5cbiAgdmFyIHJlcXVlc3RfdGltZW91dCAgICA9IG9wdGlvbnMucmVxdWVzdF90aW1lb3V0ICAgIHx8IEJBU0VfVElNRU9VVDtcbiAgdmFyIHJlc3BvbnNlX3RpbWVvdXQgICA9IG9wdGlvbnMucmVzcG9uc2VfdGltZW91dCAgIHx8IEJBU0VfVElNRU9VVDtcbiAgdmFyIGR1cGxpY2F0ZXNfdGltZW91dCA9IG9wdGlvbnMuZHVwbGljYXRlc190aW1lb3V0IHx8IEJBU0VfVElNRU9VVDtcblxuXG4gIHZhciByZXF1ZXN0SUQgPSAwO1xuXG4gIHZhciByZXF1ZXN0cyAgPSBuZXcgTWFwcGVyKCk7XG4gIHZhciByZXNwb25zZXMgPSBuZXcgTWFwcGVyKCk7XG4gIHZhciBwcm9jZXNzZWRSZXNwb25zZXMgPSBuZXcgTWFwcGVyKCk7XG5cbiAgdmFyIG1lc3NhZ2UyS2V5ID0ge307XG5cblxuICAvKipcbiAgICogU3RvcmUgdGhlIHJlc3BvbnNlIHRvIHByZXZlbnQgdG8gcHJvY2VzcyBkdXBsaWNhdGUgcmVxdWVzdCBsYXRlclxuICAgKi9cbiAgZnVuY3Rpb24gc3RvcmVSZXNwb25zZShtZXNzYWdlLCBpZCwgZGVzdClcbiAge1xuICAgIHZhciByZXNwb25zZSA9XG4gICAge1xuICAgICAgbWVzc2FnZTogbWVzc2FnZSxcbiAgICAgIC8qKiBUaW1lb3V0IHRvIGF1dG8tY2xlYW4gb2xkIHJlc3BvbnNlcyAqL1xuICAgICAgdGltZW91dDogc2V0VGltZW91dChmdW5jdGlvbigpXG4gICAgICB7XG4gICAgICAgIHJlc3BvbnNlcy5yZW1vdmUoaWQsIGRlc3QpO1xuICAgICAgfSxcbiAgICAgIHJlc3BvbnNlX3RpbWVvdXQpXG4gICAgfTtcblxuICAgIHJlc3BvbnNlcy5zZXQocmVzcG9uc2UsIGlkLCBkZXN0KTtcbiAgfTtcblxuICAvKipcbiAgICogU3RvcmUgdGhlIHJlc3BvbnNlIHRvIGlnbm9yZSBkdXBsaWNhdGVkIG1lc3NhZ2VzIGxhdGVyXG4gICAqL1xuICBmdW5jdGlvbiBzdG9yZVByb2Nlc3NlZFJlc3BvbnNlKGFjaywgZnJvbSlcbiAge1xuICAgIHZhciB0aW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbigpXG4gICAge1xuICAgICAgcHJvY2Vzc2VkUmVzcG9uc2VzLnJlbW92ZShhY2ssIGZyb20pO1xuICAgIH0sXG4gICAgZHVwbGljYXRlc190aW1lb3V0KTtcblxuICAgIHByb2Nlc3NlZFJlc3BvbnNlcy5zZXQodGltZW91dCwgYWNrLCBmcm9tKTtcbiAgfTtcblxuXG4gIC8qKlxuICAgKiBSZXByZXNlbnRhdGlvbiBvZiBhIFJQQyByZXF1ZXN0XG4gICAqXG4gICAqIEBjbGFzc1xuICAgKiBAZXh0ZW5kcyBScGNOb3RpZmljYXRpb25cbiAgICpcbiAgICogQGNvbnN0cnVjdG9yXG4gICAqXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXRob2QgLW1ldGhvZCBvZiB0aGUgbm90aWZpY2F0aW9uXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBwYXJhbWV0ZXJzIG9mIHRoZSBub3RpZmljYXRpb25cbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBpZCAtIGlkZW50aWZpZXIgb2YgdGhlIHJlcXVlc3RcbiAgICogQHBhcmFtIFtmcm9tXSAtIHNvdXJjZSBvZiB0aGUgbm90aWZpY2F0aW9uXG4gICAqL1xuICBmdW5jdGlvbiBScGNSZXF1ZXN0KG1ldGhvZCwgcGFyYW1zLCBpZCwgZnJvbSwgdHJhbnNwb3J0KVxuICB7XG4gICAgUnBjTm90aWZpY2F0aW9uLmNhbGwodGhpcywgbWV0aG9kLCBwYXJhbXMpO1xuXG4gICAgdGhpcy5nZXRUcmFuc3BvcnQgPSBmdW5jdGlvbigpXG4gICAge1xuICAgICAgcmV0dXJuIHRyYW5zcG9ydDtcbiAgICB9XG4gICAgdGhpcy5zZXRUcmFuc3BvcnQgPSBmdW5jdGlvbih2YWx1ZSlcbiAgICB7XG4gICAgICB0cmFuc3BvcnQgPSB1bmlmeVRyYW5zcG9ydCh2YWx1ZSk7XG4gICAgfVxuXG4gICAgaWYoIWRlZmluZVByb3BlcnR5X0lFOClcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAndHJhbnNwb3J0JyxcbiAgICAgIHtcbiAgICAgICAgZ2V0OiB0aGlzLmdldFRyYW5zcG9ydC5iaW5kKHRoaXMpLFxuICAgICAgICBzZXQ6IHRoaXMuc2V0VHJhbnNwb3J0LmJpbmQodGhpcylcbiAgICAgIH0pXG5cbiAgICB2YXIgcmVzcG9uc2UgPSByZXNwb25zZXMuZ2V0KGlkLCBmcm9tKTtcblxuICAgIC8qKlxuICAgICAqIEBjb25zdGFudCB7Qm9vbGVhbn0gZHVwbGljYXRlZFxuICAgICAqL1xuICAgIGlmKCEodHJhbnNwb3J0IHx8IHNlbGYuZ2V0VHJhbnNwb3J0KCkpKVxuICAgIHtcbiAgICAgIGlmKGRlZmluZVByb3BlcnR5X0lFOClcbiAgICAgICAgdGhpcy5kdXBsaWNhdGVkID0gQm9vbGVhbihyZXNwb25zZSlcbiAgICAgIGVsc2VcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICdkdXBsaWNhdGVkJyxcbiAgICAgICAge1xuICAgICAgICAgIHZhbHVlOiBCb29sZWFuKHJlc3BvbnNlKVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICB2YXIgcmVzcG9uc2VNZXRob2QgPSByZXNwb25zZU1ldGhvZHNbbWV0aG9kXTtcblxuICAgIHRoaXMucGFjayA9IHBhY2tlci5wYWNrLmJpbmQocGFja2VyLCB0aGlzLCBpZClcblxuICAgIC8qKlxuICAgICAqIEdlbmVyYXRlIGEgcmVzcG9uc2UgdG8gdGhpcyByZXF1ZXN0XG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0Vycm9yfSBbZXJyb3JdXG4gICAgICogQHBhcmFtIHsqfSBbcmVzdWx0XVxuICAgICAqXG4gICAgICogQHJldHVybnMge3N0cmluZ31cbiAgICAgKi9cbiAgICB0aGlzLnJlcGx5ID0gZnVuY3Rpb24oZXJyb3IsIHJlc3VsdCwgdHJhbnNwb3J0KVxuICAgIHtcbiAgICAgIC8vIEZpeCBvcHRpb25hbCBwYXJhbWV0ZXJzXG4gICAgICBpZihlcnJvciBpbnN0YW5jZW9mIEZ1bmN0aW9uIHx8IGVycm9yICYmIGVycm9yLnNlbmQgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAgICAgIHtcbiAgICAgICAgaWYocmVzdWx0ICE9IHVuZGVmaW5lZClcbiAgICAgICAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJUaGVyZSBjYW4ndCBiZSBwYXJhbWV0ZXJzIGFmdGVyIGNhbGxiYWNrXCIpO1xuXG4gICAgICAgIHRyYW5zcG9ydCA9IGVycm9yO1xuICAgICAgICByZXN1bHQgPSBudWxsO1xuICAgICAgICBlcnJvciA9IHVuZGVmaW5lZDtcbiAgICAgIH1cblxuICAgICAgZWxzZSBpZihyZXN1bHQgaW5zdGFuY2VvZiBGdW5jdGlvblxuICAgICAgfHwgcmVzdWx0ICYmIHJlc3VsdC5zZW5kIGluc3RhbmNlb2YgRnVuY3Rpb24pXG4gICAgICB7XG4gICAgICAgIGlmKHRyYW5zcG9ydCAhPSB1bmRlZmluZWQpXG4gICAgICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlcmUgY2FuJ3QgYmUgcGFyYW1ldGVycyBhZnRlciBjYWxsYmFja1wiKTtcblxuICAgICAgICB0cmFuc3BvcnQgPSByZXN1bHQ7XG4gICAgICAgIHJlc3VsdCA9IG51bGw7XG4gICAgICB9O1xuXG4gICAgICB0cmFuc3BvcnQgPSB1bmlmeVRyYW5zcG9ydCh0cmFuc3BvcnQpO1xuXG4gICAgICAvLyBEdXBsaWNhdGVkIHJlcXVlc3QsIHJlbW92ZSBvbGQgcmVzcG9uc2UgdGltZW91dFxuICAgICAgaWYocmVzcG9uc2UpXG4gICAgICAgIGNsZWFyVGltZW91dChyZXNwb25zZS50aW1lb3V0KTtcblxuICAgICAgaWYoZnJvbSAhPSB1bmRlZmluZWQpXG4gICAgICB7XG4gICAgICAgIGlmKGVycm9yKVxuICAgICAgICAgIGVycm9yLmRlc3QgPSBmcm9tO1xuXG4gICAgICAgIGlmKHJlc3VsdClcbiAgICAgICAgICByZXN1bHQuZGVzdCA9IGZyb207XG4gICAgICB9O1xuXG4gICAgICB2YXIgbWVzc2FnZTtcblxuICAgICAgLy8gTmV3IHJlcXVlc3Qgb3Igb3ZlcnJpZGVuIG9uZSwgY3JlYXRlIG5ldyByZXNwb25zZSB3aXRoIHByb3ZpZGVkIGRhdGFcbiAgICAgIGlmKGVycm9yIHx8IHJlc3VsdCAhPSB1bmRlZmluZWQpXG4gICAgICB7XG4gICAgICAgIGlmKHNlbGYucGVlcklEICE9IHVuZGVmaW5lZClcbiAgICAgICAge1xuICAgICAgICAgIGlmKGVycm9yKVxuICAgICAgICAgICAgZXJyb3IuZnJvbSA9IHNlbGYucGVlcklEO1xuICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgIHJlc3VsdC5mcm9tID0gc2VsZi5wZWVySUQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBQcm90b2NvbCBpbmRpY2F0ZXMgdGhhdCByZXNwb25zZXMgaGFzIG93biByZXF1ZXN0IG1ldGhvZHNcbiAgICAgICAgaWYocmVzcG9uc2VNZXRob2QpXG4gICAgICAgIHtcbiAgICAgICAgICBpZihyZXNwb25zZU1ldGhvZC5lcnJvciA9PSB1bmRlZmluZWQgJiYgZXJyb3IpXG4gICAgICAgICAgICBtZXNzYWdlID1cbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgZXJyb3I6IGVycm9yXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgZWxzZVxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHZhciBtZXRob2QgPSBlcnJvclxuICAgICAgICAgICAgICAgICAgICAgICA/IHJlc3BvbnNlTWV0aG9kLmVycm9yXG4gICAgICAgICAgICAgICAgICAgICAgIDogcmVzcG9uc2VNZXRob2QucmVzcG9uc2U7XG5cbiAgICAgICAgICAgIG1lc3NhZ2UgPVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBtZXRob2Q6IG1ldGhvZCxcbiAgICAgICAgICAgICAgcGFyYW1zOiBlcnJvciB8fCByZXN1bHRcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAgICBtZXNzYWdlID1cbiAgICAgICAgICB7XG4gICAgICAgICAgICBlcnJvcjogIGVycm9yLFxuICAgICAgICAgICAgcmVzdWx0OiByZXN1bHRcbiAgICAgICAgICB9O1xuXG4gICAgICAgIG1lc3NhZ2UgPSBwYWNrZXIucGFjayhtZXNzYWdlLCBpZCk7XG4gICAgICB9XG5cbiAgICAgIC8vIER1cGxpY2F0ZSAmIG5vdC1vdmVycmlkZW4gcmVxdWVzdCwgcmUtc2VuZCBvbGQgcmVzcG9uc2VcbiAgICAgIGVsc2UgaWYocmVzcG9uc2UpXG4gICAgICAgIG1lc3NhZ2UgPSByZXNwb25zZS5tZXNzYWdlO1xuXG4gICAgICAvLyBOZXcgZW1wdHkgcmVwbHksIHJlc3BvbnNlIG51bGwgdmFsdWVcbiAgICAgIGVsc2VcbiAgICAgICAgbWVzc2FnZSA9IHBhY2tlci5wYWNrKHtyZXN1bHQ6IG51bGx9LCBpZCk7XG5cbiAgICAgIC8vIFN0b3JlIHRoZSByZXNwb25zZSB0byBwcmV2ZW50IHRvIHByb2Nlc3MgYSBkdXBsaWNhdGVkIHJlcXVlc3QgbGF0ZXJcbiAgICAgIHN0b3JlUmVzcG9uc2UobWVzc2FnZSwgaWQsIGZyb20pO1xuXG4gICAgICAvLyBSZXR1cm4gdGhlIHN0b3JlZCByZXNwb25zZSBzbyBpdCBjYW4gYmUgZGlyZWN0bHkgc2VuZCBiYWNrXG4gICAgICB0cmFuc3BvcnQgPSB0cmFuc3BvcnQgfHwgdGhpcy5nZXRUcmFuc3BvcnQoKSB8fCBzZWxmLmdldFRyYW5zcG9ydCgpO1xuXG4gICAgICBpZih0cmFuc3BvcnQpXG4gICAgICAgIHJldHVybiB0cmFuc3BvcnQuc2VuZChtZXNzYWdlKTtcblxuICAgICAgcmV0dXJuIG1lc3NhZ2U7XG4gICAgfVxuICB9O1xuICBpbmhlcml0cyhScGNSZXF1ZXN0LCBScGNOb3RpZmljYXRpb24pO1xuXG5cbiAgZnVuY3Rpb24gY2FuY2VsKG1lc3NhZ2UpXG4gIHtcbiAgICB2YXIga2V5ID0gbWVzc2FnZTJLZXlbbWVzc2FnZV07XG4gICAgaWYoIWtleSkgcmV0dXJuO1xuXG4gICAgZGVsZXRlIG1lc3NhZ2UyS2V5W21lc3NhZ2VdO1xuXG4gICAgdmFyIHJlcXVlc3QgPSByZXF1ZXN0cy5wb3Aoa2V5LmlkLCBrZXkuZGVzdCk7XG4gICAgaWYoIXJlcXVlc3QpIHJldHVybjtcblxuICAgIGNsZWFyVGltZW91dChyZXF1ZXN0LnRpbWVvdXQpO1xuXG4gICAgLy8gU3RhcnQgZHVwbGljYXRlZCByZXNwb25zZXMgdGltZW91dFxuICAgIHN0b3JlUHJvY2Vzc2VkUmVzcG9uc2Uoa2V5LmlkLCBrZXkuZGVzdCk7XG4gIH07XG5cbiAgLyoqXG4gICAqIEFsbG93IHRvIGNhbmNlbCBhIHJlcXVlc3QgYW5kIGRvbid0IHdhaXQgZm9yIGEgcmVzcG9uc2VcbiAgICpcbiAgICogSWYgYG1lc3NhZ2VgIGlzIG5vdCBnaXZlbiwgY2FuY2VsIGFsbCB0aGUgcmVxdWVzdFxuICAgKi9cbiAgdGhpcy5jYW5jZWwgPSBmdW5jdGlvbihtZXNzYWdlKVxuICB7XG4gICAgaWYobWVzc2FnZSkgcmV0dXJuIGNhbmNlbChtZXNzYWdlKTtcblxuICAgIGZvcih2YXIgbWVzc2FnZSBpbiBtZXNzYWdlMktleSlcbiAgICAgIGNhbmNlbChtZXNzYWdlKTtcbiAgfTtcblxuXG4gIHRoaXMuY2xvc2UgPSBmdW5jdGlvbigpXG4gIHtcbiAgICAvLyBQcmV2ZW50IHRvIHJlY2VpdmUgbmV3IG1lc3NhZ2VzXG4gICAgdmFyIHRyYW5zcG9ydCA9IHRoaXMuZ2V0VHJhbnNwb3J0KCk7XG4gICAgaWYodHJhbnNwb3J0ICYmIHRyYW5zcG9ydC5jbG9zZSlcbiAgICAgICB0cmFuc3BvcnQuY2xvc2UoKTtcblxuICAgIC8vIFJlcXVlc3QgJiBwcm9jZXNzZWQgcmVzcG9uc2VzXG4gICAgdGhpcy5jYW5jZWwoKTtcblxuICAgIHByb2Nlc3NlZFJlc3BvbnNlcy5mb3JFYWNoKGNsZWFyVGltZW91dCk7XG5cbiAgICAvLyBSZXNwb25zZXNcbiAgICByZXNwb25zZXMuZm9yRWFjaChmdW5jdGlvbihyZXNwb25zZSlcbiAgICB7XG4gICAgICBjbGVhclRpbWVvdXQocmVzcG9uc2UudGltZW91dCk7XG4gICAgfSk7XG4gIH07XG5cblxuICAvKipcbiAgICogR2VuZXJhdGVzIGFuZCBlbmNvZGUgYSBKc29uUlBDIDIuMCBtZXNzYWdlXG4gICAqXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXRob2QgLW1ldGhvZCBvZiB0aGUgbm90aWZpY2F0aW9uXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBwYXJhbWV0ZXJzIG9mIHRoZSBub3RpZmljYXRpb25cbiAgICogQHBhcmFtIFtkZXN0XSAtIGRlc3RpbmF0aW9uIG9mIHRoZSBub3RpZmljYXRpb25cbiAgICogQHBhcmFtIHtvYmplY3R9IFt0cmFuc3BvcnRdIC0gdHJhbnNwb3J0IHdoZXJlIHRvIHNlbmQgdGhlIG1lc3NhZ2VcbiAgICogQHBhcmFtIFtjYWxsYmFja10gLSBmdW5jdGlvbiBjYWxsZWQgd2hlbiBhIHJlc3BvbnNlIHRvIHRoaXMgcmVxdWVzdCBpc1xuICAgKiAgIHJlY2VpdmVkLiBJZiBub3QgZGVmaW5lZCwgYSBub3RpZmljYXRpb24gd2lsbCBiZSBzZW5kIGluc3RlYWRcbiAgICpcbiAgICogQHJldHVybnMge3N0cmluZ30gQSByYXcgSnNvblJQQyAyLjAgcmVxdWVzdCBvciBub3RpZmljYXRpb24gc3RyaW5nXG4gICAqL1xuICB0aGlzLmVuY29kZSA9IGZ1bmN0aW9uKG1ldGhvZCwgcGFyYW1zLCBkZXN0LCB0cmFuc3BvcnQsIGNhbGxiYWNrKVxuICB7XG4gICAgLy8gRml4IG9wdGlvbmFsIHBhcmFtZXRlcnNcbiAgICBpZihwYXJhbXMgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAgICB7XG4gICAgICBpZihkZXN0ICE9IHVuZGVmaW5lZClcbiAgICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlcmUgY2FuJ3QgYmUgcGFyYW1ldGVycyBhZnRlciBjYWxsYmFja1wiKTtcblxuICAgICAgY2FsbGJhY2sgID0gcGFyYW1zO1xuICAgICAgdHJhbnNwb3J0ID0gdW5kZWZpbmVkO1xuICAgICAgZGVzdCAgICAgID0gdW5kZWZpbmVkO1xuICAgICAgcGFyYW1zICAgID0gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGVsc2UgaWYoZGVzdCBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICAgIHtcbiAgICAgIGlmKHRyYW5zcG9ydCAhPSB1bmRlZmluZWQpXG4gICAgICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIlRoZXJlIGNhbid0IGJlIHBhcmFtZXRlcnMgYWZ0ZXIgY2FsbGJhY2tcIik7XG5cbiAgICAgIGNhbGxiYWNrICA9IGRlc3Q7XG4gICAgICB0cmFuc3BvcnQgPSB1bmRlZmluZWQ7XG4gICAgICBkZXN0ICAgICAgPSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgZWxzZSBpZih0cmFuc3BvcnQgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAgICB7XG4gICAgICBpZihjYWxsYmFjayAhPSB1bmRlZmluZWQpXG4gICAgICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIlRoZXJlIGNhbid0IGJlIHBhcmFtZXRlcnMgYWZ0ZXIgY2FsbGJhY2tcIik7XG5cbiAgICAgIGNhbGxiYWNrICA9IHRyYW5zcG9ydDtcbiAgICAgIHRyYW5zcG9ydCA9IHVuZGVmaW5lZDtcbiAgICB9O1xuXG4gICAgaWYoc2VsZi5wZWVySUQgIT0gdW5kZWZpbmVkKVxuICAgIHtcbiAgICAgIHBhcmFtcyA9IHBhcmFtcyB8fCB7fTtcblxuICAgICAgcGFyYW1zLmZyb20gPSBzZWxmLnBlZXJJRDtcbiAgICB9O1xuXG4gICAgaWYoZGVzdCAhPSB1bmRlZmluZWQpXG4gICAge1xuICAgICAgcGFyYW1zID0gcGFyYW1zIHx8IHt9O1xuXG4gICAgICBwYXJhbXMuZGVzdCA9IGRlc3Q7XG4gICAgfTtcblxuICAgIC8vIEVuY29kZSBtZXNzYWdlXG4gICAgdmFyIG1lc3NhZ2UgPVxuICAgIHtcbiAgICAgIG1ldGhvZDogbWV0aG9kLFxuICAgICAgcGFyYW1zOiBwYXJhbXNcbiAgICB9O1xuXG4gICAgaWYoY2FsbGJhY2spXG4gICAge1xuICAgICAgdmFyIGlkID0gcmVxdWVzdElEKys7XG4gICAgICB2YXIgcmV0cmllZCA9IDA7XG5cbiAgICAgIG1lc3NhZ2UgPSBwYWNrZXIucGFjayhtZXNzYWdlLCBpZCk7XG5cbiAgICAgIGZ1bmN0aW9uIGRpc3BhdGNoQ2FsbGJhY2soZXJyb3IsIHJlc3VsdClcbiAgICAgIHtcbiAgICAgICAgc2VsZi5jYW5jZWwobWVzc2FnZSk7XG5cbiAgICAgICAgY2FsbGJhY2soZXJyb3IsIHJlc3VsdCk7XG4gICAgICB9O1xuXG4gICAgICB2YXIgcmVxdWVzdCA9XG4gICAgICB7XG4gICAgICAgIG1lc3NhZ2U6ICAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgY2FsbGJhY2s6ICAgICAgICBkaXNwYXRjaENhbGxiYWNrLFxuICAgICAgICByZXNwb25zZU1ldGhvZHM6IHJlc3BvbnNlTWV0aG9kc1ttZXRob2RdIHx8IHt9XG4gICAgICB9O1xuXG4gICAgICB2YXIgZW5jb2RlX3RyYW5zcG9ydCA9IHVuaWZ5VHJhbnNwb3J0KHRyYW5zcG9ydCk7XG5cbiAgICAgIGZ1bmN0aW9uIHNlbmRSZXF1ZXN0KHRyYW5zcG9ydClcbiAgICAgIHtcbiAgICAgICAgcmVxdWVzdC50aW1lb3V0ID0gc2V0VGltZW91dCh0aW1lb3V0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVlc3RfdGltZW91dCpNYXRoLnBvdygyLCByZXRyaWVkKyspKTtcbiAgICAgICAgbWVzc2FnZTJLZXlbbWVzc2FnZV0gPSB7aWQ6IGlkLCBkZXN0OiBkZXN0fTtcbiAgICAgICAgcmVxdWVzdHMuc2V0KHJlcXVlc3QsIGlkLCBkZXN0KTtcblxuICAgICAgICB0cmFuc3BvcnQgPSB0cmFuc3BvcnQgfHwgZW5jb2RlX3RyYW5zcG9ydCB8fCBzZWxmLmdldFRyYW5zcG9ydCgpO1xuICAgICAgICBpZih0cmFuc3BvcnQpXG4gICAgICAgICAgcmV0dXJuIHRyYW5zcG9ydC5zZW5kKG1lc3NhZ2UpO1xuXG4gICAgICAgIHJldHVybiBtZXNzYWdlO1xuICAgICAgfTtcblxuICAgICAgZnVuY3Rpb24gcmV0cnkodHJhbnNwb3J0KVxuICAgICAge1xuICAgICAgICB0cmFuc3BvcnQgPSB1bmlmeVRyYW5zcG9ydCh0cmFuc3BvcnQpO1xuXG4gICAgICAgIGNvbnNvbGUud2FybihyZXRyaWVkKycgcmV0cnkgZm9yIHJlcXVlc3QgbWVzc2FnZTonLG1lc3NhZ2UpO1xuXG4gICAgICAgIHZhciB0aW1lb3V0ID0gcHJvY2Vzc2VkUmVzcG9uc2VzLnBvcChpZCwgZGVzdCk7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcblxuICAgICAgICByZXR1cm4gc2VuZFJlcXVlc3QodHJhbnNwb3J0KTtcbiAgICAgIH07XG5cbiAgICAgIGZ1bmN0aW9uIHRpbWVvdXQoKVxuICAgICAge1xuICAgICAgICBpZihyZXRyaWVkIDwgbWF4X3JldHJpZXMpXG4gICAgICAgICAgcmV0dXJuIHJldHJ5KHRyYW5zcG9ydCk7XG5cbiAgICAgICAgdmFyIGVycm9yID0gbmV3IEVycm9yKCdSZXF1ZXN0IGhhcyB0aW1lZCBvdXQnKTtcbiAgICAgICAgICAgIGVycm9yLnJlcXVlc3QgPSBtZXNzYWdlO1xuXG4gICAgICAgIGVycm9yLnJldHJ5ID0gcmV0cnk7XG5cbiAgICAgICAgZGlzcGF0Y2hDYWxsYmFjayhlcnJvcilcbiAgICAgIH07XG5cbiAgICAgIHJldHVybiBzZW5kUmVxdWVzdCh0cmFuc3BvcnQpO1xuICAgIH07XG5cbiAgICAvLyBSZXR1cm4gdGhlIHBhY2tlZCBtZXNzYWdlXG4gICAgbWVzc2FnZSA9IHBhY2tlci5wYWNrKG1lc3NhZ2UpO1xuXG4gICAgdHJhbnNwb3J0ID0gdHJhbnNwb3J0IHx8IHRoaXMuZ2V0VHJhbnNwb3J0KCk7XG4gICAgaWYodHJhbnNwb3J0KVxuICAgICAgcmV0dXJuIHRyYW5zcG9ydC5zZW5kKG1lc3NhZ2UpO1xuXG4gICAgcmV0dXJuIG1lc3NhZ2U7XG4gIH07XG5cbiAgLyoqXG4gICAqIERlY29kZSBhbmQgcHJvY2VzcyBhIEpzb25SUEMgMi4wIG1lc3NhZ2VcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBzdHJpbmcgd2l0aCB0aGUgY29udGVudCBvZiB0aGUgbWVzc2FnZVxuICAgKlxuICAgKiBAcmV0dXJucyB7UnBjTm90aWZpY2F0aW9ufFJwY1JlcXVlc3R8dW5kZWZpbmVkfSAtIHRoZSByZXByZXNlbnRhdGlvbiBvZiB0aGVcbiAgICogICBub3RpZmljYXRpb24gb3IgdGhlIHJlcXVlc3QuIElmIGEgcmVzcG9uc2Ugd2FzIHByb2Nlc3NlZCwgaXQgd2lsbCByZXR1cm5cbiAgICogICBgdW5kZWZpbmVkYCB0byBub3RpZnkgdGhhdCBpdCB3YXMgcHJvY2Vzc2VkXG4gICAqXG4gICAqIEB0aHJvd3Mge1R5cGVFcnJvcn0gLSBNZXNzYWdlIGlzIG5vdCBkZWZpbmVkXG4gICAqL1xuICB0aGlzLmRlY29kZSA9IGZ1bmN0aW9uKG1lc3NhZ2UsIHRyYW5zcG9ydClcbiAge1xuICAgIGlmKCFtZXNzYWdlKVxuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk1lc3NhZ2UgaXMgbm90IGRlZmluZWRcIik7XG5cbiAgICB0cnlcbiAgICB7XG4gICAgICBtZXNzYWdlID0gcGFja2VyLnVucGFjayhtZXNzYWdlKTtcbiAgICB9XG4gICAgY2F0Y2goZSlcbiAgICB7XG4gICAgICAvLyBJZ25vcmUgaW52YWxpZCBtZXNzYWdlc1xuICAgICAgcmV0dXJuIGNvbnNvbGUubG9nKGUsIG1lc3NhZ2UpO1xuICAgIH07XG5cbiAgICB2YXIgaWQgICAgID0gbWVzc2FnZS5pZDtcbiAgICB2YXIgYWNrICAgID0gbWVzc2FnZS5hY2s7XG4gICAgdmFyIG1ldGhvZCA9IG1lc3NhZ2UubWV0aG9kO1xuICAgIHZhciBwYXJhbXMgPSBtZXNzYWdlLnBhcmFtcyB8fCB7fTtcblxuICAgIHZhciBmcm9tID0gcGFyYW1zLmZyb207XG4gICAgdmFyIGRlc3QgPSBwYXJhbXMuZGVzdDtcblxuICAgIC8vIElnbm9yZSBtZXNzYWdlcyBzZW5kIGJ5IHVzXG4gICAgaWYoc2VsZi5wZWVySUQgIT0gdW5kZWZpbmVkICYmIGZyb20gPT0gc2VsZi5wZWVySUQpIHJldHVybjtcblxuICAgIC8vIE5vdGlmaWNhdGlvblxuICAgIGlmKGlkID09IHVuZGVmaW5lZCAmJiBhY2sgPT0gdW5kZWZpbmVkKVxuICAgIHtcbiAgICAgIHZhciBub3RpZmljYXRpb24gPSBuZXcgUnBjTm90aWZpY2F0aW9uKG1ldGhvZCwgcGFyYW1zKTtcblxuICAgICAgaWYoc2VsZi5lbWl0KCdyZXF1ZXN0Jywgbm90aWZpY2F0aW9uKSkgcmV0dXJuO1xuICAgICAgcmV0dXJuIG5vdGlmaWNhdGlvbjtcbiAgICB9O1xuXG5cbiAgICBmdW5jdGlvbiBwcm9jZXNzUmVxdWVzdCgpXG4gICAge1xuICAgICAgLy8gSWYgd2UgaGF2ZSBhIHRyYW5zcG9ydCBhbmQgaXQncyBhIGR1cGxpY2F0ZWQgcmVxdWVzdCwgcmVwbHkgaW5tZWRpYXRseVxuICAgICAgdHJhbnNwb3J0ID0gdW5pZnlUcmFuc3BvcnQodHJhbnNwb3J0KSB8fCBzZWxmLmdldFRyYW5zcG9ydCgpO1xuICAgICAgaWYodHJhbnNwb3J0KVxuICAgICAge1xuICAgICAgICB2YXIgcmVzcG9uc2UgPSByZXNwb25zZXMuZ2V0KGlkLCBmcm9tKTtcbiAgICAgICAgaWYocmVzcG9uc2UpXG4gICAgICAgICAgcmV0dXJuIHRyYW5zcG9ydC5zZW5kKHJlc3BvbnNlLm1lc3NhZ2UpO1xuICAgICAgfTtcblxuICAgICAgdmFyIGlkQWNrID0gKGlkICE9IHVuZGVmaW5lZCkgPyBpZCA6IGFjaztcbiAgICAgIHZhciByZXF1ZXN0ID0gbmV3IFJwY1JlcXVlc3QobWV0aG9kLCBwYXJhbXMsIGlkQWNrLCBmcm9tLCB0cmFuc3BvcnQpO1xuXG4gICAgICBpZihzZWxmLmVtaXQoJ3JlcXVlc3QnLCByZXF1ZXN0KSkgcmV0dXJuO1xuICAgICAgcmV0dXJuIHJlcXVlc3Q7XG4gICAgfTtcblxuICAgIGZ1bmN0aW9uIHByb2Nlc3NSZXNwb25zZShyZXF1ZXN0LCBlcnJvciwgcmVzdWx0KVxuICAgIHtcbiAgICAgIHJlcXVlc3QuY2FsbGJhY2soZXJyb3IsIHJlc3VsdCk7XG4gICAgfTtcblxuICAgIGZ1bmN0aW9uIGR1cGxpY2F0ZWRSZXNwb25zZSh0aW1lb3V0KVxuICAgIHtcbiAgICAgIGNvbnNvbGUud2FybihcIlJlc3BvbnNlIGFscmVhZHkgcHJvY2Vzc2VkXCIsIG1lc3NhZ2UpO1xuXG4gICAgICAvLyBVcGRhdGUgZHVwbGljYXRlZCByZXNwb25zZXMgdGltZW91dFxuICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgc3RvcmVQcm9jZXNzZWRSZXNwb25zZShhY2ssIGZyb20pO1xuICAgIH07XG5cblxuICAgIC8vIFJlcXVlc3QsIG9yIHJlc3BvbnNlIHdpdGggb3duIG1ldGhvZFxuICAgIGlmKG1ldGhvZClcbiAgICB7XG4gICAgICAvLyBDaGVjayBpZiBpdCdzIGEgcmVzcG9uc2Ugd2l0aCBvd24gbWV0aG9kXG4gICAgICBpZihkZXN0ID09IHVuZGVmaW5lZCB8fCBkZXN0ID09IHNlbGYucGVlcklEKVxuICAgICAge1xuICAgICAgICB2YXIgcmVxdWVzdCA9IHJlcXVlc3RzLmdldChhY2ssIGZyb20pO1xuICAgICAgICBpZihyZXF1ZXN0KVxuICAgICAgICB7XG4gICAgICAgICAgdmFyIHJlc3BvbnNlTWV0aG9kcyA9IHJlcXVlc3QucmVzcG9uc2VNZXRob2RzO1xuXG4gICAgICAgICAgaWYobWV0aG9kID09IHJlc3BvbnNlTWV0aG9kcy5lcnJvcilcbiAgICAgICAgICAgIHJldHVybiBwcm9jZXNzUmVzcG9uc2UocmVxdWVzdCwgcGFyYW1zKTtcblxuICAgICAgICAgIGlmKG1ldGhvZCA9PSByZXNwb25zZU1ldGhvZHMucmVzcG9uc2UpXG4gICAgICAgICAgICByZXR1cm4gcHJvY2Vzc1Jlc3BvbnNlKHJlcXVlc3QsIG51bGwsIHBhcmFtcyk7XG5cbiAgICAgICAgICByZXR1cm4gcHJvY2Vzc1JlcXVlc3QoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBwcm9jZXNzZWQgPSBwcm9jZXNzZWRSZXNwb25zZXMuZ2V0KGFjaywgZnJvbSk7XG4gICAgICAgIGlmKHByb2Nlc3NlZClcbiAgICAgICAgICByZXR1cm4gZHVwbGljYXRlZFJlc3BvbnNlKHByb2Nlc3NlZCk7XG4gICAgICB9XG5cbiAgICAgIC8vIFJlcXVlc3RcbiAgICAgIHJldHVybiBwcm9jZXNzUmVxdWVzdCgpO1xuICAgIH07XG5cbiAgICB2YXIgZXJyb3IgID0gbWVzc2FnZS5lcnJvcjtcbiAgICB2YXIgcmVzdWx0ID0gbWVzc2FnZS5yZXN1bHQ7XG5cbiAgICAvLyBJZ25vcmUgcmVzcG9uc2VzIG5vdCBzZW5kIHRvIHVzXG4gICAgaWYoZXJyb3IgICYmIGVycm9yLmRlc3QgICYmIGVycm9yLmRlc3QgICE9IHNlbGYucGVlcklEKSByZXR1cm47XG4gICAgaWYocmVzdWx0ICYmIHJlc3VsdC5kZXN0ICYmIHJlc3VsdC5kZXN0ICE9IHNlbGYucGVlcklEKSByZXR1cm47XG5cbiAgICAvLyBSZXNwb25zZVxuICAgIHZhciByZXF1ZXN0ID0gcmVxdWVzdHMuZ2V0KGFjaywgZnJvbSk7XG4gICAgaWYoIXJlcXVlc3QpXG4gICAge1xuICAgICAgdmFyIHByb2Nlc3NlZCA9IHByb2Nlc3NlZFJlc3BvbnNlcy5nZXQoYWNrLCBmcm9tKTtcbiAgICAgIGlmKHByb2Nlc3NlZClcbiAgICAgICAgcmV0dXJuIGR1cGxpY2F0ZWRSZXNwb25zZShwcm9jZXNzZWQpO1xuXG4gICAgICByZXR1cm4gY29uc29sZS53YXJuKFwiTm8gY2FsbGJhY2sgd2FzIGRlZmluZWQgZm9yIHRoaXMgbWVzc2FnZVwiLCBtZXNzYWdlKTtcbiAgICB9O1xuXG4gICAgLy8gUHJvY2VzcyByZXNwb25zZVxuICAgIHByb2Nlc3NSZXNwb25zZShyZXF1ZXN0LCBlcnJvciwgcmVzdWx0KTtcbiAgfTtcbn07XG5pbmhlcml0cyhScGNCdWlsZGVyLCBFdmVudEVtaXR0ZXIpO1xuXG5cblJwY0J1aWxkZXIuUnBjTm90aWZpY2F0aW9uID0gUnBjTm90aWZpY2F0aW9uO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gUnBjQnVpbGRlcjtcblxudmFyIGNsaWVudHMgPSByZXF1aXJlKCcuL2NsaWVudHMnKTtcbnZhciB0cmFuc3BvcnRzID0gcmVxdWlyZSgnLi9jbGllbnRzL3RyYW5zcG9ydHMnKTtcblxuUnBjQnVpbGRlci5jbGllbnRzID0gY2xpZW50cztcblJwY0J1aWxkZXIuY2xpZW50cy50cmFuc3BvcnRzID0gdHJhbnNwb3J0cztcblJwY0J1aWxkZXIucGFja2VycyA9IHBhY2tlcnM7XG4iLCIvKipcbiAqIEpzb25SUEMgMi4wIHBhY2tlclxuICovXG5cbi8qKlxuICogUGFjayBhIEpzb25SUEMgMi4wIG1lc3NhZ2VcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gbWVzc2FnZSAtIG9iamVjdCB0byBiZSBwYWNrYWdlZC4gSXQgcmVxdWlyZXMgdG8gaGF2ZSBhbGwgdGhlXG4gKiAgIGZpZWxkcyBuZWVkZWQgYnkgdGhlIEpzb25SUEMgMi4wIG1lc3NhZ2UgdGhhdCBpdCdzIGdvaW5nIHRvIGJlIGdlbmVyYXRlZFxuICpcbiAqIEByZXR1cm4ge1N0cmluZ30gLSB0aGUgc3RyaW5naWZpZWQgSnNvblJQQyAyLjAgbWVzc2FnZVxuICovXG5mdW5jdGlvbiBwYWNrKG1lc3NhZ2UsIGlkKVxue1xuICB2YXIgcmVzdWx0ID1cbiAge1xuICAgIGpzb25ycGM6IFwiMi4wXCJcbiAgfTtcblxuICAvLyBSZXF1ZXN0XG4gIGlmKG1lc3NhZ2UubWV0aG9kKVxuICB7XG4gICAgcmVzdWx0Lm1ldGhvZCA9IG1lc3NhZ2UubWV0aG9kO1xuXG4gICAgaWYobWVzc2FnZS5wYXJhbXMpXG4gICAgICByZXN1bHQucGFyYW1zID0gbWVzc2FnZS5wYXJhbXM7XG5cbiAgICAvLyBSZXF1ZXN0IGlzIGEgbm90aWZpY2F0aW9uXG4gICAgaWYoaWQgIT0gdW5kZWZpbmVkKVxuICAgICAgcmVzdWx0LmlkID0gaWQ7XG4gIH1cblxuICAvLyBSZXNwb25zZVxuICBlbHNlIGlmKGlkICE9IHVuZGVmaW5lZClcbiAge1xuICAgIGlmKG1lc3NhZ2UuZXJyb3IpXG4gICAge1xuICAgICAgaWYobWVzc2FnZS5yZXN1bHQgIT09IHVuZGVmaW5lZClcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkJvdGggcmVzdWx0IGFuZCBlcnJvciBhcmUgZGVmaW5lZFwiKTtcblxuICAgICAgcmVzdWx0LmVycm9yID0gbWVzc2FnZS5lcnJvcjtcbiAgICB9XG4gICAgZWxzZSBpZihtZXNzYWdlLnJlc3VsdCAhPT0gdW5kZWZpbmVkKVxuICAgICAgcmVzdWx0LnJlc3VsdCA9IG1lc3NhZ2UucmVzdWx0O1xuICAgIGVsc2VcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJObyByZXN1bHQgb3IgZXJyb3IgaXMgZGVmaW5lZFwiKTtcblxuICAgIHJlc3VsdC5pZCA9IGlkO1xuICB9O1xuXG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShyZXN1bHQpO1xufTtcblxuLyoqXG4gKiBVbnBhY2sgYSBKc29uUlBDIDIuMCBtZXNzYWdlXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgLSBzdHJpbmcgd2l0aCB0aGUgY29udGVudCBvZiB0aGUgSnNvblJQQyAyLjAgbWVzc2FnZVxuICpcbiAqIEB0aHJvd3Mge1R5cGVFcnJvcn0gLSBJbnZhbGlkIEpzb25SUEMgdmVyc2lvblxuICpcbiAqIEByZXR1cm4ge09iamVjdH0gLSBvYmplY3QgZmlsbGVkIHdpdGggdGhlIEpzb25SUEMgMi4wIG1lc3NhZ2UgY29udGVudFxuICovXG5mdW5jdGlvbiB1bnBhY2sobWVzc2FnZSlcbntcbiAgdmFyIHJlc3VsdCA9IG1lc3NhZ2U7XG5cbiAgaWYodHlwZW9mIG1lc3NhZ2UgPT09ICdzdHJpbmcnIHx8IG1lc3NhZ2UgaW5zdGFuY2VvZiBTdHJpbmcpXG4gICAgcmVzdWx0ID0gSlNPTi5wYXJzZShtZXNzYWdlKTtcblxuICAvLyBDaGVjayBpZiBpdCdzIGEgdmFsaWQgbWVzc2FnZVxuXG4gIHZhciB2ZXJzaW9uID0gcmVzdWx0Lmpzb25ycGM7XG4gIGlmKHZlcnNpb24gIT09ICcyLjAnKVxuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJJbnZhbGlkIEpzb25SUEMgdmVyc2lvbiAnXCIgKyB2ZXJzaW9uICsgXCInOiBcIiArIG1lc3NhZ2UpO1xuXG4gIC8vIFJlc3BvbnNlXG4gIGlmKHJlc3VsdC5tZXRob2QgPT0gdW5kZWZpbmVkKVxuICB7XG4gICAgaWYocmVzdWx0LmlkID09IHVuZGVmaW5lZClcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJJbnZhbGlkIG1lc3NhZ2U6IFwiK21lc3NhZ2UpO1xuXG4gICAgdmFyIHJlc3VsdF9kZWZpbmVkID0gcmVzdWx0LnJlc3VsdCAhPT0gdW5kZWZpbmVkO1xuICAgIHZhciBlcnJvcl9kZWZpbmVkICA9IHJlc3VsdC5lcnJvciAgIT09IHVuZGVmaW5lZDtcblxuICAgIC8vIENoZWNrIG9ubHkgcmVzdWx0IG9yIGVycm9yIGlzIGRlZmluZWQsIG5vdCBib3RoIG9yIG5vbmVcbiAgICBpZihyZXN1bHRfZGVmaW5lZCAmJiBlcnJvcl9kZWZpbmVkKVxuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkJvdGggcmVzdWx0IGFuZCBlcnJvciBhcmUgZGVmaW5lZDogXCIrbWVzc2FnZSk7XG5cbiAgICBpZighcmVzdWx0X2RlZmluZWQgJiYgIWVycm9yX2RlZmluZWQpXG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTm8gcmVzdWx0IG9yIGVycm9yIGlzIGRlZmluZWQ6IFwiK21lc3NhZ2UpO1xuXG4gICAgcmVzdWx0LmFjayA9IHJlc3VsdC5pZDtcbiAgICBkZWxldGUgcmVzdWx0LmlkO1xuICB9XG5cbiAgLy8gUmV0dXJuIHVucGFja2VkIG1lc3NhZ2VcbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cblxuZXhwb3J0cy5wYWNrICAgPSBwYWNrO1xuZXhwb3J0cy51bnBhY2sgPSB1bnBhY2s7XG4iLCJmdW5jdGlvbiBwYWNrKG1lc3NhZ2UpXG57XG4gIHRocm93IG5ldyBUeXBlRXJyb3IoXCJOb3QgeWV0IGltcGxlbWVudGVkXCIpO1xufTtcblxuZnVuY3Rpb24gdW5wYWNrKG1lc3NhZ2UpXG57XG4gIHRocm93IG5ldyBUeXBlRXJyb3IoXCJOb3QgeWV0IGltcGxlbWVudGVkXCIpO1xufTtcblxuXG5leHBvcnRzLnBhY2sgICA9IHBhY2s7XG5leHBvcnRzLnVucGFjayA9IHVucGFjaztcbiIsInZhciBKc29uUlBDID0gcmVxdWlyZSgnLi9Kc29uUlBDJyk7XG52YXIgWG1sUlBDICA9IHJlcXVpcmUoJy4vWG1sUlBDJyk7XG5cblxuZXhwb3J0cy5Kc29uUlBDID0gSnNvblJQQztcbmV4cG9ydHMuWG1sUlBDICA9IFhtbFJQQztcbiIsIi8qXG4gKiAoQykgQ29weXJpZ2h0IDIwMTQtMjAxNSBLdXJlbnRvIChodHRwOi8va3VyZW50by5vcmcvKVxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxudmFyIGZyZWVpY2UgPSByZXF1aXJlKCdmcmVlaWNlJylcbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbnZhciBVQVBhcnNlciA9IHJlcXVpcmUoJ3VhLXBhcnNlci1qcycpXG52YXIgdXVpZCA9IHJlcXVpcmUoJ3V1aWQnKVxudmFyIGhhcmsgPSByZXF1aXJlKCdoYXJrJylcblxudmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlclxudmFyIHJlY3Vyc2l2ZSA9IHJlcXVpcmUoJ21lcmdlJykucmVjdXJzaXZlLmJpbmQodW5kZWZpbmVkLCB0cnVlKVxudmFyIHNkcFRyYW5zbGF0b3IgPSByZXF1aXJlKCdzZHAtdHJhbnNsYXRvcicpXG52YXIgbG9nZ2VyID0gd2luZG93LkxvZ2dlciB8fCBjb25zb2xlXG5cbi8vIHZhciBnVU0gPSBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYSB8fCBmdW5jdGlvbiAoY29uc3RyYWludHMpIHtcbi8vICAgcmV0dXJuIG5ldyBQcm9taXNlKG5hdmlnYXRvci5nZXRVc2VyTWVkaWEoY29uc3RyYWludHMsIGZ1bmN0aW9uIChzdHJlYW0pIHtcbi8vICAgICB2aWRlb1N0cmVhbSA9IHN0cmVhbVxuLy8gICAgIHN0YXJ0KClcbi8vICAgfSkuZXJvcihjYWxsYmFjaykpO1xuLy8gfVxuXG50cnkge1xuICByZXF1aXJlKCdrdXJlbnRvLWJyb3dzZXItZXh0ZW5zaW9ucycpXG59IGNhdGNoIChlcnJvcikge1xuICBpZiAodHlwZW9mIGdldFNjcmVlbkNvbnN0cmFpbnRzID09PSAndW5kZWZpbmVkJykge1xuICAgIGxvZ2dlci53YXJuKCdzY3JlZW4gc2hhcmluZyBpcyBub3QgYXZhaWxhYmxlJylcblxuICAgIGdldFNjcmVlbkNvbnN0cmFpbnRzID0gZnVuY3Rpb24gZ2V0U2NyZWVuQ29uc3RyYWludHMoc2VuZFNvdXJjZSwgY2FsbGJhY2spIHtcbiAgICAgIGNhbGxiYWNrKG5ldyBFcnJvcihcIlRoaXMgbGlicmFyeSBpcyBub3QgZW5hYmxlZCBmb3Igc2NyZWVuIHNoYXJpbmdcIikpXG4gICAgfVxuICB9XG59XG5cbnZhciBNRURJQV9DT05TVFJBSU5UUyA9IHtcbiAgYXVkaW86IHRydWUsXG4gIHZpZGVvOiB7XG4gICAgd2lkdGg6IDY0MCxcbiAgICBmcmFtZXJhdGU6IDE1XG4gIH1cbn1cblxuLy8gU29tZWhvdywgdGhlIFVBUGFyc2VyIGNvbnN0cnVjdG9yIGdldHMgYW4gZW1wdHkgd2luZG93IG9iamVjdC5cbi8vIFdlIG5lZWQgdG8gcGFzcyB0aGUgdXNlciBhZ2VudCBzdHJpbmcgaW4gb3JkZXIgdG8gZ2V0IGluZm9ybWF0aW9uXG52YXIgdWEgPSAod2luZG93ICYmIHdpbmRvdy5uYXZpZ2F0b3IpID8gd2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQgOiAnJ1xudmFyIHBhcnNlciA9IG5ldyBVQVBhcnNlcih1YSlcbnZhciBicm93c2VyID0gcGFyc2VyLmdldEJyb3dzZXIoKVxuXG52YXIgdXNlUGxhbkIgPSBmYWxzZVxuaWYgKGJyb3dzZXIubmFtZSA9PT0gJ0Nocm9tZScgfHwgYnJvd3Nlci5uYW1lID09PSAnQ2hyb21pdW0nKSB7XG4gIGxvZ2dlci5pbmZvKGJyb3dzZXIubmFtZSArIFwiOiB1c2luZyBTRFAgUGxhbkJcIilcbiAgdXNlUGxhbkIgPSB0cnVlXG59XG5cbmZ1bmN0aW9uIG5vb3AoZXJyb3IpIHtcbiAgaWYgKGVycm9yKSBsb2dnZXIuZXJyb3IoZXJyb3IpXG59XG5cbmZ1bmN0aW9uIHRyYWNrU3RvcCh0cmFjaykge1xuICB0cmFjay5zdG9wICYmIHRyYWNrLnN0b3AoKVxufVxuXG5mdW5jdGlvbiBzdHJlYW1TdG9wKHN0cmVhbSkge1xuICBzdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaCh0cmFja1N0b3ApXG59XG5cbi8qKlxuICogUmV0dXJucyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBhIFNlc3Npb25EZXNjcmlwdGlvbiBvYmplY3QuXG4gKi9cbnZhciBkdW1wU0RQID0gZnVuY3Rpb24gKGRlc2NyaXB0aW9uKSB7XG4gIGlmICh0eXBlb2YgZGVzY3JpcHRpb24gPT09ICd1bmRlZmluZWQnIHx8IGRlc2NyaXB0aW9uID09PSBudWxsKSB7XG4gICAgcmV0dXJuICcnXG4gIH1cblxuICByZXR1cm4gJ3R5cGU6ICcgKyBkZXNjcmlwdGlvbi50eXBlICsgJ1xcclxcbicgKyBkZXNjcmlwdGlvbi5zZHBcbn1cblxuZnVuY3Rpb24gYnVmZmVyaXplQ2FuZGlkYXRlcyhwYywgb25lcnJvcikge1xuICB2YXIgY2FuZGlkYXRlc1F1ZXVlID0gW11cblxuICBwYy5hZGRFdmVudExpc3RlbmVyKCdzaWduYWxpbmdzdGF0ZWNoYW5nZScsIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5zaWduYWxpbmdTdGF0ZSA9PT0gJ3N0YWJsZScpIHtcbiAgICAgIHdoaWxlIChjYW5kaWRhdGVzUXVldWUubGVuZ3RoKSB7XG4gICAgICAgIHZhciBlbnRyeSA9IGNhbmRpZGF0ZXNRdWV1ZS5zaGlmdCgpXG5cbiAgICAgICAgdGhpcy5hZGRJY2VDYW5kaWRhdGUoZW50cnkuY2FuZGlkYXRlLCBlbnRyeS5jYWxsYmFjaywgZW50cnkuY2FsbGJhY2spXG4gICAgICB9XG4gICAgfVxuICB9KVxuXG4gIHJldHVybiBmdW5jdGlvbiAoY2FuZGlkYXRlLCBjYWxsYmFjaykge1xuICAgIGNhbGxiYWNrID0gY2FsbGJhY2sgfHwgb25lcnJvclxuXG4gICAgc3dpdGNoIChwYy5zaWduYWxpbmdTdGF0ZSkge1xuICAgIGNhc2UgJ2Nsb3NlZCc6XG4gICAgICBjYWxsYmFjayhuZXcgRXJyb3IoJ1BlZXJDb25uZWN0aW9uIG9iamVjdCBpcyBjbG9zZWQnKSlcbiAgICAgIGJyZWFrXG4gICAgY2FzZSAnc3RhYmxlJzpcbiAgICAgIGlmIChwYy5yZW1vdGVEZXNjcmlwdGlvbikge1xuICAgICAgICBwYy5hZGRJY2VDYW5kaWRhdGUoY2FuZGlkYXRlLCBjYWxsYmFjaywgY2FsbGJhY2spXG4gICAgICAgIGJyZWFrXG4gICAgICB9XG4gICAgZGVmYXVsdDpcbiAgICAgIGNhbmRpZGF0ZXNRdWV1ZS5wdXNoKHtcbiAgICAgICAgY2FuZGlkYXRlOiBjYW5kaWRhdGUsXG4gICAgICAgIGNhbGxiYWNrOiBjYWxsYmFja1xuICAgICAgfSlcbiAgICB9XG4gIH1cbn1cblxuLyogU2ltdWxjYXN0IHV0aWxpdGllcyAqL1xuXG5mdW5jdGlvbiByZW1vdmVGSURGcm9tT2ZmZXIoc2RwKSB7XG4gIHZhciBuID0gc2RwLmluZGV4T2YoXCJhPXNzcmMtZ3JvdXA6RklEXCIpO1xuXG4gIGlmIChuID4gMCkge1xuICAgIHJldHVybiBzZHAuc2xpY2UoMCwgbik7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIHNkcDtcbiAgfVxufVxuXG5mdW5jdGlvbiBnZXRTaW11bGNhc3RJbmZvKHZpZGVvU3RyZWFtKSB7XG4gIHZhciB2aWRlb1RyYWNrcyA9IHZpZGVvU3RyZWFtLmdldFZpZGVvVHJhY2tzKCk7XG4gIGlmICghdmlkZW9UcmFja3MubGVuZ3RoKSB7XG4gICAgbG9nZ2VyLndhcm4oJ05vIHZpZGVvIHRyYWNrcyBhdmFpbGFibGUgaW4gdGhlIHZpZGVvIHN0cmVhbScpXG4gICAgcmV0dXJuICcnXG4gIH1cbiAgdmFyIGxpbmVzID0gW1xuICAgICdhPXgtZ29vZ2xlLWZsYWc6Y29uZmVyZW5jZScsXG4gICAgJ2E9c3NyYy1ncm91cDpTSU0gMSAyIDMnLFxuICAgICdhPXNzcmM6MSBjbmFtZTpsb2NhbFZpZGVvJyxcbiAgICAnYT1zc3JjOjEgbXNpZDonICsgdmlkZW9TdHJlYW0uaWQgKyAnICcgKyB2aWRlb1RyYWNrc1swXS5pZCxcbiAgICAnYT1zc3JjOjEgbXNsYWJlbDonICsgdmlkZW9TdHJlYW0uaWQsXG4gICAgJ2E9c3NyYzoxIGxhYmVsOicgKyB2aWRlb1RyYWNrc1swXS5pZCxcbiAgICAnYT1zc3JjOjIgY25hbWU6bG9jYWxWaWRlbycsXG4gICAgJ2E9c3NyYzoyIG1zaWQ6JyArIHZpZGVvU3RyZWFtLmlkICsgJyAnICsgdmlkZW9UcmFja3NbMF0uaWQsXG4gICAgJ2E9c3NyYzoyIG1zbGFiZWw6JyArIHZpZGVvU3RyZWFtLmlkLFxuICAgICdhPXNzcmM6MiBsYWJlbDonICsgdmlkZW9UcmFja3NbMF0uaWQsXG4gICAgJ2E9c3NyYzozIGNuYW1lOmxvY2FsVmlkZW8nLFxuICAgICdhPXNzcmM6MyBtc2lkOicgKyB2aWRlb1N0cmVhbS5pZCArICcgJyArIHZpZGVvVHJhY2tzWzBdLmlkLFxuICAgICdhPXNzcmM6MyBtc2xhYmVsOicgKyB2aWRlb1N0cmVhbS5pZCxcbiAgICAnYT1zc3JjOjMgbGFiZWw6JyArIHZpZGVvVHJhY2tzWzBdLmlkXG4gIF07XG5cbiAgbGluZXMucHVzaCgnJyk7XG5cbiAgcmV0dXJuIGxpbmVzLmpvaW4oJ1xcbicpO1xufVxuXG4vKipcbiAqIFdyYXBwZXIgb2JqZWN0IG9mIGFuIFJUQ1BlZXJDb25uZWN0aW9uLiBUaGlzIG9iamVjdCBpcyBhaW1lZCB0byBzaW1wbGlmeSB0aGVcbiAqIGRldmVsb3BtZW50IG9mIFdlYlJUQy1iYXNlZCBhcHBsaWNhdGlvbnMuXG4gKlxuICogQGNvbnN0cnVjdG9yIG1vZHVsZTprdXJlbnRvVXRpbHMuV2ViUnRjUGVlclxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtb2RlIE1vZGUgaW4gd2hpY2ggdGhlIFBlZXJDb25uZWN0aW9uIHdpbGwgYmUgY29uZmlndXJlZC5cbiAqICBWYWxpZCB2YWx1ZXMgYXJlOiAncmVjdicsICdzZW5kJywgYW5kICdzZW5kUmVjdidcbiAqIEBwYXJhbSBsb2NhbFZpZGVvIFZpZGVvIHRhZyBmb3IgdGhlIGxvY2FsIHN0cmVhbVxuICogQHBhcmFtIHJlbW90ZVZpZGVvIFZpZGVvIHRhZyBmb3IgdGhlIHJlbW90ZSBzdHJlYW1cbiAqIEBwYXJhbSB7TWVkaWFTdHJlYW19IHZpZGVvU3RyZWFtIFN0cmVhbSB0byBiZSB1c2VkIGFzIHByaW1hcnkgc291cmNlXG4gKiAgKHR5cGljYWxseSB2aWRlbyBhbmQgYXVkaW8sIG9yIG9ubHkgdmlkZW8gaWYgY29tYmluZWQgd2l0aCBhdWRpb1N0cmVhbSkgZm9yXG4gKiAgbG9jYWxWaWRlbyBhbmQgdG8gYmUgYWRkZWQgYXMgc3RyZWFtIHRvIHRoZSBSVENQZWVyQ29ubmVjdGlvblxuICogQHBhcmFtIHtNZWRpYVN0cmVhbX0gYXVkaW9TdHJlYW0gU3RyZWFtIHRvIGJlIHVzZWQgYXMgc2Vjb25kIHNvdXJjZVxuICogICh0eXBpY2FsbHkgZm9yIGF1ZGlvKSBmb3IgbG9jYWxWaWRlbyBhbmQgdG8gYmUgYWRkZWQgYXMgc3RyZWFtIHRvIHRoZVxuICogIFJUQ1BlZXJDb25uZWN0aW9uXG4gKi9cbmZ1bmN0aW9uIFdlYlJ0Y1BlZXIobW9kZSwgb3B0aW9ucywgY2FsbGJhY2spIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFdlYlJ0Y1BlZXIpKSB7XG4gICAgcmV0dXJuIG5ldyBXZWJSdGNQZWVyKG1vZGUsIG9wdGlvbnMsIGNhbGxiYWNrKVxuICB9XG5cbiAgV2ViUnRjUGVlci5zdXBlcl8uY2FsbCh0aGlzKVxuXG4gIGlmIChvcHRpb25zIGluc3RhbmNlb2YgRnVuY3Rpb24pIHtcbiAgICBjYWxsYmFjayA9IG9wdGlvbnNcbiAgICBvcHRpb25zID0gdW5kZWZpbmVkXG4gIH1cblxuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fVxuICBjYWxsYmFjayA9IChjYWxsYmFjayB8fCBub29wKS5iaW5kKHRoaXMpXG5cbiAgdmFyIHNlbGYgPSB0aGlzXG4gIHZhciBsb2NhbFZpZGVvID0gb3B0aW9ucy5sb2NhbFZpZGVvXG4gIHZhciByZW1vdGVWaWRlbyA9IG9wdGlvbnMucmVtb3RlVmlkZW9cbiAgdmFyIHZpZGVvU3RyZWFtID0gb3B0aW9ucy52aWRlb1N0cmVhbVxuICB2YXIgYXVkaW9TdHJlYW0gPSBvcHRpb25zLmF1ZGlvU3RyZWFtXG4gIHZhciBtZWRpYUNvbnN0cmFpbnRzID0gb3B0aW9ucy5tZWRpYUNvbnN0cmFpbnRzXG5cbiAgdmFyIGNvbm5lY3Rpb25Db25zdHJhaW50cyA9IG9wdGlvbnMuY29ubmVjdGlvbkNvbnN0cmFpbnRzXG4gIHZhciBwYyA9IG9wdGlvbnMucGVlckNvbm5lY3Rpb25cbiAgdmFyIHNlbmRTb3VyY2UgPSBvcHRpb25zLnNlbmRTb3VyY2UgfHwgJ3dlYmNhbSdcblxuICB2YXIgZGF0YUNoYW5uZWxDb25maWcgPSBvcHRpb25zLmRhdGFDaGFubmVsQ29uZmlnXG4gIHZhciB1c2VEYXRhQ2hhbm5lbHMgPSBvcHRpb25zLmRhdGFDaGFubmVscyB8fCBmYWxzZVxuICB2YXIgZGF0YUNoYW5uZWxcblxuICB2YXIgZ3VpZCA9IHV1aWQudjQoKVxuICB2YXIgY29uZmlndXJhdGlvbiA9IHJlY3Vyc2l2ZSh7XG4gICAgICBpY2VTZXJ2ZXJzOiBmcmVlaWNlKClcbiAgICB9LFxuICAgIG9wdGlvbnMuY29uZmlndXJhdGlvbilcblxuICB2YXIgb25pY2VjYW5kaWRhdGUgPSBvcHRpb25zLm9uaWNlY2FuZGlkYXRlXG4gIGlmIChvbmljZWNhbmRpZGF0ZSkgdGhpcy5vbignaWNlY2FuZGlkYXRlJywgb25pY2VjYW5kaWRhdGUpXG5cbiAgdmFyIG9uY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZSA9IG9wdGlvbnMub25jYW5kaWRhdGVnYXRoZXJpbmdkb25lXG4gIGlmIChvbmNhbmRpZGF0ZWdhdGhlcmluZ2RvbmUpIHtcbiAgICB0aGlzLm9uKCdjYW5kaWRhdGVnYXRoZXJpbmdkb25lJywgb25jYW5kaWRhdGVnYXRoZXJpbmdkb25lKVxuICB9XG5cbiAgdmFyIHNpbXVsY2FzdCA9IG9wdGlvbnMuc2ltdWxjYXN0XG4gIHZhciBtdWx0aXN0cmVhbSA9IG9wdGlvbnMubXVsdGlzdHJlYW1cbiAgdmFyIGludGVyb3AgPSBuZXcgc2RwVHJhbnNsYXRvci5JbnRlcm9wKClcbiAgdmFyIGNhbmRpZGF0ZXNRdWV1ZU91dCA9IFtdXG4gIHZhciBjYW5kaWRhdGVnYXRoZXJpbmdkb25lID0gZmFsc2VcblxuICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgJ3BlZXJDb25uZWN0aW9uJzoge1xuICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBwY1xuICAgICAgfVxuICAgIH0sXG5cbiAgICAnaWQnOiB7XG4gICAgICB2YWx1ZTogb3B0aW9ucy5pZCB8fCBndWlkLFxuICAgICAgd3JpdGFibGU6IGZhbHNlXG4gICAgfSxcblxuICAgICdyZW1vdGVWaWRlbyc6IHtcbiAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gcmVtb3RlVmlkZW9cbiAgICAgIH1cbiAgICB9LFxuXG4gICAgJ2xvY2FsVmlkZW8nOiB7XG4gICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGxvY2FsVmlkZW9cbiAgICAgIH1cbiAgICB9LFxuXG4gICAgJ2RhdGFDaGFubmVsJzoge1xuICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBkYXRhQ2hhbm5lbFxuICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHsoZXh0ZXJuYWw6SW1hZ2VEYXRhfHVuZGVmaW5lZCl9IGN1cnJlbnRGcmFtZVxuICAgICAqL1xuICAgICdjdXJyZW50RnJhbWUnOiB7XG4gICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gW1RvRG9dIEZpbmQgc29sdXRpb24gd2hlbiB3ZSBoYXZlIGEgcmVtb3RlIHN0cmVhbSBidXQgd2UgZGlkbid0IHNldFxuICAgICAgICAvLyBhIHJlbW90ZVZpZGVvIHRhZ1xuICAgICAgICBpZiAoIXJlbW90ZVZpZGVvKSByZXR1cm47XG5cbiAgICAgICAgaWYgKHJlbW90ZVZpZGVvLnJlYWR5U3RhdGUgPCByZW1vdGVWaWRlby5IQVZFX0NVUlJFTlRfREFUQSlcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHZpZGVvIHN0cmVhbSBkYXRhIGF2YWlsYWJsZScpXG5cbiAgICAgICAgdmFyIGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpXG4gICAgICAgIGNhbnZhcy53aWR0aCA9IHJlbW90ZVZpZGVvLnZpZGVvV2lkdGhcbiAgICAgICAgY2FudmFzLmhlaWdodCA9IHJlbW90ZVZpZGVvLnZpZGVvSGVpZ2h0XG5cbiAgICAgICAgY2FudmFzLmdldENvbnRleHQoJzJkJykuZHJhd0ltYWdlKHJlbW90ZVZpZGVvLCAwLCAwKVxuXG4gICAgICAgIHJldHVybiBjYW52YXNcbiAgICAgIH1cbiAgICB9XG4gIH0pXG5cbiAgLy8gSW5pdCBQZWVyQ29ubmVjdGlvblxuICBpZiAoIXBjKSB7XG4gICAgcGMgPSBuZXcgUlRDUGVlckNvbm5lY3Rpb24oY29uZmlndXJhdGlvbik7XG4gICAgaWYgKHVzZURhdGFDaGFubmVscyAmJiAhZGF0YUNoYW5uZWwpIHtcbiAgICAgIHZhciBkY0lkID0gJ1dlYlJ0Y1BlZXItJyArIHNlbGYuaWRcbiAgICAgIHZhciBkY09wdGlvbnMgPSB1bmRlZmluZWRcbiAgICAgIGlmIChkYXRhQ2hhbm5lbENvbmZpZykge1xuICAgICAgICBkY0lkID0gZGF0YUNoYW5uZWxDb25maWcuaWQgfHwgZGNJZFxuICAgICAgICBkY09wdGlvbnMgPSBkYXRhQ2hhbm5lbENvbmZpZy5vcHRpb25zXG4gICAgICB9XG4gICAgICBkYXRhQ2hhbm5lbCA9IHBjLmNyZWF0ZURhdGFDaGFubmVsKGRjSWQsIGRjT3B0aW9ucyk7XG4gICAgICBpZiAoZGF0YUNoYW5uZWxDb25maWcpIHtcbiAgICAgICAgZGF0YUNoYW5uZWwub25vcGVuID0gZGF0YUNoYW5uZWxDb25maWcub25vcGVuO1xuICAgICAgICBkYXRhQ2hhbm5lbC5vbmNsb3NlID0gZGF0YUNoYW5uZWxDb25maWcub25jbG9zZTtcbiAgICAgICAgZGF0YUNoYW5uZWwub25tZXNzYWdlID0gZGF0YUNoYW5uZWxDb25maWcub25tZXNzYWdlO1xuICAgICAgICBkYXRhQ2hhbm5lbC5vbmJ1ZmZlcmVkYW1vdW50bG93ID0gZGF0YUNoYW5uZWxDb25maWcub25idWZmZXJlZGFtb3VudGxvdztcbiAgICAgICAgZGF0YUNoYW5uZWwub25lcnJvciA9IGRhdGFDaGFubmVsQ29uZmlnLm9uZXJyb3IgfHwgbm9vcDtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwYy5hZGRFdmVudExpc3RlbmVyKCdpY2VjYW5kaWRhdGUnLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICB2YXIgY2FuZGlkYXRlID0gZXZlbnQuY2FuZGlkYXRlXG5cbiAgICBpZiAoRXZlbnRFbWl0dGVyLmxpc3RlbmVyQ291bnQoc2VsZiwgJ2ljZWNhbmRpZGF0ZScpIHx8XG4gICAgICBFdmVudEVtaXR0ZXIubGlzdGVuZXJDb3VudChcbiAgICAgICAgc2VsZiwgJ2NhbmRpZGF0ZWdhdGhlcmluZ2RvbmUnKSkge1xuICAgICAgaWYgKGNhbmRpZGF0ZSkge1xuICAgICAgICB2YXIgY2FuZFxuXG4gICAgICAgIGlmIChtdWx0aXN0cmVhbSAmJiB1c2VQbGFuQikge1xuICAgICAgICAgIGNhbmQgPSBpbnRlcm9wLmNhbmRpZGF0ZVRvVW5pZmllZFBsYW4oY2FuZGlkYXRlKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNhbmQgPSBjYW5kaWRhdGVcbiAgICAgICAgfVxuXG4gICAgICAgIHNlbGYuZW1pdCgnaWNlY2FuZGlkYXRlJywgY2FuZClcbiAgICAgICAgY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZSA9IGZhbHNlXG4gICAgICB9IGVsc2UgaWYgKCFjYW5kaWRhdGVnYXRoZXJpbmdkb25lKSB7XG4gICAgICAgIHNlbGYuZW1pdCgnY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZScpXG4gICAgICAgIGNhbmRpZGF0ZWdhdGhlcmluZ2RvbmUgPSB0cnVlXG4gICAgICB9XG4gICAgfSBlbHNlIGlmICghY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZSkge1xuICAgICAgLy8gTm90IGxpc3RlbmluZyB0byAnaWNlY2FuZGlkYXRlJyBvciAnY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZScgZXZlbnRzLCBxdWV1ZVxuICAgICAgLy8gdGhlIGNhbmRpZGF0ZSB1bnRpbCBvbmUgb2YgdGhlbSBpcyBsaXN0ZW5lZFxuICAgICAgY2FuZGlkYXRlc1F1ZXVlT3V0LnB1c2goY2FuZGlkYXRlKVxuXG4gICAgICBpZiAoIWNhbmRpZGF0ZSkgY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZSA9IHRydWVcbiAgICB9XG4gIH0pXG5cbiAgcGMub250cmFjayA9IG9wdGlvbnMub25hZGRzdHJlYW1cbiAgcGMub25uZWdvdGlhdGlvbm5lZWRlZCA9IG9wdGlvbnMub25uZWdvdGlhdGlvbm5lZWRlZFxuICB0aGlzLm9uKCduZXdMaXN0ZW5lcicsIGZ1bmN0aW9uIChldmVudCwgbGlzdGVuZXIpIHtcbiAgICBpZiAoZXZlbnQgPT09ICdpY2VjYW5kaWRhdGUnIHx8IGV2ZW50ID09PSAnY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZScpIHtcbiAgICAgIHdoaWxlIChjYW5kaWRhdGVzUXVldWVPdXQubGVuZ3RoKSB7XG4gICAgICAgIHZhciBjYW5kaWRhdGUgPSBjYW5kaWRhdGVzUXVldWVPdXQuc2hpZnQoKVxuXG4gICAgICAgIGlmICghY2FuZGlkYXRlID09PSAoZXZlbnQgPT09ICdjYW5kaWRhdGVnYXRoZXJpbmdkb25lJykpIHtcbiAgICAgICAgICBsaXN0ZW5lcihjYW5kaWRhdGUpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0pXG5cbiAgdmFyIGFkZEljZUNhbmRpZGF0ZSA9IGJ1ZmZlcml6ZUNhbmRpZGF0ZXMocGMpXG5cbiAgLyoqXG4gICAqIENhbGxiYWNrIGZ1bmN0aW9uIGludm9rZWQgd2hlbiBhbiBJQ0UgY2FuZGlkYXRlIGlzIHJlY2VpdmVkLiBEZXZlbG9wZXJzIGFyZVxuICAgKiBleHBlY3RlZCB0byBpbnZva2UgdGhpcyBmdW5jdGlvbiBpbiBvcmRlciB0byBjb21wbGV0ZSB0aGUgU0RQIG5lZ290aWF0aW9uLlxuICAgKlxuICAgKiBAZnVuY3Rpb24gbW9kdWxlOmt1cmVudG9VdGlscy5XZWJSdGNQZWVyLnByb3RvdHlwZS5hZGRJY2VDYW5kaWRhdGVcbiAgICpcbiAgICogQHBhcmFtIGljZUNhbmRpZGF0ZSAtIExpdGVyYWwgb2JqZWN0IHdpdGggdGhlIElDRSBjYW5kaWRhdGUgZGVzY3JpcHRpb25cbiAgICogQHBhcmFtIGNhbGxiYWNrIC0gQ2FsbGVkIHdoZW4gdGhlIElDRSBjYW5kaWRhdGUgaGFzIGJlZW4gYWRkZWQuXG4gICAqL1xuICB0aGlzLmFkZEljZUNhbmRpZGF0ZSA9IGZ1bmN0aW9uIChpY2VDYW5kaWRhdGUsIGNhbGxiYWNrKSB7XG4gICAgdmFyIGNhbmRpZGF0ZVxuXG4gICAgaWYgKG11bHRpc3RyZWFtICYmIHVzZVBsYW5CKSB7XG4gICAgICBjYW5kaWRhdGUgPSBpbnRlcm9wLmNhbmRpZGF0ZVRvUGxhbkIoaWNlQ2FuZGlkYXRlKVxuICAgIH0gZWxzZSB7XG4gICAgICBjYW5kaWRhdGUgPSBuZXcgUlRDSWNlQ2FuZGlkYXRlKGljZUNhbmRpZGF0ZSlcbiAgICB9XG5cbiAgICBsb2dnZXIuZGVidWcoJ1JlbW90ZSBJQ0UgY2FuZGlkYXRlIHJlY2VpdmVkJywgaWNlQ2FuZGlkYXRlKVxuICAgIGNhbGxiYWNrID0gKGNhbGxiYWNrIHx8IG5vb3ApLmJpbmQodGhpcylcbiAgICBhZGRJY2VDYW5kaWRhdGUoY2FuZGlkYXRlLCBjYWxsYmFjaylcbiAgfVxuXG4gIHRoaXMuZ2VuZXJhdGVPZmZlciA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgIGNhbGxiYWNrID0gY2FsbGJhY2suYmluZCh0aGlzKVxuXG4gICAgdmFyIG9mZmVyQXVkaW8gPSB0cnVlXG4gICAgdmFyIG9mZmVyVmlkZW8gPSB0cnVlXG4gICAgLy8gQ29uc3RyYWludHMgbXVzdCBoYXZlIGJvdGggYmxvY2tzXG4gICAgaWYgKG1lZGlhQ29uc3RyYWludHMpIHtcbiAgICAgIG9mZmVyQXVkaW8gPSAodHlwZW9mIG1lZGlhQ29uc3RyYWludHMuYXVkaW8gPT09ICdib29sZWFuJykgP1xuICAgICAgICBtZWRpYUNvbnN0cmFpbnRzLmF1ZGlvIDogdHJ1ZVxuICAgICAgb2ZmZXJWaWRlbyA9ICh0eXBlb2YgbWVkaWFDb25zdHJhaW50cy52aWRlbyA9PT0gJ2Jvb2xlYW4nKSA/XG4gICAgICAgIG1lZGlhQ29uc3RyYWludHMudmlkZW8gOiB0cnVlXG4gICAgfVxuXG4gICAgdmFyIGJyb3dzZXJEZXBlbmRhbnRDb25zdHJhaW50cyA9IHtcbiAgICAgIG9mZmVyVG9SZWNlaXZlQXVkaW86IChtb2RlICE9PSAnc2VuZG9ubHknICYmIG9mZmVyQXVkaW8pLFxuICAgICAgb2ZmZXJUb1JlY2VpdmVWaWRlbzogKG1vZGUgIT09ICdzZW5kb25seScgJiYgb2ZmZXJWaWRlbylcbiAgICB9XG5cbiAgICAvL0ZJWE1FOiBjbGFyaWZ5IHBvc3NpYmxlIGNvbnN0cmFpbnRzIHBhc3NlZCB0byBjcmVhdGVPZmZlcigpXG4gICAgLyp2YXIgY29uc3RyYWludHMgPSByZWN1cnNpdmUoYnJvd3NlckRlcGVuZGFudENvbnN0cmFpbnRzLFxuICAgICAgY29ubmVjdGlvbkNvbnN0cmFpbnRzKSovXG5cbiAgICB2YXIgY29uc3RyYWludHMgPSBicm93c2VyRGVwZW5kYW50Q29uc3RyYWludHM7XG5cbiAgICBsb2dnZXIuaW5mbygnY29uc3RyYWludHM6ICcgKyBKU09OLnN0cmluZ2lmeShjb25zdHJhaW50cykpXG5cbiAgICBwYy5jcmVhdGVPZmZlcihjb25zdHJhaW50cykudGhlbihmdW5jdGlvbiAob2ZmZXIpIHtcbiAgICAgIGxvZ2dlci5pbmZvKCdDcmVhdGVkIFNEUCBvZmZlcicpXG4gICAgICBvZmZlciA9IG1hbmdsZVNkcFRvQWRkU2ltdWxjYXN0KG9mZmVyKVxuICAgICAgcmV0dXJuIHBjLnNldExvY2FsRGVzY3JpcHRpb24ob2ZmZXIpXG4gICAgfSkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgbG9jYWxEZXNjcmlwdGlvbiA9IHBjLmxvY2FsRGVzY3JpcHRpb25cbiAgICAgIGxvZ2dlci5pbmZvKCdMb2NhbCBkZXNjcmlwdGlvbiBzZXQnLCBsb2NhbERlc2NyaXB0aW9uLnNkcClcbiAgICAgIGlmIChtdWx0aXN0cmVhbSAmJiB1c2VQbGFuQikge1xuICAgICAgICBsb2NhbERlc2NyaXB0aW9uID0gaW50ZXJvcC50b1VuaWZpZWRQbGFuKGxvY2FsRGVzY3JpcHRpb24pXG4gICAgICAgIGxvZ2dlci5pbmZvKCdvZmZlcjo6b3JpZ1BsYW5CLT5VbmlmaWVkUGxhbicsIGR1bXBTRFAoXG4gICAgICAgICAgbG9jYWxEZXNjcmlwdGlvbikpXG4gICAgICB9XG4gICAgICBjYWxsYmFjayhudWxsLCBsb2NhbERlc2NyaXB0aW9uLnNkcCwgc2VsZi5wcm9jZXNzQW5zd2VyLmJpbmQoXG4gICAgICAgIHNlbGYpKVxuICAgIH0pLmNhdGNoKGNhbGxiYWNrKVxuICB9XG5cbiAgdGhpcy5nZXRMb2NhbFNlc3Npb25EZXNjcmlwdG9yID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBwYy5sb2NhbERlc2NyaXB0aW9uXG4gIH1cblxuICB0aGlzLmdldFJlbW90ZVNlc3Npb25EZXNjcmlwdG9yID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBwYy5yZW1vdGVEZXNjcmlwdGlvblxuICB9XG5cbiAgZnVuY3Rpb24gc2V0UmVtb3RlVmlkZW8oKSB7XG4gICAgaWYgKHJlbW90ZVZpZGVvKSB7XG4gICAgICB2YXIgc3RyZWFtID0gcGMuZ2V0UmVtb3RlU3RyZWFtcygpWzBdXG4gICAgICB2YXIgdXJsID0gc3RyZWFtID8gVVJMLmNyZWF0ZU9iamVjdFVSTChzdHJlYW0pIDogJydcblxuICAgICAgcmVtb3RlVmlkZW8ucGF1c2UoKVxuICAgICAgcmVtb3RlVmlkZW8uc3JjID0gdXJsXG4gICAgICByZW1vdGVWaWRlby5sb2FkKClcblxuICAgICAgbG9nZ2VyLmluZm8oJ1JlbW90ZSBVUkw6JywgdXJsKVxuICAgIH1cbiAgfVxuXG4gIHRoaXMuc2hvd0xvY2FsVmlkZW8gPSBmdW5jdGlvbiAoKSB7XG4gICAgbG9jYWxWaWRlby5zcmMgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKHZpZGVvU3RyZWFtKVxuICAgIGxvY2FsVmlkZW8ubXV0ZWQgPSB0cnVlXG4gIH1cblxuICB0aGlzLnNlbmQgPSBmdW5jdGlvbiAoZGF0YSkge1xuICAgIGlmIChkYXRhQ2hhbm5lbCAmJiBkYXRhQ2hhbm5lbC5yZWFkeVN0YXRlID09PSAnb3BlbicpIHtcbiAgICAgIGRhdGFDaGFubmVsLnNlbmQoZGF0YSlcbiAgICB9IGVsc2Uge1xuICAgICAgbG9nZ2VyLndhcm4oXG4gICAgICAgICdUcnlpbmcgdG8gc2VuZCBkYXRhIG92ZXIgYSBub24tZXhpc3Rpbmcgb3IgY2xvc2VkIGRhdGEgY2hhbm5lbCcpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENhbGxiYWNrIGZ1bmN0aW9uIGludm9rZWQgd2hlbiBhIFNEUCBhbnN3ZXIgaXMgcmVjZWl2ZWQuIERldmVsb3BlcnMgYXJlXG4gICAqIGV4cGVjdGVkIHRvIGludm9rZSB0aGlzIGZ1bmN0aW9uIGluIG9yZGVyIHRvIGNvbXBsZXRlIHRoZSBTRFAgbmVnb3RpYXRpb24uXG4gICAqXG4gICAqIEBmdW5jdGlvbiBtb2R1bGU6a3VyZW50b1V0aWxzLldlYlJ0Y1BlZXIucHJvdG90eXBlLnByb2Nlc3NBbnN3ZXJcbiAgICpcbiAgICogQHBhcmFtIHNkcEFuc3dlciAtIERlc2NyaXB0aW9uIG9mIHNkcEFuc3dlclxuICAgKiBAcGFyYW0gY2FsbGJhY2sgLVxuICAgKiAgICAgICAgICAgIEludm9rZWQgYWZ0ZXIgdGhlIFNEUCBhbnN3ZXIgaXMgcHJvY2Vzc2VkLCBvciB0aGVyZSBpcyBhbiBlcnJvci5cbiAgICovXG4gIHRoaXMucHJvY2Vzc0Fuc3dlciA9IGZ1bmN0aW9uIChzZHBBbnN3ZXIsIGNhbGxiYWNrKSB7XG4gICAgY2FsbGJhY2sgPSAoY2FsbGJhY2sgfHwgbm9vcCkuYmluZCh0aGlzKVxuXG4gICAgdmFyIGFuc3dlciA9IG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgdHlwZTogJ2Fuc3dlcicsXG4gICAgICBzZHA6IHNkcEFuc3dlclxuICAgIH0pXG5cbiAgICBpZiAobXVsdGlzdHJlYW0gJiYgdXNlUGxhbkIpIHtcbiAgICAgIHZhciBwbGFuQkFuc3dlciA9IGludGVyb3AudG9QbGFuQihhbnN3ZXIpXG4gICAgICBsb2dnZXIuaW5mbygnYXNud2VyOjpwbGFuQicsIGR1bXBTRFAocGxhbkJBbnN3ZXIpKVxuICAgICAgYW5zd2VyID0gcGxhbkJBbnN3ZXJcbiAgICB9XG5cbiAgICBsb2dnZXIuaW5mbygnU0RQIGFuc3dlciByZWNlaXZlZCwgc2V0dGluZyByZW1vdGUgZGVzY3JpcHRpb24nKVxuXG4gICAgaWYgKHBjLnNpZ25hbGluZ1N0YXRlID09PSAnY2xvc2VkJykge1xuICAgICAgcmV0dXJuIGNhbGxiYWNrKCdQZWVyQ29ubmVjdGlvbiBpcyBjbG9zZWQnKVxuICAgIH1cblxuICAgIHBjLnNldFJlbW90ZURlc2NyaXB0aW9uKGFuc3dlciwgZnVuY3Rpb24gKCkge1xuICAgICAgICBzZXRSZW1vdGVWaWRlbygpXG5cbiAgICAgICAgY2FsbGJhY2soKVxuICAgICAgfSxcbiAgICAgIGNhbGxiYWNrKVxuICB9XG5cbiAgLyoqXG4gICAqIENhbGxiYWNrIGZ1bmN0aW9uIGludm9rZWQgd2hlbiBhIFNEUCBvZmZlciBpcyByZWNlaXZlZC4gRGV2ZWxvcGVycyBhcmVcbiAgICogZXhwZWN0ZWQgdG8gaW52b2tlIHRoaXMgZnVuY3Rpb24gaW4gb3JkZXIgdG8gY29tcGxldGUgdGhlIFNEUCBuZWdvdGlhdGlvbi5cbiAgICpcbiAgICogQGZ1bmN0aW9uIG1vZHVsZTprdXJlbnRvVXRpbHMuV2ViUnRjUGVlci5wcm90b3R5cGUucHJvY2Vzc09mZmVyXG4gICAqXG4gICAqIEBwYXJhbSBzZHBPZmZlciAtIERlc2NyaXB0aW9uIG9mIHNkcE9mZmVyXG4gICAqIEBwYXJhbSBjYWxsYmFjayAtIENhbGxlZCB3aGVuIHRoZSByZW1vdGUgZGVzY3JpcHRpb24gaGFzIGJlZW4gc2V0XG4gICAqICBzdWNjZXNzZnVsbHkuXG4gICAqL1xuICB0aGlzLnByb2Nlc3NPZmZlciA9IGZ1bmN0aW9uIChzZHBPZmZlciwgY2FsbGJhY2spIHtcbiAgICBjYWxsYmFjayA9IGNhbGxiYWNrLmJpbmQodGhpcylcblxuICAgIHZhciBvZmZlciA9IG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgdHlwZTogJ29mZmVyJyxcbiAgICAgIHNkcDogc2RwT2ZmZXJcbiAgICB9KVxuXG4gICAgaWYgKG11bHRpc3RyZWFtICYmIHVzZVBsYW5CKSB7XG4gICAgICB2YXIgcGxhbkJPZmZlciA9IGludGVyb3AudG9QbGFuQihvZmZlcilcbiAgICAgIGxvZ2dlci5pbmZvKCdvZmZlcjo6cGxhbkInLCBkdW1wU0RQKHBsYW5CT2ZmZXIpKVxuICAgICAgb2ZmZXIgPSBwbGFuQk9mZmVyXG4gICAgfVxuXG4gICAgbG9nZ2VyLmluZm8oJ1NEUCBvZmZlciByZWNlaXZlZCwgc2V0dGluZyByZW1vdGUgZGVzY3JpcHRpb24nKVxuXG4gICAgaWYgKHBjLnNpZ25hbGluZ1N0YXRlID09PSAnY2xvc2VkJykge1xuICAgICAgcmV0dXJuIGNhbGxiYWNrKCdQZWVyQ29ubmVjdGlvbiBpcyBjbG9zZWQnKVxuICAgIH1cblxuICAgIHBjLnNldFJlbW90ZURlc2NyaXB0aW9uKG9mZmVyKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBzZXRSZW1vdGVWaWRlbygpXG4gICAgfSkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gcGMuY3JlYXRlQW5zd2VyKClcbiAgICB9KS50aGVuKGZ1bmN0aW9uIChhbnN3ZXIpIHtcbiAgICAgIGFuc3dlciA9IG1hbmdsZVNkcFRvQWRkU2ltdWxjYXN0KGFuc3dlcilcbiAgICAgIGxvZ2dlci5pbmZvKCdDcmVhdGVkIFNEUCBhbnN3ZXInKVxuICAgICAgcmV0dXJuIHBjLnNldExvY2FsRGVzY3JpcHRpb24oYW5zd2VyKVxuICAgIH0pLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIGxvY2FsRGVzY3JpcHRpb24gPSBwYy5sb2NhbERlc2NyaXB0aW9uXG4gICAgICBpZiAobXVsdGlzdHJlYW0gJiYgdXNlUGxhbkIpIHtcbiAgICAgICAgbG9jYWxEZXNjcmlwdGlvbiA9IGludGVyb3AudG9VbmlmaWVkUGxhbihsb2NhbERlc2NyaXB0aW9uKVxuICAgICAgICBsb2dnZXIuaW5mbygnYW5zd2VyOjpvcmlnUGxhbkItPlVuaWZpZWRQbGFuJywgZHVtcFNEUChcbiAgICAgICAgICBsb2NhbERlc2NyaXB0aW9uKSlcbiAgICAgIH1cbiAgICAgIGxvZ2dlci5pbmZvKCdMb2NhbCBkZXNjcmlwdGlvbiBzZXQnLCBsb2NhbERlc2NyaXB0aW9uLnNkcClcbiAgICAgIGNhbGxiYWNrKG51bGwsIGxvY2FsRGVzY3JpcHRpb24uc2RwKVxuICAgIH0pLmNhdGNoKGNhbGxiYWNrKVxuICB9XG5cbiAgZnVuY3Rpb24gbWFuZ2xlU2RwVG9BZGRTaW11bGNhc3QoYW5zd2VyKSB7XG4gICAgaWYgKHNpbXVsY2FzdCkge1xuICAgICAgaWYgKGJyb3dzZXIubmFtZSA9PT0gJ0Nocm9tZScgfHwgYnJvd3Nlci5uYW1lID09PSAnQ2hyb21pdW0nKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKCdBZGRpbmcgbXVsdGljYXN0IGluZm8nKVxuICAgICAgICBhbnN3ZXIgPSBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgICAgICAndHlwZSc6IGFuc3dlci50eXBlLFxuICAgICAgICAgICdzZHAnOiByZW1vdmVGSURGcm9tT2ZmZXIoYW5zd2VyLnNkcCkgKyBnZXRTaW11bGNhc3RJbmZvKFxuICAgICAgICAgICAgdmlkZW9TdHJlYW0pXG4gICAgICAgIH0pXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsb2dnZXIud2FybignU2ltdWxjYXN0IGlzIG9ubHkgYXZhaWxhYmxlIGluIENocm9tZSBicm93c2VyLicpXG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGFuc3dlclxuICB9XG5cbiAgLyoqXG4gICAqIFRoaXMgZnVuY3Rpb24gY3JlYXRlcyB0aGUgUlRDUGVlckNvbm5lY3Rpb24gb2JqZWN0IHRha2luZyBpbnRvIGFjY291bnQgdGhlXG4gICAqIHByb3BlcnRpZXMgcmVjZWl2ZWQgaW4gdGhlIGNvbnN0cnVjdG9yLiBJdCBzdGFydHMgdGhlIFNEUCBuZWdvdGlhdGlvblxuICAgKiBwcm9jZXNzOiBnZW5lcmF0ZXMgdGhlIFNEUCBvZmZlciBhbmQgaW52b2tlcyB0aGUgb25zZHBvZmZlciBjYWxsYmFjay4gVGhpc1xuICAgKiBjYWxsYmFjayBpcyBleHBlY3RlZCB0byBzZW5kIHRoZSBTRFAgb2ZmZXIsIGluIG9yZGVyIHRvIG9idGFpbiBhbiBTRFBcbiAgICogYW5zd2VyIGZyb20gYW5vdGhlciBwZWVyLlxuICAgKi9cbiAgZnVuY3Rpb24gc3RhcnQoKSB7XG4gICAgaWYgKHBjLnNpZ25hbGluZ1N0YXRlID09PSAnY2xvc2VkJykge1xuICAgICAgY2FsbGJhY2soXG4gICAgICAgICdUaGUgcGVlciBjb25uZWN0aW9uIG9iamVjdCBpcyBpbiBcImNsb3NlZFwiIHN0YXRlLiBUaGlzIGlzIG1vc3QgbGlrZWx5IGR1ZSB0byBhbiBpbnZvY2F0aW9uIG9mIHRoZSBkaXNwb3NlIG1ldGhvZCBiZWZvcmUgYWNjZXB0aW5nIGluIHRoZSBkaWFsb2d1ZSdcbiAgICAgIClcbiAgICB9XG5cbiAgICBpZiAodmlkZW9TdHJlYW0gJiYgbG9jYWxWaWRlbykge1xuICAgICAgc2VsZi5zaG93TG9jYWxWaWRlbygpXG4gICAgfVxuXG4gICAgaWYgKHZpZGVvU3RyZWFtKSB7XG4gICAgICBwYy5hZGRTdHJlYW0odmlkZW9TdHJlYW0pXG4gICAgfVxuXG4gICAgaWYgKGF1ZGlvU3RyZWFtKSB7XG4gICAgICBwYy5hZGRTdHJlYW0oYXVkaW9TdHJlYW0pXG4gICAgfVxuXG4gICAgLy8gW0hhY2tdIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD00NDM1NThcbiAgICB2YXIgYnJvd3NlciA9IHBhcnNlci5nZXRCcm93c2VyKClcbiAgICBpZiAobW9kZSA9PT0gJ3NlbmRvbmx5JyAmJlxuICAgICAgKGJyb3dzZXIubmFtZSA9PT0gJ0Nocm9tZScgfHwgYnJvd3Nlci5uYW1lID09PSAnQ2hyb21pdW0nKSAmJlxuICAgICAgYnJvd3Nlci5tYWpvciA9PT0gMzkpIHtcbiAgICAgIG1vZGUgPSAnc2VuZHJlY3YnXG4gICAgfVxuXG4gICAgY2FsbGJhY2soKVxuICB9XG5cbiAgaWYgKG1vZGUgIT09ICdyZWN2b25seScgJiYgIXZpZGVvU3RyZWFtICYmICFhdWRpb1N0cmVhbSkge1xuICAgIGZ1bmN0aW9uIGdldE1lZGlhKGNvbnN0cmFpbnRzKSB7XG4gICAgICBpZiAoY29uc3RyYWludHMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb25zdHJhaW50cyA9IE1FRElBX0NPTlNUUkFJTlRTXG4gICAgICB9XG5cbiAgICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKGNvbnN0cmFpbnRzKS50aGVuKGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgdmlkZW9TdHJlYW0gPSBzdHJlYW1cbiAgICAgICAgc3RhcnQoKVxuICAgICAgfSkuY2F0Y2goY2FsbGJhY2spO1xuICAgIH1cbiAgICBpZiAoc2VuZFNvdXJjZSA9PT0gJ3dlYmNhbScpIHtcbiAgICAgIGdldE1lZGlhKG1lZGlhQ29uc3RyYWludHMpXG4gICAgfSBlbHNlIHtcbiAgICAgIGdldFNjcmVlbkNvbnN0cmFpbnRzKHNlbmRTb3VyY2UsIGZ1bmN0aW9uIChlcnJvciwgY29uc3RyYWludHNfKSB7XG4gICAgICAgIGlmIChlcnJvcilcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyb3IpXG5cbiAgICAgICAgY29uc3RyYWludHMgPSBbbWVkaWFDb25zdHJhaW50c11cbiAgICAgICAgY29uc3RyYWludHMudW5zaGlmdChjb25zdHJhaW50c18pXG4gICAgICAgIGdldE1lZGlhKHJlY3Vyc2l2ZS5hcHBseSh1bmRlZmluZWQsIGNvbnN0cmFpbnRzKSlcbiAgICAgIH0sIGd1aWQpXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHNldFRpbWVvdXQoc3RhcnQsIDApXG4gIH1cblxuICB0aGlzLm9uKCdfZGlzcG9zZScsIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAobG9jYWxWaWRlbykge1xuICAgICAgbG9jYWxWaWRlby5wYXVzZSgpXG4gICAgICBsb2NhbFZpZGVvLnNyYyA9ICcnXG4gICAgICBsb2NhbFZpZGVvLmxvYWQoKVxuICAgICAgLy9Vbm11dGUgbG9jYWwgdmlkZW8gaW4gY2FzZSB0aGUgdmlkZW8gdGFnIGlzIGxhdGVyIHVzZWQgZm9yIHJlbW90ZSB2aWRlb1xuICAgICAgbG9jYWxWaWRlby5tdXRlZCA9IGZhbHNlXG4gICAgfVxuICAgIGlmIChyZW1vdGVWaWRlbykge1xuICAgICAgcmVtb3RlVmlkZW8ucGF1c2UoKVxuICAgICAgcmVtb3RlVmlkZW8uc3JjID0gJydcbiAgICAgIHJlbW90ZVZpZGVvLmxvYWQoKVxuICAgIH1cbiAgICBzZWxmLnJlbW92ZUFsbExpc3RlbmVycygpXG5cbiAgICBpZiAod2luZG93LmNhbmNlbENob29zZURlc2t0b3BNZWRpYSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB3aW5kb3cuY2FuY2VsQ2hvb3NlRGVza3RvcE1lZGlhKGd1aWQpXG4gICAgfVxuICB9KVxufVxuaW5oZXJpdHMoV2ViUnRjUGVlciwgRXZlbnRFbWl0dGVyKVxuXG5mdW5jdGlvbiBjcmVhdGVFbmFibGVEZXNjcmlwdG9yKHR5cGUpIHtcbiAgdmFyIG1ldGhvZCA9ICdnZXQnICsgdHlwZSArICdUcmFja3MnXG5cbiAgcmV0dXJuIHtcbiAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgLy8gW1RvRG9dIFNob3VsZCByZXR1cm4gdW5kZWZpbmVkIGlmIG5vdCBhbGwgdHJhY2tzIGhhdmUgdGhlIHNhbWUgdmFsdWU/XG5cbiAgICAgIGlmICghdGhpcy5wZWVyQ29ubmVjdGlvbikgcmV0dXJuXG5cbiAgICAgIHZhciBzdHJlYW1zID0gdGhpcy5wZWVyQ29ubmVjdGlvbi5nZXRMb2NhbFN0cmVhbXMoKVxuICAgICAgaWYgKCFzdHJlYW1zLmxlbmd0aCkgcmV0dXJuXG5cbiAgICAgIGZvciAodmFyIGkgPSAwLCBzdHJlYW07IHN0cmVhbSA9IHN0cmVhbXNbaV07IGkrKykge1xuICAgICAgICB2YXIgdHJhY2tzID0gc3RyZWFtW21ldGhvZF0oKVxuICAgICAgICBmb3IgKHZhciBqID0gMCwgdHJhY2s7IHRyYWNrID0gdHJhY2tzW2pdOyBqKyspXG4gICAgICAgICAgaWYgKCF0cmFjay5lbmFibGVkKSByZXR1cm4gZmFsc2VcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRydWVcbiAgICB9LFxuICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICBmdW5jdGlvbiB0cmFja1NldEVuYWJsZSh0cmFjaykge1xuICAgICAgICB0cmFjay5lbmFibGVkID0gdmFsdWVcbiAgICAgIH1cblxuICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbi5nZXRMb2NhbFN0cmVhbXMoKS5mb3JFYWNoKGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgc3RyZWFtW21ldGhvZF0oKS5mb3JFYWNoKHRyYWNrU2V0RW5hYmxlKVxuICAgICAgfSlcbiAgICB9XG4gIH1cbn1cblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoV2ViUnRjUGVlci5wcm90b3R5cGUsIHtcbiAgJ2VuYWJsZWQnOiB7XG4gICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiB0aGlzLmF1ZGlvRW5hYmxlZCAmJiB0aGlzLnZpZGVvRW5hYmxlZFxuICAgIH0sXG4gICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgIHRoaXMuYXVkaW9FbmFibGVkID0gdGhpcy52aWRlb0VuYWJsZWQgPSB2YWx1ZVxuICAgIH1cbiAgfSxcbiAgJ2F1ZGlvRW5hYmxlZCc6IGNyZWF0ZUVuYWJsZURlc2NyaXB0b3IoJ0F1ZGlvJyksXG4gICd2aWRlb0VuYWJsZWQnOiBjcmVhdGVFbmFibGVEZXNjcmlwdG9yKCdWaWRlbycpXG59KVxuXG5XZWJSdGNQZWVyLnByb3RvdHlwZS5nZXRMb2NhbFN0cmVhbSA9IGZ1bmN0aW9uIChpbmRleCkge1xuICBpZiAodGhpcy5wZWVyQ29ubmVjdGlvbikge1xuICAgIHJldHVybiB0aGlzLnBlZXJDb25uZWN0aW9uLmdldExvY2FsU3RyZWFtcygpW2luZGV4IHx8IDBdXG4gIH1cbn1cblxuV2ViUnRjUGVlci5wcm90b3R5cGUuZ2V0UmVtb3RlU3RyZWFtID0gZnVuY3Rpb24gKGluZGV4KSB7XG4gIGlmICh0aGlzLnBlZXJDb25uZWN0aW9uKSB7XG4gICAgcmV0dXJuIHRoaXMucGVlckNvbm5lY3Rpb24uZ2V0UmVtb3RlU3RyZWFtcygpW2luZGV4IHx8IDBdXG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gVGhpcyBtZXRob2QgZnJlZXMgdGhlIHJlc291cmNlcyB1c2VkIGJ5IFdlYlJ0Y1BlZXIuXG4gKlxuICogQGZ1bmN0aW9uIG1vZHVsZTprdXJlbnRvVXRpbHMuV2ViUnRjUGVlci5wcm90b3R5cGUuZGlzcG9zZVxuICovXG5XZWJSdGNQZWVyLnByb3RvdHlwZS5kaXNwb3NlID0gZnVuY3Rpb24gKCkge1xuICBsb2dnZXIuaW5mbygnRGlzcG9zaW5nIFdlYlJ0Y1BlZXInKVxuXG4gIHZhciBwYyA9IHRoaXMucGVlckNvbm5lY3Rpb25cbiAgdmFyIGRjID0gdGhpcy5kYXRhQ2hhbm5lbFxuICB0cnkge1xuICAgIGlmIChkYykge1xuICAgICAgaWYgKGRjLnNpZ25hbGluZ1N0YXRlID09PSAnY2xvc2VkJykgcmV0dXJuXG5cbiAgICAgIGRjLmNsb3NlKClcbiAgICB9XG5cbiAgICBpZiAocGMpIHtcbiAgICAgIGlmIChwYy5zaWduYWxpbmdTdGF0ZSA9PT0gJ2Nsb3NlZCcpIHJldHVyblxuXG4gICAgICBwYy5nZXRMb2NhbFN0cmVhbXMoKS5mb3JFYWNoKHN0cmVhbVN0b3ApXG5cbiAgICAgIC8vIEZJWE1FIFRoaXMgaXMgbm90IHlldCBpbXBsZW1lbnRlZCBpbiBmaXJlZm94XG4gICAgICAvLyBpZih2aWRlb1N0cmVhbSkgcGMucmVtb3ZlU3RyZWFtKHZpZGVvU3RyZWFtKTtcbiAgICAgIC8vIGlmKGF1ZGlvU3RyZWFtKSBwYy5yZW1vdmVTdHJlYW0oYXVkaW9TdHJlYW0pO1xuXG4gICAgICBwYy5jbG9zZSgpXG4gICAgfVxuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2dnZXIud2FybignRXhjZXB0aW9uIGRpc3Bvc2luZyB3ZWJydGMgcGVlciAnICsgZXJyKVxuICB9XG5cbiAgdGhpcy5lbWl0KCdfZGlzcG9zZScpXG59XG5cbi8vXG4vLyBTcGVjaWFsaXplZCBjaGlsZCBjbGFzc2VzXG4vL1xuXG5mdW5jdGlvbiBXZWJSdGNQZWVyUmVjdm9ubHkob3B0aW9ucywgY2FsbGJhY2spIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFdlYlJ0Y1BlZXJSZWN2b25seSkpIHtcbiAgICByZXR1cm4gbmV3IFdlYlJ0Y1BlZXJSZWN2b25seShvcHRpb25zLCBjYWxsYmFjaylcbiAgfVxuXG4gIFdlYlJ0Y1BlZXJSZWN2b25seS5zdXBlcl8uY2FsbCh0aGlzLCAncmVjdm9ubHknLCBvcHRpb25zLCBjYWxsYmFjaylcbn1cbmluaGVyaXRzKFdlYlJ0Y1BlZXJSZWN2b25seSwgV2ViUnRjUGVlcilcblxuZnVuY3Rpb24gV2ViUnRjUGVlclNlbmRvbmx5KG9wdGlvbnMsIGNhbGxiYWNrKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBXZWJSdGNQZWVyU2VuZG9ubHkpKSB7XG4gICAgcmV0dXJuIG5ldyBXZWJSdGNQZWVyU2VuZG9ubHkob3B0aW9ucywgY2FsbGJhY2spXG4gIH1cblxuICBXZWJSdGNQZWVyU2VuZG9ubHkuc3VwZXJfLmNhbGwodGhpcywgJ3NlbmRvbmx5Jywgb3B0aW9ucywgY2FsbGJhY2spXG59XG5pbmhlcml0cyhXZWJSdGNQZWVyU2VuZG9ubHksIFdlYlJ0Y1BlZXIpXG5cbmZ1bmN0aW9uIFdlYlJ0Y1BlZXJTZW5kcmVjdihvcHRpb25zLCBjYWxsYmFjaykge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgV2ViUnRjUGVlclNlbmRyZWN2KSkge1xuICAgIHJldHVybiBuZXcgV2ViUnRjUGVlclNlbmRyZWN2KG9wdGlvbnMsIGNhbGxiYWNrKVxuICB9XG5cbiAgV2ViUnRjUGVlclNlbmRyZWN2LnN1cGVyXy5jYWxsKHRoaXMsICdzZW5kcmVjdicsIG9wdGlvbnMsIGNhbGxiYWNrKVxufVxuaW5oZXJpdHMoV2ViUnRjUGVlclNlbmRyZWN2LCBXZWJSdGNQZWVyKVxuXG5mdW5jdGlvbiBoYXJrVXRpbHMoc3RyZWFtLCBvcHRpb25zKSB7XG4gIHJldHVybiBoYXJrKHN0cmVhbSwgb3B0aW9ucyk7XG59XG5cbmV4cG9ydHMuYnVmZmVyaXplQ2FuZGlkYXRlcyA9IGJ1ZmZlcml6ZUNhbmRpZGF0ZXNcblxuZXhwb3J0cy5XZWJSdGNQZWVyUmVjdm9ubHkgPSBXZWJSdGNQZWVyUmVjdm9ubHlcbmV4cG9ydHMuV2ViUnRjUGVlclNlbmRvbmx5ID0gV2ViUnRjUGVlclNlbmRvbmx5XG5leHBvcnRzLldlYlJ0Y1BlZXJTZW5kcmVjdiA9IFdlYlJ0Y1BlZXJTZW5kcmVjdlxuZXhwb3J0cy5oYXJrID0gaGFya1V0aWxzXG4iLCIvKlxuICogKEMpIENvcHlyaWdodCAyMDE0IEt1cmVudG8gKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKi9cblxuLyoqXG4gKiBUaGlzIG1vZHVsZSBjb250YWlucyBhIHNldCBvZiByZXVzYWJsZSBjb21wb25lbnRzIHRoYXQgaGF2ZSBiZWVuIGZvdW5kIHVzZWZ1bFxuICogZHVyaW5nIHRoZSBkZXZlbG9wbWVudCBvZiB0aGUgV2ViUlRDIGFwcGxpY2F0aW9ucyB3aXRoIEt1cmVudG8uXG4gKiBcbiAqIEBtb2R1bGUga3VyZW50b1V0aWxzXG4gKiBcbiAqIEBjb3B5cmlnaHQgMjAxNCBLdXJlbnRvIChodHRwOi8va3VyZW50by5vcmcvKVxuICogQGxpY2Vuc2UgQUx2MlxuICovXG5cbnZhciBXZWJSdGNQZWVyID0gcmVxdWlyZSgnLi9XZWJSdGNQZWVyJyk7XG5cbmV4cG9ydHMuV2ViUnRjUGVlciA9IFdlYlJ0Y1BlZXI7XG4iLCIvKiFcclxuICogQG5hbWUgSmF2YVNjcmlwdC9Ob2RlSlMgTWVyZ2UgdjEuMi4wXHJcbiAqIEBhdXRob3IgeWVpa29zXHJcbiAqIEByZXBvc2l0b3J5IGh0dHBzOi8vZ2l0aHViLmNvbS95ZWlrb3MvanMubWVyZ2VcclxuXHJcbiAqIENvcHlyaWdodCAyMDE0IHllaWtvcyAtIE1JVCBsaWNlbnNlXHJcbiAqIGh0dHBzOi8vcmF3LmdpdGh1Yi5jb20veWVpa29zL2pzLm1lcmdlL21hc3Rlci9MSUNFTlNFXHJcbiAqL1xyXG5cclxuOyhmdW5jdGlvbihpc05vZGUpIHtcclxuXHJcblx0LyoqXHJcblx0ICogTWVyZ2Ugb25lIG9yIG1vcmUgb2JqZWN0cyBcclxuXHQgKiBAcGFyYW0gYm9vbD8gY2xvbmVcclxuXHQgKiBAcGFyYW0gbWl4ZWQsLi4uIGFyZ3VtZW50c1xyXG5cdCAqIEByZXR1cm4gb2JqZWN0XHJcblx0ICovXHJcblxyXG5cdHZhciBQdWJsaWMgPSBmdW5jdGlvbihjbG9uZSkge1xyXG5cclxuXHRcdHJldHVybiBtZXJnZShjbG9uZSA9PT0gdHJ1ZSwgZmFsc2UsIGFyZ3VtZW50cyk7XHJcblxyXG5cdH0sIHB1YmxpY05hbWUgPSAnbWVyZ2UnO1xyXG5cclxuXHQvKipcclxuXHQgKiBNZXJnZSB0d28gb3IgbW9yZSBvYmplY3RzIHJlY3Vyc2l2ZWx5IFxyXG5cdCAqIEBwYXJhbSBib29sPyBjbG9uZVxyXG5cdCAqIEBwYXJhbSBtaXhlZCwuLi4gYXJndW1lbnRzXHJcblx0ICogQHJldHVybiBvYmplY3RcclxuXHQgKi9cclxuXHJcblx0UHVibGljLnJlY3Vyc2l2ZSA9IGZ1bmN0aW9uKGNsb25lKSB7XHJcblxyXG5cdFx0cmV0dXJuIG1lcmdlKGNsb25lID09PSB0cnVlLCB0cnVlLCBhcmd1bWVudHMpO1xyXG5cclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBDbG9uZSB0aGUgaW5wdXQgcmVtb3ZpbmcgYW55IHJlZmVyZW5jZVxyXG5cdCAqIEBwYXJhbSBtaXhlZCBpbnB1dFxyXG5cdCAqIEByZXR1cm4gbWl4ZWRcclxuXHQgKi9cclxuXHJcblx0UHVibGljLmNsb25lID0gZnVuY3Rpb24oaW5wdXQpIHtcclxuXHJcblx0XHR2YXIgb3V0cHV0ID0gaW5wdXQsXHJcblx0XHRcdHR5cGUgPSB0eXBlT2YoaW5wdXQpLFxyXG5cdFx0XHRpbmRleCwgc2l6ZTtcclxuXHJcblx0XHRpZiAodHlwZSA9PT0gJ2FycmF5Jykge1xyXG5cclxuXHRcdFx0b3V0cHV0ID0gW107XHJcblx0XHRcdHNpemUgPSBpbnB1dC5sZW5ndGg7XHJcblxyXG5cdFx0XHRmb3IgKGluZGV4PTA7aW5kZXg8c2l6ZTsrK2luZGV4KVxyXG5cclxuXHRcdFx0XHRvdXRwdXRbaW5kZXhdID0gUHVibGljLmNsb25lKGlucHV0W2luZGV4XSk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICh0eXBlID09PSAnb2JqZWN0Jykge1xyXG5cclxuXHRcdFx0b3V0cHV0ID0ge307XHJcblxyXG5cdFx0XHRmb3IgKGluZGV4IGluIGlucHV0KVxyXG5cclxuXHRcdFx0XHRvdXRwdXRbaW5kZXhdID0gUHVibGljLmNsb25lKGlucHV0W2luZGV4XSk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBvdXRwdXQ7XHJcblxyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIE1lcmdlIHR3byBvYmplY3RzIHJlY3Vyc2l2ZWx5XHJcblx0ICogQHBhcmFtIG1peGVkIGlucHV0XHJcblx0ICogQHBhcmFtIG1peGVkIGV4dGVuZFxyXG5cdCAqIEByZXR1cm4gbWl4ZWRcclxuXHQgKi9cclxuXHJcblx0ZnVuY3Rpb24gbWVyZ2VfcmVjdXJzaXZlKGJhc2UsIGV4dGVuZCkge1xyXG5cclxuXHRcdGlmICh0eXBlT2YoYmFzZSkgIT09ICdvYmplY3QnKVxyXG5cclxuXHRcdFx0cmV0dXJuIGV4dGVuZDtcclxuXHJcblx0XHRmb3IgKHZhciBrZXkgaW4gZXh0ZW5kKSB7XHJcblxyXG5cdFx0XHRpZiAodHlwZU9mKGJhc2Vba2V5XSkgPT09ICdvYmplY3QnICYmIHR5cGVPZihleHRlbmRba2V5XSkgPT09ICdvYmplY3QnKSB7XHJcblxyXG5cdFx0XHRcdGJhc2Vba2V5XSA9IG1lcmdlX3JlY3Vyc2l2ZShiYXNlW2tleV0sIGV4dGVuZFtrZXldKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGJhc2Vba2V5XSA9IGV4dGVuZFtrZXldO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gYmFzZTtcclxuXHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBNZXJnZSB0d28gb3IgbW9yZSBvYmplY3RzXHJcblx0ICogQHBhcmFtIGJvb2wgY2xvbmVcclxuXHQgKiBAcGFyYW0gYm9vbCByZWN1cnNpdmVcclxuXHQgKiBAcGFyYW0gYXJyYXkgYXJndlxyXG5cdCAqIEByZXR1cm4gb2JqZWN0XHJcblx0ICovXHJcblxyXG5cdGZ1bmN0aW9uIG1lcmdlKGNsb25lLCByZWN1cnNpdmUsIGFyZ3YpIHtcclxuXHJcblx0XHR2YXIgcmVzdWx0ID0gYXJndlswXSxcclxuXHRcdFx0c2l6ZSA9IGFyZ3YubGVuZ3RoO1xyXG5cclxuXHRcdGlmIChjbG9uZSB8fCB0eXBlT2YocmVzdWx0KSAhPT0gJ29iamVjdCcpXHJcblxyXG5cdFx0XHRyZXN1bHQgPSB7fTtcclxuXHJcblx0XHRmb3IgKHZhciBpbmRleD0wO2luZGV4PHNpemU7KytpbmRleCkge1xyXG5cclxuXHRcdFx0dmFyIGl0ZW0gPSBhcmd2W2luZGV4XSxcclxuXHJcblx0XHRcdFx0dHlwZSA9IHR5cGVPZihpdGVtKTtcclxuXHJcblx0XHRcdGlmICh0eXBlICE9PSAnb2JqZWN0JykgY29udGludWU7XHJcblxyXG5cdFx0XHRmb3IgKHZhciBrZXkgaW4gaXRlbSkge1xyXG5cclxuXHRcdFx0XHR2YXIgc2l0ZW0gPSBjbG9uZSA/IFB1YmxpYy5jbG9uZShpdGVtW2tleV0pIDogaXRlbVtrZXldO1xyXG5cclxuXHRcdFx0XHRpZiAocmVjdXJzaXZlKSB7XHJcblxyXG5cdFx0XHRcdFx0cmVzdWx0W2tleV0gPSBtZXJnZV9yZWN1cnNpdmUocmVzdWx0W2tleV0sIHNpdGVtKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRyZXN1bHRba2V5XSA9IHNpdGVtO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiByZXN1bHQ7XHJcblxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogR2V0IHR5cGUgb2YgdmFyaWFibGVcclxuXHQgKiBAcGFyYW0gbWl4ZWQgaW5wdXRcclxuXHQgKiBAcmV0dXJuIHN0cmluZ1xyXG5cdCAqXHJcblx0ICogQHNlZSBodHRwOi8vanNwZXJmLmNvbS90eXBlb2Z2YXJcclxuXHQgKi9cclxuXHJcblx0ZnVuY3Rpb24gdHlwZU9mKGlucHV0KSB7XHJcblxyXG5cdFx0cmV0dXJuICh7fSkudG9TdHJpbmcuY2FsbChpbnB1dCkuc2xpY2UoOCwgLTEpLnRvTG93ZXJDYXNlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0aWYgKGlzTm9kZSkge1xyXG5cclxuXHRcdG1vZHVsZS5leHBvcnRzID0gUHVibGljO1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdHdpbmRvd1twdWJsaWNOYW1lXSA9IFB1YmxpYztcclxuXHJcblx0fVxyXG5cclxufSkodHlwZW9mIG1vZHVsZSA9PT0gJ29iamVjdCcgJiYgbW9kdWxlICYmIHR5cGVvZiBtb2R1bGUuZXhwb3J0cyA9PT0gJ29iamVjdCcgJiYgbW9kdWxlLmV4cG9ydHMpOyIsIi8qKlxuICogSGVscGVycy5cbiAqL1xuXG52YXIgcyA9IDEwMDA7XG52YXIgbSA9IHMgKiA2MDtcbnZhciBoID0gbSAqIDYwO1xudmFyIGQgPSBoICogMjQ7XG52YXIgeSA9IGQgKiAzNjUuMjU7XG5cbi8qKlxuICogUGFyc2Ugb3IgZm9ybWF0IHRoZSBnaXZlbiBgdmFsYC5cbiAqXG4gKiBPcHRpb25zOlxuICpcbiAqICAtIGBsb25nYCB2ZXJib3NlIGZvcm1hdHRpbmcgW2ZhbHNlXVxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfE51bWJlcn0gdmFsXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnNdXG4gKiBAdGhyb3dzIHtFcnJvcn0gdGhyb3cgYW4gZXJyb3IgaWYgdmFsIGlzIG5vdCBhIG5vbi1lbXB0eSBzdHJpbmcgb3IgYSBudW1iZXJcbiAqIEByZXR1cm4ge1N0cmluZ3xOdW1iZXJ9XG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24odmFsLCBvcHRpb25zKSB7XG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICB2YXIgdHlwZSA9IHR5cGVvZiB2YWw7XG4gIGlmICh0eXBlID09PSAnc3RyaW5nJyAmJiB2YWwubGVuZ3RoID4gMCkge1xuICAgIHJldHVybiBwYXJzZSh2YWwpO1xuICB9IGVsc2UgaWYgKHR5cGUgPT09ICdudW1iZXInICYmIGlzTmFOKHZhbCkgPT09IGZhbHNlKSB7XG4gICAgcmV0dXJuIG9wdGlvbnMubG9uZyA/IGZtdExvbmcodmFsKSA6IGZtdFNob3J0KHZhbCk7XG4gIH1cbiAgdGhyb3cgbmV3IEVycm9yKFxuICAgICd2YWwgaXMgbm90IGEgbm9uLWVtcHR5IHN0cmluZyBvciBhIHZhbGlkIG51bWJlci4gdmFsPScgK1xuICAgICAgSlNPTi5zdHJpbmdpZnkodmFsKVxuICApO1xufTtcblxuLyoqXG4gKiBQYXJzZSB0aGUgZ2l2ZW4gYHN0cmAgYW5kIHJldHVybiBtaWxsaXNlY29uZHMuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHN0clxuICogQHJldHVybiB7TnVtYmVyfVxuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gcGFyc2Uoc3RyKSB7XG4gIHN0ciA9IFN0cmluZyhzdHIpO1xuICBpZiAoc3RyLmxlbmd0aCA+IDEwMCkge1xuICAgIHJldHVybjtcbiAgfVxuICB2YXIgbWF0Y2ggPSAvXigoPzpcXGQrKT9cXC4/XFxkKykgKihtaWxsaXNlY29uZHM/fG1zZWNzP3xtc3xzZWNvbmRzP3xzZWNzP3xzfG1pbnV0ZXM/fG1pbnM/fG18aG91cnM/fGhycz98aHxkYXlzP3xkfHllYXJzP3x5cnM/fHkpPyQvaS5leGVjKFxuICAgIHN0clxuICApO1xuICBpZiAoIW1hdGNoKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBuID0gcGFyc2VGbG9hdChtYXRjaFsxXSk7XG4gIHZhciB0eXBlID0gKG1hdGNoWzJdIHx8ICdtcycpLnRvTG93ZXJDYXNlKCk7XG4gIHN3aXRjaCAodHlwZSkge1xuICAgIGNhc2UgJ3llYXJzJzpcbiAgICBjYXNlICd5ZWFyJzpcbiAgICBjYXNlICd5cnMnOlxuICAgIGNhc2UgJ3lyJzpcbiAgICBjYXNlICd5JzpcbiAgICAgIHJldHVybiBuICogeTtcbiAgICBjYXNlICdkYXlzJzpcbiAgICBjYXNlICdkYXknOlxuICAgIGNhc2UgJ2QnOlxuICAgICAgcmV0dXJuIG4gKiBkO1xuICAgIGNhc2UgJ2hvdXJzJzpcbiAgICBjYXNlICdob3VyJzpcbiAgICBjYXNlICdocnMnOlxuICAgIGNhc2UgJ2hyJzpcbiAgICBjYXNlICdoJzpcbiAgICAgIHJldHVybiBuICogaDtcbiAgICBjYXNlICdtaW51dGVzJzpcbiAgICBjYXNlICdtaW51dGUnOlxuICAgIGNhc2UgJ21pbnMnOlxuICAgIGNhc2UgJ21pbic6XG4gICAgY2FzZSAnbSc6XG4gICAgICByZXR1cm4gbiAqIG07XG4gICAgY2FzZSAnc2Vjb25kcyc6XG4gICAgY2FzZSAnc2Vjb25kJzpcbiAgICBjYXNlICdzZWNzJzpcbiAgICBjYXNlICdzZWMnOlxuICAgIGNhc2UgJ3MnOlxuICAgICAgcmV0dXJuIG4gKiBzO1xuICAgIGNhc2UgJ21pbGxpc2Vjb25kcyc6XG4gICAgY2FzZSAnbWlsbGlzZWNvbmQnOlxuICAgIGNhc2UgJ21zZWNzJzpcbiAgICBjYXNlICdtc2VjJzpcbiAgICBjYXNlICdtcyc6XG4gICAgICByZXR1cm4gbjtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIFNob3J0IGZvcm1hdCBmb3IgYG1zYC5cbiAqXG4gKiBAcGFyYW0ge051bWJlcn0gbXNcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIGZtdFNob3J0KG1zKSB7XG4gIGlmIChtcyA+PSBkKSB7XG4gICAgcmV0dXJuIE1hdGgucm91bmQobXMgLyBkKSArICdkJztcbiAgfVxuICBpZiAobXMgPj0gaCkge1xuICAgIHJldHVybiBNYXRoLnJvdW5kKG1zIC8gaCkgKyAnaCc7XG4gIH1cbiAgaWYgKG1zID49IG0pIHtcbiAgICByZXR1cm4gTWF0aC5yb3VuZChtcyAvIG0pICsgJ20nO1xuICB9XG4gIGlmIChtcyA+PSBzKSB7XG4gICAgcmV0dXJuIE1hdGgucm91bmQobXMgLyBzKSArICdzJztcbiAgfVxuICByZXR1cm4gbXMgKyAnbXMnO1xufVxuXG4vKipcbiAqIExvbmcgZm9ybWF0IGZvciBgbXNgLlxuICpcbiAqIEBwYXJhbSB7TnVtYmVyfSBtc1xuICogQHJldHVybiB7U3RyaW5nfVxuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gZm10TG9uZyhtcykge1xuICByZXR1cm4gcGx1cmFsKG1zLCBkLCAnZGF5JykgfHxcbiAgICBwbHVyYWwobXMsIGgsICdob3VyJykgfHxcbiAgICBwbHVyYWwobXMsIG0sICdtaW51dGUnKSB8fFxuICAgIHBsdXJhbChtcywgcywgJ3NlY29uZCcpIHx8XG4gICAgbXMgKyAnIG1zJztcbn1cblxuLyoqXG4gKiBQbHVyYWxpemF0aW9uIGhlbHBlci5cbiAqL1xuXG5mdW5jdGlvbiBwbHVyYWwobXMsIG4sIG5hbWUpIHtcbiAgaWYgKG1zIDwgbikge1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAobXMgPCBuICogMS41KSB7XG4gICAgcmV0dXJuIE1hdGguZmxvb3IobXMgLyBuKSArICcgJyArIG5hbWU7XG4gIH1cbiAgcmV0dXJuIE1hdGguY2VpbChtcyAvIG4pICsgJyAnICsgbmFtZSArICdzJztcbn1cbiIsIi8qKlxuICAjIG5vcm1hbGljZVxuXG4gIE5vcm1hbGl6ZSBhbiBpY2Ugc2VydmVyIGNvbmZpZ3VyYXRpb24gb2JqZWN0IChvciBwbGFpbiBvbGQgc3RyaW5nKSBpbnRvIGEgZm9ybWF0XG4gIHRoYXQgaXMgdXNhYmxlIGluIGFsbCBicm93c2VycyBzdXBwb3J0aW5nIFdlYlJUQy4gIFByaW1hcmlseSB0aGlzIG1vZHVsZSBpcyBkZXNpZ25lZFxuICB0byBoZWxwIHdpdGggdGhlIHRyYW5zaXRpb24gb2YgdGhlIGB1cmxgIGF0dHJpYnV0ZSBvZiB0aGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG9cbiAgdGhlIGB1cmxzYCBhdHRyaWJ1dGUuXG5cbiAgIyMgRXhhbXBsZSBVc2FnZVxuXG4gIDw8PCBleGFtcGxlcy9zaW1wbGUuanNcblxuKiovXG5cbnZhciBwcm90b2NvbHMgPSBbXG4gICdzdHVuOicsXG4gICd0dXJuOidcbl07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oaW5wdXQpIHtcbiAgdmFyIHVybCA9IChpbnB1dCB8fCB7fSkudXJsIHx8IGlucHV0O1xuICB2YXIgcHJvdG9jb2w7XG4gIHZhciBwYXJ0cztcbiAgdmFyIG91dHB1dCA9IHt9O1xuXG4gIC8vIGlmIHdlIGRvbid0IGhhdmUgYSBzdHJpbmcgdXJsLCB0aGVuIGFsbG93IHRoZSBpbnB1dCB0byBwYXNzdGhyb3VnaFxuICBpZiAodHlwZW9mIHVybCAhPSAnc3RyaW5nJyAmJiAoISAodXJsIGluc3RhbmNlb2YgU3RyaW5nKSkpIHtcbiAgICByZXR1cm4gaW5wdXQ7XG4gIH1cblxuICAvLyB0cmltIHRoZSB1cmwgc3RyaW5nLCBhbmQgY29udmVydCB0byBhbiBhcnJheVxuICB1cmwgPSB1cmwudHJpbSgpO1xuXG4gIC8vIGlmIHRoZSBwcm90b2NvbCBpcyBub3Qga25vd24sIHRoZW4gcGFzc3Rocm91Z2hcbiAgcHJvdG9jb2wgPSBwcm90b2NvbHNbcHJvdG9jb2xzLmluZGV4T2YodXJsLnNsaWNlKDAsIDUpKV07XG4gIGlmICghIHByb3RvY29sKSB7XG4gICAgcmV0dXJuIGlucHV0O1xuICB9XG5cbiAgLy8gbm93IGxldCdzIGF0dGFjayB0aGUgcmVtYWluaW5nIHVybCBwYXJ0c1xuICB1cmwgPSB1cmwuc2xpY2UoNSk7XG4gIHBhcnRzID0gdXJsLnNwbGl0KCdAJyk7XG5cbiAgb3V0cHV0LnVzZXJuYW1lID0gaW5wdXQudXNlcm5hbWU7XG4gIG91dHB1dC5jcmVkZW50aWFsID0gaW5wdXQuY3JlZGVudGlhbDtcbiAgLy8gaWYgd2UgaGF2ZSBhbiBhdXRoZW50aWNhdGlvbiBwYXJ0LCB0aGVuIHNldCB0aGUgY3JlZGVudGlhbHNcbiAgaWYgKHBhcnRzLmxlbmd0aCA+IDEpIHtcbiAgICB1cmwgPSBwYXJ0c1sxXTtcbiAgICBwYXJ0cyA9IHBhcnRzWzBdLnNwbGl0KCc6Jyk7XG5cbiAgICAvLyBhZGQgdGhlIG91dHB1dCBjcmVkZW50aWFsIGFuZCB1c2VybmFtZVxuICAgIG91dHB1dC51c2VybmFtZSA9IHBhcnRzWzBdO1xuICAgIG91dHB1dC5jcmVkZW50aWFsID0gKGlucHV0IHx8IHt9KS5jcmVkZW50aWFsIHx8IHBhcnRzWzFdIHx8ICcnO1xuICB9XG5cbiAgb3V0cHV0LnVybCA9IHByb3RvY29sICsgdXJsO1xuICBvdXRwdXQudXJscyA9IFsgb3V0cHV0LnVybCBdO1xuXG4gIHJldHVybiBvdXRwdXQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIENoZWNrIGlmIHdlJ3JlIHJlcXVpcmVkIHRvIGFkZCBhIHBvcnQgbnVtYmVyLlxuICpcbiAqIEBzZWUgaHR0cHM6Ly91cmwuc3BlYy53aGF0d2cub3JnLyNkZWZhdWx0LXBvcnRcbiAqIEBwYXJhbSB7TnVtYmVyfFN0cmluZ30gcG9ydCBQb3J0IG51bWJlciB3ZSBuZWVkIHRvIGNoZWNrXG4gKiBAcGFyYW0ge1N0cmluZ30gcHJvdG9jb2wgUHJvdG9jb2wgd2UgbmVlZCB0byBjaGVjayBhZ2FpbnN0LlxuICogQHJldHVybnMge0Jvb2xlYW59IElzIGl0IGEgZGVmYXVsdCBwb3J0IGZvciB0aGUgZ2l2ZW4gcHJvdG9jb2xcbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHJlcXVpcmVkKHBvcnQsIHByb3RvY29sKSB7XG4gIHByb3RvY29sID0gcHJvdG9jb2wuc3BsaXQoJzonKVswXTtcbiAgcG9ydCA9ICtwb3J0O1xuXG4gIGlmICghcG9ydCkgcmV0dXJuIGZhbHNlO1xuXG4gIHN3aXRjaCAocHJvdG9jb2wpIHtcbiAgICBjYXNlICdodHRwJzpcbiAgICBjYXNlICd3cyc6XG4gICAgcmV0dXJuIHBvcnQgIT09IDgwO1xuXG4gICAgY2FzZSAnaHR0cHMnOlxuICAgIGNhc2UgJ3dzcyc6XG4gICAgcmV0dXJuIHBvcnQgIT09IDQ0MztcblxuICAgIGNhc2UgJ2Z0cCc6XG4gICAgcmV0dXJuIHBvcnQgIT09IDIxO1xuXG4gICAgY2FzZSAnZ29waGVyJzpcbiAgICByZXR1cm4gcG9ydCAhPT0gNzA7XG5cbiAgICBjYXNlICdmaWxlJzpcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICByZXR1cm4gcG9ydCAhPT0gMDtcbn07XG4iLCJ2YXIgZ3JhbW1hciA9IG1vZHVsZS5leHBvcnRzID0ge1xuICB2OiBbe1xuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxuICAgICAgcmVnOiAvXihcXGQqKSQvXG4gIH1dLFxuICBvOiBbeyAvL289LSAyMDUxOCAwIElOIElQNCAyMDMuMC4xMTMuMVxuICAgIC8vIE5COiBzZXNzaW9uSWQgd2lsbCBiZSBhIFN0cmluZyBpbiBtb3N0IGNhc2VzIGJlY2F1c2UgaXQgaXMgaHVnZVxuICAgIG5hbWU6ICdvcmlnaW4nLFxuICAgIHJlZzogL14oXFxTKikgKFxcZCopIChcXGQqKSAoXFxTKikgSVAoXFxkKSAoXFxTKikvLFxuICAgIG5hbWVzOiBbJ3VzZXJuYW1lJywgJ3Nlc3Npb25JZCcsICdzZXNzaW9uVmVyc2lvbicsICduZXRUeXBlJywgJ2lwVmVyJywgJ2FkZHJlc3MnXSxcbiAgICBmb3JtYXQ6IFwiJXMgJXMgJWQgJXMgSVAlZCAlc1wiXG4gIH1dLFxuICAvLyBkZWZhdWx0IHBhcnNpbmcgb2YgdGhlc2Ugb25seSAodGhvdWdoIHNvbWUgb2YgdGhlc2UgZmVlbCBvdXRkYXRlZClcbiAgczogW3sgbmFtZTogJ25hbWUnIH1dLFxuICBpOiBbeyBuYW1lOiAnZGVzY3JpcHRpb24nIH1dLFxuICB1OiBbeyBuYW1lOiAndXJpJyB9XSxcbiAgZTogW3sgbmFtZTogJ2VtYWlsJyB9XSxcbiAgcDogW3sgbmFtZTogJ3Bob25lJyB9XSxcbiAgejogW3sgbmFtZTogJ3RpbWV6b25lcycgfV0sIC8vIFRPRE86IHRoaXMgb25lIGNhbiBhY3R1YWxseSBiZSBwYXJzZWQgcHJvcGVybHkuLlxuICByOiBbeyBuYW1lOiAncmVwZWF0cycgfV0sICAgLy8gVE9ETzogdGhpcyBvbmUgY2FuIGFsc28gYmUgcGFyc2VkIHByb3Blcmx5XG4gIC8vazogW3t9XSwgLy8gb3V0ZGF0ZWQgdGhpbmcgaWdub3JlZFxuICB0OiBbeyAvL3Q9MCAwXG4gICAgbmFtZTogJ3RpbWluZycsXG4gICAgcmVnOiAvXihcXGQqKSAoXFxkKikvLFxuICAgIG5hbWVzOiBbJ3N0YXJ0JywgJ3N0b3AnXSxcbiAgICBmb3JtYXQ6IFwiJWQgJWRcIlxuICB9XSxcbiAgYzogW3sgLy9jPUlOIElQNCAxMC40Ny4xOTcuMjZcbiAgICAgIG5hbWU6ICdjb25uZWN0aW9uJyxcbiAgICAgIHJlZzogL15JTiBJUChcXGQpIChcXFMqKS8sXG4gICAgICBuYW1lczogWyd2ZXJzaW9uJywgJ2lwJ10sXG4gICAgICBmb3JtYXQ6IFwiSU4gSVAlZCAlc1wiXG4gIH1dLFxuICBiOiBbeyAvL2I9QVM6NDAwMFxuICAgICAgcHVzaDogJ2JhbmR3aWR0aCcsXG4gICAgICByZWc6IC9eKFRJQVN8QVN8Q1R8UlJ8UlMpOihcXGQqKS8sXG4gICAgICBuYW1lczogWyd0eXBlJywgJ2xpbWl0J10sXG4gICAgICBmb3JtYXQ6IFwiJXM6JXNcIlxuICB9XSxcbiAgbTogW3sgLy9tPXZpZGVvIDUxNzQ0IFJUUC9BVlAgMTI2IDk3IDk4IDM0IDMxXG4gICAgICAvLyBOQjogc3BlY2lhbCAtIHB1c2hlcyB0byBzZXNzaW9uXG4gICAgICAvLyBUT0RPOiBydHAvZm10cCBzaG91bGQgYmUgZmlsdGVyZWQgYnkgdGhlIHBheWxvYWRzIGZvdW5kIGhlcmU/XG4gICAgICByZWc6IC9eKFxcdyopIChcXGQqKSAoW1xcd1xcL10qKSg/OiAoLiopKT8vLFxuICAgICAgbmFtZXM6IFsndHlwZScsICdwb3J0JywgJ3Byb3RvY29sJywgJ3BheWxvYWRzJ10sXG4gICAgICBmb3JtYXQ6IFwiJXMgJWQgJXMgJXNcIlxuICB9XSxcbiAgYTogW1xuICAgIHsgLy9hPXJ0cG1hcDoxMTAgb3B1cy80ODAwMC8yXG4gICAgICBwdXNoOiAncnRwJyxcbiAgICAgIHJlZzogL15ydHBtYXA6KFxcZCopIChbXFx3XFwtXSopKD86XFxzKlxcLyhcXGQqKSg/OlxccypcXC8oXFxTKikpPyk/LyxcbiAgICAgIG5hbWVzOiBbJ3BheWxvYWQnLCAnY29kZWMnLCAncmF0ZScsICdlbmNvZGluZyddLFxuICAgICAgZm9ybWF0OiBmdW5jdGlvbiAobykge1xuICAgICAgICByZXR1cm4gKG8uZW5jb2RpbmcpID9cbiAgICAgICAgICBcInJ0cG1hcDolZCAlcy8lcy8lc1wiOlxuICAgICAgICAgIG8ucmF0ZSA/XG4gICAgICAgICAgXCJydHBtYXA6JWQgJXMvJXNcIjpcbiAgICAgICAgICBcInJ0cG1hcDolZCAlc1wiO1xuICAgICAgfVxuICAgIH0sXG4gICAge1xuICAgICAgLy9hPWZtdHA6MTA4IHByb2ZpbGUtbGV2ZWwtaWQ9MjQ7b2JqZWN0PTIzO2JpdHJhdGU9NjQwMDBcbiAgICAgIC8vYT1mbXRwOjExMSBtaW5wdGltZT0xMDsgdXNlaW5iYW5kZmVjPTFcbiAgICAgIHB1c2g6ICdmbXRwJyxcbiAgICAgIHJlZzogL15mbXRwOihcXGQqKSAoW1xcU3wgXSopLyxcbiAgICAgIG5hbWVzOiBbJ3BheWxvYWQnLCAnY29uZmlnJ10sXG4gICAgICBmb3JtYXQ6IFwiZm10cDolZCAlc1wiXG4gICAgfSxcbiAgICB7IC8vYT1jb250cm9sOnN0cmVhbWlkPTBcbiAgICAgICAgbmFtZTogJ2NvbnRyb2wnLFxuICAgICAgICByZWc6IC9eY29udHJvbDooLiopLyxcbiAgICAgICAgZm9ybWF0OiBcImNvbnRyb2w6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9cnRjcDo2NTE3OSBJTiBJUDQgMTkzLjg0Ljc3LjE5NFxuICAgICAgbmFtZTogJ3J0Y3AnLFxuICAgICAgcmVnOiAvXnJ0Y3A6KFxcZCopKD86IChcXFMqKSBJUChcXGQpIChcXFMqKSk/LyxcbiAgICAgIG5hbWVzOiBbJ3BvcnQnLCAnbmV0VHlwZScsICdpcFZlcicsICdhZGRyZXNzJ10sXG4gICAgICBmb3JtYXQ6IGZ1bmN0aW9uIChvKSB7XG4gICAgICAgIHJldHVybiAoby5hZGRyZXNzICE9IG51bGwpID9cbiAgICAgICAgICBcInJ0Y3A6JWQgJXMgSVAlZCAlc1wiOlxuICAgICAgICAgIFwicnRjcDolZFwiO1xuICAgICAgfVxuICAgIH0sXG4gICAgeyAvL2E9cnRjcC1mYjo5OCB0cnItaW50IDEwMFxuICAgICAgcHVzaDogJ3J0Y3BGYlRyckludCcsXG4gICAgICByZWc6IC9ecnRjcC1mYjooXFwqfFxcZCopIHRyci1pbnQgKFxcZCopLyxcbiAgICAgIG5hbWVzOiBbJ3BheWxvYWQnLCAndmFsdWUnXSxcbiAgICAgIGZvcm1hdDogXCJydGNwLWZiOiVkIHRyci1pbnQgJWRcIlxuICAgIH0sXG4gICAgeyAvL2E9cnRjcC1mYjo5OCBuYWNrIHJwc2lcbiAgICAgIHB1c2g6ICdydGNwRmInLFxuICAgICAgcmVnOiAvXnJ0Y3AtZmI6KFxcKnxcXGQqKSAoW1xcdy1fXSopKD86IChbXFx3LV9dKikpPy8sXG4gICAgICBuYW1lczogWydwYXlsb2FkJywgJ3R5cGUnLCAnc3VidHlwZSddLFxuICAgICAgZm9ybWF0OiBmdW5jdGlvbiAobykge1xuICAgICAgICByZXR1cm4gKG8uc3VidHlwZSAhPSBudWxsKSA/XG4gICAgICAgICAgXCJydGNwLWZiOiVzICVzICVzXCI6XG4gICAgICAgICAgXCJydGNwLWZiOiVzICVzXCI7XG4gICAgICB9XG4gICAgfSxcbiAgICB7IC8vYT1leHRtYXA6MiB1cm46aWV0ZjpwYXJhbXM6cnRwLWhkcmV4dDp0b2Zmc2V0XG4gICAgICAvL2E9ZXh0bWFwOjEvcmVjdm9ubHkgVVJJLWdwcy1zdHJpbmdcbiAgICAgIHB1c2g6ICdleHQnLFxuICAgICAgcmVnOiAvXmV4dG1hcDooW1xcd19cXC9dKikgKFxcUyopKD86IChcXFMqKSk/LyxcbiAgICAgIG5hbWVzOiBbJ3ZhbHVlJywgJ3VyaScsICdjb25maWcnXSwgLy8gdmFsdWUgbWF5IGluY2x1ZGUgXCIvZGlyZWN0aW9uXCIgc3VmZml4XG4gICAgICBmb3JtYXQ6IGZ1bmN0aW9uIChvKSB7XG4gICAgICAgIHJldHVybiAoby5jb25maWcgIT0gbnVsbCkgP1xuICAgICAgICAgIFwiZXh0bWFwOiVzICVzICVzXCI6XG4gICAgICAgICAgXCJleHRtYXA6JXMgJXNcIjtcbiAgICAgIH1cbiAgICB9LFxuICAgIHtcbiAgICAgIC8vYT1jcnlwdG86MSBBRVNfQ01fMTI4X0hNQUNfU0hBMV84MCBpbmxpbmU6UFMxdVFDVmVlQ0ZDYW5WbWNqa3BQeXdqTldoY1lEMG1YWHR4YVZCUnwyXjIwfDE6MzJcbiAgICAgIHB1c2g6ICdjcnlwdG8nLFxuICAgICAgcmVnOiAvXmNyeXB0bzooXFxkKikgKFtcXHdfXSopIChcXFMqKSg/OiAoXFxTKikpPy8sXG4gICAgICBuYW1lczogWydpZCcsICdzdWl0ZScsICdjb25maWcnLCAnc2Vzc2lvbkNvbmZpZyddLFxuICAgICAgZm9ybWF0OiBmdW5jdGlvbiAobykge1xuICAgICAgICByZXR1cm4gKG8uc2Vzc2lvbkNvbmZpZyAhPSBudWxsKSA/XG4gICAgICAgICAgXCJjcnlwdG86JWQgJXMgJXMgJXNcIjpcbiAgICAgICAgICBcImNyeXB0bzolZCAlcyAlc1wiO1xuICAgICAgfVxuICAgIH0sXG4gICAgeyAvL2E9c2V0dXA6YWN0cGFzc1xuICAgICAgbmFtZTogJ3NldHVwJyxcbiAgICAgIHJlZzogL15zZXR1cDooXFx3KikvLFxuICAgICAgZm9ybWF0OiBcInNldHVwOiVzXCJcbiAgICB9LFxuICAgIHsgLy9hPW1pZDoxXG4gICAgICBuYW1lOiAnbWlkJyxcbiAgICAgIHJlZzogL15taWQ6KFteXFxzXSopLyxcbiAgICAgIGZvcm1hdDogXCJtaWQ6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9bXNpZDowYzhiMDY0ZC1kODA3LTQzYjQtYjQzNC1mOTJhODg5ZDg1ODcgOTgxNzg2ODUtZDQwOS00NmUwLThlMTYtN2VmMGRiMGRiNjRhXG4gICAgICBuYW1lOiAnbXNpZCcsXG4gICAgICByZWc6IC9ebXNpZDooLiopLyxcbiAgICAgIGZvcm1hdDogXCJtc2lkOiVzXCJcbiAgICB9LFxuICAgIHsgLy9hPXB0aW1lOjIwXG4gICAgICBuYW1lOiAncHRpbWUnLFxuICAgICAgcmVnOiAvXnB0aW1lOihcXGQqKS8sXG4gICAgICBmb3JtYXQ6IFwicHRpbWU6JWRcIlxuICAgIH0sXG4gICAgeyAvL2E9bWF4cHRpbWU6NjBcbiAgICAgIG5hbWU6ICdtYXhwdGltZScsXG4gICAgICByZWc6IC9ebWF4cHRpbWU6KFxcZCopLyxcbiAgICAgIGZvcm1hdDogXCJtYXhwdGltZTolZFwiXG4gICAgfSxcbiAgICB7IC8vYT1zZW5kcmVjdlxuICAgICAgbmFtZTogJ2RpcmVjdGlvbicsXG4gICAgICByZWc6IC9eKHNlbmRyZWN2fHJlY3Zvbmx5fHNlbmRvbmx5fGluYWN0aXZlKS9cbiAgICB9LFxuICAgIHsgLy9hPWljZS1saXRlXG4gICAgICBuYW1lOiAnaWNlbGl0ZScsXG4gICAgICByZWc6IC9eKGljZS1saXRlKS9cbiAgICB9LFxuICAgIHsgLy9hPWljZS11ZnJhZzpGN2dJXG4gICAgICBuYW1lOiAnaWNlVWZyYWcnLFxuICAgICAgcmVnOiAvXmljZS11ZnJhZzooXFxTKikvLFxuICAgICAgZm9ybWF0OiBcImljZS11ZnJhZzolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1pY2UtcHdkOng5Y21sL1l6aWNoVjIrWGxoaU11OGdcbiAgICAgIG5hbWU6ICdpY2VQd2QnLFxuICAgICAgcmVnOiAvXmljZS1wd2Q6KFxcUyopLyxcbiAgICAgIGZvcm1hdDogXCJpY2UtcHdkOiVzXCJcbiAgICB9LFxuICAgIHsgLy9hPWZpbmdlcnByaW50OlNIQS0xIDAwOjExOjIyOjMzOjQ0OjU1OjY2Ojc3Ojg4Ojk5OkFBOkJCOkNDOkREOkVFOkZGOjAwOjExOjIyOjMzXG4gICAgICBuYW1lOiAnZmluZ2VycHJpbnQnLFxuICAgICAgcmVnOiAvXmZpbmdlcnByaW50OihcXFMqKSAoXFxTKikvLFxuICAgICAgbmFtZXM6IFsndHlwZScsICdoYXNoJ10sXG4gICAgICBmb3JtYXQ6IFwiZmluZ2VycHJpbnQ6JXMgJXNcIlxuICAgIH0sXG4gICAge1xuICAgICAgLy9hPWNhbmRpZGF0ZTowIDEgVURQIDIxMTM2NjczMjcgMjAzLjAuMTEzLjEgNTQ0MDAgdHlwIGhvc3RcbiAgICAgIC8vYT1jYW5kaWRhdGU6MTE2Mjg3NTA4MSAxIHVkcCAyMTEzOTM3MTUxIDE5Mi4xNjguMzQuNzUgNjAwMTcgdHlwIGhvc3QgZ2VuZXJhdGlvbiAwXG4gICAgICAvL2E9Y2FuZGlkYXRlOjMyODk5MTI5NTcgMiB1ZHAgMTg0NTUwMTY5NSAxOTMuODQuNzcuMTk0IDYwMDE3IHR5cCBzcmZseCByYWRkciAxOTIuMTY4LjM0Ljc1IHJwb3J0IDYwMDE3IGdlbmVyYXRpb24gMFxuICAgICAgLy9hPWNhbmRpZGF0ZToyMjk4MTU2MjAgMSB0Y3AgMTUxODI4MDQ0NyAxOTIuMTY4LjE1MC4xOSA2MDAxNyB0eXAgaG9zdCB0Y3B0eXBlIGFjdGl2ZSBnZW5lcmF0aW9uIDBcbiAgICAgIC8vYT1jYW5kaWRhdGU6MzI4OTkxMjk1NyAyIHRjcCAxODQ1NTAxNjk1IDE5My44NC43Ny4xOTQgNjAwMTcgdHlwIHNyZmx4IHJhZGRyIDE5Mi4xNjguMzQuNzUgcnBvcnQgNjAwMTcgdGNwdHlwZSBwYXNzaXZlIGdlbmVyYXRpb24gMFxuICAgICAgcHVzaDonY2FuZGlkYXRlcycsXG4gICAgICByZWc6IC9eY2FuZGlkYXRlOihcXFMqKSAoXFxkKikgKFxcUyopIChcXGQqKSAoXFxTKikgKFxcZCopIHR5cCAoXFxTKikoPzogcmFkZHIgKFxcUyopIHJwb3J0IChcXGQqKSk/KD86IHRjcHR5cGUgKFxcUyopKT8oPzogZ2VuZXJhdGlvbiAoXFxkKikpPy8sXG4gICAgICBuYW1lczogWydmb3VuZGF0aW9uJywgJ2NvbXBvbmVudCcsICd0cmFuc3BvcnQnLCAncHJpb3JpdHknLCAnaXAnLCAncG9ydCcsICd0eXBlJywgJ3JhZGRyJywgJ3Jwb3J0JywgJ3RjcHR5cGUnLCAnZ2VuZXJhdGlvbiddLFxuICAgICAgZm9ybWF0OiBmdW5jdGlvbiAobykge1xuICAgICAgICB2YXIgc3RyID0gXCJjYW5kaWRhdGU6JXMgJWQgJXMgJWQgJXMgJWQgdHlwICVzXCI7XG5cbiAgICAgICAgc3RyICs9IChvLnJhZGRyICE9IG51bGwpID8gXCIgcmFkZHIgJXMgcnBvcnQgJWRcIiA6IFwiJXYldlwiO1xuXG4gICAgICAgIC8vIE5COiBjYW5kaWRhdGUgaGFzIHRocmVlIG9wdGlvbmFsIGNodW5rcywgc28gJXZvaWQgbWlkZGxlcyBvbmUgaWYgaXQncyBtaXNzaW5nXG4gICAgICAgIHN0ciArPSAoby50Y3B0eXBlICE9IG51bGwpID8gXCIgdGNwdHlwZSAlc1wiIDogXCIldlwiO1xuXG4gICAgICAgIGlmIChvLmdlbmVyYXRpb24gIT0gbnVsbCkge1xuICAgICAgICAgIHN0ciArPSBcIiBnZW5lcmF0aW9uICVkXCI7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN0cjtcbiAgICAgIH1cbiAgICB9LFxuICAgIHsgLy9hPWVuZC1vZi1jYW5kaWRhdGVzIChrZWVwIGFmdGVyIHRoZSBjYW5kaWRhdGVzIGxpbmUgZm9yIHJlYWRhYmlsaXR5KVxuICAgICAgbmFtZTogJ2VuZE9mQ2FuZGlkYXRlcycsXG4gICAgICByZWc6IC9eKGVuZC1vZi1jYW5kaWRhdGVzKS9cbiAgICB9LFxuICAgIHsgLy9hPXJlbW90ZS1jYW5kaWRhdGVzOjEgMjAzLjAuMTEzLjEgNTQ0MDAgMiAyMDMuMC4xMTMuMSA1NDQwMSAuLi5cbiAgICAgIG5hbWU6ICdyZW1vdGVDYW5kaWRhdGVzJyxcbiAgICAgIHJlZzogL15yZW1vdGUtY2FuZGlkYXRlczooLiopLyxcbiAgICAgIGZvcm1hdDogXCJyZW1vdGUtY2FuZGlkYXRlczolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1pY2Utb3B0aW9uczpnb29nbGUtaWNlXG4gICAgICBuYW1lOiAnaWNlT3B0aW9ucycsXG4gICAgICByZWc6IC9eaWNlLW9wdGlvbnM6KFxcUyopLyxcbiAgICAgIGZvcm1hdDogXCJpY2Utb3B0aW9uczolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1zc3JjOjI1NjYxMDc1NjkgY25hbWU6dDlZVThNMVV4VEY4WTFBMVxuICAgICAgcHVzaDogXCJzc3Jjc1wiLFxuICAgICAgcmVnOiAvXnNzcmM6KFxcZCopIChbXFx3X10qKTooLiopLyxcbiAgICAgIG5hbWVzOiBbJ2lkJywgJ2F0dHJpYnV0ZScsICd2YWx1ZSddLFxuICAgICAgZm9ybWF0OiBcInNzcmM6JWQgJXM6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9c3NyYy1ncm91cDpGRUMgMSAyXG4gICAgICBwdXNoOiBcInNzcmNHcm91cHNcIixcbiAgICAgIHJlZzogL15zc3JjLWdyb3VwOihcXHcqKSAoLiopLyxcbiAgICAgIG5hbWVzOiBbJ3NlbWFudGljcycsICdzc3JjcyddLFxuICAgICAgZm9ybWF0OiBcInNzcmMtZ3JvdXA6JXMgJXNcIlxuICAgIH0sXG4gICAgeyAvL2E9bXNpZC1zZW1hbnRpYzogV01TIEp2bGFtNVgzU1gxT1A2cG4yMHpXb2d2YUtKejVIamY5T25sVlxuICAgICAgbmFtZTogXCJtc2lkU2VtYW50aWNcIixcbiAgICAgIHJlZzogL15tc2lkLXNlbWFudGljOlxccz8oXFx3KikgKFxcUyopLyxcbiAgICAgIG5hbWVzOiBbJ3NlbWFudGljJywgJ3Rva2VuJ10sXG4gICAgICBmb3JtYXQ6IFwibXNpZC1zZW1hbnRpYzogJXMgJXNcIiAvLyBzcGFjZSBhZnRlciBcIjpcIiBpcyBub3QgYWNjaWRlbnRhbFxuICAgIH0sXG4gICAgeyAvL2E9Z3JvdXA6QlVORExFIGF1ZGlvIHZpZGVvXG4gICAgICBwdXNoOiAnZ3JvdXBzJyxcbiAgICAgIHJlZzogL15ncm91cDooXFx3KikgKC4qKS8sXG4gICAgICBuYW1lczogWyd0eXBlJywgJ21pZHMnXSxcbiAgICAgIGZvcm1hdDogXCJncm91cDolcyAlc1wiXG4gICAgfSxcbiAgICB7IC8vYT1ydGNwLW11eFxuICAgICAgbmFtZTogJ3J0Y3BNdXgnLFxuICAgICAgcmVnOiAvXihydGNwLW11eCkvXG4gICAgfSxcbiAgICB7IC8vYT1ydGNwLXJzaXplXG4gICAgICBuYW1lOiAncnRjcFJzaXplJyxcbiAgICAgIHJlZzogL14ocnRjcC1yc2l6ZSkvXG4gICAgfSxcbiAgICB7IC8vIGFueSBhPSB0aGF0IHdlIGRvbid0IHVuZGVyc3RhbmQgaXMga2VwdHMgdmVyYmF0aW0gb24gbWVkaWEuaW52YWxpZFxuICAgICAgcHVzaDogJ2ludmFsaWQnLFxuICAgICAgbmFtZXM6IFtcInZhbHVlXCJdXG4gICAgfVxuICBdXG59O1xuXG4vLyBzZXQgc2Vuc2libGUgZGVmYXVsdHMgdG8gYXZvaWQgcG9sbHV0aW5nIHRoZSBncmFtbWFyIHdpdGggYm9yaW5nIGRldGFpbHNcbk9iamVjdC5rZXlzKGdyYW1tYXIpLmZvckVhY2goZnVuY3Rpb24gKGtleSkge1xuICB2YXIgb2JqcyA9IGdyYW1tYXJba2V5XTtcbiAgb2Jqcy5mb3JFYWNoKGZ1bmN0aW9uIChvYmopIHtcbiAgICBpZiAoIW9iai5yZWcpIHtcbiAgICAgIG9iai5yZWcgPSAvKC4qKS87XG4gICAgfVxuICAgIGlmICghb2JqLmZvcm1hdCkge1xuICAgICAgb2JqLmZvcm1hdCA9IFwiJXNcIjtcbiAgICB9XG4gIH0pO1xufSk7XG4iLCJ2YXIgcGFyc2VyID0gcmVxdWlyZSgnLi9wYXJzZXInKTtcbnZhciB3cml0ZXIgPSByZXF1aXJlKCcuL3dyaXRlcicpO1xuXG5leHBvcnRzLndyaXRlID0gd3JpdGVyO1xuZXhwb3J0cy5wYXJzZSA9IHBhcnNlci5wYXJzZTtcbmV4cG9ydHMucGFyc2VGbXRwQ29uZmlnID0gcGFyc2VyLnBhcnNlRm10cENvbmZpZztcbmV4cG9ydHMucGFyc2VQYXlsb2FkcyA9IHBhcnNlci5wYXJzZVBheWxvYWRzO1xuZXhwb3J0cy5wYXJzZVJlbW90ZUNhbmRpZGF0ZXMgPSBwYXJzZXIucGFyc2VSZW1vdGVDYW5kaWRhdGVzO1xuIiwidmFyIHRvSW50SWZJbnQgPSBmdW5jdGlvbiAodikge1xuICByZXR1cm4gU3RyaW5nKE51bWJlcih2KSkgPT09IHYgPyBOdW1iZXIodikgOiB2O1xufTtcblxudmFyIGF0dGFjaFByb3BlcnRpZXMgPSBmdW5jdGlvbiAobWF0Y2gsIGxvY2F0aW9uLCBuYW1lcywgcmF3TmFtZSkge1xuICBpZiAocmF3TmFtZSAmJiAhbmFtZXMpIHtcbiAgICBsb2NhdGlvbltyYXdOYW1lXSA9IHRvSW50SWZJbnQobWF0Y2hbMV0pO1xuICB9XG4gIGVsc2Uge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbmFtZXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIGlmIChtYXRjaFtpKzFdICE9IG51bGwpIHtcbiAgICAgICAgbG9jYXRpb25bbmFtZXNbaV1dID0gdG9JbnRJZkludChtYXRjaFtpKzFdKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn07XG5cbnZhciBwYXJzZVJlZyA9IGZ1bmN0aW9uIChvYmosIGxvY2F0aW9uLCBjb250ZW50KSB7XG4gIHZhciBuZWVkc0JsYW5rID0gb2JqLm5hbWUgJiYgb2JqLm5hbWVzO1xuICBpZiAob2JqLnB1c2ggJiYgIWxvY2F0aW9uW29iai5wdXNoXSkge1xuICAgIGxvY2F0aW9uW29iai5wdXNoXSA9IFtdO1xuICB9XG4gIGVsc2UgaWYgKG5lZWRzQmxhbmsgJiYgIWxvY2F0aW9uW29iai5uYW1lXSkge1xuICAgIGxvY2F0aW9uW29iai5uYW1lXSA9IHt9O1xuICB9XG4gIHZhciBrZXlMb2NhdGlvbiA9IG9iai5wdXNoID9cbiAgICB7fSA6ICAvLyBibGFuayBvYmplY3QgdGhhdCB3aWxsIGJlIHB1c2hlZFxuICAgIG5lZWRzQmxhbmsgPyBsb2NhdGlvbltvYmoubmFtZV0gOiBsb2NhdGlvbjsgLy8gb3RoZXJ3aXNlLCBuYW1lZCBsb2NhdGlvbiBvciByb290XG5cbiAgYXR0YWNoUHJvcGVydGllcyhjb250ZW50Lm1hdGNoKG9iai5yZWcpLCBrZXlMb2NhdGlvbiwgb2JqLm5hbWVzLCBvYmoubmFtZSk7XG5cbiAgaWYgKG9iai5wdXNoKSB7XG4gICAgbG9jYXRpb25bb2JqLnB1c2hdLnB1c2goa2V5TG9jYXRpb24pO1xuICB9XG59O1xuXG52YXIgZ3JhbW1hciA9IHJlcXVpcmUoJy4vZ3JhbW1hcicpO1xudmFyIHZhbGlkTGluZSA9IFJlZ0V4cC5wcm90b3R5cGUudGVzdC5iaW5kKC9eKFthLXpdKT0oLiopLyk7XG5cbmV4cG9ydHMucGFyc2UgPSBmdW5jdGlvbiAoc2RwKSB7XG4gIHZhciBzZXNzaW9uID0ge31cbiAgICAsIG1lZGlhID0gW11cbiAgICAsIGxvY2F0aW9uID0gc2Vzc2lvbjsgLy8gcG9pbnRzIGF0IHdoZXJlIHByb3BlcnRpZXMgZ28gdW5kZXIgKG9uZSBvZiB0aGUgYWJvdmUpXG5cbiAgLy8gcGFyc2UgbGluZXMgd2UgdW5kZXJzdGFuZFxuICBzZHAuc3BsaXQoLyhcXHJcXG58XFxyfFxcbikvKS5maWx0ZXIodmFsaWRMaW5lKS5mb3JFYWNoKGZ1bmN0aW9uIChsKSB7XG4gICAgdmFyIHR5cGUgPSBsWzBdO1xuICAgIHZhciBjb250ZW50ID0gbC5zbGljZSgyKTtcbiAgICBpZiAodHlwZSA9PT0gJ20nKSB7XG4gICAgICBtZWRpYS5wdXNoKHtydHA6IFtdLCBmbXRwOiBbXX0pO1xuICAgICAgbG9jYXRpb24gPSBtZWRpYVttZWRpYS5sZW5ndGgtMV07IC8vIHBvaW50IGF0IGxhdGVzdCBtZWRpYSBsaW5lXG4gICAgfVxuXG4gICAgZm9yICh2YXIgaiA9IDA7IGogPCAoZ3JhbW1hclt0eXBlXSB8fCBbXSkubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgIHZhciBvYmogPSBncmFtbWFyW3R5cGVdW2pdO1xuICAgICAgaWYgKG9iai5yZWcudGVzdChjb250ZW50KSkge1xuICAgICAgICByZXR1cm4gcGFyc2VSZWcob2JqLCBsb2NhdGlvbiwgY29udGVudCk7XG4gICAgICB9XG4gICAgfVxuICB9KTtcblxuICBzZXNzaW9uLm1lZGlhID0gbWVkaWE7IC8vIGxpbmsgaXQgdXBcbiAgcmV0dXJuIHNlc3Npb247XG59O1xuXG52YXIgZm10cFJlZHVjZXIgPSBmdW5jdGlvbiAoYWNjLCBleHByKSB7XG4gIHZhciBzID0gZXhwci5zcGxpdCgnPScpO1xuICBpZiAocy5sZW5ndGggPT09IDIpIHtcbiAgICBhY2Nbc1swXV0gPSB0b0ludElmSW50KHNbMV0pO1xuICB9XG4gIHJldHVybiBhY2M7XG59O1xuXG5leHBvcnRzLnBhcnNlRm10cENvbmZpZyA9IGZ1bmN0aW9uIChzdHIpIHtcbiAgcmV0dXJuIHN0ci5zcGxpdCgvXFw7XFxzPy8pLnJlZHVjZShmbXRwUmVkdWNlciwge30pO1xufTtcblxuZXhwb3J0cy5wYXJzZVBheWxvYWRzID0gZnVuY3Rpb24gKHN0cikge1xuICByZXR1cm4gc3RyLnNwbGl0KCcgJykubWFwKE51bWJlcik7XG59O1xuXG5leHBvcnRzLnBhcnNlUmVtb3RlQ2FuZGlkYXRlcyA9IGZ1bmN0aW9uIChzdHIpIHtcbiAgdmFyIGNhbmRpZGF0ZXMgPSBbXTtcbiAgdmFyIHBhcnRzID0gc3RyLnNwbGl0KCcgJykubWFwKHRvSW50SWZJbnQpO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHBhcnRzLmxlbmd0aDsgaSArPSAzKSB7XG4gICAgY2FuZGlkYXRlcy5wdXNoKHtcbiAgICAgIGNvbXBvbmVudDogcGFydHNbaV0sXG4gICAgICBpcDogcGFydHNbaSArIDFdLFxuICAgICAgcG9ydDogcGFydHNbaSArIDJdXG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIGNhbmRpZGF0ZXM7XG59O1xuIiwidmFyIGdyYW1tYXIgPSByZXF1aXJlKCcuL2dyYW1tYXInKTtcblxuLy8gY3VzdG9taXplZCB1dGlsLmZvcm1hdCAtIGRpc2NhcmRzIGV4Y2VzcyBhcmd1bWVudHMgYW5kIGNhbiB2b2lkIG1pZGRsZSBvbmVzXG52YXIgZm9ybWF0UmVnRXhwID0gLyVbc2R2JV0vZztcbnZhciBmb3JtYXQgPSBmdW5jdGlvbiAoZm9ybWF0U3RyKSB7XG4gIHZhciBpID0gMTtcbiAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG4gIHZhciBsZW4gPSBhcmdzLmxlbmd0aDtcbiAgcmV0dXJuIGZvcm1hdFN0ci5yZXBsYWNlKGZvcm1hdFJlZ0V4cCwgZnVuY3Rpb24gKHgpIHtcbiAgICBpZiAoaSA+PSBsZW4pIHtcbiAgICAgIHJldHVybiB4OyAvLyBtaXNzaW5nIGFyZ3VtZW50XG4gICAgfVxuICAgIHZhciBhcmcgPSBhcmdzW2ldO1xuICAgIGkgKz0gMTtcbiAgICBzd2l0Y2ggKHgpIHtcbiAgICAgIGNhc2UgJyUlJzpcbiAgICAgICAgcmV0dXJuICclJztcbiAgICAgIGNhc2UgJyVzJzpcbiAgICAgICAgcmV0dXJuIFN0cmluZyhhcmcpO1xuICAgICAgY2FzZSAnJWQnOlxuICAgICAgICByZXR1cm4gTnVtYmVyKGFyZyk7XG4gICAgICBjYXNlICcldic6XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG4gIH0pO1xuICAvLyBOQjogd2UgZGlzY2FyZCBleGNlc3MgYXJndW1lbnRzIC0gdGhleSBhcmUgdHlwaWNhbGx5IHVuZGVmaW5lZCBmcm9tIG1ha2VMaW5lXG59O1xuXG52YXIgbWFrZUxpbmUgPSBmdW5jdGlvbiAodHlwZSwgb2JqLCBsb2NhdGlvbikge1xuICB2YXIgc3RyID0gb2JqLmZvcm1hdCBpbnN0YW5jZW9mIEZ1bmN0aW9uID9cbiAgICAob2JqLmZvcm1hdChvYmoucHVzaCA/IGxvY2F0aW9uIDogbG9jYXRpb25bb2JqLm5hbWVdKSkgOlxuICAgIG9iai5mb3JtYXQ7XG5cbiAgdmFyIGFyZ3MgPSBbdHlwZSArICc9JyArIHN0cl07XG4gIGlmIChvYmoubmFtZXMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG9iai5uYW1lcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgdmFyIG4gPSBvYmoubmFtZXNbaV07XG4gICAgICBpZiAob2JqLm5hbWUpIHtcbiAgICAgICAgYXJncy5wdXNoKGxvY2F0aW9uW29iai5uYW1lXVtuXSk7XG4gICAgICB9XG4gICAgICBlbHNlIHsgLy8gZm9yIG1MaW5lIGFuZCBwdXNoIGF0dHJpYnV0ZXNcbiAgICAgICAgYXJncy5wdXNoKGxvY2F0aW9uW29iai5uYW1lc1tpXV0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBlbHNlIHtcbiAgICBhcmdzLnB1c2gobG9jYXRpb25bb2JqLm5hbWVdKTtcbiAgfVxuICByZXR1cm4gZm9ybWF0LmFwcGx5KG51bGwsIGFyZ3MpO1xufTtcblxuLy8gUkZDIHNwZWNpZmllZCBvcmRlclxuLy8gVE9ETzogZXh0ZW5kIHRoaXMgd2l0aCBhbGwgdGhlIHJlc3RcbnZhciBkZWZhdWx0T3V0ZXJPcmRlciA9IFtcbiAgJ3YnLCAnbycsICdzJywgJ2knLFxuICAndScsICdlJywgJ3AnLCAnYycsXG4gICdiJywgJ3QnLCAncicsICd6JywgJ2EnXG5dO1xudmFyIGRlZmF1bHRJbm5lck9yZGVyID0gWydpJywgJ2MnLCAnYicsICdhJ107XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoc2Vzc2lvbiwgb3B0cykge1xuICBvcHRzID0gb3B0cyB8fCB7fTtcbiAgLy8gZW5zdXJlIGNlcnRhaW4gcHJvcGVydGllcyBleGlzdFxuICBpZiAoc2Vzc2lvbi52ZXJzaW9uID09IG51bGwpIHtcbiAgICBzZXNzaW9uLnZlcnNpb24gPSAwOyAvLyBcInY9MFwiIG11c3QgYmUgdGhlcmUgKG9ubHkgZGVmaW5lZCB2ZXJzaW9uIGF0bSlcbiAgfVxuICBpZiAoc2Vzc2lvbi5uYW1lID09IG51bGwpIHtcbiAgICBzZXNzaW9uLm5hbWUgPSBcIiBcIjsgLy8gXCJzPSBcIiBtdXN0IGJlIHRoZXJlIGlmIG5vIG1lYW5pbmdmdWwgbmFtZSBzZXRcbiAgfVxuICBzZXNzaW9uLm1lZGlhLmZvckVhY2goZnVuY3Rpb24gKG1MaW5lKSB7XG4gICAgaWYgKG1MaW5lLnBheWxvYWRzID09IG51bGwpIHtcbiAgICAgIG1MaW5lLnBheWxvYWRzID0gXCJcIjtcbiAgICB9XG4gIH0pO1xuXG4gIHZhciBvdXRlck9yZGVyID0gb3B0cy5vdXRlck9yZGVyIHx8IGRlZmF1bHRPdXRlck9yZGVyO1xuICB2YXIgaW5uZXJPcmRlciA9IG9wdHMuaW5uZXJPcmRlciB8fCBkZWZhdWx0SW5uZXJPcmRlcjtcbiAgdmFyIHNkcCA9IFtdO1xuXG4gIC8vIGxvb3AgdGhyb3VnaCBvdXRlck9yZGVyIGZvciBtYXRjaGluZyBwcm9wZXJ0aWVzIG9uIHNlc3Npb25cbiAgb3V0ZXJPcmRlci5mb3JFYWNoKGZ1bmN0aW9uICh0eXBlKSB7XG4gICAgZ3JhbW1hclt0eXBlXS5mb3JFYWNoKGZ1bmN0aW9uIChvYmopIHtcbiAgICAgIGlmIChvYmoubmFtZSBpbiBzZXNzaW9uICYmIHNlc3Npb25bb2JqLm5hbWVdICE9IG51bGwpIHtcbiAgICAgICAgc2RwLnB1c2gobWFrZUxpbmUodHlwZSwgb2JqLCBzZXNzaW9uKSk7XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChvYmoucHVzaCBpbiBzZXNzaW9uICYmIHNlc3Npb25bb2JqLnB1c2hdICE9IG51bGwpIHtcbiAgICAgICAgc2Vzc2lvbltvYmoucHVzaF0uZm9yRWFjaChmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgICBzZHAucHVzaChtYWtlTGluZSh0eXBlLCBvYmosIGVsKSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICB9KTtcblxuICAvLyB0aGVuIGZvciBlYWNoIG1lZGlhIGxpbmUsIGZvbGxvdyB0aGUgaW5uZXJPcmRlclxuICBzZXNzaW9uLm1lZGlhLmZvckVhY2goZnVuY3Rpb24gKG1MaW5lKSB7XG4gICAgc2RwLnB1c2gobWFrZUxpbmUoJ20nLCBncmFtbWFyLm1bMF0sIG1MaW5lKSk7XG5cbiAgICBpbm5lck9yZGVyLmZvckVhY2goZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgIGdyYW1tYXJbdHlwZV0uZm9yRWFjaChmdW5jdGlvbiAob2JqKSB7XG4gICAgICAgIGlmIChvYmoubmFtZSBpbiBtTGluZSAmJiBtTGluZVtvYmoubmFtZV0gIT0gbnVsbCkge1xuICAgICAgICAgIHNkcC5wdXNoKG1ha2VMaW5lKHR5cGUsIG9iaiwgbUxpbmUpKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChvYmoucHVzaCBpbiBtTGluZSAmJiBtTGluZVtvYmoucHVzaF0gIT0gbnVsbCkge1xuICAgICAgICAgIG1MaW5lW29iai5wdXNoXS5mb3JFYWNoKGZ1bmN0aW9uIChlbCkge1xuICAgICAgICAgICAgc2RwLnB1c2gobWFrZUxpbmUodHlwZSwgb2JqLCBlbCkpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgcmV0dXJuIHNkcC5qb2luKCdcXHJcXG4nKSArICdcXHJcXG4nO1xufTtcbiIsIi8qIENvcHlyaWdodCBAIDIwMTUgQXRsYXNzaWFuIFB0eSBMdGRcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBhcnJheUVxdWFscyhhcnJheSkge1xuICAgIC8vIGlmIHRoZSBvdGhlciBhcnJheSBpcyBhIGZhbHN5IHZhbHVlLCByZXR1cm5cbiAgICBpZiAoIWFycmF5KVxuICAgICAgICByZXR1cm4gZmFsc2U7XG5cbiAgICAvLyBjb21wYXJlIGxlbmd0aHMgLSBjYW4gc2F2ZSBhIGxvdCBvZiB0aW1lXG4gICAgaWYgKHRoaXMubGVuZ3RoICE9IGFycmF5Lmxlbmd0aClcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuXG4gICAgZm9yICh2YXIgaSA9IDAsIGwgPSB0aGlzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICAvLyBDaGVjayBpZiB3ZSBoYXZlIG5lc3RlZCBhcnJheXNcbiAgICAgICAgaWYgKHRoaXNbaV0gaW5zdGFuY2VvZiBBcnJheSAmJiBhcnJheVtpXSBpbnN0YW5jZW9mIEFycmF5KSB7XG4gICAgICAgICAgICAvLyByZWN1cnNlIGludG8gdGhlIG5lc3RlZCBhcnJheXNcbiAgICAgICAgICAgIGlmICghYXJyYXlFcXVhbHMuYXBwbHkodGhpc1tpXSwgW2FycmF5W2ldXSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXNbaV0gIT0gYXJyYXlbaV0pIHtcbiAgICAgICAgICAgIC8vIFdhcm5pbmcgLSB0d28gZGlmZmVyZW50IG9iamVjdCBpbnN0YW5jZXMgd2lsbCBuZXZlciBiZSBlcXVhbDpcbiAgICAgICAgICAgIC8vIHt4OjIwfSAhPSB7eDoyMH1cbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn07XG5cbiIsIi8qIENvcHlyaWdodCBAIDIwMTUgQXRsYXNzaWFuIFB0eSBMdGRcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuZXhwb3J0cy5JbnRlcm9wID0gcmVxdWlyZSgnLi9pbnRlcm9wJyk7XG4iLCIvKiBDb3B5cmlnaHQgQCAyMDE1IEF0bGFzc2lhbiBQdHkgTHRkXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbi8qIGdsb2JhbCBSVENTZXNzaW9uRGVzY3JpcHRpb24gKi9cbi8qIGdsb2JhbCBSVENJY2VDYW5kaWRhdGUgKi9cbi8qIGpzaGludCAtVzA5NyAqL1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciB0cmFuc2Zvcm0gPSByZXF1aXJlKCcuL3RyYW5zZm9ybScpO1xudmFyIGFycmF5RXF1YWxzID0gcmVxdWlyZSgnLi9hcnJheS1lcXVhbHMnKTtcblxuZnVuY3Rpb24gSW50ZXJvcCgpIHtcblxuICAgIC8qKlxuICAgICAqIFRoaXMgbWFwIGhvbGRzIHRoZSBtb3N0IHJlY2VudCBVbmlmaWVkIFBsYW4gb2ZmZXIvYW5zd2VyIFNEUCB0aGF0IHdhc1xuICAgICAqIGNvbnZlcnRlZCB0byBQbGFuIEIsIHdpdGggdGhlIFNEUCB0eXBlICgnb2ZmZXInIG9yICdhbnN3ZXInKSBhcyBrZXlzIGFuZFxuICAgICAqIHRoZSBTRFAgc3RyaW5nIGFzIHZhbHVlcy5cbiAgICAgKlxuICAgICAqIEB0eXBlIHt7fX1cbiAgICAgKi9cbiAgICB0aGlzLmNhY2hlID0ge1xuICAgICAgICBtbEIyVU1hcCA6IHt9LFxuICAgICAgICBtbFUyQk1hcCA6IHt9XG4gICAgfTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBJbnRlcm9wO1xuXG4vKipcbiAqIENoYW5nZXMgdGhlIGNhbmRpZGF0ZSBhcmdzIHRvIG1hdGNoIHdpdGggdGhlIHJlbGF0ZWQgVW5pZmllZCBQbGFuXG4gKi9cbkludGVyb3AucHJvdG90eXBlLmNhbmRpZGF0ZVRvVW5pZmllZFBsYW4gPSBmdW5jdGlvbihjYW5kaWRhdGUpIHtcbiAgICB2YXIgY2FuZCA9IG5ldyBSVENJY2VDYW5kaWRhdGUoY2FuZGlkYXRlKTtcblxuICAgIGNhbmQuc2RwTUxpbmVJbmRleCA9IHRoaXMuY2FjaGUubWxCMlVNYXBbY2FuZC5zZHBNTGluZUluZGV4XTtcbiAgICAvKiBUT0RPOiBjaGFuZ2Ugc2RwTWlkIHRvIChhdWRpb3x2aWRlbyktU1NSQyAqL1xuXG4gICAgcmV0dXJuIGNhbmQ7XG59O1xuXG4vKipcbiAqIENoYW5nZXMgdGhlIGNhbmRpZGF0ZSBhcmdzIHRvIG1hdGNoIHdpdGggdGhlIHJlbGF0ZWQgUGxhbiBCXG4gKi9cbkludGVyb3AucHJvdG90eXBlLmNhbmRpZGF0ZVRvUGxhbkIgPSBmdW5jdGlvbihjYW5kaWRhdGUpIHtcbiAgICB2YXIgY2FuZCA9IG5ldyBSVENJY2VDYW5kaWRhdGUoY2FuZGlkYXRlKTtcblxuICAgIGlmIChjYW5kLnNkcE1pZC5pbmRleE9mKCdhdWRpbycpID09PSAwKSB7XG4gICAgICBjYW5kLnNkcE1pZCA9ICdhdWRpbyc7XG4gICAgfSBlbHNlIGlmIChjYW5kLnNkcE1pZC5pbmRleE9mKCd2aWRlbycpID09PSAwKSB7XG4gICAgICBjYW5kLnNkcE1pZCA9ICd2aWRlbyc7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY2FuZGlkYXRlIHdpdGggJyArIGNhbmQuc2RwTWlkICsgJyBub3QgYWxsb3dlZCcpO1xuICAgIH1cblxuICAgIGNhbmQuc2RwTUxpbmVJbmRleCA9IHRoaXMuY2FjaGUubWxVMkJNYXBbY2FuZC5zZHBNTGluZUluZGV4XTtcblxuICAgIHJldHVybiBjYW5kO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBpbmRleCBvZiB0aGUgZmlyc3QgbS1saW5lIHdpdGggdGhlIGdpdmVuIG1lZGlhIHR5cGUgYW5kIHdpdGggYVxuICogZGlyZWN0aW9uIHdoaWNoIGFsbG93cyBzZW5kaW5nLCBpbiB0aGUgbGFzdCBVbmlmaWVkIFBsYW4gZGVzY3JpcHRpb24gd2l0aFxuICogdHlwZSBcImFuc3dlclwiIGNvbnZlcnRlZCB0byBQbGFuIEIuIFJldHVybnMge251bGx9IGlmIHRoZXJlIGlzIG5vIHNhdmVkXG4gKiBhbnN3ZXIsIG9yIGlmIG5vbmUgb2YgaXRzIG0tbGluZXMgd2l0aCB0aGUgZ2l2ZW4gdHlwZSBhbGxvdyBzZW5kaW5nLlxuICogQHBhcmFtIHR5cGUgdGhlIG1lZGlhIHR5cGUgKFwiYXVkaW9cIiBvciBcInZpZGVvXCIpLlxuICogQHJldHVybnMgeyp9XG4gKi9cbkludGVyb3AucHJvdG90eXBlLmdldEZpcnN0U2VuZGluZ0luZGV4RnJvbUFuc3dlciA9IGZ1bmN0aW9uKHR5cGUpIHtcbiAgICBpZiAoIXRoaXMuY2FjaGUuYW5zd2VyKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHZhciBzZXNzaW9uID0gdHJhbnNmb3JtLnBhcnNlKHRoaXMuY2FjaGUuYW5zd2VyKTtcbiAgICBpZiAoc2Vzc2lvbiAmJiBzZXNzaW9uLm1lZGlhICYmIEFycmF5LmlzQXJyYXkoc2Vzc2lvbi5tZWRpYSkpe1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlc3Npb24ubWVkaWEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChzZXNzaW9uLm1lZGlhW2ldLnR5cGUgPT0gdHlwZSAmJlxuICAgICAgICAgICAgICAgICghc2Vzc2lvbi5tZWRpYVtpXS5kaXJlY3Rpb24gLyogZGVmYXVsdCB0byBzZW5kcmVjdiAqLyB8fFxuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uLm1lZGlhW2ldLmRpcmVjdGlvbiA9PT0gJ3NlbmRyZWN2JyB8fFxuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uLm1lZGlhW2ldLmRpcmVjdGlvbiA9PT0gJ3NlbmRvbmx5Jykpe1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHRyYW5zZm9ybXMgYSBVbmlmaWVkIFBsYW4gU0RQIHRvIGFuIGVxdWl2YWxlbnQgUGxhbiBCIFNEUC4gQVxuICogUGVlckNvbm5lY3Rpb24gd3JhcHBlciB0cmFuc2Zvcm1zIHRoZSBTRFAgdG8gUGxhbiBCIGJlZm9yZSBwYXNzaW5nIGl0IHRvIHRoZVxuICogYXBwbGljYXRpb24uXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHsqfVxuICovXG5JbnRlcm9wLnByb3RvdHlwZS50b1BsYW5CID0gZnVuY3Rpb24oZGVzYykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAvLyNyZWdpb24gUHJlbGltaW5hcnkgaW5wdXQgdmFsaWRhdGlvbi5cblxuICAgIGlmICh0eXBlb2YgZGVzYyAhPT0gJ29iamVjdCcgfHwgZGVzYyA9PT0gbnVsbCB8fFxuICAgICAgICB0eXBlb2YgZGVzYy5zZHAgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignQW4gZW1wdHkgZGVzY3JpcHRpb24gd2FzIHBhc3NlZCBhcyBhbiBhcmd1bWVudC4nKTtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfVxuXG4gICAgLy8gT2JqZWN0aWZ5IHRoZSBTRFAgZm9yIGVhc2llciBtYW5pcHVsYXRpb24uXG4gICAgdmFyIHNlc3Npb24gPSB0cmFuc2Zvcm0ucGFyc2UoZGVzYy5zZHApO1xuXG4gICAgLy8gSWYgdGhlIFNEUCBjb250YWlucyBubyBtZWRpYSwgdGhlcmUncyBub3RoaW5nIHRvIHRyYW5zZm9ybS5cbiAgICBpZiAodHlwZW9mIHNlc3Npb24ubWVkaWEgPT09ICd1bmRlZmluZWQnIHx8XG4gICAgICAgICFBcnJheS5pc0FycmF5KHNlc3Npb24ubWVkaWEpIHx8IHNlc3Npb24ubWVkaWEubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignVGhlIGRlc2NyaXB0aW9uIGhhcyBubyBtZWRpYS4nKTtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfVxuXG4gICAgLy8gVHJ5IHNvbWUgaGV1cmlzdGljcyB0byBcIm1ha2Ugc3VyZVwiIHRoaXMgaXMgYSBVbmlmaWVkIFBsYW4gU0RQLiBQbGFuIEJcbiAgICAvLyBTRFAgaGFzIGEgdmlkZW8sIGFuIGF1ZGlvIGFuZCBhIGRhdGEgXCJjaGFubmVsXCIgYXQgbW9zdC5cbiAgICBpZiAoc2Vzc2lvbi5tZWRpYS5sZW5ndGggPD0gMyAmJiBzZXNzaW9uLm1lZGlhLmV2ZXJ5KGZ1bmN0aW9uKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBbJ3ZpZGVvJywgJ2F1ZGlvJywgJ2RhdGEnXS5pbmRleE9mKG0ubWlkKSAhPT0gLTE7XG4gICAgICAgIH0pKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignVGhpcyBkZXNjcmlwdGlvbiBkb2VzIG5vdCBsb29rIGxpa2UgVW5pZmllZCBQbGFuLicpO1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICAvLyNlbmRyZWdpb25cblxuICAgIC8vIEhBQ0sgaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MTExMzQ0M1xuICAgIHZhciBzZHAgPSBkZXNjLnNkcDtcbiAgICB2YXIgcmV3cml0ZSA9IGZhbHNlO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2Vzc2lvbi5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgdUxpbmUgPSBzZXNzaW9uLm1lZGlhW2ldO1xuICAgICAgICB1TGluZS5ydHAuZm9yRWFjaChmdW5jdGlvbihydHApIHtcbiAgICAgICAgICAgIGlmIChydHAuY29kZWMgPT09ICdOVUxMJylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICByZXdyaXRlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB2YXIgb2ZmZXIgPSB0cmFuc2Zvcm0ucGFyc2Uoc2VsZi5jYWNoZS5vZmZlcik7XG4gICAgICAgICAgICAgICAgcnRwLmNvZGVjID0gb2ZmZXIubWVkaWFbaV0ucnRwWzBdLmNvZGVjO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgaWYgKHJld3JpdGUpIHtcbiAgICAgICAgc2RwID0gdHJhbnNmb3JtLndyaXRlKHNlc3Npb24pO1xuICAgIH1cblxuICAgIC8vIFVuaWZpZWQgUGxhbiBTRFAgaXMgb3VyIFwicHJlY2lvdXNcIi4gQ2FjaGUgaXQgZm9yIGxhdGVyIHVzZSBpbiB0aGUgUGxhbiBCXG4gICAgLy8gLT4gVW5pZmllZCBQbGFuIHRyYW5zZm9ybWF0aW9uLlxuICAgIHRoaXMuY2FjaGVbZGVzYy50eXBlXSA9IHNkcDtcblxuICAgIC8vI3JlZ2lvbiBDb252ZXJ0IGZyb20gVW5pZmllZCBQbGFuIHRvIFBsYW4gQi5cblxuICAgIC8vIFdlIHJlYnVpbGQgdGhlIHNlc3Npb24ubWVkaWEgYXJyYXkuXG4gICAgdmFyIG1lZGlhID0gc2Vzc2lvbi5tZWRpYTtcbiAgICBzZXNzaW9uLm1lZGlhID0gW107XG5cbiAgICAvLyBBc3NvY2lhdGl2ZSBhcnJheSB0aGF0IG1hcHMgY2hhbm5lbCB0eXBlcyB0byBjaGFubmVsIG9iamVjdHMgZm9yIGZhc3RcbiAgICAvLyBhY2Nlc3MgdG8gY2hhbm5lbCBvYmplY3RzIGJ5IHRoZWlyIHR5cGUsIGUuZy4gdHlwZTJibFsnYXVkaW8nXS0+Y2hhbm5lbFxuICAgIC8vIG9iai5cbiAgICB2YXIgdHlwZTJibCA9IHt9O1xuXG4gICAgLy8gVXNlZCB0byBidWlsZCB0aGUgZ3JvdXA6QlVORExFIHZhbHVlIGFmdGVyIHRoZSBjaGFubmVscyBjb25zdHJ1Y3Rpb25cbiAgICAvLyBsb29wLlxuICAgIHZhciB0eXBlcyA9IFtdO1xuXG4gICAgbWVkaWEuZm9yRWFjaChmdW5jdGlvbih1TGluZSkge1xuICAgICAgICAvLyBydGNwLW11eCBpcyByZXF1aXJlZCBpbiB0aGUgUGxhbiBCIFNEUC5cbiAgICAgICAgaWYgKCh0eXBlb2YgdUxpbmUucnRjcE11eCAhPT0gJ3N0cmluZycgfHxcbiAgICAgICAgICAgIHVMaW5lLnJ0Y3BNdXggIT09ICdydGNwLW11eCcpICYmXG4gICAgICAgICAgICB1TGluZS5kaXJlY3Rpb24gIT09ICdpbmFjdGl2ZScpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IGNvbnZlcnQgdG8gUGxhbiBCIGJlY2F1c2UgbS1saW5lcyAnICtcbiAgICAgICAgICAgICAgICAnd2l0aG91dCB0aGUgcnRjcC1tdXggYXR0cmlidXRlIHdlcmUgZm91bmQuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiB3ZSBkb24ndCBoYXZlIGEgY2hhbm5lbCBmb3IgdGhpcyB1TGluZS50eXBlIE9SIHRoZSBzZWxlY3RlZCBpc1xuICAgICAgICAvLyBpbmFjdGl2ZSwgdGhlbiBzZWxlY3QgdGhpcyB1TGluZSBhcyB0aGUgY2hhbm5lbCBiYXNpcy5cbiAgICAgICAgaWYgKHR5cGVvZiB0eXBlMmJsW3VMaW5lLnR5cGVdID09PSAndW5kZWZpbmVkJyB8fFxuICAgICAgICAgICAgdHlwZTJibFt1TGluZS50eXBlXS5kaXJlY3Rpb24gPT09ICdpbmFjdGl2ZScpIHtcbiAgICAgICAgICAgIHR5cGUyYmxbdUxpbmUudHlwZV0gPSB1TGluZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh1TGluZS5wcm90b2NvbCAhPSB0eXBlMmJsW3VMaW5lLnR5cGVdLnByb3RvY29sKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgY29udmVydCB0byBQbGFuIEIgYmVjYXVzZSBtLWxpbmVzICcgK1xuICAgICAgICAgICAgICAnaGF2ZSBkaWZmZXJlbnQgcHJvdG9jb2xzIGFuZCB0aGlzIGxpYnJhcnkgZG9lcyBub3QgaGF2ZSAnICtcbiAgICAgICAgICAgICAgJ3N1cHBvcnQgZm9yIHRoYXQnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh1TGluZS5wYXlsb2FkcyAhPSB0eXBlMmJsW3VMaW5lLnR5cGVdLnBheWxvYWRzKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgY29udmVydCB0byBQbGFuIEIgYmVjYXVzZSBtLWxpbmVzICcgK1xuICAgICAgICAgICAgICAnaGF2ZSBkaWZmZXJlbnQgcGF5bG9hZHMgYW5kIHRoaXMgbGlicmFyeSBkb2VzIG5vdCBoYXZlICcgK1xuICAgICAgICAgICAgICAnc3VwcG9ydCBmb3IgdGhhdCcpO1xuICAgICAgICB9XG5cbiAgICB9KTtcblxuICAgIC8vIEltcGxvZGUgdGhlIFVuaWZpZWQgUGxhbiBtLWxpbmVzL3RyYWNrcyBpbnRvIFBsYW4gQiBjaGFubmVscy5cbiAgICBtZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKHVMaW5lKSB7XG4gICAgICAgIGlmICh1TGluZS50eXBlID09PSAnYXBwbGljYXRpb24nKSB7XG4gICAgICAgICAgICBzZXNzaW9uLm1lZGlhLnB1c2godUxpbmUpO1xuICAgICAgICAgICAgdHlwZXMucHVzaCh1TGluZS5taWQpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQWRkIHNvdXJjZXMgdG8gdGhlIGNoYW5uZWwgYW5kIGhhbmRsZSBhPW1zaWQuXG4gICAgICAgIGlmICh0eXBlb2YgdUxpbmUuc291cmNlcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIE9iamVjdC5rZXlzKHVMaW5lLnNvdXJjZXMpLmZvckVhY2goZnVuY3Rpb24oc3NyYykge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdHlwZTJibFt1TGluZS50eXBlXS5zb3VyY2VzICE9PSAnb2JqZWN0JylcbiAgICAgICAgICAgICAgICAgICAgdHlwZTJibFt1TGluZS50eXBlXS5zb3VyY2VzID0ge307XG5cbiAgICAgICAgICAgICAgICAvLyBBc3NpZ24gdGhlIHNvdXJjZXMgdG8gdGhlIGNoYW5uZWwuXG4gICAgICAgICAgICAgICAgdHlwZTJibFt1TGluZS50eXBlXS5zb3VyY2VzW3NzcmNdID1cbiAgICAgICAgICAgICAgICAgICAgdUxpbmUuc291cmNlc1tzc3JjXTtcblxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdUxpbmUubXNpZCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gSW4gUGxhbiBCIHRoZSBtc2lkIGlzIGFuIFNTUkMgYXR0cmlidXRlLiBBbHNvLCB3ZSBkb24ndFxuICAgICAgICAgICAgICAgICAgICAvLyBjYXJlIGFib3V0IHRoZSBvYnNvbGV0ZSBsYWJlbCBhbmQgbXNsYWJlbCBhdHRyaWJ1dGVzLlxuICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAvLyBOb3RlIHRoYXQgaXQgaXMgbm90IGd1YXJhbnRlZWQgdGhhdCB0aGUgdUxpbmUgd2lsbFxuICAgICAgICAgICAgICAgICAgICAvLyBoYXZlIGFuIG1zaWQuIHJlY3Zvbmx5IGNoYW5uZWxzIGluIHBhcnRpY3VsYXIgZG9uJ3QgaGF2ZVxuICAgICAgICAgICAgICAgICAgICAvLyBvbmUuXG4gICAgICAgICAgICAgICAgICAgIHR5cGUyYmxbdUxpbmUudHlwZV0uc291cmNlc1tzc3JjXS5tc2lkID1cbiAgICAgICAgICAgICAgICAgICAgICAgIHVMaW5lLm1zaWQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIE5PVEUgc3NyY3MgaW4gc3NyYyBncm91cHMgd2lsbCBzaGFyZSBtc2lkcywgYXNcbiAgICAgICAgICAgICAgICAvLyBkcmFmdC11YmVydGktcnRjd2ViLXBsYW4tMDAgbWFuZGF0ZXMuXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFkZCBzc3JjIGdyb3VwcyB0byB0aGUgY2hhbm5lbC5cbiAgICAgICAgaWYgKHR5cGVvZiB1TGluZS5zc3JjR3JvdXBzICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgICAgIEFycmF5LmlzQXJyYXkodUxpbmUuc3NyY0dyb3VwcykpIHtcblxuICAgICAgICAgICAgLy8gQ3JlYXRlIHRoZSBzc3JjR3JvdXBzIGFycmF5LCBpZiBpdCdzIG5vdCBkZWZpbmVkLlxuICAgICAgICAgICAgaWYgKHR5cGVvZiB0eXBlMmJsW3VMaW5lLnR5cGVdLnNzcmNHcm91cHMgPT09ICd1bmRlZmluZWQnIHx8XG4gICAgICAgICAgICAgICAgICAgICFBcnJheS5pc0FycmF5KHR5cGUyYmxbdUxpbmUudHlwZV0uc3NyY0dyb3VwcykpIHtcbiAgICAgICAgICAgICAgICB0eXBlMmJsW3VMaW5lLnR5cGVdLnNzcmNHcm91cHMgPSBbXTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdHlwZTJibFt1TGluZS50eXBlXS5zc3JjR3JvdXBzID1cbiAgICAgICAgICAgICAgICB0eXBlMmJsW3VMaW5lLnR5cGVdLnNzcmNHcm91cHMuY29uY2F0KFxuICAgICAgICAgICAgICAgICAgICB1TGluZS5zc3JjR3JvdXBzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlMmJsW3VMaW5lLnR5cGVdID09PSB1TGluZSkge1xuICAgICAgICAgICAgLy8gUGxhbiBCIG1pZHMgYXJlIGluIFsnYXVkaW8nLCAndmlkZW8nLCAnZGF0YSddXG4gICAgICAgICAgICB1TGluZS5taWQgPSB1TGluZS50eXBlO1xuXG4gICAgICAgICAgICAvLyBQbGFuIEIgZG9lc24ndCBzdXBwb3J0L25lZWQgdGhlIGJ1bmRsZS1vbmx5IGF0dHJpYnV0ZS5cbiAgICAgICAgICAgIGRlbGV0ZSB1TGluZS5idW5kbGVPbmx5O1xuXG4gICAgICAgICAgICAvLyBJbiBQbGFuIEIgdGhlIG1zaWQgaXMgYW4gU1NSQyBhdHRyaWJ1dGUuXG4gICAgICAgICAgICBkZWxldGUgdUxpbmUubXNpZDtcblxuXHQgICAgaWYgKHVMaW5lLnR5cGUgPT0gbWVkaWFbMF0udHlwZSkge1xuXHQgICAgICB0eXBlcy51bnNoaWZ0KHVMaW5lLnR5cGUpO1xuXHQgICAgICAvLyBBZGQgdGhlIGNoYW5uZWwgdG8gdGhlIG5ldyBtZWRpYSBhcnJheS5cblx0ICAgICAgc2Vzc2lvbi5tZWRpYS51bnNoaWZ0KHVMaW5lKTtcblx0ICAgIH0gZWxzZSB7XG5cdCAgICAgIHR5cGVzLnB1c2godUxpbmUudHlwZSk7XG5cdCAgICAgIC8vIEFkZCB0aGUgY2hhbm5lbCB0byB0aGUgbmV3IG1lZGlhIGFycmF5LlxuXHQgICAgICBzZXNzaW9uLm1lZGlhLnB1c2godUxpbmUpO1xuXHQgICAgfVxuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICBpZiAodHlwZW9mIHNlc3Npb24uZ3JvdXBzICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgLy8gV2UgcmVnZW5lcmF0ZSB0aGUgQlVORExFIGdyb3VwIHdpdGggdGhlIG5ldyBtaWRzLlxuICAgICAgc2Vzc2lvbi5ncm91cHMuc29tZShmdW5jdGlvbihncm91cCkge1xuXHQgIGlmIChncm91cC50eXBlID09PSAnQlVORExFJykge1xuXHQgICAgICBncm91cC5taWRzID0gdHlwZXMuam9pbignICcpO1xuXHQgICAgICByZXR1cm4gdHJ1ZTtcblx0ICB9XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBtc2lkIHNlbWFudGljXG4gICAgc2Vzc2lvbi5tc2lkU2VtYW50aWMgPSB7XG4gICAgICAgIHNlbWFudGljOiAnV01TJyxcbiAgICAgICAgdG9rZW46ICcqJ1xuICAgIH07XG5cbiAgICB2YXIgcmVzU3RyID0gdHJhbnNmb3JtLndyaXRlKHNlc3Npb24pO1xuXG4gICAgcmV0dXJuIG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgICB0eXBlOiBkZXNjLnR5cGUsXG4gICAgICAgIHNkcDogcmVzU3RyXG4gICAgfSk7XG5cbiAgICAvLyNlbmRyZWdpb25cbn07XG5cbi8qIGZvbGxvdyBydWxlcyBkZWZpbmVkIGluIFJGQzQxNDUgKi9cbmZ1bmN0aW9uIGFkZFNldHVwQXR0cih1TGluZSkge1xuICAgIGlmICh0eXBlb2YgdUxpbmUuc2V0dXAgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodUxpbmUuc2V0dXAgPT09IFwiYWN0aXZlXCIpIHtcbiAgICAgICAgICAgIHVMaW5lLnNldHVwID0gXCJwYXNzaXZlXCI7XG4gICAgfSBlbHNlIGlmICh1TGluZS5zZXR1cCA9PT0gXCJwYXNzaXZlXCIpIHtcbiAgICAgICAgdUxpbmUuc2V0dXAgPSBcImFjdGl2ZVwiO1xuICAgIH1cbn1cblxuLyoqXG4gKiBUaGlzIG1ldGhvZCB0cmFuc2Zvcm1zIGEgUGxhbiBCIFNEUCB0byBhbiBlcXVpdmFsZW50IFVuaWZpZWQgUGxhbiBTRFAuIEFcbiAqIFBlZXJDb25uZWN0aW9uIHdyYXBwZXIgdHJhbnNmb3JtcyB0aGUgU0RQIHRvIFVuaWZpZWQgUGxhbiBiZWZvcmUgcGFzc2luZyBpdFxuICogdG8gRkYuXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHsqfVxuICovXG5JbnRlcm9wLnByb3RvdHlwZS50b1VuaWZpZWRQbGFuID0gZnVuY3Rpb24oZGVzYykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAvLyNyZWdpb24gUHJlbGltaW5hcnkgaW5wdXQgdmFsaWRhdGlvbi5cblxuICAgIGlmICh0eXBlb2YgZGVzYyAhPT0gJ29iamVjdCcgfHwgZGVzYyA9PT0gbnVsbCB8fFxuICAgICAgICB0eXBlb2YgZGVzYy5zZHAgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignQW4gZW1wdHkgZGVzY3JpcHRpb24gd2FzIHBhc3NlZCBhcyBhbiBhcmd1bWVudC4nKTtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfVxuXG4gICAgdmFyIHNlc3Npb24gPSB0cmFuc2Zvcm0ucGFyc2UoZGVzYy5zZHApO1xuXG4gICAgLy8gSWYgdGhlIFNEUCBjb250YWlucyBubyBtZWRpYSwgdGhlcmUncyBub3RoaW5nIHRvIHRyYW5zZm9ybS5cbiAgICBpZiAodHlwZW9mIHNlc3Npb24ubWVkaWEgPT09ICd1bmRlZmluZWQnIHx8XG4gICAgICAgICFBcnJheS5pc0FycmF5KHNlc3Npb24ubWVkaWEpIHx8IHNlc3Npb24ubWVkaWEubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignVGhlIGRlc2NyaXB0aW9uIGhhcyBubyBtZWRpYS4nKTtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfVxuXG4gICAgLy8gVHJ5IHNvbWUgaGV1cmlzdGljcyB0byBcIm1ha2Ugc3VyZVwiIHRoaXMgaXMgYSBQbGFuIEIgU0RQLiBQbGFuIEIgU0RQIGhhc1xuICAgIC8vIGEgdmlkZW8sIGFuIGF1ZGlvIGFuZCBhIGRhdGEgXCJjaGFubmVsXCIgYXQgbW9zdC5cbiAgICBpZiAoc2Vzc2lvbi5tZWRpYS5sZW5ndGggPiAzIHx8ICFzZXNzaW9uLm1lZGlhLmV2ZXJ5KGZ1bmN0aW9uKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBbJ3ZpZGVvJywgJ2F1ZGlvJywgJ2RhdGEnXS5pbmRleE9mKG0ubWlkKSAhPT0gLTE7XG4gICAgICAgIH0pKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignVGhpcyBkZXNjcmlwdGlvbiBkb2VzIG5vdCBsb29rIGxpa2UgUGxhbiBCLicpO1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICAvLyBNYWtlIHN1cmUgdGhpcyBQbGFuIEIgU0RQIGNhbiBiZSBjb252ZXJ0ZWQgdG8gYSBVbmlmaWVkIFBsYW4gU0RQLlxuICAgIHZhciBtaWRzID0gW107XG4gICAgc2Vzc2lvbi5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKG0pIHtcbiAgICAgICAgbWlkcy5wdXNoKG0ubWlkKTtcbiAgICB9KTtcblxuICAgIHZhciBoYXNCdW5kbGUgPSBmYWxzZTtcbiAgICBpZiAodHlwZW9mIHNlc3Npb24uZ3JvdXBzICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICBBcnJheS5pc0FycmF5KHNlc3Npb24uZ3JvdXBzKSkge1xuICAgICAgICBoYXNCdW5kbGUgPSBzZXNzaW9uLmdyb3Vwcy5ldmVyeShmdW5jdGlvbihnKSB7XG4gICAgICAgICAgICByZXR1cm4gZy50eXBlICE9PSAnQlVORExFJyB8fFxuICAgICAgICAgICAgICAgIGFycmF5RXF1YWxzLmFwcGx5KGcubWlkcy5zb3J0KCksIFttaWRzLnNvcnQoKV0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAoIWhhc0J1bmRsZSkge1xuICAgICAgICB2YXIgbXVzdEJlQnVuZGxlID0gZmFsc2U7XG5cbiAgICAgICAgc2Vzc2lvbi5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKG0pIHtcbiAgICAgICAgICAgIGlmIChtLmRpcmVjdGlvbiAhPT0gJ2luYWN0aXZlJykge1xuICAgICAgICAgICAgICAgIG11c3RCZUJ1bmRsZSA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChtdXN0QmVCdW5kbGUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNhbm5vdCBjb252ZXJ0IHRvIFVuaWZpZWQgUGxhbiBiZWNhdXNlIG0tbGluZXMgdGhhdFwiICtcbiAgICAgICAgICAgICAgXCIgYXJlIG5vdCBidW5kbGVkIHdlcmUgZm91bmQuXCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8jZW5kcmVnaW9uXG5cblxuICAgIC8vI3JlZ2lvbiBDb252ZXJ0IGZyb20gUGxhbiBCIHRvIFVuaWZpZWQgUGxhbi5cblxuICAgIC8vIFVuZm9ydHVuYXRlbHksIGEgUGxhbiBCIG9mZmVyL2Fuc3dlciBkb2Vzbid0IGhhdmUgZW5vdWdoIGluZm9ybWF0aW9uIHRvXG4gICAgLy8gcmVidWlsZCBhbiBlcXVpdmFsZW50IFVuaWZpZWQgUGxhbiBvZmZlci9hbnN3ZXIuXG4gICAgLy9cbiAgICAvLyBGb3IgZXhhbXBsZSwgaWYgdGhpcyBpcyBhIGxvY2FsIGFuc3dlciAoaW4gVW5pZmllZCBQbGFuIHN0eWxlKSB0aGF0IHdlXG4gICAgLy8gY29udmVydCB0byBQbGFuIEIgcHJpb3IgdG8gaGFuZGluZyBpdCBvdmVyIHRvIHRoZSBhcHBsaWNhdGlvbiAodGhlXG4gICAgLy8gUGVlckNvbm5lY3Rpb24gd3JhcHBlciBjYWxsZWQgdXMsIGZvciBpbnN0YW5jZSwgYWZ0ZXIgYSBzdWNjZXNzZnVsXG4gICAgLy8gY3JlYXRlQW5zd2VyKSwgd2Ugd2FudCB0byByZW1lbWJlciB0aGUgbS1saW5lIGF0IHdoaWNoIHdlJ3ZlIHNlZW4gdGhlXG4gICAgLy8gKGxvY2FsKSBTU1JDLiBUaGF0J3MgYmVjYXVzZSB3aGVuIHRoZSBhcHBsaWNhdGlvbiB3YW50cyB0byBkbyBjYWxsIHRoZVxuICAgIC8vIFNMRCBtZXRob2QsIGZvcmNpbmcgdXMgdG8gZG8gdGhlIGludmVyc2UgdHJhbnNmb3JtYXRpb24gKGZyb20gUGxhbiBCIHRvXG4gICAgLy8gVW5pZmllZCBQbGFuKSwgd2UgbmVlZCB0byBrbm93IHRvIHdoaWNoIG0tbGluZSB0byBhc3NpZ24gdGhlIChsb2NhbClcbiAgICAvLyBTU1JDLiBXZSBhbHNvIG5lZWQgdG8ga25vdyBhbGwgdGhlIG90aGVyIG0tbGluZXMgdGhhdCB0aGUgb3JpZ2luYWxcbiAgICAvLyBhbnN3ZXIgaGFkIGFuZCBpbmNsdWRlIHRoZW0gaW4gdGhlIHRyYW5zZm9ybWVkIGFuc3dlciBhcyB3ZWxsLlxuICAgIC8vXG4gICAgLy8gQW5vdGhlciBleGFtcGxlIGlzIGlmIHRoaXMgaXMgYSByZW1vdGUgb2ZmZXIgdGhhdCB3ZSBjb252ZXJ0IHRvIFBsYW4gQlxuICAgIC8vIHByaW9yIHRvIGdpdmluZyBpdCB0byB0aGUgYXBwbGljYXRpb24sIHdlIHdhbnQgdG8gcmVtZW1iZXIgdGhlIG1pZCBhdFxuICAgIC8vIHdoaWNoIHdlJ3ZlIHNlZW4gdGhlIChyZW1vdGUpIFNTUkMuXG4gICAgLy9cbiAgICAvLyBJbiB0aGUgaXRlcmF0aW9uIHRoYXQgZm9sbG93cywgd2UgdXNlIHRoZSBjYWNoZWQgVW5pZmllZCBQbGFuIChpZiBpdFxuICAgIC8vIGV4aXN0cykgdG8gYXNzaWduIG1pZHMgdG8gc3NyY3MuXG5cbiAgICB2YXIgdHlwZTtcbiAgICBpZiAoZGVzYy50eXBlID09PSAnYW5zd2VyJykge1xuICAgICAgICB0eXBlID0gJ29mZmVyJztcbiAgICB9IGVsc2UgaWYgKGRlc2MudHlwZSA9PT0gJ29mZmVyJykge1xuICAgICAgICB0eXBlID0gJ2Fuc3dlcic7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVHlwZSAnXCIgKyBkZXNjLnR5cGUgKyBcIicgbm90IHN1cHBvcnRlZC5cIik7XG4gICAgfVxuXG4gICAgdmFyIGNhY2hlZDtcbiAgICBpZiAodHlwZW9mIHRoaXMuY2FjaGVbdHlwZV0gIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIGNhY2hlZCA9IHRyYW5zZm9ybS5wYXJzZSh0aGlzLmNhY2hlW3R5cGVdKTtcbiAgICB9XG5cbiAgICB2YXIgcmVjdm9ubHlTc3JjcyA9IHtcbiAgICAgICAgYXVkaW86IHt9LFxuICAgICAgICB2aWRlbzoge31cbiAgICB9O1xuXG4gICAgLy8gQSBoZWxwZXIgbWFwIHRoYXQgc2VuZHMgbWlkcyB0byBtLWxpbmUgb2JqZWN0cy4gV2UgdXNlIGl0IGxhdGVyIHRvXG4gICAgLy8gcmVidWlsZCB0aGUgVW5pZmllZCBQbGFuIHN0eWxlIHNlc3Npb24ubWVkaWEgYXJyYXkuXG4gICAgdmFyIG1pZDJ1bCA9IHt9O1xuICAgIHZhciBiSWR4ID0gMDtcbiAgICB2YXIgdUlkeCA9IDA7XG5cbiAgICB2YXIgc291cmNlczJ1bCA9IHt9O1xuXG4gICAgdmFyIGNhbmRpZGF0ZXM7XG4gICAgdmFyIGljZVVmcmFnO1xuICAgIHZhciBpY2VQd2Q7XG4gICAgdmFyIGZpbmdlcnByaW50O1xuICAgIHZhciBwYXlsb2FkcyA9IHt9O1xuICAgIHZhciBydGNwRmIgPSB7fTtcbiAgICB2YXIgcnRwID0ge307XG5cbiAgICBzZXNzaW9uLm1lZGlhLmZvckVhY2goZnVuY3Rpb24oYkxpbmUpIHtcbiAgICAgICAgaWYgKCh0eXBlb2YgYkxpbmUucnRjcE11eCAhPT0gJ3N0cmluZycgfHxcbiAgICAgICAgICAgIGJMaW5lLnJ0Y3BNdXggIT09ICdydGNwLW11eCcpICYmXG4gICAgICAgICAgICBiTGluZS5kaXJlY3Rpb24gIT09ICdpbmFjdGl2ZScpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNhbm5vdCBjb252ZXJ0IHRvIFVuaWZpZWQgUGxhbiBiZWNhdXNlIG0tbGluZXMgXCIgK1xuICAgICAgICAgICAgICAgIFwid2l0aG91dCB0aGUgcnRjcC1tdXggYXR0cmlidXRlIHdlcmUgZm91bmQuXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGJMaW5lLnR5cGUgPT09ICdhcHBsaWNhdGlvbicpIHtcbiAgICAgICAgICAgIG1pZDJ1bFtiTGluZS5taWRdID0gYkxpbmU7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBXaXRoIHJ0Y3AtbXV4IGFuZCBidW5kbGUgYWxsIHRoZSBjaGFubmVscyBzaG91bGQgaGF2ZSB0aGUgc2FtZSBJQ0VcbiAgICAgICAgLy8gc3R1ZmYuXG4gICAgICAgIHZhciBzb3VyY2VzID0gYkxpbmUuc291cmNlcztcbiAgICAgICAgdmFyIHNzcmNHcm91cHMgPSBiTGluZS5zc3JjR3JvdXBzO1xuICAgICAgICB2YXIgcG9ydCA9IGJMaW5lLnBvcnQ7XG5cbiAgICAgICAgLyogQ2hyb21lIGFkZHMgZGlmZmVyZW50IGNhbmRpZGF0ZXMgZXZlbiB1c2luZyBidW5kbGUsIHNvIHdlIGNvbmNhdCB0aGUgY2FuZGlkYXRlcyBsaXN0ICovXG4gICAgICAgIGlmICh0eXBlb2YgYkxpbmUuY2FuZGlkYXRlcyAhPSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBjYW5kaWRhdGVzICE9ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgY2FuZGlkYXRlcyA9IGNhbmRpZGF0ZXMuY29uY2F0KGJMaW5lLmNhbmRpZGF0ZXMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjYW5kaWRhdGVzID0gYkxpbmUuY2FuZGlkYXRlcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgodHlwZW9mIGljZVVmcmFnICE9ICd1bmRlZmluZWQnKSAmJiAodHlwZW9mIGJMaW5lLmljZVVmcmFnICE9ICd1bmRlZmluZWQnKSAmJiAoaWNlVWZyYWcgIT0gYkxpbmUuaWNlVWZyYWcpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJPbmx5IEJVTkRMRSBzdXBwb3J0ZWQsIGljZVVmcmFnIG11c3QgYmUgdGhlIHNhbWUgZm9yIGFsbCBtLWxpbmVzLlxcblwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIlxcdExhc3QgaWNlVWZyYWc6IFwiICsgaWNlVWZyYWcgKyBcIlxcblwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIlxcdE5ldyBpY2VVZnJhZzogXCIgKyBiTGluZS5pY2VVZnJhZ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgYkxpbmUuaWNlVWZyYWcgIT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICBpY2VVZnJhZyA9IGJMaW5lLmljZVVmcmFnO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCh0eXBlb2YgaWNlUHdkICE9ICd1bmRlZmluZWQnKSAmJiAodHlwZW9mIGJMaW5lLmljZVB3ZCAhPSAndW5kZWZpbmVkJykgJiYgKGljZVB3ZCAhPSBiTGluZS5pY2VQd2QpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJPbmx5IEJVTkRMRSBzdXBwb3J0ZWQsIGljZVB3ZCBtdXN0IGJlIHRoZSBzYW1lIGZvciBhbGwgbS1saW5lcy5cXG5cIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJcXHRMYXN0IGljZVB3ZDogXCIgKyBpY2VQd2QgKyBcIlxcblwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIlxcdE5ldyBpY2VQd2Q6IFwiICsgYkxpbmUuaWNlUHdkXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBiTGluZS5pY2VQd2QgIT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICBpY2VQd2QgPSBiTGluZS5pY2VQd2Q7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoKHR5cGVvZiBmaW5nZXJwcmludCAhPSAndW5kZWZpbmVkJykgJiYgKHR5cGVvZiBiTGluZS5maW5nZXJwcmludCAhPSAndW5kZWZpbmVkJykgJiZcbiAgICAgICAgICAgIChmaW5nZXJwcmludC50eXBlICE9IGJMaW5lLmZpbmdlcnByaW50LnR5cGUgfHwgZmluZ2VycHJpbnQuaGFzaCAhPSBiTGluZS5maW5nZXJwcmludC5oYXNoKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiT25seSBCVU5ETEUgc3VwcG9ydGVkLCBmaW5nZXJwcmludCBtdXN0IGJlIHRoZSBzYW1lIGZvciBhbGwgbS1saW5lcy5cXG5cIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJcXHRMYXN0IGZpbmdlcnByaW50OiBcIiArIEpTT04uc3RyaW5naWZ5KGZpbmdlcnByaW50KSArIFwiXFxuXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiXFx0TmV3IGZpbmdlcnByaW50OiBcIiArIEpTT04uc3RyaW5naWZ5KGJMaW5lLmZpbmdlcnByaW50KVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgYkxpbmUuZmluZ2VycHJpbnQgIT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICBmaW5nZXJwcmludCA9IGJMaW5lLmZpbmdlcnByaW50O1xuICAgICAgICB9XG5cbiAgICAgICAgcGF5bG9hZHNbYkxpbmUudHlwZV0gPSBiTGluZS5wYXlsb2FkcztcbiAgICAgICAgcnRjcEZiW2JMaW5lLnR5cGVdID0gYkxpbmUucnRjcEZiO1xuICAgICAgICBydHBbYkxpbmUudHlwZV0gPSBiTGluZS5ydHA7XG5cbiAgICAgICAgLy8gaW52ZXJ0ZWQgc3NyYyBncm91cCBtYXBcbiAgICAgICAgdmFyIHNzcmMyZ3JvdXAgPSB7fTtcbiAgICAgICAgaWYgKHR5cGVvZiBzc3JjR3JvdXBzICE9PSAndW5kZWZpbmVkJyAmJiBBcnJheS5pc0FycmF5KHNzcmNHcm91cHMpKSB7XG4gICAgICAgICAgICBzc3JjR3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKHNzcmNHcm91cCkge1xuICAgICAgICAgICAgICAgIC8vIFhYWCBUaGlzIG1pZ2h0IGJyYWtlIGlmIGFuIFNTUkMgaXMgaW4gbW9yZSB0aGFuIG9uZSBncm91cFxuICAgICAgICAgICAgICAgIC8vIGZvciBzb21lIHJlYXNvbi5cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHNzcmNHcm91cC5zc3JjcyAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgICAgICAgICAgICAgQXJyYXkuaXNBcnJheShzc3JjR3JvdXAuc3NyY3MpKSB7XG4gICAgICAgICAgICAgICAgICAgIHNzcmNHcm91cC5zc3Jjcy5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHNzcmMyZ3JvdXBbc3NyY10gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3NyYzJncm91cFtzc3JjXSA9IFtdO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBzc3JjMmdyb3VwW3NzcmNdLnB1c2goc3NyY0dyb3VwKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBzc3JjIHRvIG0tbGluZSBpbmRleC5cbiAgICAgICAgdmFyIHNzcmMybWwgPSB7fTtcblxuICAgICAgICBpZiAodHlwZW9mIHNvdXJjZXMgPT09ICdvYmplY3QnKSB7XG5cbiAgICAgICAgICAgIC8vIFdlJ2xsIHVzZSB0aGUgXCJiTGluZVwiIG9iamVjdCBhcyBhIHByb3RvdHlwZSBmb3IgZWFjaCBuZXcgXCJtTGluZVwiXG4gICAgICAgICAgICAvLyB0aGF0IHdlIGNyZWF0ZSwgYnV0IGZpcnN0IHdlIG5lZWQgdG8gY2xlYW4gaXQgdXAgYSBiaXQuXG4gICAgICAgICAgICBkZWxldGUgYkxpbmUuc291cmNlcztcbiAgICAgICAgICAgIGRlbGV0ZSBiTGluZS5zc3JjR3JvdXBzO1xuICAgICAgICAgICAgZGVsZXRlIGJMaW5lLmNhbmRpZGF0ZXM7XG4gICAgICAgICAgICBkZWxldGUgYkxpbmUuaWNlVWZyYWc7XG4gICAgICAgICAgICBkZWxldGUgYkxpbmUuaWNlUHdkO1xuICAgICAgICAgICAgZGVsZXRlIGJMaW5lLmZpbmdlcnByaW50O1xuICAgICAgICAgICAgZGVsZXRlIGJMaW5lLnBvcnQ7XG4gICAgICAgICAgICBkZWxldGUgYkxpbmUubWlkO1xuXG4gICAgICAgICAgICAvLyBFeHBsb2RlIHRoZSBQbGFuIEIgY2hhbm5lbCBzb3VyY2VzIHdpdGggb25lIG0tbGluZSBwZXIgc291cmNlLlxuICAgICAgICAgICAgT2JqZWN0LmtleXMoc291cmNlcykuZm9yRWFjaChmdW5jdGlvbihzc3JjKSB7XG5cbiAgICAgICAgICAgICAgICAvLyBUaGUgKHVuaWZpZWQpIG0tbGluZSBmb3IgdGhpcyBTU1JDLiBXZSBlaXRoZXIgY3JlYXRlIGl0IGZyb21cbiAgICAgICAgICAgICAgICAvLyBzY3JhdGNoIG9yLCBpZiBpdCdzIGEgZ3JvdXBlZCBTU1JDLCB3ZSByZS11c2UgYSByZWxhdGVkXG4gICAgICAgICAgICAgICAgLy8gbWxpbmUuIEluIG90aGVyIHdvcmRzLCBpZiB0aGUgc291cmNlIGlzIGdyb3VwZWQgd2l0aCBhbm90aGVyXG4gICAgICAgICAgICAgICAgLy8gc291cmNlLCBwdXQgdGhlIHR3byB0b2dldGhlciBpbiB0aGUgc2FtZSBtLWxpbmUuXG4gICAgICAgICAgICAgICAgdmFyIHVMaW5lO1xuXG4gICAgICAgICAgICAgICAgLy8gV2UgYXNzdW1lIGhlcmUgdGhhdCB3ZSBhcmUgdGhlIGFuc3dlcmVyIGluIHRoZSBPL0EsIHNvIGFueVxuICAgICAgICAgICAgICAgIC8vIG9mZmVycyB3aGljaCB3ZSB0cmFuc2xhdGUgY29tZSBmcm9tIHRoZSByZW1vdGUgc2lkZSwgd2hpbGVcbiAgICAgICAgICAgICAgICAvLyBhbnN3ZXJzIGFyZSBsb2NhbC4gU28gdGhlIGNoZWNrIGJlbG93IGlzIHRvIG1ha2UgdGhhdCB3ZVxuICAgICAgICAgICAgICAgIC8vIGhhbmRsZSByZWNlaXZlLW9ubHkgU1NSQ3MgaW4gYSBzcGVjaWFsIHdheSBvbmx5IGlmIHRoZXkgY29tZVxuICAgICAgICAgICAgICAgIC8vIGZyb20gdGhlIHJlbW90ZSBzaWRlLlxuICAgICAgICAgICAgICAgIGlmIChkZXNjLnR5cGU9PT0nb2ZmZXInKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFdlIHdhbnQgdG8gZGV0ZWN0IFNTUkNzIHdoaWNoIGFyZSB1c2VkIGJ5IGEgcmVtb3RlIHBlZXJcbiAgICAgICAgICAgICAgICAgICAgLy8gaW4gYW4gbS1saW5lIHdpdGggZGlyZWN0aW9uPXJlY3Zvbmx5IChpLmUuIHRoZXkgYXJlXG4gICAgICAgICAgICAgICAgICAgIC8vIGJlaW5nIHVzZWQgZm9yIFJUQ1Agb25seSkuXG4gICAgICAgICAgICAgICAgICAgIC8vIFRoaXMgaW5mb3JtYXRpb24gd291bGQgaGF2ZSBnb3R0ZW4gbG9zdCBpZiB0aGUgcmVtb3RlXG4gICAgICAgICAgICAgICAgICAgIC8vIHBlZXIgdXNlZCBVbmlmaWVkIFBsYW4gYW5kIHRoZWlyIGxvY2FsIGRlc2NyaXB0aW9uIHdhc1xuICAgICAgICAgICAgICAgICAgICAvLyB0cmFuc2xhdGVkIHRvIFBsYW4gQi4gU28gd2UgdXNlIHRoZSBsYWNrIG9mIGFuIE1TSURcbiAgICAgICAgICAgICAgICAgICAgLy8gYXR0cmlidXRlIHRvIGRlZHVjZSBhIFwicmVjZWl2ZSBvbmx5XCIgU1NSQy5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFzb3VyY2VzW3NzcmNdLm1zaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlY3Zvbmx5U3NyY3NbYkxpbmUudHlwZV1bc3NyY10gPSBzb3VyY2VzW3NzcmNdO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmVjZWl2ZS1vbmx5IFNTUkNzIG11c3Qgbm90IGNyZWF0ZSBuZXcgbS1saW5lcy4gV2VcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdpbGwgYXNzaWduIHRoZW0gdG8gYW4gZXhpc3RpbmcgbS1saW5lIGxhdGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBzc3JjMmdyb3VwW3NzcmNdICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgICAgICAgICBBcnJheS5pc0FycmF5KHNzcmMyZ3JvdXBbc3NyY10pKSB7XG4gICAgICAgICAgICAgICAgICAgIHNzcmMyZ3JvdXBbc3NyY10uc29tZShmdW5jdGlvbiAoc3NyY0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzc3JjR3JvdXAuc3NyY3MgKmlzKiBhbiBBcnJheSwgbm8gbmVlZCB0byBjaGVja1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdhaW4gaGVyZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBzc3JjR3JvdXAuc3NyY3Muc29tZShmdW5jdGlvbiAocmVsYXRlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2Ygc3NyYzJtbFtyZWxhdGVkXSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdUxpbmUgPSBzc3JjMm1sW3JlbGF0ZWRdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1TGluZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gdGhlIG0tbGluZSBhbHJlYWR5IGV4aXN0cy4gSnVzdCBhZGQgdGhlIHNvdXJjZS5cbiAgICAgICAgICAgICAgICAgICAgdUxpbmUuc291cmNlc1tzc3JjXSA9IHNvdXJjZXNbc3NyY107XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBzb3VyY2VzW3NzcmNdLm1zaWQ7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gVXNlIHRoZSBcImJMaW5lXCIgYXMgYSBwcm90b3R5cGUgZm9yIHRoZSBcInVMaW5lXCIuXG4gICAgICAgICAgICAgICAgICAgIHVMaW5lID0gT2JqZWN0LmNyZWF0ZShiTGluZSk7XG4gICAgICAgICAgICAgICAgICAgIHNzcmMybWxbc3NyY10gPSB1TGluZTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHNvdXJjZXNbc3NyY10ubXNpZCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFzc2lnbiB0aGUgbXNpZCBvZiB0aGUgc291cmNlIHRvIHRoZSBtLWxpbmUuIE5vdGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoYXQgaXQgaXMgbm90IGd1YXJhbnRlZWQgdGhhdCB0aGUgc291cmNlIHdpbGwgaGF2ZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbXNpZC4gSW4gcGFydGljdWxhciBcInJlY3Zvbmx5XCIgc291cmNlcyBkb24ndCBoYXZlIGFuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBtc2lkLiBOb3RlIHRoYXQgXCJyZWN2b25seVwiIGlzIGEgdGVybSBvbmx5IGRlZmluZWRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGZvciBtLWxpbmVzLlxuICAgICAgICAgICAgICAgICAgICAgICAgdUxpbmUubXNpZCA9IHNvdXJjZXNbc3NyY10ubXNpZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBzb3VyY2VzW3NzcmNdLm1zaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBXZSBhc3NpZ24gb25lIFNTUkMgcGVyIG1lZGlhIGxpbmUuXG4gICAgICAgICAgICAgICAgICAgIHVMaW5lLnNvdXJjZXMgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgdUxpbmUuc291cmNlc1tzc3JjXSA9IHNvdXJjZXNbc3NyY107XG4gICAgICAgICAgICAgICAgICAgIHVMaW5lLnNzcmNHcm91cHMgPSBzc3JjMmdyb3VwW3NzcmNdO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIFVzZSB0aGUgY2FjaGVkIFVuaWZpZWQgUGxhbiBTRFAgKGlmIGl0IGV4aXN0cykgdG8gYXNzaWduXG4gICAgICAgICAgICAgICAgICAgIC8vIFNTUkNzIHRvIG1pZHMuXG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgY2FjaGVkICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZW9mIGNhY2hlZC5tZWRpYSAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIEFycmF5LmlzQXJyYXkoY2FjaGVkLm1lZGlhKSkge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBjYWNoZWQubWVkaWEuZm9yRWFjaChmdW5jdGlvbiAobSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgbS5zb3VyY2VzID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBPYmplY3Qua2V5cyhtLnNvdXJjZXMpLmZvckVhY2goZnVuY3Rpb24gKHMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzID09PSBzc3JjKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdUxpbmUubWlkID0gbS5taWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1TGluZS5taWQgPT09ICd1bmRlZmluZWQnKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHRoaXMgaXMgYW4gU1NSQyB0aGF0IHdlIHNlZSBmb3IgdGhlIGZpcnN0IHRpbWVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFzc2lnbiBpdCBhIG5ldyBtaWQuIFRoaXMgaXMgdHlwaWNhbGx5IHRoZSBjYXNlIHdoZW5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoaXMgbWV0aG9kIGlzIGNhbGxlZCB0byB0cmFuc2Zvcm0gYSByZW1vdGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRlc2NyaXB0aW9uIGZvciB0aGUgZmlyc3QgdGltZSBvciB3aGVuIHRoZXJlIGlzIGFcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5ldyBTU1JDIGluIHRoZSByZW1vdGUgZGVzY3JpcHRpb24gYmVjYXVzZSBhIG5ld1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcGVlciBoYXMgam9pbmVkIHRoZSBjb25mZXJlbmNlLiBMb2NhbCBTU1JDcyBzaG91bGRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGhhdmUgYWxyZWFkeSBiZWVuIGFkZGVkIHRvIHRoZSBtYXAgaW4gdGhlIHRvUGxhbkJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1ldGhvZC5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBCZWNhdXNlIEZGIGdlbmVyYXRlcyBhbnN3ZXJzIGluIFVuaWZpZWQgUGxhbiBzdHlsZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdlIE1VU1QgYWxyZWFkeSBoYXZlIGEgY2FjaGVkIGFuc3dlciB3aXRoIGFsbCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxvY2FsIFNTUkNzIG1hcHBlZCB0byBzb21lIG0tbGluZS9taWQuXG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHVMaW5lLm1pZCA9IFtiTGluZS50eXBlLCAnLScsIHNzcmNdLmpvaW4oJycpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gSW5jbHVkZSB0aGUgY2FuZGlkYXRlcyBpbiB0aGUgMXN0IG1lZGlhIGxpbmUuXG4gICAgICAgICAgICAgICAgICAgIHVMaW5lLmNhbmRpZGF0ZXMgPSBjYW5kaWRhdGVzO1xuICAgICAgICAgICAgICAgICAgICB1TGluZS5pY2VVZnJhZyA9IGljZVVmcmFnO1xuICAgICAgICAgICAgICAgICAgICB1TGluZS5pY2VQd2QgPSBpY2VQd2Q7XG4gICAgICAgICAgICAgICAgICAgIHVMaW5lLmZpbmdlcnByaW50ID0gZmluZ2VycHJpbnQ7XG4gICAgICAgICAgICAgICAgICAgIHVMaW5lLnBvcnQgPSBwb3J0O1xuXG4gICAgICAgICAgICAgICAgICAgIG1pZDJ1bFt1TGluZS5taWRdID0gdUxpbmU7XG4gICAgICAgICAgICAgICAgICAgIHNvdXJjZXMydWxbdUlkeF0gPSB1TGluZS5zb3VyY2VzO1xuXG4gICAgICAgICAgICAgICAgICAgIHNlbGYuY2FjaGUubWxVMkJNYXBbdUlkeF0gPSBiSWR4O1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHNlbGYuY2FjaGUubWxCMlVNYXBbYklkeF0gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgc2VsZi5jYWNoZS5tbEIyVU1hcFtiSWR4XSA9IHVJZHg7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdUlkeCsrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhciB1TGluZSA9IGJMaW5lO1xuXG4gICAgICAgICAgdUxpbmUuY2FuZGlkYXRlcyA9IGNhbmRpZGF0ZXM7XG4gICAgICAgICAgdUxpbmUuaWNlVWZyYWcgPSBpY2VVZnJhZztcbiAgICAgICAgICB1TGluZS5pY2VQd2QgPSBpY2VQd2Q7XG4gICAgICAgICAgdUxpbmUuZmluZ2VycHJpbnQgPSBmaW5nZXJwcmludDtcbiAgICAgICAgICB1TGluZS5wb3J0ID0gcG9ydDtcblxuICAgICAgICAgIG1pZDJ1bFt1TGluZS5taWRdID0gdUxpbmU7XG5cbiAgICAgICAgICBzZWxmLmNhY2hlLm1sVTJCTWFwW3VJZHhdID0gYklkeDtcbiAgICAgICAgICBpZiAodHlwZW9mIHNlbGYuY2FjaGUubWxCMlVNYXBbYklkeF0gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICBzZWxmLmNhY2hlLm1sQjJVTWFwW2JJZHhdID0gdUlkeDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBiSWR4Kys7XG4gICAgfSk7XG5cbiAgICAvLyBSZWJ1aWxkIHRoZSBtZWRpYSBhcnJheSBpbiB0aGUgcmlnaHQgb3JkZXIgYW5kIGFkZCB0aGUgbWlzc2luZyBtTGluZXNcbiAgICAvLyAobWlzc2luZyBmcm9tIHRoZSBQbGFuIEIgU0RQKS5cbiAgICBzZXNzaW9uLm1lZGlhID0gW107XG4gICAgbWlkcyA9IFtdOyAvLyByZXVzZVxuXG4gICAgaWYgKGRlc2MudHlwZSA9PT0gJ2Fuc3dlcicpIHtcblxuICAgICAgICAvLyBUaGUgbWVkaWEgbGluZXMgaW4gdGhlIGFuc3dlciBtdXN0IG1hdGNoIHRoZSBtZWRpYSBsaW5lcyBpbiB0aGVcbiAgICAgICAgLy8gb2ZmZXIuIFRoZSBvcmRlciBpcyBpbXBvcnRhbnQgdG9vLiBIZXJlIHdlIGFzc3VtZSB0aGF0IEZpcmVmb3ggaXNcbiAgICAgICAgLy8gdGhlIGFuc3dlcmVyLCBzbyB3ZSBtZXJlbHkgaGF2ZSB0byB1c2UgdGhlIHJlY29uc3RydWN0ZWQgKHVuaWZpZWQpXG4gICAgICAgIC8vIGFuc3dlciB0byB1cGRhdGUgdGhlIGNhY2hlZCAodW5pZmllZCkgYW5zd2VyIGFjY29yZGluZ2x5LlxuICAgICAgICAvL1xuICAgICAgICAvLyBJbiB0aGUgZ2VuZXJhbCBjYXNlLCBvbmUgd291bGQgaGF2ZSB0byB1c2UgdGhlIGNhY2hlZCAodW5pZmllZClcbiAgICAgICAgLy8gb2ZmZXIgdG8gZmluZCB0aGUgbS1saW5lcyB0aGF0IGFyZSBtaXNzaW5nIGZyb20gdGhlIHJlY29uc3RydWN0ZWRcbiAgICAgICAgLy8gYW5zd2VyLCBwb3RlbnRpYWxseSBncmFiYmluZyB0aGVtIGZyb20gdGhlIGNhY2hlZCAodW5pZmllZCkgYW5zd2VyLlxuICAgICAgICAvLyBPbmUgaGFzIHRvIGJlIGNhcmVmdWwgd2l0aCB0aGlzIGFwcHJvYWNoIGJlY2F1c2UgaW5hY3RpdmUgbS1saW5lcyBkb1xuICAgICAgICAvLyBub3QgYWx3YXlzIGhhdmUgYW4gbWlkLCBtYWtpbmcgaXQgdHJpY2t5IChpbXBvc3NpYmxlPykgdG8gZmluZCB3aGVyZVxuICAgICAgICAvLyBleGFjdGx5IGFuZCB3aGljaCBtLWxpbmVzIGFyZSBtaXNzaW5nIGZyb20gdGhlIHJlY29uc3RydWN0ZWQgYW5zd2VyLlxuXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2FjaGVkLm1lZGlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB2YXIgdUxpbmUgPSBjYWNoZWQubWVkaWFbaV07XG5cbiAgICAgICAgICAgIGRlbGV0ZSB1TGluZS5tc2lkO1xuICAgICAgICAgICAgZGVsZXRlIHVMaW5lLnNvdXJjZXM7XG4gICAgICAgICAgICBkZWxldGUgdUxpbmUuc3NyY0dyb3VwcztcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiBzb3VyY2VzMnVsW2ldID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICBpZiAoIXVMaW5lLmRpcmVjdGlvblxuICAgICAgICAgICAgICAgICAgfHwgdUxpbmUuZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnKVxuICAgICAgICAgICAgICAgICAgdUxpbmUuZGlyZWN0aW9uID0gJ3JlY3Zvbmx5JztcbiAgICAgICAgICAgICAgZWxzZSBpZiAodUxpbmUuZGlyZWN0aW9uID09PSAnc2VuZG9ubHknKVxuICAgICAgICAgICAgICAgICAgdUxpbmUuZGlyZWN0aW9uID0gJ2luYWN0aXZlJztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGlmICghdUxpbmUuZGlyZWN0aW9uXG4gICAgICAgICAgICAgICAgICB8fCB1TGluZS5kaXJlY3Rpb24gPT09ICdzZW5kcmVjdicpXG4gICAgICAgICAgICAgICAgICB1TGluZS5kaXJlY3Rpb24gPSAnc2VuZHJlY3YnO1xuICAgICAgICAgICAgICBlbHNlIGlmICh1TGluZS5kaXJlY3Rpb24gPT09ICdyZWN2b25seScpXG4gICAgICAgICAgICAgICAgICB1TGluZS5kaXJlY3Rpb24gPSAnc2VuZG9ubHknO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB1TGluZS5zb3VyY2VzID0gc291cmNlczJ1bFtpXTtcbiAgICAgICAgICAgIHVMaW5lLmNhbmRpZGF0ZXMgPSBjYW5kaWRhdGVzO1xuICAgICAgICAgICAgdUxpbmUuaWNlVWZyYWcgPSBpY2VVZnJhZztcbiAgICAgICAgICAgIHVMaW5lLmljZVB3ZCA9IGljZVB3ZDtcbiAgICAgICAgICAgIHVMaW5lLmZpbmdlcnByaW50ID0gZmluZ2VycHJpbnQ7XG5cbiAgICAgICAgICAgIHVMaW5lLnJ0cCA9IHJ0cFt1TGluZS50eXBlXTtcbiAgICAgICAgICAgIHVMaW5lLnBheWxvYWRzID0gcGF5bG9hZHNbdUxpbmUudHlwZV07XG4gICAgICAgICAgICB1TGluZS5ydGNwRmIgPSBydGNwRmJbdUxpbmUudHlwZV07XG5cbiAgICAgICAgICAgIHNlc3Npb24ubWVkaWEucHVzaCh1TGluZSk7XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdUxpbmUubWlkID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIC8vIGluYWN0aXZlIGxpbmVzIGRvbid0L21heSBub3QgaGF2ZSBhbiBtaWQuXG4gICAgICAgICAgICAgICAgbWlkcy5wdXNoKHVMaW5lLm1pZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuXG4gICAgICAgIC8vIFNEUCBvZmZlci9hbnN3ZXIgKGFuZCB0aGUgSlNFUCBzcGVjKSBmb3JiaWRzIHJlbW92aW5nIGFuIG0tc2VjdGlvblxuICAgICAgICAvLyB1bmRlciBhbnkgY2lyY3Vtc3RhbmNlcy4gSWYgd2UgYXJlIG5vIGxvbmdlciBpbnRlcmVzdGVkIGluIHNlbmRpbmcgYVxuICAgICAgICAvLyB0cmFjaywgd2UganVzdCByZW1vdmUgdGhlIG1zaWQgYW5kIHNzcmMgYXR0cmlidXRlcyBhbmQgc2V0IGl0IHRvXG4gICAgICAgIC8vIGVpdGhlciBhPXJlY3Zvbmx5IChhcyB0aGUgcmVvZmZlcmVyLCB3ZSBtdXN0IHVzZSByZWN2b25seSBpZiB0aGVcbiAgICAgICAgLy8gb3RoZXIgc2lkZSB3YXMgcHJldmlvdXNseSBzZW5kaW5nIG9uIHRoZSBtLXNlY3Rpb24sIGJ1dCB3ZSBjYW4gYWxzb1xuICAgICAgICAvLyBsZWF2ZSB0aGUgcG9zc2liaWxpdHkgb3BlbiBpZiBpdCB3YXNuJ3QgcHJldmlvdXNseSBpbiB1c2UpLCBvclxuICAgICAgICAvLyBhPWluYWN0aXZlLlxuXG4gICAgICAgIGlmICh0eXBlb2YgY2FjaGVkICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgdHlwZW9mIGNhY2hlZC5tZWRpYSAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgICAgIEFycmF5LmlzQXJyYXkoY2FjaGVkLm1lZGlhKSkge1xuICAgICAgICAgICAgY2FjaGVkLm1lZGlhLmZvckVhY2goZnVuY3Rpb24odUxpbmUpIHtcbiAgICAgICAgICAgICAgICBtaWRzLnB1c2godUxpbmUubWlkKTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIG1pZDJ1bFt1TGluZS5taWRdICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uLm1lZGlhLnB1c2gobWlkMnVsW3VMaW5lLm1pZF0pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB1TGluZS5tc2lkO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgdUxpbmUuc291cmNlcztcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHVMaW5lLnNzcmNHcm91cHM7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCF1TGluZS5kaXJlY3Rpb25cbiAgICAgICAgICAgICAgICAgICAgICAgIHx8IHVMaW5lLmRpcmVjdGlvbiA9PT0gJ3NlbmRyZWN2Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdUxpbmUuZGlyZWN0aW9uID0gJ3NlbmRvbmx5JztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoIXVMaW5lLmRpcmVjdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgfHwgdUxpbmUuZGlyZWN0aW9uID09PSAncmVjdm9ubHknKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB1TGluZS5kaXJlY3Rpb24gPSAnaW5hY3RpdmUnO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgYWRkU2V0dXBBdHRyICh1TGluZSk7XG4gICAgICAgICAgICAgICAgICAgIHNlc3Npb24ubWVkaWEucHVzaCh1TGluZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBZGQgYWxsIHRoZSByZW1haW5pbmcgKG5ldykgbS1saW5lcyBvZiB0aGUgdHJhbnNmb3JtZWQgU0RQLlxuICAgICAgICBPYmplY3Qua2V5cyhtaWQydWwpLmZvckVhY2goZnVuY3Rpb24obWlkKSB7XG4gICAgICAgICAgICBpZiAobWlkcy5pbmRleE9mKG1pZCkgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgbWlkcy5wdXNoKG1pZCk7XG4gICAgICAgICAgICAgICAgaWYgKG1pZDJ1bFttaWRdLmRpcmVjdGlvbiA9PT0gJ3JlY3Zvbmx5Jykge1xuICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIGlzIGEgcmVtb3RlIHJlY3Zvbmx5IGNoYW5uZWwuIEFkZCBpdHMgU1NSQyB0byB0aGVcbiAgICAgICAgICAgICAgICAgICAgLy8gYXBwcm9wcmlhdGUgc2VuZHJlY3Ygb3Igc2VuZG9ubHkgY2hhbm5lbC5cbiAgICAgICAgICAgICAgICAgICAgLy8gVE9ETyhncCkgd2hhdCBpZiB3ZSBkb24ndCBoYXZlIHNlbmRyZWN2L3NlbmRvbmx5XG4gICAgICAgICAgICAgICAgICAgIC8vIGNoYW5uZWw/XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIGRvbmUgPSBmYWxzZTtcblxuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uLm1lZGlhLnNvbWUoZnVuY3Rpb24gKHVMaW5lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoKHVMaW5lLmRpcmVjdGlvbiA9PT0gJ3NlbmRyZWN2JyB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVMaW5lLmRpcmVjdGlvbiA9PT0gJ3NlbmRvbmx5JykgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1TGluZS50eXBlID09PSBtaWQydWxbbWlkXS50eXBlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbWlkMnVsW21pZF0gc2hvdWxkbid0IGhhdmUgYW55IHNzcmMtZ3JvdXBzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgT2JqZWN0LmtleXMobWlkMnVsW21pZF0uc291cmNlcykuZm9yRWFjaChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKHNzcmMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdUxpbmUuc291cmNlc1tzc3JjXSA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaWQydWxbbWlkXS5zb3VyY2VzW3NzcmNdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9uZSA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICghZG9uZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbi5tZWRpYS5wdXNoKG1pZDJ1bFttaWRdKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHNlc3Npb24ubWVkaWEucHVzaChtaWQydWxbbWlkXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBBZnRlciB3ZSBoYXZlIGNvbnN0cnVjdGVkIHRoZSBQbGFuIFVuaWZpZWQgbS1saW5lcyB3ZSBjYW4gZmlndXJlIG91dFxuICAgIC8vIHdoZXJlIChpbiB3aGljaCBtLWxpbmUpIHRvIHBsYWNlIHRoZSAncmVjdm9ubHkgU1NSQ3MnLlxuICAgIC8vIE5vdGU6IHdlIGFzc3VtZSBoZXJlIHRoYXQgd2UgYXJlIHRoZSBhbnN3ZXJlciBpbiB0aGUgTy9BLCBzbyBhbnkgb2ZmZXJzXG4gICAgLy8gd2hpY2ggd2UgdHJhbnNsYXRlIGNvbWUgZnJvbSB0aGUgcmVtb3RlIHNpZGUsIHdoaWxlIGFuc3dlcnMgYXJlIGxvY2FsXG4gICAgLy8gKGFuZCBzbyBvdXIgbGFzdCBsb2NhbCBkZXNjcmlwdGlvbiBpcyBjYWNoZWQgYXMgYW4gJ2Fuc3dlcicpLlxuICAgIFtcImF1ZGlvXCIsIFwidmlkZW9cIl0uZm9yRWFjaChmdW5jdGlvbiAodHlwZSkge1xuICAgICAgICBpZiAoIXNlc3Npb24gfHwgIXNlc3Npb24ubWVkaWEgfHwgIUFycmF5LmlzQXJyYXkoc2Vzc2lvbi5tZWRpYSkpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdmFyIGlkeCA9IG51bGw7XG4gICAgICAgIGlmIChPYmplY3Qua2V5cyhyZWN2b25seVNzcmNzW3R5cGVdKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBpZHggPSBzZWxmLmdldEZpcnN0U2VuZGluZ0luZGV4RnJvbUFuc3dlcih0eXBlKTtcbiAgICAgICAgICAgIGlmIChpZHggPT09IG51bGwpe1xuICAgICAgICAgICAgICAgIC8vIElmIHRoaXMgaXMgdGhlIGZpcnN0IG9mZmVyIHdlIHJlY2VpdmUsIHdlIGRvbid0IGhhdmUgYVxuICAgICAgICAgICAgICAgIC8vIGNhY2hlZCBhbnN3ZXIuIEFzc3VtZSB0aGF0IHdlIHdpbGwgYmUgc2VuZGluZyBtZWRpYSB1c2luZ1xuICAgICAgICAgICAgICAgIC8vIHRoZSBmaXJzdCBtLWxpbmUgZm9yIGVhY2ggbWVkaWEgdHlwZS5cblxuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2Vzc2lvbi5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICBpZiAoc2Vzc2lvbi5tZWRpYVtpXS50eXBlID09PSB0eXBlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZHggPSBpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaWR4ICYmIHNlc3Npb24ubWVkaWEubGVuZ3RoID4gaWR4KSB7XG4gICAgICAgICAgICB2YXIgbUxpbmUgPSBzZXNzaW9uLm1lZGlhW2lkeF07XG4gICAgICAgICAgICBPYmplY3Qua2V5cyhyZWN2b25seVNzcmNzW3R5cGVdKS5mb3JFYWNoKGZ1bmN0aW9uKHNzcmMpIHtcbiAgICAgICAgICAgICAgICBpZiAobUxpbmUuc291cmNlcyAmJiBtTGluZS5zb3VyY2VzW3NzcmNdKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcIlJlcGxhY2luZyBhbiBleGlzdGluZyBTU1JDLlwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCFtTGluZS5zb3VyY2VzKSB7XG4gICAgICAgICAgICAgICAgICAgIG1MaW5lLnNvdXJjZXMgPSB7fTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBtTGluZS5zb3VyY2VzW3NzcmNdID0gcmVjdm9ubHlTc3Jjc1t0eXBlXVtzc3JjXTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICBpZiAodHlwZW9mIHNlc3Npb24uZ3JvdXBzICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgLy8gV2UgcmVnZW5lcmF0ZSB0aGUgQlVORExFIGdyb3VwIChzaW5jZSB3ZSByZWdlbmVyYXRlZCB0aGUgbWlkcylcbiAgICAgIHNlc3Npb24uZ3JvdXBzLnNvbWUoZnVuY3Rpb24oZ3JvdXApIHtcblx0ICBpZiAoZ3JvdXAudHlwZSA9PT0gJ0JVTkRMRScpIHtcblx0ICAgICAgZ3JvdXAubWlkcyA9IG1pZHMuam9pbignICcpO1xuXHQgICAgICByZXR1cm4gdHJ1ZTtcblx0ICB9XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBtc2lkIHNlbWFudGljXG4gICAgc2Vzc2lvbi5tc2lkU2VtYW50aWMgPSB7XG4gICAgICAgIHNlbWFudGljOiAnV01TJyxcbiAgICAgICAgdG9rZW46ICcqJ1xuICAgIH07XG5cbiAgICB2YXIgcmVzU3RyID0gdHJhbnNmb3JtLndyaXRlKHNlc3Npb24pO1xuXG4gICAgLy8gQ2FjaGUgdGhlIHRyYW5zZm9ybWVkIFNEUCAoVW5pZmllZCBQbGFuKSBmb3IgbGF0ZXIgcmUtdXNlIGluIHRoaXNcbiAgICAvLyBmdW5jdGlvbi5cbiAgICB0aGlzLmNhY2hlW2Rlc2MudHlwZV0gPSByZXNTdHI7XG5cbiAgICByZXR1cm4gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICAgIHR5cGU6IGRlc2MudHlwZSxcbiAgICAgICAgc2RwOiByZXNTdHJcbiAgICB9KTtcblxuICAgIC8vI2VuZHJlZ2lvblxufTtcbiIsIi8qIENvcHlyaWdodCBAIDIwMTUgQXRsYXNzaWFuIFB0eSBMdGRcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxudmFyIHRyYW5zZm9ybSA9IHJlcXVpcmUoJ3NkcC10cmFuc2Zvcm0nKTtcblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uKHNlc3Npb24sIG9wdHMpIHtcblxuICBpZiAodHlwZW9mIHNlc3Npb24gIT09ICd1bmRlZmluZWQnICYmXG4gICAgICB0eXBlb2Ygc2Vzc2lvbi5tZWRpYSAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgIEFycmF5LmlzQXJyYXkoc2Vzc2lvbi5tZWRpYSkpIHtcblxuICAgIHNlc3Npb24ubWVkaWEuZm9yRWFjaChmdW5jdGlvbiAobUxpbmUpIHtcbiAgICAgIC8vIGV4cGFuZCBzb3VyY2VzIHRvIHNzcmNzXG4gICAgICBpZiAodHlwZW9mIG1MaW5lLnNvdXJjZXMgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgIE9iamVjdC5rZXlzKG1MaW5lLnNvdXJjZXMpLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICAgIG1MaW5lLnNzcmNzID0gW107XG4gICAgICAgICAgT2JqZWN0LmtleXMobUxpbmUuc291cmNlcykuZm9yRWFjaChmdW5jdGlvbiAoc3NyYykge1xuICAgICAgICAgICAgdmFyIHNvdXJjZSA9IG1MaW5lLnNvdXJjZXNbc3NyY107XG4gICAgICAgICAgICBPYmplY3Qua2V5cyhzb3VyY2UpLmZvckVhY2goZnVuY3Rpb24gKGF0dHJpYnV0ZSkge1xuICAgICAgICAgICAgICBtTGluZS5zc3Jjcy5wdXNoKHtcbiAgICAgICAgICAgICAgICBpZDogc3NyYyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6IGF0dHJpYnV0ZSxcbiAgICAgICAgICAgICAgICB2YWx1ZTogc291cmNlW2F0dHJpYnV0ZV1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBkZWxldGUgbUxpbmUuc291cmNlcztcbiAgICAgICAgfVxuXG4gICAgICAvLyBqb2luIHNzcmNzIGluIHNzcmMgZ3JvdXBzXG4gICAgICBpZiAodHlwZW9mIG1MaW5lLnNzcmNHcm91cHMgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgIEFycmF5LmlzQXJyYXkobUxpbmUuc3NyY0dyb3VwcykpIHtcbiAgICAgICAgICBtTGluZS5zc3JjR3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKHNzcmNHcm91cCkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBzc3JjR3JvdXAuc3NyY3MgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICAgICAgQXJyYXkuaXNBcnJheShzc3JjR3JvdXAuc3NyY3MpKSB7XG4gICAgICAgICAgICAgIHNzcmNHcm91cC5zc3JjcyA9IHNzcmNHcm91cC5zc3Jjcy5qb2luKCcgJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8vIGpvaW4gZ3JvdXAgbWlkc1xuICBpZiAodHlwZW9mIHNlc3Npb24gIT09ICd1bmRlZmluZWQnICYmXG4gICAgICB0eXBlb2Ygc2Vzc2lvbi5ncm91cHMgIT09ICd1bmRlZmluZWQnICYmIEFycmF5LmlzQXJyYXkoc2Vzc2lvbi5ncm91cHMpKSB7XG5cbiAgICBzZXNzaW9uLmdyb3Vwcy5mb3JFYWNoKGZ1bmN0aW9uIChnKSB7XG4gICAgICBpZiAodHlwZW9mIGcubWlkcyAhPT0gJ3VuZGVmaW5lZCcgJiYgQXJyYXkuaXNBcnJheShnLm1pZHMpKSB7XG4gICAgICAgIGcubWlkcyA9IGcubWlkcy5qb2luKCcgJyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gdHJhbnNmb3JtLndyaXRlKHNlc3Npb24sIG9wdHMpO1xufTtcblxuZXhwb3J0cy5wYXJzZSA9IGZ1bmN0aW9uKHNkcCkge1xuICB2YXIgc2Vzc2lvbiA9IHRyYW5zZm9ybS5wYXJzZShzZHApO1xuXG4gIGlmICh0eXBlb2Ygc2Vzc2lvbiAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIHNlc3Npb24ubWVkaWEgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICBBcnJheS5pc0FycmF5KHNlc3Npb24ubWVkaWEpKSB7XG5cbiAgICBzZXNzaW9uLm1lZGlhLmZvckVhY2goZnVuY3Rpb24gKG1MaW5lKSB7XG4gICAgICAvLyBncm91cCBzb3VyY2VzIGF0dHJpYnV0ZXMgYnkgc3NyY1xuICAgICAgaWYgKHR5cGVvZiBtTGluZS5zc3JjcyAhPT0gJ3VuZGVmaW5lZCcgJiYgQXJyYXkuaXNBcnJheShtTGluZS5zc3JjcykpIHtcbiAgICAgICAgbUxpbmUuc291cmNlcyA9IHt9O1xuICAgICAgICBtTGluZS5zc3Jjcy5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgICAgaWYgKCFtTGluZS5zb3VyY2VzW3NzcmMuaWRdKVxuICAgICAgICAgIG1MaW5lLnNvdXJjZXNbc3NyYy5pZF0gPSB7fTtcbiAgICAgICAgbUxpbmUuc291cmNlc1tzc3JjLmlkXVtzc3JjLmF0dHJpYnV0ZV0gPSBzc3JjLnZhbHVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBkZWxldGUgbUxpbmUuc3NyY3M7XG4gICAgICB9XG5cbiAgICAgIC8vIHNwbGl0IHNzcmNzIGluIHNzcmMgZ3JvdXBzXG4gICAgICBpZiAodHlwZW9mIG1MaW5lLnNzcmNHcm91cHMgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgIEFycmF5LmlzQXJyYXkobUxpbmUuc3NyY0dyb3VwcykpIHtcbiAgICAgICAgICBtTGluZS5zc3JjR3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKHNzcmNHcm91cCkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBzc3JjR3JvdXAuc3NyY3MgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgIHNzcmNHcm91cC5zc3JjcyA9IHNzcmNHcm91cC5zc3Jjcy5zcGxpdCgnICcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfSk7XG4gIH1cbiAgLy8gc3BsaXQgZ3JvdXAgbWlkc1xuICBpZiAodHlwZW9mIHNlc3Npb24gIT09ICd1bmRlZmluZWQnICYmXG4gICAgICB0eXBlb2Ygc2Vzc2lvbi5ncm91cHMgIT09ICd1bmRlZmluZWQnICYmIEFycmF5LmlzQXJyYXkoc2Vzc2lvbi5ncm91cHMpKSB7XG5cbiAgICBzZXNzaW9uLmdyb3Vwcy5mb3JFYWNoKGZ1bmN0aW9uIChnKSB7XG4gICAgICBpZiAodHlwZW9mIGcubWlkcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgZy5taWRzID0gZy5taWRzLnNwbGl0KCcgJyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gc2Vzc2lvbjtcbn07XG5cbiIsIiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcblxuLy8gU0RQIGhlbHBlcnMuXG52YXIgU0RQVXRpbHMgPSB7fTtcblxuLy8gR2VuZXJhdGUgYW4gYWxwaGFudW1lcmljIGlkZW50aWZpZXIgZm9yIGNuYW1lIG9yIG1pZHMuXG4vLyBUT0RPOiB1c2UgVVVJRHMgaW5zdGVhZD8gaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vamVkLzk4Mjg4M1xuU0RQVXRpbHMuZ2VuZXJhdGVJZGVudGlmaWVyID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiBNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zdWJzdHIoMiwgMTApO1xufTtcblxuLy8gVGhlIFJUQ1AgQ05BTUUgdXNlZCBieSBhbGwgcGVlcmNvbm5lY3Rpb25zIGZyb20gdGhlIHNhbWUgSlMuXG5TRFBVdGlscy5sb2NhbENOYW1lID0gU0RQVXRpbHMuZ2VuZXJhdGVJZGVudGlmaWVyKCk7XG5cbi8vIFNwbGl0cyBTRFAgaW50byBsaW5lcywgZGVhbGluZyB3aXRoIGJvdGggQ1JMRiBhbmQgTEYuXG5TRFBVdGlscy5zcGxpdExpbmVzID0gZnVuY3Rpb24oYmxvYikge1xuICByZXR1cm4gYmxvYi50cmltKCkuc3BsaXQoJ1xcbicpLm1hcChmdW5jdGlvbihsaW5lKSB7XG4gICAgcmV0dXJuIGxpbmUudHJpbSgpO1xuICB9KTtcbn07XG4vLyBTcGxpdHMgU0RQIGludG8gc2Vzc2lvbnBhcnQgYW5kIG1lZGlhc2VjdGlvbnMuIEVuc3VyZXMgQ1JMRi5cblNEUFV0aWxzLnNwbGl0U2VjdGlvbnMgPSBmdW5jdGlvbihibG9iKSB7XG4gIHZhciBwYXJ0cyA9IGJsb2Iuc3BsaXQoJ1xcbm09Jyk7XG4gIHJldHVybiBwYXJ0cy5tYXAoZnVuY3Rpb24ocGFydCwgaW5kZXgpIHtcbiAgICByZXR1cm4gKGluZGV4ID4gMCA/ICdtPScgKyBwYXJ0IDogcGFydCkudHJpbSgpICsgJ1xcclxcbic7XG4gIH0pO1xufTtcblxuLy8gUmV0dXJucyBsaW5lcyB0aGF0IHN0YXJ0IHdpdGggYSBjZXJ0YWluIHByZWZpeC5cblNEUFV0aWxzLm1hdGNoUHJlZml4ID0gZnVuY3Rpb24oYmxvYiwgcHJlZml4KSB7XG4gIHJldHVybiBTRFBVdGlscy5zcGxpdExpbmVzKGJsb2IpLmZpbHRlcihmdW5jdGlvbihsaW5lKSB7XG4gICAgcmV0dXJuIGxpbmUuaW5kZXhPZihwcmVmaXgpID09PSAwO1xuICB9KTtcbn07XG5cbi8vIFBhcnNlcyBhbiBJQ0UgY2FuZGlkYXRlIGxpbmUuIFNhbXBsZSBpbnB1dDpcbi8vIGNhbmRpZGF0ZTo3MDI3ODYzNTAgMiB1ZHAgNDE4MTk5MDIgOC44LjguOCA2MDc2OSB0eXAgcmVsYXkgcmFkZHIgOC44LjguOFxuLy8gcnBvcnQgNTU5OTZcIlxuU0RQVXRpbHMucGFyc2VDYW5kaWRhdGUgPSBmdW5jdGlvbihsaW5lKSB7XG4gIHZhciBwYXJ0cztcbiAgLy8gUGFyc2UgYm90aCB2YXJpYW50cy5cbiAgaWYgKGxpbmUuaW5kZXhPZignYT1jYW5kaWRhdGU6JykgPT09IDApIHtcbiAgICBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDEyKS5zcGxpdCgnICcpO1xuICB9IGVsc2Uge1xuICAgIHBhcnRzID0gbGluZS5zdWJzdHJpbmcoMTApLnNwbGl0KCcgJyk7XG4gIH1cblxuICB2YXIgY2FuZGlkYXRlID0ge1xuICAgIGZvdW5kYXRpb246IHBhcnRzWzBdLFxuICAgIGNvbXBvbmVudDogcGFydHNbMV0sXG4gICAgcHJvdG9jb2w6IHBhcnRzWzJdLnRvTG93ZXJDYXNlKCksXG4gICAgcHJpb3JpdHk6IHBhcnNlSW50KHBhcnRzWzNdLCAxMCksXG4gICAgaXA6IHBhcnRzWzRdLFxuICAgIHBvcnQ6IHBhcnNlSW50KHBhcnRzWzVdLCAxMCksXG4gICAgLy8gc2tpcCBwYXJ0c1s2XSA9PSAndHlwJ1xuICAgIHR5cGU6IHBhcnRzWzddXG4gIH07XG5cbiAgZm9yICh2YXIgaSA9IDg7IGkgPCBwYXJ0cy5sZW5ndGg7IGkgKz0gMikge1xuICAgIHN3aXRjaCAocGFydHNbaV0pIHtcbiAgICAgIGNhc2UgJ3JhZGRyJzpcbiAgICAgICAgY2FuZGlkYXRlLnJlbGF0ZWRBZGRyZXNzID0gcGFydHNbaSArIDFdO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3Jwb3J0JzpcbiAgICAgICAgY2FuZGlkYXRlLnJlbGF0ZWRQb3J0ID0gcGFyc2VJbnQocGFydHNbaSArIDFdLCAxMCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAndGNwdHlwZSc6XG4gICAgICAgIGNhbmRpZGF0ZS50Y3BUeXBlID0gcGFydHNbaSArIDFdO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6IC8vIGV4dGVuc2lvbiBoYW5kbGluZywgaW4gcGFydGljdWxhciB1ZnJhZ1xuICAgICAgICBjYW5kaWRhdGVbcGFydHNbaV1dID0gcGFydHNbaSArIDFdO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNhbmRpZGF0ZTtcbn07XG5cbi8vIFRyYW5zbGF0ZXMgYSBjYW5kaWRhdGUgb2JqZWN0IGludG8gU0RQIGNhbmRpZGF0ZSBhdHRyaWJ1dGUuXG5TRFBVdGlscy53cml0ZUNhbmRpZGF0ZSA9IGZ1bmN0aW9uKGNhbmRpZGF0ZSkge1xuICB2YXIgc2RwID0gW107XG4gIHNkcC5wdXNoKGNhbmRpZGF0ZS5mb3VuZGF0aW9uKTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLmNvbXBvbmVudCk7XG4gIHNkcC5wdXNoKGNhbmRpZGF0ZS5wcm90b2NvbC50b1VwcGVyQ2FzZSgpKTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLnByaW9yaXR5KTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLmlwKTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLnBvcnQpO1xuXG4gIHZhciB0eXBlID0gY2FuZGlkYXRlLnR5cGU7XG4gIHNkcC5wdXNoKCd0eXAnKTtcbiAgc2RwLnB1c2godHlwZSk7XG4gIGlmICh0eXBlICE9PSAnaG9zdCcgJiYgY2FuZGlkYXRlLnJlbGF0ZWRBZGRyZXNzICYmXG4gICAgICBjYW5kaWRhdGUucmVsYXRlZFBvcnQpIHtcbiAgICBzZHAucHVzaCgncmFkZHInKTtcbiAgICBzZHAucHVzaChjYW5kaWRhdGUucmVsYXRlZEFkZHJlc3MpOyAvLyB3YXM6IHJlbEFkZHJcbiAgICBzZHAucHVzaCgncnBvcnQnKTtcbiAgICBzZHAucHVzaChjYW5kaWRhdGUucmVsYXRlZFBvcnQpOyAvLyB3YXM6IHJlbFBvcnRcbiAgfVxuICBpZiAoY2FuZGlkYXRlLnRjcFR5cGUgJiYgY2FuZGlkYXRlLnByb3RvY29sLnRvTG93ZXJDYXNlKCkgPT09ICd0Y3AnKSB7XG4gICAgc2RwLnB1c2goJ3RjcHR5cGUnKTtcbiAgICBzZHAucHVzaChjYW5kaWRhdGUudGNwVHlwZSk7XG4gIH1cbiAgcmV0dXJuICdjYW5kaWRhdGU6JyArIHNkcC5qb2luKCcgJyk7XG59O1xuXG4vLyBQYXJzZXMgYW4gaWNlLW9wdGlvbnMgbGluZSwgcmV0dXJucyBhbiBhcnJheSBvZiBvcHRpb24gdGFncy5cbi8vIGE9aWNlLW9wdGlvbnM6Zm9vIGJhclxuU0RQVXRpbHMucGFyc2VJY2VPcHRpb25zID0gZnVuY3Rpb24obGluZSkge1xuICByZXR1cm4gbGluZS5zdWJzdHIoMTQpLnNwbGl0KCcgJyk7XG59XG5cbi8vIFBhcnNlcyBhbiBydHBtYXAgbGluZSwgcmV0dXJucyBSVENSdHBDb2RkZWNQYXJhbWV0ZXJzLiBTYW1wbGUgaW5wdXQ6XG4vLyBhPXJ0cG1hcDoxMTEgb3B1cy80ODAwMC8yXG5TRFBVdGlscy5wYXJzZVJ0cE1hcCA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgdmFyIHBhcnRzID0gbGluZS5zdWJzdHIoOSkuc3BsaXQoJyAnKTtcbiAgdmFyIHBhcnNlZCA9IHtcbiAgICBwYXlsb2FkVHlwZTogcGFyc2VJbnQocGFydHMuc2hpZnQoKSwgMTApIC8vIHdhczogaWRcbiAgfTtcblxuICBwYXJ0cyA9IHBhcnRzWzBdLnNwbGl0KCcvJyk7XG5cbiAgcGFyc2VkLm5hbWUgPSBwYXJ0c1swXTtcbiAgcGFyc2VkLmNsb2NrUmF0ZSA9IHBhcnNlSW50KHBhcnRzWzFdLCAxMCk7IC8vIHdhczogY2xvY2tyYXRlXG4gIC8vIHdhczogY2hhbm5lbHNcbiAgcGFyc2VkLm51bUNoYW5uZWxzID0gcGFydHMubGVuZ3RoID09PSAzID8gcGFyc2VJbnQocGFydHNbMl0sIDEwKSA6IDE7XG4gIHJldHVybiBwYXJzZWQ7XG59O1xuXG4vLyBHZW5lcmF0ZSBhbiBhPXJ0cG1hcCBsaW5lIGZyb20gUlRDUnRwQ29kZWNDYXBhYmlsaXR5IG9yXG4vLyBSVENSdHBDb2RlY1BhcmFtZXRlcnMuXG5TRFBVdGlscy53cml0ZVJ0cE1hcCA9IGZ1bmN0aW9uKGNvZGVjKSB7XG4gIHZhciBwdCA9IGNvZGVjLnBheWxvYWRUeXBlO1xuICBpZiAoY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGUgIT09IHVuZGVmaW5lZCkge1xuICAgIHB0ID0gY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGU7XG4gIH1cbiAgcmV0dXJuICdhPXJ0cG1hcDonICsgcHQgKyAnICcgKyBjb2RlYy5uYW1lICsgJy8nICsgY29kZWMuY2xvY2tSYXRlICtcbiAgICAgIChjb2RlYy5udW1DaGFubmVscyAhPT0gMSA/ICcvJyArIGNvZGVjLm51bUNoYW5uZWxzIDogJycpICsgJ1xcclxcbic7XG59O1xuXG4vLyBQYXJzZXMgYW4gYT1leHRtYXAgbGluZSAoaGVhZGVyZXh0ZW5zaW9uIGZyb20gUkZDIDUyODUpLiBTYW1wbGUgaW5wdXQ6XG4vLyBhPWV4dG1hcDoyIHVybjppZXRmOnBhcmFtczpydHAtaGRyZXh0OnRvZmZzZXRcbi8vIGE9ZXh0bWFwOjIvc2VuZG9ubHkgdXJuOmlldGY6cGFyYW1zOnJ0cC1oZHJleHQ6dG9mZnNldFxuU0RQVXRpbHMucGFyc2VFeHRtYXAgPSBmdW5jdGlvbihsaW5lKSB7XG4gIHZhciBwYXJ0cyA9IGxpbmUuc3Vic3RyKDkpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAgaWQ6IHBhcnNlSW50KHBhcnRzWzBdLCAxMCksXG4gICAgZGlyZWN0aW9uOiBwYXJ0c1swXS5pbmRleE9mKCcvJykgPiAwID8gcGFydHNbMF0uc3BsaXQoJy8nKVsxXSA6ICdzZW5kcmVjdicsXG4gICAgdXJpOiBwYXJ0c1sxXVxuICB9O1xufTtcblxuLy8gR2VuZXJhdGVzIGE9ZXh0bWFwIGxpbmUgZnJvbSBSVENSdHBIZWFkZXJFeHRlbnNpb25QYXJhbWV0ZXJzIG9yXG4vLyBSVENSdHBIZWFkZXJFeHRlbnNpb24uXG5TRFBVdGlscy53cml0ZUV4dG1hcCA9IGZ1bmN0aW9uKGhlYWRlckV4dGVuc2lvbikge1xuICByZXR1cm4gJ2E9ZXh0bWFwOicgKyAoaGVhZGVyRXh0ZW5zaW9uLmlkIHx8IGhlYWRlckV4dGVuc2lvbi5wcmVmZXJyZWRJZCkgK1xuICAgICAgKGhlYWRlckV4dGVuc2lvbi5kaXJlY3Rpb24gJiYgaGVhZGVyRXh0ZW5zaW9uLmRpcmVjdGlvbiAhPT0gJ3NlbmRyZWN2J1xuICAgICAgICAgID8gJy8nICsgaGVhZGVyRXh0ZW5zaW9uLmRpcmVjdGlvblxuICAgICAgICAgIDogJycpICtcbiAgICAgICcgJyArIGhlYWRlckV4dGVuc2lvbi51cmkgKyAnXFxyXFxuJztcbn07XG5cbi8vIFBhcnNlcyBhbiBmdG1wIGxpbmUsIHJldHVybnMgZGljdGlvbmFyeS4gU2FtcGxlIGlucHV0OlxuLy8gYT1mbXRwOjk2IHZicj1vbjtjbmc9b25cbi8vIEFsc28gZGVhbHMgd2l0aCB2YnI9b247IGNuZz1vblxuU0RQVXRpbHMucGFyc2VGbXRwID0gZnVuY3Rpb24obGluZSkge1xuICB2YXIgcGFyc2VkID0ge307XG4gIHZhciBrdjtcbiAgdmFyIHBhcnRzID0gbGluZS5zdWJzdHIobGluZS5pbmRleE9mKCcgJykgKyAxKS5zcGxpdCgnOycpO1xuICBmb3IgKHZhciBqID0gMDsgaiA8IHBhcnRzLmxlbmd0aDsgaisrKSB7XG4gICAga3YgPSBwYXJ0c1tqXS50cmltKCkuc3BsaXQoJz0nKTtcbiAgICBwYXJzZWRba3ZbMF0udHJpbSgpXSA9IGt2WzFdO1xuICB9XG4gIHJldHVybiBwYXJzZWQ7XG59O1xuXG4vLyBHZW5lcmF0ZXMgYW4gYT1mdG1wIGxpbmUgZnJvbSBSVENSdHBDb2RlY0NhcGFiaWxpdHkgb3IgUlRDUnRwQ29kZWNQYXJhbWV0ZXJzLlxuU0RQVXRpbHMud3JpdGVGbXRwID0gZnVuY3Rpb24oY29kZWMpIHtcbiAgdmFyIGxpbmUgPSAnJztcbiAgdmFyIHB0ID0gY29kZWMucGF5bG9hZFR5cGU7XG4gIGlmIChjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcHQgPSBjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZTtcbiAgfVxuICBpZiAoY29kZWMucGFyYW1ldGVycyAmJiBPYmplY3Qua2V5cyhjb2RlYy5wYXJhbWV0ZXJzKS5sZW5ndGgpIHtcbiAgICB2YXIgcGFyYW1zID0gW107XG4gICAgT2JqZWN0LmtleXMoY29kZWMucGFyYW1ldGVycykuZm9yRWFjaChmdW5jdGlvbihwYXJhbSkge1xuICAgICAgcGFyYW1zLnB1c2gocGFyYW0gKyAnPScgKyBjb2RlYy5wYXJhbWV0ZXJzW3BhcmFtXSk7XG4gICAgfSk7XG4gICAgbGluZSArPSAnYT1mbXRwOicgKyBwdCArICcgJyArIHBhcmFtcy5qb2luKCc7JykgKyAnXFxyXFxuJztcbiAgfVxuICByZXR1cm4gbGluZTtcbn07XG5cbi8vIFBhcnNlcyBhbiBydGNwLWZiIGxpbmUsIHJldHVybnMgUlRDUFJ0Y3BGZWVkYmFjayBvYmplY3QuIFNhbXBsZSBpbnB1dDpcbi8vIGE9cnRjcC1mYjo5OCBuYWNrIHJwc2lcblNEUFV0aWxzLnBhcnNlUnRjcEZiID0gZnVuY3Rpb24obGluZSkge1xuICB2YXIgcGFydHMgPSBsaW5lLnN1YnN0cihsaW5lLmluZGV4T2YoJyAnKSArIDEpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAgdHlwZTogcGFydHMuc2hpZnQoKSxcbiAgICBwYXJhbWV0ZXI6IHBhcnRzLmpvaW4oJyAnKVxuICB9O1xufTtcbi8vIEdlbmVyYXRlIGE9cnRjcC1mYiBsaW5lcyBmcm9tIFJUQ1J0cENvZGVjQ2FwYWJpbGl0eSBvciBSVENSdHBDb2RlY1BhcmFtZXRlcnMuXG5TRFBVdGlscy53cml0ZVJ0Y3BGYiA9IGZ1bmN0aW9uKGNvZGVjKSB7XG4gIHZhciBsaW5lcyA9ICcnO1xuICB2YXIgcHQgPSBjb2RlYy5wYXlsb2FkVHlwZTtcbiAgaWYgKGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlICE9PSB1bmRlZmluZWQpIHtcbiAgICBwdCA9IGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlO1xuICB9XG4gIGlmIChjb2RlYy5ydGNwRmVlZGJhY2sgJiYgY29kZWMucnRjcEZlZWRiYWNrLmxlbmd0aCkge1xuICAgIC8vIEZJWE1FOiBzcGVjaWFsIGhhbmRsaW5nIGZvciB0cnItaW50P1xuICAgIGNvZGVjLnJ0Y3BGZWVkYmFjay5mb3JFYWNoKGZ1bmN0aW9uKGZiKSB7XG4gICAgICBsaW5lcyArPSAnYT1ydGNwLWZiOicgKyBwdCArICcgJyArIGZiLnR5cGUgK1xuICAgICAgKGZiLnBhcmFtZXRlciAmJiBmYi5wYXJhbWV0ZXIubGVuZ3RoID8gJyAnICsgZmIucGFyYW1ldGVyIDogJycpICtcbiAgICAgICAgICAnXFxyXFxuJztcbiAgICB9KTtcbiAgfVxuICByZXR1cm4gbGluZXM7XG59O1xuXG4vLyBQYXJzZXMgYW4gUkZDIDU1NzYgc3NyYyBtZWRpYSBhdHRyaWJ1dGUuIFNhbXBsZSBpbnB1dDpcbi8vIGE9c3NyYzozNzM1OTI4NTU5IGNuYW1lOnNvbWV0aGluZ1xuU0RQVXRpbHMucGFyc2VTc3JjTWVkaWEgPSBmdW5jdGlvbihsaW5lKSB7XG4gIHZhciBzcCA9IGxpbmUuaW5kZXhPZignICcpO1xuICB2YXIgcGFydHMgPSB7XG4gICAgc3NyYzogcGFyc2VJbnQobGluZS5zdWJzdHIoNywgc3AgLSA3KSwgMTApXG4gIH07XG4gIHZhciBjb2xvbiA9IGxpbmUuaW5kZXhPZignOicsIHNwKTtcbiAgaWYgKGNvbG9uID4gLTEpIHtcbiAgICBwYXJ0cy5hdHRyaWJ1dGUgPSBsaW5lLnN1YnN0cihzcCArIDEsIGNvbG9uIC0gc3AgLSAxKTtcbiAgICBwYXJ0cy52YWx1ZSA9IGxpbmUuc3Vic3RyKGNvbG9uICsgMSk7XG4gIH0gZWxzZSB7XG4gICAgcGFydHMuYXR0cmlidXRlID0gbGluZS5zdWJzdHIoc3AgKyAxKTtcbiAgfVxuICByZXR1cm4gcGFydHM7XG59O1xuXG4vLyBFeHRyYWN0cyB0aGUgTUlEIChSRkMgNTg4OCkgZnJvbSBhIG1lZGlhIHNlY3Rpb24uXG4vLyByZXR1cm5zIHRoZSBNSUQgb3IgdW5kZWZpbmVkIGlmIG5vIG1pZCBsaW5lIHdhcyBmb3VuZC5cblNEUFV0aWxzLmdldE1pZCA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICB2YXIgbWlkID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1taWQ6JylbMF07XG4gIGlmIChtaWQpIHtcbiAgICByZXR1cm4gbWlkLnN1YnN0cig2KTtcbiAgfVxufVxuXG5TRFBVdGlscy5wYXJzZUZpbmdlcnByaW50ID0gZnVuY3Rpb24obGluZSkge1xuICB2YXIgcGFydHMgPSBsaW5lLnN1YnN0cigxNCkuc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICBhbGdvcml0aG06IHBhcnRzWzBdLnRvTG93ZXJDYXNlKCksIC8vIGFsZ29yaXRobSBpcyBjYXNlLXNlbnNpdGl2ZSBpbiBFZGdlLlxuICAgIHZhbHVlOiBwYXJ0c1sxXVxuICB9O1xufTtcblxuLy8gRXh0cmFjdHMgRFRMUyBwYXJhbWV0ZXJzIGZyb20gU0RQIG1lZGlhIHNlY3Rpb24gb3Igc2Vzc2lvbnBhcnQuXG4vLyBGSVhNRTogZm9yIGNvbnNpc3RlbmN5IHdpdGggb3RoZXIgZnVuY3Rpb25zIHRoaXMgc2hvdWxkIG9ubHlcbi8vICAgZ2V0IHRoZSBmaW5nZXJwcmludCBsaW5lIGFzIGlucHV0LiBTZWUgYWxzbyBnZXRJY2VQYXJhbWV0ZXJzLlxuU0RQVXRpbHMuZ2V0RHRsc1BhcmFtZXRlcnMgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KSB7XG4gIHZhciBsaW5lcyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiArIHNlc3Npb25wYXJ0LFxuICAgICAgJ2E9ZmluZ2VycHJpbnQ6Jyk7XG4gIC8vIE5vdGU6IGE9c2V0dXAgbGluZSBpcyBpZ25vcmVkIHNpbmNlIHdlIHVzZSB0aGUgJ2F1dG8nIHJvbGUuXG4gIC8vIE5vdGUyOiAnYWxnb3JpdGhtJyBpcyBub3QgY2FzZSBzZW5zaXRpdmUgZXhjZXB0IGluIEVkZ2UuXG4gIHJldHVybiB7XG4gICAgcm9sZTogJ2F1dG8nLFxuICAgIGZpbmdlcnByaW50czogbGluZXMubWFwKFNEUFV0aWxzLnBhcnNlRmluZ2VycHJpbnQpXG4gIH07XG59O1xuXG4vLyBTZXJpYWxpemVzIERUTFMgcGFyYW1ldGVycyB0byBTRFAuXG5TRFBVdGlscy53cml0ZUR0bHNQYXJhbWV0ZXJzID0gZnVuY3Rpb24ocGFyYW1zLCBzZXR1cFR5cGUpIHtcbiAgdmFyIHNkcCA9ICdhPXNldHVwOicgKyBzZXR1cFR5cGUgKyAnXFxyXFxuJztcbiAgcGFyYW1zLmZpbmdlcnByaW50cy5mb3JFYWNoKGZ1bmN0aW9uKGZwKSB7XG4gICAgc2RwICs9ICdhPWZpbmdlcnByaW50OicgKyBmcC5hbGdvcml0aG0gKyAnICcgKyBmcC52YWx1ZSArICdcXHJcXG4nO1xuICB9KTtcbiAgcmV0dXJuIHNkcDtcbn07XG4vLyBQYXJzZXMgSUNFIGluZm9ybWF0aW9uIGZyb20gU0RQIG1lZGlhIHNlY3Rpb24gb3Igc2Vzc2lvbnBhcnQuXG4vLyBGSVhNRTogZm9yIGNvbnNpc3RlbmN5IHdpdGggb3RoZXIgZnVuY3Rpb25zIHRoaXMgc2hvdWxkIG9ubHlcbi8vICAgZ2V0IHRoZSBpY2UtdWZyYWcgYW5kIGljZS1wd2QgbGluZXMgYXMgaW5wdXQuXG5TRFBVdGlscy5nZXRJY2VQYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZXNzaW9ucGFydCkge1xuICB2YXIgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIC8vIFNlYXJjaCBpbiBzZXNzaW9uIHBhcnQsIHRvby5cbiAgbGluZXMgPSBsaW5lcy5jb25jYXQoU0RQVXRpbHMuc3BsaXRMaW5lcyhzZXNzaW9ucGFydCkpO1xuICB2YXIgaWNlUGFyYW1ldGVycyA9IHtcbiAgICB1c2VybmFtZUZyYWdtZW50OiBsaW5lcy5maWx0ZXIoZnVuY3Rpb24obGluZSkge1xuICAgICAgcmV0dXJuIGxpbmUuaW5kZXhPZignYT1pY2UtdWZyYWc6JykgPT09IDA7XG4gICAgfSlbMF0uc3Vic3RyKDEyKSxcbiAgICBwYXNzd29yZDogbGluZXMuZmlsdGVyKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICAgIHJldHVybiBsaW5lLmluZGV4T2YoJ2E9aWNlLXB3ZDonKSA9PT0gMDtcbiAgICB9KVswXS5zdWJzdHIoMTApXG4gIH07XG4gIHJldHVybiBpY2VQYXJhbWV0ZXJzO1xufTtcblxuLy8gU2VyaWFsaXplcyBJQ0UgcGFyYW1ldGVycyB0byBTRFAuXG5TRFBVdGlscy53cml0ZUljZVBhcmFtZXRlcnMgPSBmdW5jdGlvbihwYXJhbXMpIHtcbiAgcmV0dXJuICdhPWljZS11ZnJhZzonICsgcGFyYW1zLnVzZXJuYW1lRnJhZ21lbnQgKyAnXFxyXFxuJyArXG4gICAgICAnYT1pY2UtcHdkOicgKyBwYXJhbXMucGFzc3dvcmQgKyAnXFxyXFxuJztcbn07XG5cbi8vIFBhcnNlcyB0aGUgU0RQIG1lZGlhIHNlY3Rpb24gYW5kIHJldHVybnMgUlRDUnRwUGFyYW1ldGVycy5cblNEUFV0aWxzLnBhcnNlUnRwUGFyYW1ldGVycyA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICB2YXIgZGVzY3JpcHRpb24gPSB7XG4gICAgY29kZWNzOiBbXSxcbiAgICBoZWFkZXJFeHRlbnNpb25zOiBbXSxcbiAgICBmZWNNZWNoYW5pc21zOiBbXSxcbiAgICBydGNwOiBbXVxuICB9O1xuICB2YXIgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIHZhciBtbGluZSA9IGxpbmVzWzBdLnNwbGl0KCcgJyk7XG4gIGZvciAodmFyIGkgPSAzOyBpIDwgbWxpbmUubGVuZ3RoOyBpKyspIHsgLy8gZmluZCBhbGwgY29kZWNzIGZyb20gbWxpbmVbMy4uXVxuICAgIHZhciBwdCA9IG1saW5lW2ldO1xuICAgIHZhciBydHBtYXBsaW5lID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgoXG4gICAgICAgIG1lZGlhU2VjdGlvbiwgJ2E9cnRwbWFwOicgKyBwdCArICcgJylbMF07XG4gICAgaWYgKHJ0cG1hcGxpbmUpIHtcbiAgICAgIHZhciBjb2RlYyA9IFNEUFV0aWxzLnBhcnNlUnRwTWFwKHJ0cG1hcGxpbmUpO1xuICAgICAgdmFyIGZtdHBzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgoXG4gICAgICAgICAgbWVkaWFTZWN0aW9uLCAnYT1mbXRwOicgKyBwdCArICcgJyk7XG4gICAgICAvLyBPbmx5IHRoZSBmaXJzdCBhPWZtdHA6PHB0PiBpcyBjb25zaWRlcmVkLlxuICAgICAgY29kZWMucGFyYW1ldGVycyA9IGZtdHBzLmxlbmd0aCA/IFNEUFV0aWxzLnBhcnNlRm10cChmbXRwc1swXSkgOiB7fTtcbiAgICAgIGNvZGVjLnJ0Y3BGZWVkYmFjayA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KFxuICAgICAgICAgIG1lZGlhU2VjdGlvbiwgJ2E9cnRjcC1mYjonICsgcHQgKyAnICcpXG4gICAgICAgIC5tYXAoU0RQVXRpbHMucGFyc2VSdGNwRmIpO1xuICAgICAgZGVzY3JpcHRpb24uY29kZWNzLnB1c2goY29kZWMpO1xuICAgICAgLy8gcGFyc2UgRkVDIG1lY2hhbmlzbXMgZnJvbSBydHBtYXAgbGluZXMuXG4gICAgICBzd2l0Y2ggKGNvZGVjLm5hbWUudG9VcHBlckNhc2UoKSkge1xuICAgICAgICBjYXNlICdSRUQnOlxuICAgICAgICBjYXNlICdVTFBGRUMnOlxuICAgICAgICAgIGRlc2NyaXB0aW9uLmZlY01lY2hhbmlzbXMucHVzaChjb2RlYy5uYW1lLnRvVXBwZXJDYXNlKCkpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OiAvLyBvbmx5IFJFRCBhbmQgVUxQRkVDIGFyZSByZWNvZ25pemVkIGFzIEZFQyBtZWNoYW5pc21zLlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPWV4dG1hcDonKS5mb3JFYWNoKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICBkZXNjcmlwdGlvbi5oZWFkZXJFeHRlbnNpb25zLnB1c2goU0RQVXRpbHMucGFyc2VFeHRtYXAobGluZSkpO1xuICB9KTtcbiAgLy8gRklYTUU6IHBhcnNlIHJ0Y3AuXG4gIHJldHVybiBkZXNjcmlwdGlvbjtcbn07XG5cbi8vIEdlbmVyYXRlcyBwYXJ0cyBvZiB0aGUgU0RQIG1lZGlhIHNlY3Rpb24gZGVzY3JpYmluZyB0aGUgY2FwYWJpbGl0aWVzIC9cbi8vIHBhcmFtZXRlcnMuXG5TRFBVdGlscy53cml0ZVJ0cERlc2NyaXB0aW9uID0gZnVuY3Rpb24oa2luZCwgY2Fwcykge1xuICB2YXIgc2RwID0gJyc7XG5cbiAgLy8gQnVpbGQgdGhlIG1saW5lLlxuICBzZHAgKz0gJ209JyArIGtpbmQgKyAnICc7XG4gIHNkcCArPSBjYXBzLmNvZGVjcy5sZW5ndGggPiAwID8gJzknIDogJzAnOyAvLyByZWplY3QgaWYgbm8gY29kZWNzLlxuICBzZHAgKz0gJyBVRFAvVExTL1JUUC9TQVZQRiAnO1xuICBzZHAgKz0gY2Fwcy5jb2RlY3MubWFwKGZ1bmN0aW9uKGNvZGVjKSB7XG4gICAgaWYgKGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZTtcbiAgICB9XG4gICAgcmV0dXJuIGNvZGVjLnBheWxvYWRUeXBlO1xuICB9KS5qb2luKCcgJykgKyAnXFxyXFxuJztcblxuICBzZHAgKz0gJ2M9SU4gSVA0IDAuMC4wLjBcXHJcXG4nO1xuICBzZHAgKz0gJ2E9cnRjcDo5IElOIElQNCAwLjAuMC4wXFxyXFxuJztcblxuICAvLyBBZGQgYT1ydHBtYXAgbGluZXMgZm9yIGVhY2ggY29kZWMuIEFsc28gZm10cCBhbmQgcnRjcC1mYi5cbiAgY2Fwcy5jb2RlY3MuZm9yRWFjaChmdW5jdGlvbihjb2RlYykge1xuICAgIHNkcCArPSBTRFBVdGlscy53cml0ZVJ0cE1hcChjb2RlYyk7XG4gICAgc2RwICs9IFNEUFV0aWxzLndyaXRlRm10cChjb2RlYyk7XG4gICAgc2RwICs9IFNEUFV0aWxzLndyaXRlUnRjcEZiKGNvZGVjKTtcbiAgfSk7XG4gIHZhciBtYXhwdGltZSA9IDA7XG4gIGNhcHMuY29kZWNzLmZvckVhY2goZnVuY3Rpb24oY29kZWMpIHtcbiAgICBpZiAoY29kZWMubWF4cHRpbWUgPiBtYXhwdGltZSkge1xuICAgICAgbWF4cHRpbWUgPSBjb2RlYy5tYXhwdGltZTtcbiAgICB9XG4gIH0pO1xuICBpZiAobWF4cHRpbWUgPiAwKSB7XG4gICAgc2RwICs9ICdhPW1heHB0aW1lOicgKyBtYXhwdGltZSArICdcXHJcXG4nO1xuICB9XG4gIHNkcCArPSAnYT1ydGNwLW11eFxcclxcbic7XG5cbiAgY2Fwcy5oZWFkZXJFeHRlbnNpb25zLmZvckVhY2goZnVuY3Rpb24oZXh0ZW5zaW9uKSB7XG4gICAgc2RwICs9IFNEUFV0aWxzLndyaXRlRXh0bWFwKGV4dGVuc2lvbik7XG4gIH0pO1xuICAvLyBGSVhNRTogd3JpdGUgZmVjTWVjaGFuaXNtcy5cbiAgcmV0dXJuIHNkcDtcbn07XG5cbi8vIFBhcnNlcyB0aGUgU0RQIG1lZGlhIHNlY3Rpb24gYW5kIHJldHVybnMgYW4gYXJyYXkgb2Zcbi8vIFJUQ1J0cEVuY29kaW5nUGFyYW1ldGVycy5cblNEUFV0aWxzLnBhcnNlUnRwRW5jb2RpbmdQYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIHZhciBlbmNvZGluZ1BhcmFtZXRlcnMgPSBbXTtcbiAgdmFyIGRlc2NyaXB0aW9uID0gU0RQVXRpbHMucGFyc2VSdHBQYXJhbWV0ZXJzKG1lZGlhU2VjdGlvbik7XG4gIHZhciBoYXNSZWQgPSBkZXNjcmlwdGlvbi5mZWNNZWNoYW5pc21zLmluZGV4T2YoJ1JFRCcpICE9PSAtMTtcbiAgdmFyIGhhc1VscGZlYyA9IGRlc2NyaXB0aW9uLmZlY01lY2hhbmlzbXMuaW5kZXhPZignVUxQRkVDJykgIT09IC0xO1xuXG4gIC8vIGZpbHRlciBhPXNzcmM6Li4uIGNuYW1lOiwgaWdub3JlIFBsYW5CLW1zaWRcbiAgdmFyIHNzcmNzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1zc3JjOicpXG4gIC5tYXAoZnVuY3Rpb24obGluZSkge1xuICAgIHJldHVybiBTRFBVdGlscy5wYXJzZVNzcmNNZWRpYShsaW5lKTtcbiAgfSlcbiAgLmZpbHRlcihmdW5jdGlvbihwYXJ0cykge1xuICAgIHJldHVybiBwYXJ0cy5hdHRyaWJ1dGUgPT09ICdjbmFtZSc7XG4gIH0pO1xuICB2YXIgcHJpbWFyeVNzcmMgPSBzc3Jjcy5sZW5ndGggPiAwICYmIHNzcmNzWzBdLnNzcmM7XG4gIHZhciBzZWNvbmRhcnlTc3JjO1xuXG4gIHZhciBmbG93cyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9c3NyYy1ncm91cDpGSUQnKVxuICAubWFwKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICB2YXIgcGFydHMgPSBsaW5lLnNwbGl0KCcgJyk7XG4gICAgcGFydHMuc2hpZnQoKTtcbiAgICByZXR1cm4gcGFydHMubWFwKGZ1bmN0aW9uKHBhcnQpIHtcbiAgICAgIHJldHVybiBwYXJzZUludChwYXJ0LCAxMCk7XG4gICAgfSk7XG4gIH0pO1xuICBpZiAoZmxvd3MubGVuZ3RoID4gMCAmJiBmbG93c1swXS5sZW5ndGggPiAxICYmIGZsb3dzWzBdWzBdID09PSBwcmltYXJ5U3NyYykge1xuICAgIHNlY29uZGFyeVNzcmMgPSBmbG93c1swXVsxXTtcbiAgfVxuXG4gIGRlc2NyaXB0aW9uLmNvZGVjcy5mb3JFYWNoKGZ1bmN0aW9uKGNvZGVjKSB7XG4gICAgaWYgKGNvZGVjLm5hbWUudG9VcHBlckNhc2UoKSA9PT0gJ1JUWCcgJiYgY29kZWMucGFyYW1ldGVycy5hcHQpIHtcbiAgICAgIHZhciBlbmNQYXJhbSA9IHtcbiAgICAgICAgc3NyYzogcHJpbWFyeVNzcmMsXG4gICAgICAgIGNvZGVjUGF5bG9hZFR5cGU6IHBhcnNlSW50KGNvZGVjLnBhcmFtZXRlcnMuYXB0LCAxMCksXG4gICAgICAgIHJ0eDoge1xuICAgICAgICAgIHNzcmM6IHNlY29uZGFyeVNzcmNcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIGVuY29kaW5nUGFyYW1ldGVycy5wdXNoKGVuY1BhcmFtKTtcbiAgICAgIGlmIChoYXNSZWQpIHtcbiAgICAgICAgZW5jUGFyYW0gPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGVuY1BhcmFtKSk7XG4gICAgICAgIGVuY1BhcmFtLmZlYyA9IHtcbiAgICAgICAgICBzc3JjOiBzZWNvbmRhcnlTc3JjLFxuICAgICAgICAgIG1lY2hhbmlzbTogaGFzVWxwZmVjID8gJ3JlZCt1bHBmZWMnIDogJ3JlZCdcbiAgICAgICAgfTtcbiAgICAgICAgZW5jb2RpbmdQYXJhbWV0ZXJzLnB1c2goZW5jUGFyYW0pO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIGlmIChlbmNvZGluZ1BhcmFtZXRlcnMubGVuZ3RoID09PSAwICYmIHByaW1hcnlTc3JjKSB7XG4gICAgZW5jb2RpbmdQYXJhbWV0ZXJzLnB1c2goe1xuICAgICAgc3NyYzogcHJpbWFyeVNzcmNcbiAgICB9KTtcbiAgfVxuXG4gIC8vIHdlIHN1cHBvcnQgYm90aCBiPUFTIGFuZCBiPVRJQVMgYnV0IGludGVycHJldCBBUyBhcyBUSUFTLlxuICB2YXIgYmFuZHdpZHRoID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYj0nKTtcbiAgaWYgKGJhbmR3aWR0aC5sZW5ndGgpIHtcbiAgICBpZiAoYmFuZHdpZHRoWzBdLmluZGV4T2YoJ2I9VElBUzonKSA9PT0gMCkge1xuICAgICAgYmFuZHdpZHRoID0gcGFyc2VJbnQoYmFuZHdpZHRoWzBdLnN1YnN0cig3KSwgMTApO1xuICAgIH0gZWxzZSBpZiAoYmFuZHdpZHRoWzBdLmluZGV4T2YoJ2I9QVM6JykgPT09IDApIHtcbiAgICAgIGJhbmR3aWR0aCA9IHBhcnNlSW50KGJhbmR3aWR0aFswXS5zdWJzdHIoNSksIDEwKTtcbiAgICB9XG4gICAgZW5jb2RpbmdQYXJhbWV0ZXJzLmZvckVhY2goZnVuY3Rpb24ocGFyYW1zKSB7XG4gICAgICBwYXJhbXMubWF4Qml0cmF0ZSA9IGJhbmR3aWR0aDtcbiAgICB9KTtcbiAgfVxuICByZXR1cm4gZW5jb2RpbmdQYXJhbWV0ZXJzO1xufTtcblxuLy8gcGFyc2VzIGh0dHA6Ly9kcmFmdC5vcnRjLm9yZy8jcnRjcnRjcHBhcmFtZXRlcnMqXG5TRFBVdGlscy5wYXJzZVJ0Y3BQYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIHZhciBydGNwUGFyYW1ldGVycyA9IHt9O1xuXG4gIHZhciBjbmFtZTtcbiAgLy8gR2V0cyB0aGUgZmlyc3QgU1NSQy4gTm90ZSB0aGF0IHdpdGggUlRYIHRoZXJlIG1pZ2h0IGJlIG11bHRpcGxlXG4gIC8vIFNTUkNzLlxuICB2YXIgcmVtb3RlU3NyYyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9c3NyYzonKVxuICAgICAgLm1hcChmdW5jdGlvbihsaW5lKSB7XG4gICAgICAgIHJldHVybiBTRFBVdGlscy5wYXJzZVNzcmNNZWRpYShsaW5lKTtcbiAgICAgIH0pXG4gICAgICAuZmlsdGVyKGZ1bmN0aW9uKG9iaikge1xuICAgICAgICByZXR1cm4gb2JqLmF0dHJpYnV0ZSA9PT0gJ2NuYW1lJztcbiAgICAgIH0pWzBdO1xuICBpZiAocmVtb3RlU3NyYykge1xuICAgIHJ0Y3BQYXJhbWV0ZXJzLmNuYW1lID0gcmVtb3RlU3NyYy52YWx1ZTtcbiAgICBydGNwUGFyYW1ldGVycy5zc3JjID0gcmVtb3RlU3NyYy5zc3JjO1xuICB9XG5cbiAgLy8gRWRnZSB1c2VzIHRoZSBjb21wb3VuZCBhdHRyaWJ1dGUgaW5zdGVhZCBvZiByZWR1Y2VkU2l6ZVxuICAvLyBjb21wb3VuZCBpcyAhcmVkdWNlZFNpemVcbiAgdmFyIHJzaXplID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1ydGNwLXJzaXplJyk7XG4gIHJ0Y3BQYXJhbWV0ZXJzLnJlZHVjZWRTaXplID0gcnNpemUubGVuZ3RoID4gMDtcbiAgcnRjcFBhcmFtZXRlcnMuY29tcG91bmQgPSByc2l6ZS5sZW5ndGggPT09IDA7XG5cbiAgLy8gcGFyc2VzIHRoZSBydGNwLW11eCBhdHRy0ZZidXRlLlxuICAvLyBOb3RlIHRoYXQgRWRnZSBkb2VzIG5vdCBzdXBwb3J0IHVubXV4ZWQgUlRDUC5cbiAgdmFyIG11eCA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9cnRjcC1tdXgnKTtcbiAgcnRjcFBhcmFtZXRlcnMubXV4ID0gbXV4Lmxlbmd0aCA+IDA7XG5cbiAgcmV0dXJuIHJ0Y3BQYXJhbWV0ZXJzO1xufTtcblxuLy8gcGFyc2VzIGVpdGhlciBhPW1zaWQ6IG9yIGE9c3NyYzouLi4gbXNpZCBsaW5lcyBhbmQgcmV0dXJuc1xuLy8gdGhlIGlkIG9mIHRoZSBNZWRpYVN0cmVhbSBhbmQgTWVkaWFTdHJlYW1UcmFjay5cblNEUFV0aWxzLnBhcnNlTXNpZCA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICB2YXIgcGFydHM7XG4gIHZhciBzcGVjID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1tc2lkOicpO1xuICBpZiAoc3BlYy5sZW5ndGggPT09IDEpIHtcbiAgICBwYXJ0cyA9IHNwZWNbMF0uc3Vic3RyKDcpLnNwbGl0KCcgJyk7XG4gICAgcmV0dXJuIHtzdHJlYW06IHBhcnRzWzBdLCB0cmFjazogcGFydHNbMV19O1xuICB9XG4gIHZhciBwbGFuQiA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9c3NyYzonKVxuICAubWFwKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICByZXR1cm4gU0RQVXRpbHMucGFyc2VTc3JjTWVkaWEobGluZSk7XG4gIH0pXG4gIC5maWx0ZXIoZnVuY3Rpb24ocGFydHMpIHtcbiAgICByZXR1cm4gcGFydHMuYXR0cmlidXRlID09PSAnbXNpZCc7XG4gIH0pO1xuICBpZiAocGxhbkIubGVuZ3RoID4gMCkge1xuICAgIHBhcnRzID0gcGxhbkJbMF0udmFsdWUuc3BsaXQoJyAnKTtcbiAgICByZXR1cm4ge3N0cmVhbTogcGFydHNbMF0sIHRyYWNrOiBwYXJ0c1sxXX07XG4gIH1cbn07XG5cblNEUFV0aWxzLndyaXRlU2Vzc2lvbkJvaWxlcnBsYXRlID0gZnVuY3Rpb24oKSB7XG4gIC8vIEZJWE1FOiBzZXNzLWlkIHNob3VsZCBiZSBhbiBOVFAgdGltZXN0YW1wLlxuICByZXR1cm4gJ3Y9MFxcclxcbicgK1xuICAgICAgJ289dGhpc2lzYWRhcHRlcm9ydGMgODE2OTYzOTkxNTY0Njk0MzEzNyAyIElOIElQNCAxMjcuMC4wLjFcXHJcXG4nICtcbiAgICAgICdzPS1cXHJcXG4nICtcbiAgICAgICd0PTAgMFxcclxcbic7XG59O1xuXG5TRFBVdGlscy53cml0ZU1lZGlhU2VjdGlvbiA9IGZ1bmN0aW9uKHRyYW5zY2VpdmVyLCBjYXBzLCB0eXBlLCBzdHJlYW0pIHtcbiAgdmFyIHNkcCA9IFNEUFV0aWxzLndyaXRlUnRwRGVzY3JpcHRpb24odHJhbnNjZWl2ZXIua2luZCwgY2Fwcyk7XG5cbiAgLy8gTWFwIElDRSBwYXJhbWV0ZXJzICh1ZnJhZywgcHdkKSB0byBTRFAuXG4gIHNkcCArPSBTRFBVdGlscy53cml0ZUljZVBhcmFtZXRlcnMoXG4gICAgICB0cmFuc2NlaXZlci5pY2VHYXRoZXJlci5nZXRMb2NhbFBhcmFtZXRlcnMoKSk7XG5cbiAgLy8gTWFwIERUTFMgcGFyYW1ldGVycyB0byBTRFAuXG4gIHNkcCArPSBTRFBVdGlscy53cml0ZUR0bHNQYXJhbWV0ZXJzKFxuICAgICAgdHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydC5nZXRMb2NhbFBhcmFtZXRlcnMoKSxcbiAgICAgIHR5cGUgPT09ICdvZmZlcicgPyAnYWN0cGFzcycgOiAnYWN0aXZlJyk7XG5cbiAgc2RwICs9ICdhPW1pZDonICsgdHJhbnNjZWl2ZXIubWlkICsgJ1xcclxcbic7XG5cbiAgaWYgKHRyYW5zY2VpdmVyLmRpcmVjdGlvbikge1xuICAgIHNkcCArPSAnYT0nICsgdHJhbnNjZWl2ZXIuZGlyZWN0aW9uICsgJ1xcclxcbic7XG4gIH0gZWxzZSBpZiAodHJhbnNjZWl2ZXIucnRwU2VuZGVyICYmIHRyYW5zY2VpdmVyLnJ0cFJlY2VpdmVyKSB7XG4gICAgc2RwICs9ICdhPXNlbmRyZWN2XFxyXFxuJztcbiAgfSBlbHNlIGlmICh0cmFuc2NlaXZlci5ydHBTZW5kZXIpIHtcbiAgICBzZHAgKz0gJ2E9c2VuZG9ubHlcXHJcXG4nO1xuICB9IGVsc2UgaWYgKHRyYW5zY2VpdmVyLnJ0cFJlY2VpdmVyKSB7XG4gICAgc2RwICs9ICdhPXJlY3Zvbmx5XFxyXFxuJztcbiAgfSBlbHNlIHtcbiAgICBzZHAgKz0gJ2E9aW5hY3RpdmVcXHJcXG4nO1xuICB9XG5cbiAgaWYgKHRyYW5zY2VpdmVyLnJ0cFNlbmRlcikge1xuICAgIC8vIHNwZWMuXG4gICAgdmFyIG1zaWQgPSAnbXNpZDonICsgc3RyZWFtLmlkICsgJyAnICtcbiAgICAgICAgdHJhbnNjZWl2ZXIucnRwU2VuZGVyLnRyYWNrLmlkICsgJ1xcclxcbic7XG4gICAgc2RwICs9ICdhPScgKyBtc2lkO1xuXG4gICAgLy8gZm9yIENocm9tZS5cbiAgICBzZHAgKz0gJ2E9c3NyYzonICsgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5zc3JjICtcbiAgICAgICAgJyAnICsgbXNpZDtcbiAgICBpZiAodHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHgpIHtcbiAgICAgIHNkcCArPSAnYT1zc3JjOicgKyB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eC5zc3JjICtcbiAgICAgICAgICAnICcgKyBtc2lkO1xuICAgICAgc2RwICs9ICdhPXNzcmMtZ3JvdXA6RklEICcgK1xuICAgICAgICAgIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0uc3NyYyArICcgJyArXG4gICAgICAgICAgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHguc3NyYyArXG4gICAgICAgICAgJ1xcclxcbic7XG4gICAgfVxuICB9XG4gIC8vIEZJWE1FOiB0aGlzIHNob3VsZCBiZSB3cml0dGVuIGJ5IHdyaXRlUnRwRGVzY3JpcHRpb24uXG4gIHNkcCArPSAnYT1zc3JjOicgKyB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnNzcmMgK1xuICAgICAgJyBjbmFtZTonICsgU0RQVXRpbHMubG9jYWxDTmFtZSArICdcXHJcXG4nO1xuICBpZiAodHJhbnNjZWl2ZXIucnRwU2VuZGVyICYmIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0ucnR4KSB7XG4gICAgc2RwICs9ICdhPXNzcmM6JyArIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0ucnR4LnNzcmMgK1xuICAgICAgICAnIGNuYW1lOicgKyBTRFBVdGlscy5sb2NhbENOYW1lICsgJ1xcclxcbic7XG4gIH1cbiAgcmV0dXJuIHNkcDtcbn07XG5cbi8vIEdldHMgdGhlIGRpcmVjdGlvbiBmcm9tIHRoZSBtZWRpYVNlY3Rpb24gb3IgdGhlIHNlc3Npb25wYXJ0LlxuU0RQVXRpbHMuZ2V0RGlyZWN0aW9uID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZXNzaW9ucGFydCkge1xuICAvLyBMb29rIGZvciBzZW5kcmVjdiwgc2VuZG9ubHksIHJlY3Zvbmx5LCBpbmFjdGl2ZSwgZGVmYXVsdCB0byBzZW5kcmVjdi5cbiAgdmFyIGxpbmVzID0gU0RQVXRpbHMuc3BsaXRMaW5lcyhtZWRpYVNlY3Rpb24pO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgc3dpdGNoIChsaW5lc1tpXSkge1xuICAgICAgY2FzZSAnYT1zZW5kcmVjdic6XG4gICAgICBjYXNlICdhPXNlbmRvbmx5JzpcbiAgICAgIGNhc2UgJ2E9cmVjdm9ubHknOlxuICAgICAgY2FzZSAnYT1pbmFjdGl2ZSc6XG4gICAgICAgIHJldHVybiBsaW5lc1tpXS5zdWJzdHIoMik7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICAvLyBGSVhNRTogV2hhdCBzaG91bGQgaGFwcGVuIGhlcmU/XG4gICAgfVxuICB9XG4gIGlmIChzZXNzaW9ucGFydCkge1xuICAgIHJldHVybiBTRFBVdGlscy5nZXREaXJlY3Rpb24oc2Vzc2lvbnBhcnQpO1xuICB9XG4gIHJldHVybiAnc2VuZHJlY3YnO1xufTtcblxuU0RQVXRpbHMuZ2V0S2luZCA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICB2YXIgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIHZhciBtbGluZSA9IGxpbmVzWzBdLnNwbGl0KCcgJyk7XG4gIHJldHVybiBtbGluZVswXS5zdWJzdHIoMik7XG59O1xuXG5TRFBVdGlscy5pc1JlamVjdGVkID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIHJldHVybiBtZWRpYVNlY3Rpb24uc3BsaXQoJyAnLCAyKVsxXSA9PT0gJzAnO1xufTtcblxuLy8gRXhwb3NlIHB1YmxpYyBtZXRob2RzLlxubW9kdWxlLmV4cG9ydHMgPSBTRFBVdGlscztcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHRyYW5zcG9ydExpc3QgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC1saXN0Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9tYWluJykodHJhbnNwb3J0TGlzdCk7XG5cbi8vIFRPRE8gY2FuJ3QgZ2V0IHJpZCBvZiB0aGlzIHVudGlsIGFsbCBzZXJ2ZXJzIGRvXG5pZiAoJ19zb2NranNfb25sb2FkJyBpbiBnbG9iYWwpIHtcbiAgc2V0VGltZW91dChnbG9iYWwuX3NvY2tqc19vbmxvYWQsIDEpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgRXZlbnQgPSByZXF1aXJlKCcuL2V2ZW50JylcbiAgO1xuXG5mdW5jdGlvbiBDbG9zZUV2ZW50KCkge1xuICBFdmVudC5jYWxsKHRoaXMpO1xuICB0aGlzLmluaXRFdmVudCgnY2xvc2UnLCBmYWxzZSwgZmFsc2UpO1xuICB0aGlzLndhc0NsZWFuID0gZmFsc2U7XG4gIHRoaXMuY29kZSA9IDA7XG4gIHRoaXMucmVhc29uID0gJyc7XG59XG5cbmluaGVyaXRzKENsb3NlRXZlbnQsIEV2ZW50KTtcblxubW9kdWxlLmV4cG9ydHMgPSBDbG9zZUV2ZW50O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgRXZlbnRUYXJnZXQgPSByZXF1aXJlKCcuL2V2ZW50dGFyZ2V0JylcbiAgO1xuXG5mdW5jdGlvbiBFdmVudEVtaXR0ZXIoKSB7XG4gIEV2ZW50VGFyZ2V0LmNhbGwodGhpcyk7XG59XG5cbmluaGVyaXRzKEV2ZW50RW1pdHRlciwgRXZlbnRUYXJnZXQpO1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnJlbW92ZUFsbExpc3RlbmVycyA9IGZ1bmN0aW9uKHR5cGUpIHtcbiAgaWYgKHR5cGUpIHtcbiAgICBkZWxldGUgdGhpcy5fbGlzdGVuZXJzW3R5cGVdO1xuICB9IGVsc2Uge1xuICAgIHRoaXMuX2xpc3RlbmVycyA9IHt9O1xuICB9XG59O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLm9uY2UgPSBmdW5jdGlvbih0eXBlLCBsaXN0ZW5lcikge1xuICB2YXIgc2VsZiA9IHRoaXNcbiAgICAsIGZpcmVkID0gZmFsc2U7XG5cbiAgZnVuY3Rpb24gZygpIHtcbiAgICBzZWxmLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGcpO1xuXG4gICAgaWYgKCFmaXJlZCkge1xuICAgICAgZmlyZWQgPSB0cnVlO1xuICAgICAgbGlzdGVuZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9XG4gIH1cblxuICB0aGlzLm9uKHR5cGUsIGcpO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5lbWl0ID0gZnVuY3Rpb24oKSB7XG4gIHZhciB0eXBlID0gYXJndW1lbnRzWzBdO1xuICB2YXIgbGlzdGVuZXJzID0gdGhpcy5fbGlzdGVuZXJzW3R5cGVdO1xuICBpZiAoIWxpc3RlbmVycykge1xuICAgIHJldHVybjtcbiAgfVxuICAvLyBlcXVpdmFsZW50IG9mIEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gIHZhciBsID0gYXJndW1lbnRzLmxlbmd0aDtcbiAgdmFyIGFyZ3MgPSBuZXcgQXJyYXkobCAtIDEpO1xuICBmb3IgKHZhciBhaSA9IDE7IGFpIDwgbDsgYWkrKykge1xuICAgIGFyZ3NbYWkgLSAxXSA9IGFyZ3VtZW50c1thaV07XG4gIH1cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaXN0ZW5lcnMubGVuZ3RoOyBpKyspIHtcbiAgICBsaXN0ZW5lcnNbaV0uYXBwbHkodGhpcywgYXJncyk7XG4gIH1cbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub24gPSBFdmVudEVtaXR0ZXIucHJvdG90eXBlLmFkZExpc3RlbmVyID0gRXZlbnRUYXJnZXQucHJvdG90eXBlLmFkZEV2ZW50TGlzdGVuZXI7XG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnJlbW92ZUxpc3RlbmVyID0gRXZlbnRUYXJnZXQucHJvdG90eXBlLnJlbW92ZUV2ZW50TGlzdGVuZXI7XG5cbm1vZHVsZS5leHBvcnRzLkV2ZW50RW1pdHRlciA9IEV2ZW50RW1pdHRlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxuZnVuY3Rpb24gRXZlbnQoZXZlbnRUeXBlKSB7XG4gIHRoaXMudHlwZSA9IGV2ZW50VHlwZTtcbn1cblxuRXZlbnQucHJvdG90eXBlLmluaXRFdmVudCA9IGZ1bmN0aW9uKGV2ZW50VHlwZSwgY2FuQnViYmxlLCBjYW5jZWxhYmxlKSB7XG4gIHRoaXMudHlwZSA9IGV2ZW50VHlwZTtcbiAgdGhpcy5idWJibGVzID0gY2FuQnViYmxlO1xuICB0aGlzLmNhbmNlbGFibGUgPSBjYW5jZWxhYmxlO1xuICB0aGlzLnRpbWVTdGFtcCA9ICtuZXcgRGF0ZSgpO1xuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50LnByb3RvdHlwZS5zdG9wUHJvcGFnYXRpb24gPSBmdW5jdGlvbigpIHt9O1xuRXZlbnQucHJvdG90eXBlLnByZXZlbnREZWZhdWx0ID0gZnVuY3Rpb24oKSB7fTtcblxuRXZlbnQuQ0FQVFVSSU5HX1BIQVNFID0gMTtcbkV2ZW50LkFUX1RBUkdFVCA9IDI7XG5FdmVudC5CVUJCTElOR19QSEFTRSA9IDM7XG5cbm1vZHVsZS5leHBvcnRzID0gRXZlbnQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qIFNpbXBsaWZpZWQgaW1wbGVtZW50YXRpb24gb2YgRE9NMiBFdmVudFRhcmdldC5cbiAqICAgaHR0cDovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTItRXZlbnRzL2V2ZW50cy5odG1sI0V2ZW50cy1FdmVudFRhcmdldFxuICovXG5cbmZ1bmN0aW9uIEV2ZW50VGFyZ2V0KCkge1xuICB0aGlzLl9saXN0ZW5lcnMgPSB7fTtcbn1cblxuRXZlbnRUYXJnZXQucHJvdG90eXBlLmFkZEV2ZW50TGlzdGVuZXIgPSBmdW5jdGlvbihldmVudFR5cGUsIGxpc3RlbmVyKSB7XG4gIGlmICghKGV2ZW50VHlwZSBpbiB0aGlzLl9saXN0ZW5lcnMpKSB7XG4gICAgdGhpcy5fbGlzdGVuZXJzW2V2ZW50VHlwZV0gPSBbXTtcbiAgfVxuICB2YXIgYXJyID0gdGhpcy5fbGlzdGVuZXJzW2V2ZW50VHlwZV07XG4gIC8vICM0XG4gIGlmIChhcnIuaW5kZXhPZihsaXN0ZW5lcikgPT09IC0xKSB7XG4gICAgLy8gTWFrZSBhIGNvcHkgc28gYXMgbm90IHRvIGludGVyZmVyZSB3aXRoIGEgY3VycmVudCBkaXNwYXRjaEV2ZW50LlxuICAgIGFyciA9IGFyci5jb25jYXQoW2xpc3RlbmVyXSk7XG4gIH1cbiAgdGhpcy5fbGlzdGVuZXJzW2V2ZW50VHlwZV0gPSBhcnI7XG59O1xuXG5FdmVudFRhcmdldC5wcm90b3R5cGUucmVtb3ZlRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKGV2ZW50VHlwZSwgbGlzdGVuZXIpIHtcbiAgdmFyIGFyciA9IHRoaXMuX2xpc3RlbmVyc1tldmVudFR5cGVdO1xuICBpZiAoIWFycikge1xuICAgIHJldHVybjtcbiAgfVxuICB2YXIgaWR4ID0gYXJyLmluZGV4T2YobGlzdGVuZXIpO1xuICBpZiAoaWR4ICE9PSAtMSkge1xuICAgIGlmIChhcnIubGVuZ3RoID4gMSkge1xuICAgICAgLy8gTWFrZSBhIGNvcHkgc28gYXMgbm90IHRvIGludGVyZmVyZSB3aXRoIGEgY3VycmVudCBkaXNwYXRjaEV2ZW50LlxuICAgICAgdGhpcy5fbGlzdGVuZXJzW2V2ZW50VHlwZV0gPSBhcnIuc2xpY2UoMCwgaWR4KS5jb25jYXQoYXJyLnNsaWNlKGlkeCArIDEpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZGVsZXRlIHRoaXMuX2xpc3RlbmVyc1tldmVudFR5cGVdO1xuICAgIH1cbiAgICByZXR1cm47XG4gIH1cbn07XG5cbkV2ZW50VGFyZ2V0LnByb3RvdHlwZS5kaXNwYXRjaEV2ZW50ID0gZnVuY3Rpb24oKSB7XG4gIHZhciBldmVudCA9IGFyZ3VtZW50c1swXTtcbiAgdmFyIHQgPSBldmVudC50eXBlO1xuICAvLyBlcXVpdmFsZW50IG9mIEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMCk7XG4gIHZhciBhcmdzID0gYXJndW1lbnRzLmxlbmd0aCA9PT0gMSA/IFtldmVudF0gOiBBcnJheS5hcHBseShudWxsLCBhcmd1bWVudHMpO1xuICAvLyBUT0RPOiBUaGlzIGRvZXNuJ3QgbWF0Y2ggdGhlIHJlYWwgYmVoYXZpb3I7IHBlciBzcGVjLCBvbmZvbyBnZXRcbiAgLy8gdGhlaXIgcGxhY2UgaW4gbGluZSBmcm9tIHRoZSAvZmlyc3QvIHRpbWUgdGhleSdyZSBzZXQgZnJvbVxuICAvLyBub24tbnVsbC4gQWx0aG91Z2ggV2ViS2l0IGJ1bXBzIGl0IHRvIHRoZSBlbmQgZXZlcnkgdGltZSBpdCdzXG4gIC8vIHNldC5cbiAgaWYgKHRoaXNbJ29uJyArIHRdKSB7XG4gICAgdGhpc1snb24nICsgdF0uYXBwbHkodGhpcywgYXJncyk7XG4gIH1cbiAgaWYgKHQgaW4gdGhpcy5fbGlzdGVuZXJzKSB7XG4gICAgLy8gR3JhYiBhIHJlZmVyZW5jZSB0byB0aGUgbGlzdGVuZXJzIGxpc3QuIHJlbW92ZUV2ZW50TGlzdGVuZXIgbWF5IGFsdGVyIHRoZSBsaXN0LlxuICAgIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnNbdF07XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaXN0ZW5lcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGxpc3RlbmVyc1tpXS5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICB9XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRXZlbnRUYXJnZXQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBFdmVudCA9IHJlcXVpcmUoJy4vZXZlbnQnKVxuICA7XG5cbmZ1bmN0aW9uIFRyYW5zcG9ydE1lc3NhZ2VFdmVudChkYXRhKSB7XG4gIEV2ZW50LmNhbGwodGhpcyk7XG4gIHRoaXMuaW5pdEV2ZW50KCdtZXNzYWdlJywgZmFsc2UsIGZhbHNlKTtcbiAgdGhpcy5kYXRhID0gZGF0YTtcbn1cblxuaW5oZXJpdHMoVHJhbnNwb3J0TWVzc2FnZUV2ZW50LCBFdmVudCk7XG5cbm1vZHVsZS5leHBvcnRzID0gVHJhbnNwb3J0TWVzc2FnZUV2ZW50O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgSlNPTjMgPSByZXF1aXJlKCdqc29uMycpXG4gICwgaWZyYW1lVXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzL2lmcmFtZScpXG4gIDtcblxuZnVuY3Rpb24gRmFjYWRlSlModHJhbnNwb3J0KSB7XG4gIHRoaXMuX3RyYW5zcG9ydCA9IHRyYW5zcG9ydDtcbiAgdHJhbnNwb3J0Lm9uKCdtZXNzYWdlJywgdGhpcy5fdHJhbnNwb3J0TWVzc2FnZS5iaW5kKHRoaXMpKTtcbiAgdHJhbnNwb3J0Lm9uKCdjbG9zZScsIHRoaXMuX3RyYW5zcG9ydENsb3NlLmJpbmQodGhpcykpO1xufVxuXG5GYWNhZGVKUy5wcm90b3R5cGUuX3RyYW5zcG9ydENsb3NlID0gZnVuY3Rpb24oY29kZSwgcmVhc29uKSB7XG4gIGlmcmFtZVV0aWxzLnBvc3RNZXNzYWdlKCdjJywgSlNPTjMuc3RyaW5naWZ5KFtjb2RlLCByZWFzb25dKSk7XG59O1xuRmFjYWRlSlMucHJvdG90eXBlLl90cmFuc3BvcnRNZXNzYWdlID0gZnVuY3Rpb24oZnJhbWUpIHtcbiAgaWZyYW1lVXRpbHMucG9zdE1lc3NhZ2UoJ3QnLCBmcmFtZSk7XG59O1xuRmFjYWRlSlMucHJvdG90eXBlLl9zZW5kID0gZnVuY3Rpb24oZGF0YSkge1xuICB0aGlzLl90cmFuc3BvcnQuc2VuZChkYXRhKTtcbn07XG5GYWNhZGVKUy5wcm90b3R5cGUuX2Nsb3NlID0gZnVuY3Rpb24oKSB7XG4gIHRoaXMuX3RyYW5zcG9ydC5jbG9zZSgpO1xuICB0aGlzLl90cmFuc3BvcnQucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEZhY2FkZUpTO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXJsVXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzL3VybCcpXG4gICwgZXZlbnRVdGlscyA9IHJlcXVpcmUoJy4vdXRpbHMvZXZlbnQnKVxuICAsIEpTT04zID0gcmVxdWlyZSgnanNvbjMnKVxuICAsIEZhY2FkZUpTID0gcmVxdWlyZSgnLi9mYWNhZGUnKVxuICAsIEluZm9JZnJhbWVSZWNlaXZlciA9IHJlcXVpcmUoJy4vaW5mby1pZnJhbWUtcmVjZWl2ZXInKVxuICAsIGlmcmFtZVV0aWxzID0gcmVxdWlyZSgnLi91dGlscy9pZnJhbWUnKVxuICAsIGxvYyA9IHJlcXVpcmUoJy4vbG9jYXRpb24nKVxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6aWZyYW1lLWJvb3RzdHJhcCcpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKFNvY2tKUywgYXZhaWxhYmxlVHJhbnNwb3J0cykge1xuICB2YXIgdHJhbnNwb3J0TWFwID0ge307XG4gIGF2YWlsYWJsZVRyYW5zcG9ydHMuZm9yRWFjaChmdW5jdGlvbihhdCkge1xuICAgIGlmIChhdC5mYWNhZGVUcmFuc3BvcnQpIHtcbiAgICAgIHRyYW5zcG9ydE1hcFthdC5mYWNhZGVUcmFuc3BvcnQudHJhbnNwb3J0TmFtZV0gPSBhdC5mYWNhZGVUcmFuc3BvcnQ7XG4gICAgfVxuICB9KTtcblxuICAvLyBoYXJkLWNvZGVkIGZvciB0aGUgaW5mbyBpZnJhbWVcbiAgLy8gVE9ETyBzZWUgaWYgd2UgY2FuIG1ha2UgdGhpcyBtb3JlIGR5bmFtaWNcbiAgdHJhbnNwb3J0TWFwW0luZm9JZnJhbWVSZWNlaXZlci50cmFuc3BvcnROYW1lXSA9IEluZm9JZnJhbWVSZWNlaXZlcjtcbiAgdmFyIHBhcmVudE9yaWdpbjtcblxuICAvKiBlc2xpbnQtZGlzYWJsZSBjYW1lbGNhc2UgKi9cbiAgU29ja0pTLmJvb3RzdHJhcF9pZnJhbWUgPSBmdW5jdGlvbigpIHtcbiAgICAvKiBlc2xpbnQtZW5hYmxlIGNhbWVsY2FzZSAqL1xuICAgIHZhciBmYWNhZGU7XG4gICAgaWZyYW1lVXRpbHMuY3VycmVudFdpbmRvd0lkID0gbG9jLmhhc2guc2xpY2UoMSk7XG4gICAgdmFyIG9uTWVzc2FnZSA9IGZ1bmN0aW9uKGUpIHtcbiAgICAgIGlmIChlLnNvdXJjZSAhPT0gcGFyZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmICh0eXBlb2YgcGFyZW50T3JpZ2luID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICBwYXJlbnRPcmlnaW4gPSBlLm9yaWdpbjtcbiAgICAgIH1cbiAgICAgIGlmIChlLm9yaWdpbiAhPT0gcGFyZW50T3JpZ2luKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIGlmcmFtZU1lc3NhZ2U7XG4gICAgICB0cnkge1xuICAgICAgICBpZnJhbWVNZXNzYWdlID0gSlNPTjMucGFyc2UoZS5kYXRhKTtcbiAgICAgIH0gY2F0Y2ggKGlnbm9yZWQpIHtcbiAgICAgICAgZGVidWcoJ2JhZCBqc29uJywgZS5kYXRhKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoaWZyYW1lTWVzc2FnZS53aW5kb3dJZCAhPT0gaWZyYW1lVXRpbHMuY3VycmVudFdpbmRvd0lkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHN3aXRjaCAoaWZyYW1lTWVzc2FnZS50eXBlKSB7XG4gICAgICBjYXNlICdzJzpcbiAgICAgICAgdmFyIHA7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcCA9IEpTT04zLnBhcnNlKGlmcmFtZU1lc3NhZ2UuZGF0YSk7XG4gICAgICAgIH0gY2F0Y2ggKGlnbm9yZWQpIHtcbiAgICAgICAgICBkZWJ1ZygnYmFkIGpzb24nLCBpZnJhbWVNZXNzYWdlLmRhdGEpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIHZhciB2ZXJzaW9uID0gcFswXTtcbiAgICAgICAgdmFyIHRyYW5zcG9ydCA9IHBbMV07XG4gICAgICAgIHZhciB0cmFuc1VybCA9IHBbMl07XG4gICAgICAgIHZhciBiYXNlVXJsID0gcFszXTtcbiAgICAgICAgZGVidWcodmVyc2lvbiwgdHJhbnNwb3J0LCB0cmFuc1VybCwgYmFzZVVybCk7XG4gICAgICAgIC8vIGNoYW5nZSB0aGlzIHRvIHNlbXZlciBsb2dpY1xuICAgICAgICBpZiAodmVyc2lvbiAhPT0gU29ja0pTLnZlcnNpb24pIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0luY29tcGF0aWJsZSBTb2NrSlMhIE1haW4gc2l0ZSB1c2VzOicgK1xuICAgICAgICAgICAgICAgICAgICAnIFwiJyArIHZlcnNpb24gKyAnXCIsIHRoZSBpZnJhbWU6JyArXG4gICAgICAgICAgICAgICAgICAgICcgXCInICsgU29ja0pTLnZlcnNpb24gKyAnXCIuJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXVybFV0aWxzLmlzT3JpZ2luRXF1YWwodHJhbnNVcmwsIGxvYy5ocmVmKSB8fFxuICAgICAgICAgICAgIXVybFV0aWxzLmlzT3JpZ2luRXF1YWwoYmFzZVVybCwgbG9jLmhyZWYpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5cXCd0IGNvbm5lY3QgdG8gZGlmZmVyZW50IGRvbWFpbiBmcm9tIHdpdGhpbiBhbiAnICtcbiAgICAgICAgICAgICAgICAgICAgJ2lmcmFtZS4gKCcgKyBsb2MuaHJlZiArICcsICcgKyB0cmFuc1VybCArICcsICcgKyBiYXNlVXJsICsgJyknKTtcbiAgICAgICAgfVxuICAgICAgICBmYWNhZGUgPSBuZXcgRmFjYWRlSlMobmV3IHRyYW5zcG9ydE1hcFt0cmFuc3BvcnRdKHRyYW5zVXJsLCBiYXNlVXJsKSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnbSc6XG4gICAgICAgIGZhY2FkZS5fc2VuZChpZnJhbWVNZXNzYWdlLmRhdGEpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2MnOlxuICAgICAgICBpZiAoZmFjYWRlKSB7XG4gICAgICAgICAgZmFjYWRlLl9jbG9zZSgpO1xuICAgICAgICB9XG4gICAgICAgIGZhY2FkZSA9IG51bGw7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBldmVudFV0aWxzLmF0dGFjaEV2ZW50KCdtZXNzYWdlJywgb25NZXNzYWdlKTtcblxuICAgIC8vIFN0YXJ0XG4gICAgaWZyYW1lVXRpbHMucG9zdE1lc3NhZ2UoJ3MnKTtcbiAgfTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCdldmVudHMnKS5FdmVudEVtaXR0ZXJcbiAgLCBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBKU09OMyA9IHJlcXVpcmUoJ2pzb24zJylcbiAgLCBvYmplY3RVdGlscyA9IHJlcXVpcmUoJy4vdXRpbHMvb2JqZWN0JylcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OmluZm8tYWpheCcpO1xufVxuXG5mdW5jdGlvbiBJbmZvQWpheCh1cmwsIEFqYXhPYmplY3QpIHtcbiAgRXZlbnRFbWl0dGVyLmNhbGwodGhpcyk7XG5cbiAgdmFyIHNlbGYgPSB0aGlzO1xuICB2YXIgdDAgPSArbmV3IERhdGUoKTtcbiAgdGhpcy54byA9IG5ldyBBamF4T2JqZWN0KCdHRVQnLCB1cmwpO1xuXG4gIHRoaXMueG8ub25jZSgnZmluaXNoJywgZnVuY3Rpb24oc3RhdHVzLCB0ZXh0KSB7XG4gICAgdmFyIGluZm8sIHJ0dDtcbiAgICBpZiAoc3RhdHVzID09PSAyMDApIHtcbiAgICAgIHJ0dCA9ICgrbmV3IERhdGUoKSkgLSB0MDtcbiAgICAgIGlmICh0ZXh0KSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaW5mbyA9IEpTT04zLnBhcnNlKHRleHQpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgZGVidWcoJ2JhZCBqc29uJywgdGV4dCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKCFvYmplY3RVdGlscy5pc09iamVjdChpbmZvKSkge1xuICAgICAgICBpbmZvID0ge307XG4gICAgICB9XG4gICAgfVxuICAgIHNlbGYuZW1pdCgnZmluaXNoJywgaW5mbywgcnR0KTtcbiAgICBzZWxmLnJlbW92ZUFsbExpc3RlbmVycygpO1xuICB9KTtcbn1cblxuaW5oZXJpdHMoSW5mb0FqYXgsIEV2ZW50RW1pdHRlcik7XG5cbkluZm9BamF4LnByb3RvdHlwZS5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygpO1xuICB0aGlzLnhvLmNsb3NlKCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEluZm9BamF4O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gICwgSlNPTjMgPSByZXF1aXJlKCdqc29uMycpXG4gICwgWEhSTG9jYWxPYmplY3QgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9zZW5kZXIveGhyLWxvY2FsJylcbiAgLCBJbmZvQWpheCA9IHJlcXVpcmUoJy4vaW5mby1hamF4JylcbiAgO1xuXG5mdW5jdGlvbiBJbmZvUmVjZWl2ZXJJZnJhbWUodHJhbnNVcmwpIHtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICBFdmVudEVtaXR0ZXIuY2FsbCh0aGlzKTtcblxuICB0aGlzLmlyID0gbmV3IEluZm9BamF4KHRyYW5zVXJsLCBYSFJMb2NhbE9iamVjdCk7XG4gIHRoaXMuaXIub25jZSgnZmluaXNoJywgZnVuY3Rpb24oaW5mbywgcnR0KSB7XG4gICAgc2VsZi5pciA9IG51bGw7XG4gICAgc2VsZi5lbWl0KCdtZXNzYWdlJywgSlNPTjMuc3RyaW5naWZ5KFtpbmZvLCBydHRdKSk7XG4gIH0pO1xufVxuXG5pbmhlcml0cyhJbmZvUmVjZWl2ZXJJZnJhbWUsIEV2ZW50RW1pdHRlcik7XG5cbkluZm9SZWNlaXZlcklmcmFtZS50cmFuc3BvcnROYW1lID0gJ2lmcmFtZS1pbmZvLXJlY2VpdmVyJztcblxuSW5mb1JlY2VpdmVySWZyYW1lLnByb3RvdHlwZS5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICBpZiAodGhpcy5pcikge1xuICAgIHRoaXMuaXIuY2xvc2UoKTtcbiAgICB0aGlzLmlyID0gbnVsbDtcbiAgfVxuICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBJbmZvUmVjZWl2ZXJJZnJhbWU7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCdldmVudHMnKS5FdmVudEVtaXR0ZXJcbiAgLCBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBKU09OMyA9IHJlcXVpcmUoJ2pzb24zJylcbiAgLCB1dGlscyA9IHJlcXVpcmUoJy4vdXRpbHMvZXZlbnQnKVxuICAsIElmcmFtZVRyYW5zcG9ydCA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L2lmcmFtZScpXG4gICwgSW5mb1JlY2VpdmVySWZyYW1lID0gcmVxdWlyZSgnLi9pbmZvLWlmcmFtZS1yZWNlaXZlcicpXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDppbmZvLWlmcmFtZScpO1xufVxuXG5mdW5jdGlvbiBJbmZvSWZyYW1lKGJhc2VVcmwsIHVybCkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuXG4gIHZhciBnbyA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBpZnIgPSBzZWxmLmlmciA9IG5ldyBJZnJhbWVUcmFuc3BvcnQoSW5mb1JlY2VpdmVySWZyYW1lLnRyYW5zcG9ydE5hbWUsIHVybCwgYmFzZVVybCk7XG5cbiAgICBpZnIub25jZSgnbWVzc2FnZScsIGZ1bmN0aW9uKG1zZykge1xuICAgICAgaWYgKG1zZykge1xuICAgICAgICB2YXIgZDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBkID0gSlNPTjMucGFyc2UobXNnKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIGRlYnVnKCdiYWQganNvbicsIG1zZyk7XG4gICAgICAgICAgc2VsZi5lbWl0KCdmaW5pc2gnKTtcbiAgICAgICAgICBzZWxmLmNsb3NlKCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGluZm8gPSBkWzBdLCBydHQgPSBkWzFdO1xuICAgICAgICBzZWxmLmVtaXQoJ2ZpbmlzaCcsIGluZm8sIHJ0dCk7XG4gICAgICB9XG4gICAgICBzZWxmLmNsb3NlKCk7XG4gICAgfSk7XG5cbiAgICBpZnIub25jZSgnY2xvc2UnLCBmdW5jdGlvbigpIHtcbiAgICAgIHNlbGYuZW1pdCgnZmluaXNoJyk7XG4gICAgICBzZWxmLmNsb3NlKCk7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gVE9ETyB0aGlzIHNlZW1zIHRoZSBzYW1lIGFzIHRoZSAnbmVlZEJvZHknIGZyb20gdHJhbnNwb3J0c1xuICBpZiAoIWdsb2JhbC5kb2N1bWVudC5ib2R5KSB7XG4gICAgdXRpbHMuYXR0YWNoRXZlbnQoJ2xvYWQnLCBnbyk7XG4gIH0gZWxzZSB7XG4gICAgZ28oKTtcbiAgfVxufVxuXG5pbmhlcml0cyhJbmZvSWZyYW1lLCBFdmVudEVtaXR0ZXIpO1xuXG5JbmZvSWZyYW1lLmVuYWJsZWQgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIElmcmFtZVRyYW5zcG9ydC5lbmFibGVkKCk7XG59O1xuXG5JbmZvSWZyYW1lLnByb3RvdHlwZS5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICBpZiAodGhpcy5pZnIpIHtcbiAgICB0aGlzLmlmci5jbG9zZSgpO1xuICB9XG4gIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gIHRoaXMuaWZyID0gbnVsbDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSW5mb0lmcmFtZTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlclxuICAsIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIHVybFV0aWxzID0gcmVxdWlyZSgnLi91dGlscy91cmwnKVxuICAsIFhEUiA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L3NlbmRlci94ZHInKVxuICAsIFhIUkNvcnMgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9zZW5kZXIveGhyLWNvcnMnKVxuICAsIFhIUkxvY2FsID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvc2VuZGVyL3hoci1sb2NhbCcpXG4gICwgWEhSRmFrZSA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L3NlbmRlci94aHItZmFrZScpXG4gICwgSW5mb0lmcmFtZSA9IHJlcXVpcmUoJy4vaW5mby1pZnJhbWUnKVxuICAsIEluZm9BamF4ID0gcmVxdWlyZSgnLi9pbmZvLWFqYXgnKVxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6aW5mby1yZWNlaXZlcicpO1xufVxuXG5mdW5jdGlvbiBJbmZvUmVjZWl2ZXIoYmFzZVVybCwgdXJsSW5mbykge1xuICBkZWJ1ZyhiYXNlVXJsKTtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICBFdmVudEVtaXR0ZXIuY2FsbCh0aGlzKTtcblxuICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgIHNlbGYuZG9YaHIoYmFzZVVybCwgdXJsSW5mbyk7XG4gIH0sIDApO1xufVxuXG5pbmhlcml0cyhJbmZvUmVjZWl2ZXIsIEV2ZW50RW1pdHRlcik7XG5cbi8vIFRPRE8gdGhpcyBpcyBjdXJyZW50bHkgaWdub3JpbmcgdGhlIGxpc3Qgb2YgYXZhaWxhYmxlIHRyYW5zcG9ydHMgYW5kIHRoZSB3aGl0ZWxpc3RcblxuSW5mb1JlY2VpdmVyLl9nZXRSZWNlaXZlciA9IGZ1bmN0aW9uKGJhc2VVcmwsIHVybCwgdXJsSW5mbykge1xuICAvLyBkZXRlcm1pbmUgbWV0aG9kIG9mIENPUlMgc3VwcG9ydCAoaWYgbmVlZGVkKVxuICBpZiAodXJsSW5mby5zYW1lT3JpZ2luKSB7XG4gICAgcmV0dXJuIG5ldyBJbmZvQWpheCh1cmwsIFhIUkxvY2FsKTtcbiAgfVxuICBpZiAoWEhSQ29ycy5lbmFibGVkKSB7XG4gICAgcmV0dXJuIG5ldyBJbmZvQWpheCh1cmwsIFhIUkNvcnMpO1xuICB9XG4gIGlmIChYRFIuZW5hYmxlZCAmJiB1cmxJbmZvLnNhbWVTY2hlbWUpIHtcbiAgICByZXR1cm4gbmV3IEluZm9BamF4KHVybCwgWERSKTtcbiAgfVxuICBpZiAoSW5mb0lmcmFtZS5lbmFibGVkKCkpIHtcbiAgICByZXR1cm4gbmV3IEluZm9JZnJhbWUoYmFzZVVybCwgdXJsKTtcbiAgfVxuICByZXR1cm4gbmV3IEluZm9BamF4KHVybCwgWEhSRmFrZSk7XG59O1xuXG5JbmZvUmVjZWl2ZXIucHJvdG90eXBlLmRvWGhyID0gZnVuY3Rpb24oYmFzZVVybCwgdXJsSW5mbykge1xuICB2YXIgc2VsZiA9IHRoaXNcbiAgICAsIHVybCA9IHVybFV0aWxzLmFkZFBhdGgoYmFzZVVybCwgJy9pbmZvJylcbiAgICA7XG4gIGRlYnVnKCdkb1hocicsIHVybCk7XG5cbiAgdGhpcy54byA9IEluZm9SZWNlaXZlci5fZ2V0UmVjZWl2ZXIoYmFzZVVybCwgdXJsLCB1cmxJbmZvKTtcblxuICB0aGlzLnRpbWVvdXRSZWYgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgIGRlYnVnKCd0aW1lb3V0Jyk7XG4gICAgc2VsZi5fY2xlYW51cChmYWxzZSk7XG4gICAgc2VsZi5lbWl0KCdmaW5pc2gnKTtcbiAgfSwgSW5mb1JlY2VpdmVyLnRpbWVvdXQpO1xuXG4gIHRoaXMueG8ub25jZSgnZmluaXNoJywgZnVuY3Rpb24oaW5mbywgcnR0KSB7XG4gICAgZGVidWcoJ2ZpbmlzaCcsIGluZm8sIHJ0dCk7XG4gICAgc2VsZi5fY2xlYW51cCh0cnVlKTtcbiAgICBzZWxmLmVtaXQoJ2ZpbmlzaCcsIGluZm8sIHJ0dCk7XG4gIH0pO1xufTtcblxuSW5mb1JlY2VpdmVyLnByb3RvdHlwZS5fY2xlYW51cCA9IGZ1bmN0aW9uKHdhc0NsZWFuKSB7XG4gIGRlYnVnKCdfY2xlYW51cCcpO1xuICBjbGVhclRpbWVvdXQodGhpcy50aW1lb3V0UmVmKTtcbiAgdGhpcy50aW1lb3V0UmVmID0gbnVsbDtcbiAgaWYgKCF3YXNDbGVhbiAmJiB0aGlzLnhvKSB7XG4gICAgdGhpcy54by5jbG9zZSgpO1xuICB9XG4gIHRoaXMueG8gPSBudWxsO1xufTtcblxuSW5mb1JlY2VpdmVyLnByb3RvdHlwZS5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnY2xvc2UnKTtcbiAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgdGhpcy5fY2xlYW51cChmYWxzZSk7XG59O1xuXG5JbmZvUmVjZWl2ZXIudGltZW91dCA9IDgwMDA7XG5cbm1vZHVsZS5leHBvcnRzID0gSW5mb1JlY2VpdmVyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGdsb2JhbC5sb2NhdGlvbiB8fCB7XG4gIG9yaWdpbjogJ2h0dHA6Ly9sb2NhbGhvc3Q6ODAnXG4sIHByb3RvY29sOiAnaHR0cCdcbiwgaG9zdDogJ2xvY2FsaG9zdCdcbiwgcG9ydDogODBcbiwgaHJlZjogJ2h0dHA6Ly9sb2NhbGhvc3QvJ1xuLCBoYXNoOiAnJ1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxucmVxdWlyZSgnLi9zaGltcycpO1xuXG52YXIgVVJMID0gcmVxdWlyZSgndXJsLXBhcnNlJylcbiAgLCBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBKU09OMyA9IHJlcXVpcmUoJ2pzb24zJylcbiAgLCByYW5kb20gPSByZXF1aXJlKCcuL3V0aWxzL3JhbmRvbScpXG4gICwgZXNjYXBlID0gcmVxdWlyZSgnLi91dGlscy9lc2NhcGUnKVxuICAsIHVybFV0aWxzID0gcmVxdWlyZSgnLi91dGlscy91cmwnKVxuICAsIGV2ZW50VXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzL2V2ZW50JylcbiAgLCB0cmFuc3BvcnQgPSByZXF1aXJlKCcuL3V0aWxzL3RyYW5zcG9ydCcpXG4gICwgb2JqZWN0VXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzL29iamVjdCcpXG4gICwgYnJvd3NlciA9IHJlcXVpcmUoJy4vdXRpbHMvYnJvd3NlcicpXG4gICwgbG9nID0gcmVxdWlyZSgnLi91dGlscy9sb2cnKVxuICAsIEV2ZW50ID0gcmVxdWlyZSgnLi9ldmVudC9ldmVudCcpXG4gICwgRXZlbnRUYXJnZXQgPSByZXF1aXJlKCcuL2V2ZW50L2V2ZW50dGFyZ2V0JylcbiAgLCBsb2MgPSByZXF1aXJlKCcuL2xvY2F0aW9uJylcbiAgLCBDbG9zZUV2ZW50ID0gcmVxdWlyZSgnLi9ldmVudC9jbG9zZScpXG4gICwgVHJhbnNwb3J0TWVzc2FnZUV2ZW50ID0gcmVxdWlyZSgnLi9ldmVudC90cmFucy1tZXNzYWdlJylcbiAgLCBJbmZvUmVjZWl2ZXIgPSByZXF1aXJlKCcuL2luZm8tcmVjZWl2ZXInKVxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6bWFpbicpO1xufVxuXG52YXIgdHJhbnNwb3J0cztcblxuLy8gZm9sbG93IGNvbnN0cnVjdG9yIHN0ZXBzIGRlZmluZWQgYXQgaHR0cDovL2Rldi53My5vcmcvaHRtbDUvd2Vic29ja2V0cy8jdGhlLXdlYnNvY2tldC1pbnRlcmZhY2VcbmZ1bmN0aW9uIFNvY2tKUyh1cmwsIHByb3RvY29scywgb3B0aW9ucykge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgU29ja0pTKSkge1xuICAgIHJldHVybiBuZXcgU29ja0pTKHVybCwgcHJvdG9jb2xzLCBvcHRpb25zKTtcbiAgfVxuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA8IDEpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiRmFpbGVkIHRvIGNvbnN0cnVjdCAnU29ja0pTOiAxIGFyZ3VtZW50IHJlcXVpcmVkLCBidXQgb25seSAwIHByZXNlbnRcIik7XG4gIH1cbiAgRXZlbnRUYXJnZXQuY2FsbCh0aGlzKTtcblxuICB0aGlzLnJlYWR5U3RhdGUgPSBTb2NrSlMuQ09OTkVDVElORztcbiAgdGhpcy5leHRlbnNpb25zID0gJyc7XG4gIHRoaXMucHJvdG9jb2wgPSAnJztcblxuICAvLyBub24tc3RhbmRhcmQgZXh0ZW5zaW9uXG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICBpZiAob3B0aW9ucy5wcm90b2NvbHNfd2hpdGVsaXN0KSB7XG4gICAgbG9nLndhcm4oXCIncHJvdG9jb2xzX3doaXRlbGlzdCcgaXMgREVQUkVDQVRFRC4gVXNlICd0cmFuc3BvcnRzJyBpbnN0ZWFkLlwiKTtcbiAgfVxuICB0aGlzLl90cmFuc3BvcnRzV2hpdGVsaXN0ID0gb3B0aW9ucy50cmFuc3BvcnRzO1xuICB0aGlzLl90cmFuc3BvcnRPcHRpb25zID0gb3B0aW9ucy50cmFuc3BvcnRPcHRpb25zIHx8IHt9O1xuXG4gIHZhciBzZXNzaW9uSWQgPSBvcHRpb25zLnNlc3Npb25JZCB8fCA4O1xuICBpZiAodHlwZW9mIHNlc3Npb25JZCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgIHRoaXMuX2dlbmVyYXRlU2Vzc2lvbklkID0gc2Vzc2lvbklkO1xuICB9IGVsc2UgaWYgKHR5cGVvZiBzZXNzaW9uSWQgPT09ICdudW1iZXInKSB7XG4gICAgdGhpcy5fZ2VuZXJhdGVTZXNzaW9uSWQgPSBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiByYW5kb20uc3RyaW5nKHNlc3Npb25JZCk7XG4gICAgfTtcbiAgfSBlbHNlIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdJZiBzZXNzaW9uSWQgaXMgdXNlZCBpbiB0aGUgb3B0aW9ucywgaXQgbmVlZHMgdG8gYmUgYSBudW1iZXIgb3IgYSBmdW5jdGlvbi4nKTtcbiAgfVxuXG4gIHRoaXMuX3NlcnZlciA9IG9wdGlvbnMuc2VydmVyIHx8IHJhbmRvbS5udW1iZXJTdHJpbmcoMTAwMCk7XG5cbiAgLy8gU3RlcCAxIG9mIFdTIHNwZWMgLSBwYXJzZSBhbmQgdmFsaWRhdGUgdGhlIHVybC4gSXNzdWUgIzhcbiAgdmFyIHBhcnNlZFVybCA9IG5ldyBVUkwodXJsKTtcbiAgaWYgKCFwYXJzZWRVcmwuaG9zdCB8fCAhcGFyc2VkVXJsLnByb3RvY29sKSB7XG4gICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlIFVSTCAnXCIgKyB1cmwgKyBcIicgaXMgaW52YWxpZFwiKTtcbiAgfSBlbHNlIGlmIChwYXJzZWRVcmwuaGFzaCkge1xuICAgIHRocm93IG5ldyBTeW50YXhFcnJvcignVGhlIFVSTCBtdXN0IG5vdCBjb250YWluIGEgZnJhZ21lbnQnKTtcbiAgfSBlbHNlIGlmIChwYXJzZWRVcmwucHJvdG9jb2wgIT09ICdodHRwOicgJiYgcGFyc2VkVXJsLnByb3RvY29sICE9PSAnaHR0cHM6Jykge1xuICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIlRoZSBVUkwncyBzY2hlbWUgbXVzdCBiZSBlaXRoZXIgJ2h0dHA6JyBvciAnaHR0cHM6Jy4gJ1wiICsgcGFyc2VkVXJsLnByb3RvY29sICsgXCInIGlzIG5vdCBhbGxvd2VkLlwiKTtcbiAgfVxuXG4gIHZhciBzZWN1cmUgPSBwYXJzZWRVcmwucHJvdG9jb2wgPT09ICdodHRwczonO1xuICAvLyBTdGVwIDIgLSBkb24ndCBhbGxvdyBzZWN1cmUgb3JpZ2luIHdpdGggYW4gaW5zZWN1cmUgcHJvdG9jb2xcbiAgaWYgKGxvYy5wcm90b2NvbCA9PT0gJ2h0dHBzJyAmJiAhc2VjdXJlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdTZWN1cml0eUVycm9yOiBBbiBpbnNlY3VyZSBTb2NrSlMgY29ubmVjdGlvbiBtYXkgbm90IGJlIGluaXRpYXRlZCBmcm9tIGEgcGFnZSBsb2FkZWQgb3ZlciBIVFRQUycpO1xuICB9XG5cbiAgLy8gU3RlcCAzIC0gY2hlY2sgcG9ydCBhY2Nlc3MgLSBubyBuZWVkIGhlcmVcbiAgLy8gU3RlcCA0IC0gcGFyc2UgcHJvdG9jb2xzIGFyZ3VtZW50XG4gIGlmICghcHJvdG9jb2xzKSB7XG4gICAgcHJvdG9jb2xzID0gW107XG4gIH0gZWxzZSBpZiAoIUFycmF5LmlzQXJyYXkocHJvdG9jb2xzKSkge1xuICAgIHByb3RvY29scyA9IFtwcm90b2NvbHNdO1xuICB9XG5cbiAgLy8gU3RlcCA1IC0gY2hlY2sgcHJvdG9jb2xzIGFyZ3VtZW50XG4gIHZhciBzb3J0ZWRQcm90b2NvbHMgPSBwcm90b2NvbHMuc29ydCgpO1xuICBzb3J0ZWRQcm90b2NvbHMuZm9yRWFjaChmdW5jdGlvbihwcm90bywgaSkge1xuICAgIGlmICghcHJvdG8pIHtcbiAgICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIlRoZSBwcm90b2NvbHMgZW50cnkgJ1wiICsgcHJvdG8gKyBcIicgaXMgaW52YWxpZC5cIik7XG4gICAgfVxuICAgIGlmIChpIDwgKHNvcnRlZFByb3RvY29scy5sZW5ndGggLSAxKSAmJiBwcm90byA9PT0gc29ydGVkUHJvdG9jb2xzW2kgKyAxXSkge1xuICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlIHByb3RvY29scyBlbnRyeSAnXCIgKyBwcm90byArIFwiJyBpcyBkdXBsaWNhdGVkLlwiKTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFN0ZXAgNiAtIGNvbnZlcnQgb3JpZ2luXG4gIHZhciBvID0gdXJsVXRpbHMuZ2V0T3JpZ2luKGxvYy5ocmVmKTtcbiAgdGhpcy5fb3JpZ2luID0gbyA/IG8udG9Mb3dlckNhc2UoKSA6IG51bGw7XG5cbiAgLy8gcmVtb3ZlIHRoZSB0cmFpbGluZyBzbGFzaFxuICBwYXJzZWRVcmwuc2V0KCdwYXRobmFtZScsIHBhcnNlZFVybC5wYXRobmFtZS5yZXBsYWNlKC9cXC8rJC8sICcnKSk7XG5cbiAgLy8gc3RvcmUgdGhlIHNhbml0aXplZCB1cmxcbiAgdGhpcy51cmwgPSBwYXJzZWRVcmwuaHJlZjtcbiAgZGVidWcoJ3VzaW5nIHVybCcsIHRoaXMudXJsKTtcblxuICAvLyBTdGVwIDcgLSBzdGFydCBjb25uZWN0aW9uIGluIGJhY2tncm91bmRcbiAgLy8gb2J0YWluIHNlcnZlciBpbmZvXG4gIC8vIGh0dHA6Ly9zb2NranMuZ2l0aHViLmlvL3NvY2tqcy1wcm90b2NvbC9zb2NranMtcHJvdG9jb2wtMC4zLjMuaHRtbCNzZWN0aW9uLTI2XG4gIHRoaXMuX3VybEluZm8gPSB7XG4gICAgbnVsbE9yaWdpbjogIWJyb3dzZXIuaGFzRG9tYWluKClcbiAgLCBzYW1lT3JpZ2luOiB1cmxVdGlscy5pc09yaWdpbkVxdWFsKHRoaXMudXJsLCBsb2MuaHJlZilcbiAgLCBzYW1lU2NoZW1lOiB1cmxVdGlscy5pc1NjaGVtZUVxdWFsKHRoaXMudXJsLCBsb2MuaHJlZilcbiAgfTtcblxuICB0aGlzLl9pciA9IG5ldyBJbmZvUmVjZWl2ZXIodGhpcy51cmwsIHRoaXMuX3VybEluZm8pO1xuICB0aGlzLl9pci5vbmNlKCdmaW5pc2gnLCB0aGlzLl9yZWNlaXZlSW5mby5iaW5kKHRoaXMpKTtcbn1cblxuaW5oZXJpdHMoU29ja0pTLCBFdmVudFRhcmdldCk7XG5cbmZ1bmN0aW9uIHVzZXJTZXRDb2RlKGNvZGUpIHtcbiAgcmV0dXJuIGNvZGUgPT09IDEwMDAgfHwgKGNvZGUgPj0gMzAwMCAmJiBjb2RlIDw9IDQ5OTkpO1xufVxuXG5Tb2NrSlMucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24oY29kZSwgcmVhc29uKSB7XG4gIC8vIFN0ZXAgMVxuICBpZiAoY29kZSAmJiAhdXNlclNldENvZGUoY29kZSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWRBY2Nlc3NFcnJvcjogSW52YWxpZCBjb2RlJyk7XG4gIH1cbiAgLy8gU3RlcCAyLjQgc3RhdGVzIHRoZSBtYXggaXMgMTIzIGJ5dGVzLCBidXQgd2UgYXJlIGp1c3QgY2hlY2tpbmcgbGVuZ3RoXG4gIGlmIChyZWFzb24gJiYgcmVhc29uLmxlbmd0aCA+IDEyMykge1xuICAgIHRocm93IG5ldyBTeW50YXhFcnJvcigncmVhc29uIGFyZ3VtZW50IGhhcyBhbiBpbnZhbGlkIGxlbmd0aCcpO1xuICB9XG5cbiAgLy8gU3RlcCAzLjFcbiAgaWYgKHRoaXMucmVhZHlTdGF0ZSA9PT0gU29ja0pTLkNMT1NJTkcgfHwgdGhpcy5yZWFkeVN0YXRlID09PSBTb2NrSlMuQ0xPU0VEKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gVE9ETyBsb29rIGF0IGRvY3MgdG8gZGV0ZXJtaW5lIGhvdyB0byBzZXQgdGhpc1xuICB2YXIgd2FzQ2xlYW4gPSB0cnVlO1xuICB0aGlzLl9jbG9zZShjb2RlIHx8IDEwMDAsIHJlYXNvbiB8fCAnTm9ybWFsIGNsb3N1cmUnLCB3YXNDbGVhbik7XG59O1xuXG5Tb2NrSlMucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbihkYXRhKSB7XG4gIC8vICMxMyAtIGNvbnZlcnQgYW55dGhpbmcgbm9uLXN0cmluZyB0byBzdHJpbmdcbiAgLy8gVE9ETyB0aGlzIGN1cnJlbnRseSB0dXJucyBvYmplY3RzIGludG8gW29iamVjdCBPYmplY3RdXG4gIGlmICh0eXBlb2YgZGF0YSAhPT0gJ3N0cmluZycpIHtcbiAgICBkYXRhID0gJycgKyBkYXRhO1xuICB9XG4gIGlmICh0aGlzLnJlYWR5U3RhdGUgPT09IFNvY2tKUy5DT05ORUNUSU5HKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkU3RhdGVFcnJvcjogVGhlIGNvbm5lY3Rpb24gaGFzIG5vdCBiZWVuIGVzdGFibGlzaGVkIHlldCcpO1xuICB9XG4gIGlmICh0aGlzLnJlYWR5U3RhdGUgIT09IFNvY2tKUy5PUEVOKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHRoaXMuX3RyYW5zcG9ydC5zZW5kKGVzY2FwZS5xdW90ZShkYXRhKSk7XG59O1xuXG5Tb2NrSlMudmVyc2lvbiA9IHJlcXVpcmUoJy4vdmVyc2lvbicpO1xuXG5Tb2NrSlMuQ09OTkVDVElORyA9IDA7XG5Tb2NrSlMuT1BFTiA9IDE7XG5Tb2NrSlMuQ0xPU0lORyA9IDI7XG5Tb2NrSlMuQ0xPU0VEID0gMztcblxuU29ja0pTLnByb3RvdHlwZS5fcmVjZWl2ZUluZm8gPSBmdW5jdGlvbihpbmZvLCBydHQpIHtcbiAgZGVidWcoJ19yZWNlaXZlSW5mbycsIHJ0dCk7XG4gIHRoaXMuX2lyID0gbnVsbDtcbiAgaWYgKCFpbmZvKSB7XG4gICAgdGhpcy5fY2xvc2UoMTAwMiwgJ0Nhbm5vdCBjb25uZWN0IHRvIHNlcnZlcicpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIGVzdGFibGlzaCBhIHJvdW5kLXRyaXAgdGltZW91dCAoUlRPKSBiYXNlZCBvbiB0aGVcbiAgLy8gcm91bmQtdHJpcCB0aW1lIChSVFQpXG4gIHRoaXMuX3J0byA9IHRoaXMuY291bnRSVE8ocnR0KTtcbiAgLy8gYWxsb3cgc2VydmVyIHRvIG92ZXJyaWRlIHVybCB1c2VkIGZvciB0aGUgYWN0dWFsIHRyYW5zcG9ydFxuICB0aGlzLl90cmFuc1VybCA9IGluZm8uYmFzZV91cmwgPyBpbmZvLmJhc2VfdXJsIDogdGhpcy51cmw7XG4gIGluZm8gPSBvYmplY3RVdGlscy5leHRlbmQoaW5mbywgdGhpcy5fdXJsSW5mbyk7XG4gIGRlYnVnKCdpbmZvJywgaW5mbyk7XG4gIC8vIGRldGVybWluZSBsaXN0IG9mIGRlc2lyZWQgYW5kIHN1cHBvcnRlZCB0cmFuc3BvcnRzXG4gIHZhciBlbmFibGVkVHJhbnNwb3J0cyA9IHRyYW5zcG9ydHMuZmlsdGVyVG9FbmFibGVkKHRoaXMuX3RyYW5zcG9ydHNXaGl0ZWxpc3QsIGluZm8pO1xuICB0aGlzLl90cmFuc3BvcnRzID0gZW5hYmxlZFRyYW5zcG9ydHMubWFpbjtcbiAgZGVidWcodGhpcy5fdHJhbnNwb3J0cy5sZW5ndGggKyAnIGVuYWJsZWQgdHJhbnNwb3J0cycpO1xuXG4gIHRoaXMuX2Nvbm5lY3QoKTtcbn07XG5cblNvY2tKUy5wcm90b3R5cGUuX2Nvbm5lY3QgPSBmdW5jdGlvbigpIHtcbiAgZm9yICh2YXIgVHJhbnNwb3J0ID0gdGhpcy5fdHJhbnNwb3J0cy5zaGlmdCgpOyBUcmFuc3BvcnQ7IFRyYW5zcG9ydCA9IHRoaXMuX3RyYW5zcG9ydHMuc2hpZnQoKSkge1xuICAgIGRlYnVnKCdhdHRlbXB0JywgVHJhbnNwb3J0LnRyYW5zcG9ydE5hbWUpO1xuICAgIGlmIChUcmFuc3BvcnQubmVlZEJvZHkpIHtcbiAgICAgIGlmICghZ2xvYmFsLmRvY3VtZW50LmJvZHkgfHxcbiAgICAgICAgICAodHlwZW9mIGdsb2JhbC5kb2N1bWVudC5yZWFkeVN0YXRlICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgZ2xvYmFsLmRvY3VtZW50LnJlYWR5U3RhdGUgIT09ICdjb21wbGV0ZScgJiZcbiAgICAgICAgICAgIGdsb2JhbC5kb2N1bWVudC5yZWFkeVN0YXRlICE9PSAnaW50ZXJhY3RpdmUnKSkge1xuICAgICAgICBkZWJ1Zygnd2FpdGluZyBmb3IgYm9keScpO1xuICAgICAgICB0aGlzLl90cmFuc3BvcnRzLnVuc2hpZnQoVHJhbnNwb3J0KTtcbiAgICAgICAgZXZlbnRVdGlscy5hdHRhY2hFdmVudCgnbG9hZCcsIHRoaXMuX2Nvbm5lY3QuYmluZCh0aGlzKSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBjYWxjdWxhdGUgdGltZW91dCBiYXNlZCBvbiBSVE8gYW5kIHJvdW5kIHRyaXBzLiBEZWZhdWx0IHRvIDVzXG4gICAgdmFyIHRpbWVvdXRNcyA9ICh0aGlzLl9ydG8gKiBUcmFuc3BvcnQucm91bmRUcmlwcykgfHwgNTAwMDtcbiAgICB0aGlzLl90cmFuc3BvcnRUaW1lb3V0SWQgPSBzZXRUaW1lb3V0KHRoaXMuX3RyYW5zcG9ydFRpbWVvdXQuYmluZCh0aGlzKSwgdGltZW91dE1zKTtcbiAgICBkZWJ1ZygndXNpbmcgdGltZW91dCcsIHRpbWVvdXRNcyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0VXJsID0gdXJsVXRpbHMuYWRkUGF0aCh0aGlzLl90cmFuc1VybCwgJy8nICsgdGhpcy5fc2VydmVyICsgJy8nICsgdGhpcy5fZ2VuZXJhdGVTZXNzaW9uSWQoKSk7XG4gICAgdmFyIG9wdGlvbnMgPSB0aGlzLl90cmFuc3BvcnRPcHRpb25zW1RyYW5zcG9ydC50cmFuc3BvcnROYW1lXTtcbiAgICBkZWJ1ZygndHJhbnNwb3J0IHVybCcsIHRyYW5zcG9ydFVybCk7XG4gICAgdmFyIHRyYW5zcG9ydE9iaiA9IG5ldyBUcmFuc3BvcnQodHJhbnNwb3J0VXJsLCB0aGlzLl90cmFuc1VybCwgb3B0aW9ucyk7XG4gICAgdHJhbnNwb3J0T2JqLm9uKCdtZXNzYWdlJywgdGhpcy5fdHJhbnNwb3J0TWVzc2FnZS5iaW5kKHRoaXMpKTtcbiAgICB0cmFuc3BvcnRPYmoub25jZSgnY2xvc2UnLCB0aGlzLl90cmFuc3BvcnRDbG9zZS5iaW5kKHRoaXMpKTtcbiAgICB0cmFuc3BvcnRPYmoudHJhbnNwb3J0TmFtZSA9IFRyYW5zcG9ydC50cmFuc3BvcnROYW1lO1xuICAgIHRoaXMuX3RyYW5zcG9ydCA9IHRyYW5zcG9ydE9iajtcblxuICAgIHJldHVybjtcbiAgfVxuICB0aGlzLl9jbG9zZSgyMDAwLCAnQWxsIHRyYW5zcG9ydHMgZmFpbGVkJywgZmFsc2UpO1xufTtcblxuU29ja0pTLnByb3RvdHlwZS5fdHJhbnNwb3J0VGltZW91dCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnX3RyYW5zcG9ydFRpbWVvdXQnKTtcbiAgaWYgKHRoaXMucmVhZHlTdGF0ZSA9PT0gU29ja0pTLkNPTk5FQ1RJTkcpIHtcbiAgICB0aGlzLl90cmFuc3BvcnRDbG9zZSgyMDA3LCAnVHJhbnNwb3J0IHRpbWVkIG91dCcpO1xuICB9XG59O1xuXG5Tb2NrSlMucHJvdG90eXBlLl90cmFuc3BvcnRNZXNzYWdlID0gZnVuY3Rpb24obXNnKSB7XG4gIGRlYnVnKCdfdHJhbnNwb3J0TWVzc2FnZScsIG1zZyk7XG4gIHZhciBzZWxmID0gdGhpc1xuICAgICwgdHlwZSA9IG1zZy5zbGljZSgwLCAxKVxuICAgICwgY29udGVudCA9IG1zZy5zbGljZSgxKVxuICAgICwgcGF5bG9hZFxuICAgIDtcblxuICAvLyBmaXJzdCBjaGVjayBmb3IgbWVzc2FnZXMgdGhhdCBkb24ndCBuZWVkIGEgcGF5bG9hZFxuICBzd2l0Y2ggKHR5cGUpIHtcbiAgICBjYXNlICdvJzpcbiAgICAgIHRoaXMuX29wZW4oKTtcbiAgICAgIHJldHVybjtcbiAgICBjYXNlICdoJzpcbiAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoJ2hlYXJ0YmVhdCcpKTtcbiAgICAgIGRlYnVnKCdoZWFydGJlYXQnLCB0aGlzLnRyYW5zcG9ydCk7XG4gICAgICByZXR1cm47XG4gIH1cblxuICBpZiAoY29udGVudCkge1xuICAgIHRyeSB7XG4gICAgICBwYXlsb2FkID0gSlNPTjMucGFyc2UoY29udGVudCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgZGVidWcoJ2JhZCBqc29uJywgY29udGVudCk7XG4gICAgfVxuICB9XG5cbiAgaWYgKHR5cGVvZiBwYXlsb2FkID09PSAndW5kZWZpbmVkJykge1xuICAgIGRlYnVnKCdlbXB0eSBwYXlsb2FkJywgY29udGVudCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgc3dpdGNoICh0eXBlKSB7XG4gICAgY2FzZSAnYSc6XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShwYXlsb2FkKSkge1xuICAgICAgICBwYXlsb2FkLmZvckVhY2goZnVuY3Rpb24ocCkge1xuICAgICAgICAgIGRlYnVnKCdtZXNzYWdlJywgc2VsZi50cmFuc3BvcnQsIHApO1xuICAgICAgICAgIHNlbGYuZGlzcGF0Y2hFdmVudChuZXcgVHJhbnNwb3J0TWVzc2FnZUV2ZW50KHApKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICBicmVhaztcbiAgICBjYXNlICdtJzpcbiAgICAgIGRlYnVnKCdtZXNzYWdlJywgdGhpcy50cmFuc3BvcnQsIHBheWxvYWQpO1xuICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBUcmFuc3BvcnRNZXNzYWdlRXZlbnQocGF5bG9hZCkpO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAnYyc6XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShwYXlsb2FkKSAmJiBwYXlsb2FkLmxlbmd0aCA9PT0gMikge1xuICAgICAgICB0aGlzLl9jbG9zZShwYXlsb2FkWzBdLCBwYXlsb2FkWzFdLCB0cnVlKTtcbiAgICAgIH1cbiAgICAgIGJyZWFrO1xuICB9XG59O1xuXG5Tb2NrSlMucHJvdG90eXBlLl90cmFuc3BvcnRDbG9zZSA9IGZ1bmN0aW9uKGNvZGUsIHJlYXNvbikge1xuICBkZWJ1ZygnX3RyYW5zcG9ydENsb3NlJywgdGhpcy50cmFuc3BvcnQsIGNvZGUsIHJlYXNvbik7XG4gIGlmICh0aGlzLl90cmFuc3BvcnQpIHtcbiAgICB0aGlzLl90cmFuc3BvcnQucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgdGhpcy5fdHJhbnNwb3J0ID0gbnVsbDtcbiAgICB0aGlzLnRyYW5zcG9ydCA9IG51bGw7XG4gIH1cblxuICBpZiAoIXVzZXJTZXRDb2RlKGNvZGUpICYmIGNvZGUgIT09IDIwMDAgJiYgdGhpcy5yZWFkeVN0YXRlID09PSBTb2NrSlMuQ09OTkVDVElORykge1xuICAgIHRoaXMuX2Nvbm5lY3QoKTtcbiAgICByZXR1cm47XG4gIH1cblxuICB0aGlzLl9jbG9zZShjb2RlLCByZWFzb24pO1xufTtcblxuU29ja0pTLnByb3RvdHlwZS5fb3BlbiA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnX29wZW4nLCB0aGlzLl90cmFuc3BvcnQudHJhbnNwb3J0TmFtZSwgdGhpcy5yZWFkeVN0YXRlKTtcbiAgaWYgKHRoaXMucmVhZHlTdGF0ZSA9PT0gU29ja0pTLkNPTk5FQ1RJTkcpIHtcbiAgICBpZiAodGhpcy5fdHJhbnNwb3J0VGltZW91dElkKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5fdHJhbnNwb3J0VGltZW91dElkKTtcbiAgICAgIHRoaXMuX3RyYW5zcG9ydFRpbWVvdXRJZCA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMucmVhZHlTdGF0ZSA9IFNvY2tKUy5PUEVOO1xuICAgIHRoaXMudHJhbnNwb3J0ID0gdGhpcy5fdHJhbnNwb3J0LnRyYW5zcG9ydE5hbWU7XG4gICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgnb3BlbicpKTtcbiAgICBkZWJ1ZygnY29ubmVjdGVkJywgdGhpcy50cmFuc3BvcnQpO1xuICB9IGVsc2Uge1xuICAgIC8vIFRoZSBzZXJ2ZXIgbWlnaHQgaGF2ZSBiZWVuIHJlc3RhcnRlZCwgYW5kIGxvc3QgdHJhY2sgb2Ygb3VyXG4gICAgLy8gY29ubmVjdGlvbi5cbiAgICB0aGlzLl9jbG9zZSgxMDA2LCAnU2VydmVyIGxvc3Qgc2Vzc2lvbicpO1xuICB9XG59O1xuXG5Tb2NrSlMucHJvdG90eXBlLl9jbG9zZSA9IGZ1bmN0aW9uKGNvZGUsIHJlYXNvbiwgd2FzQ2xlYW4pIHtcbiAgZGVidWcoJ19jbG9zZScsIHRoaXMudHJhbnNwb3J0LCBjb2RlLCByZWFzb24sIHdhc0NsZWFuLCB0aGlzLnJlYWR5U3RhdGUpO1xuICB2YXIgZm9yY2VGYWlsID0gZmFsc2U7XG5cbiAgaWYgKHRoaXMuX2lyKSB7XG4gICAgZm9yY2VGYWlsID0gdHJ1ZTtcbiAgICB0aGlzLl9pci5jbG9zZSgpO1xuICAgIHRoaXMuX2lyID0gbnVsbDtcbiAgfVxuICBpZiAodGhpcy5fdHJhbnNwb3J0KSB7XG4gICAgdGhpcy5fdHJhbnNwb3J0LmNsb3NlKCk7XG4gICAgdGhpcy5fdHJhbnNwb3J0ID0gbnVsbDtcbiAgICB0aGlzLnRyYW5zcG9ydCA9IG51bGw7XG4gIH1cblxuICBpZiAodGhpcy5yZWFkeVN0YXRlID09PSBTb2NrSlMuQ0xPU0VEKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkU3RhdGVFcnJvcjogU29ja0pTIGhhcyBhbHJlYWR5IGJlZW4gY2xvc2VkJyk7XG4gIH1cblxuICB0aGlzLnJlYWR5U3RhdGUgPSBTb2NrSlMuQ0xPU0lORztcbiAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICB0aGlzLnJlYWR5U3RhdGUgPSBTb2NrSlMuQ0xPU0VEO1xuXG4gICAgaWYgKGZvcmNlRmFpbCkge1xuICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgnZXJyb3InKSk7XG4gICAgfVxuXG4gICAgdmFyIGUgPSBuZXcgQ2xvc2VFdmVudCgnY2xvc2UnKTtcbiAgICBlLndhc0NsZWFuID0gd2FzQ2xlYW4gfHwgZmFsc2U7XG4gICAgZS5jb2RlID0gY29kZSB8fCAxMDAwO1xuICAgIGUucmVhc29uID0gcmVhc29uO1xuXG4gICAgdGhpcy5kaXNwYXRjaEV2ZW50KGUpO1xuICAgIHRoaXMub25tZXNzYWdlID0gdGhpcy5vbmNsb3NlID0gdGhpcy5vbmVycm9yID0gbnVsbDtcbiAgICBkZWJ1ZygnZGlzY29ubmVjdGVkJyk7XG4gIH0uYmluZCh0aGlzKSwgMCk7XG59O1xuXG4vLyBTZWU6IGh0dHA6Ly93d3cuZXJnLmFiZG4uYWMudWsvfmdlcnJpdC9kY2NwL25vdGVzL2NjaWQyL3J0b19lc3RpbWF0b3IvXG4vLyBhbmQgUkZDIDI5ODguXG5Tb2NrSlMucHJvdG90eXBlLmNvdW50UlRPID0gZnVuY3Rpb24ocnR0KSB7XG4gIC8vIEluIGEgbG9jYWwgZW52aXJvbm1lbnQsIHdoZW4gdXNpbmcgSUU4LzkgYW5kIHRoZSBganNvbnAtcG9sbGluZ2BcbiAgLy8gdHJhbnNwb3J0IHRoZSB0aW1lIG5lZWRlZCB0byBlc3RhYmxpc2ggYSBjb25uZWN0aW9uICh0aGUgdGltZSB0aGF0IHBhc3NcbiAgLy8gZnJvbSB0aGUgb3BlbmluZyBvZiB0aGUgdHJhbnNwb3J0IHRvIHRoZSBjYWxsIG9mIGBfZGlzcGF0Y2hPcGVuYCkgaXNcbiAgLy8gYXJvdW5kIDIwMG1zZWMgKHRoZSBsb3dlciBib3VuZCB1c2VkIGluIHRoZSBhcnRpY2xlIGFib3ZlKSBhbmQgdGhpc1xuICAvLyBjYXVzZXMgc3B1cmlvdXMgdGltZW91dHMuIEZvciB0aGlzIHJlYXNvbiB3ZSBjYWxjdWxhdGUgYSB2YWx1ZSBzbGlnaHRseVxuICAvLyBsYXJnZXIgdGhhbiB0aGF0IHVzZWQgaW4gdGhlIGFydGljbGUuXG4gIGlmIChydHQgPiAxMDApIHtcbiAgICByZXR1cm4gNCAqIHJ0dDsgLy8gcnRvID4gNDAwbXNlY1xuICB9XG4gIHJldHVybiAzMDAgKyBydHQ7IC8vIDMwMG1zZWMgPCBydG8gPD0gNDAwbXNlY1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihhdmFpbGFibGVUcmFuc3BvcnRzKSB7XG4gIHRyYW5zcG9ydHMgPSB0cmFuc3BvcnQoYXZhaWxhYmxlVHJhbnNwb3J0cyk7XG4gIHJlcXVpcmUoJy4vaWZyYW1lLWJvb3RzdHJhcCcpKFNvY2tKUywgYXZhaWxhYmxlVHJhbnNwb3J0cyk7XG4gIHJldHVybiBTb2NrSlM7XG59O1xuIiwiLyogZXNsaW50LWRpc2FibGUgKi9cbi8qIGpzY3M6IGRpc2FibGUgKi9cbid1c2Ugc3RyaWN0JztcblxuLy8gcHVsbGVkIHNwZWNpZmljIHNoaW1zIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL2VzLXNoaW1zL2VzNS1zaGltXG5cbnZhciBBcnJheVByb3RvdHlwZSA9IEFycmF5LnByb3RvdHlwZTtcbnZhciBPYmplY3RQcm90b3R5cGUgPSBPYmplY3QucHJvdG90eXBlO1xudmFyIEZ1bmN0aW9uUHJvdG90eXBlID0gRnVuY3Rpb24ucHJvdG90eXBlO1xudmFyIFN0cmluZ1Byb3RvdHlwZSA9IFN0cmluZy5wcm90b3R5cGU7XG52YXIgYXJyYXlfc2xpY2UgPSBBcnJheVByb3RvdHlwZS5zbGljZTtcblxudmFyIF90b1N0cmluZyA9IE9iamVjdFByb3RvdHlwZS50b1N0cmluZztcbnZhciBpc0Z1bmN0aW9uID0gZnVuY3Rpb24gKHZhbCkge1xuICAgIHJldHVybiBPYmplY3RQcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YWwpID09PSAnW29iamVjdCBGdW5jdGlvbl0nO1xufTtcbnZhciBpc0FycmF5ID0gZnVuY3Rpb24gaXNBcnJheShvYmopIHtcbiAgICByZXR1cm4gX3RvU3RyaW5nLmNhbGwob2JqKSA9PT0gJ1tvYmplY3QgQXJyYXldJztcbn07XG52YXIgaXNTdHJpbmcgPSBmdW5jdGlvbiBpc1N0cmluZyhvYmopIHtcbiAgICByZXR1cm4gX3RvU3RyaW5nLmNhbGwob2JqKSA9PT0gJ1tvYmplY3QgU3RyaW5nXSc7XG59O1xuXG52YXIgc3VwcG9ydHNEZXNjcmlwdG9ycyA9IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSAmJiAoZnVuY3Rpb24gKCkge1xuICAgIHRyeSB7XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh7fSwgJ3gnLCB7fSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHsgLyogdGhpcyBpcyBFUzMgKi9cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0oKSk7XG5cbi8vIERlZmluZSBjb25maWd1cmFibGUsIHdyaXRhYmxlIGFuZCBub24tZW51bWVyYWJsZSBwcm9wc1xuLy8gaWYgdGhleSBkb24ndCBleGlzdC5cbnZhciBkZWZpbmVQcm9wZXJ0eTtcbmlmIChzdXBwb3J0c0Rlc2NyaXB0b3JzKSB7XG4gICAgZGVmaW5lUHJvcGVydHkgPSBmdW5jdGlvbiAob2JqZWN0LCBuYW1lLCBtZXRob2QsIGZvcmNlQXNzaWduKSB7XG4gICAgICAgIGlmICghZm9yY2VBc3NpZ24gJiYgKG5hbWUgaW4gb2JqZWN0KSkgeyByZXR1cm47IH1cbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iamVjdCwgbmFtZSwge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICAgICAgICB3cml0YWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiBtZXRob2RcbiAgICAgICAgfSk7XG4gICAgfTtcbn0gZWxzZSB7XG4gICAgZGVmaW5lUHJvcGVydHkgPSBmdW5jdGlvbiAob2JqZWN0LCBuYW1lLCBtZXRob2QsIGZvcmNlQXNzaWduKSB7XG4gICAgICAgIGlmICghZm9yY2VBc3NpZ24gJiYgKG5hbWUgaW4gb2JqZWN0KSkgeyByZXR1cm47IH1cbiAgICAgICAgb2JqZWN0W25hbWVdID0gbWV0aG9kO1xuICAgIH07XG59XG52YXIgZGVmaW5lUHJvcGVydGllcyA9IGZ1bmN0aW9uIChvYmplY3QsIG1hcCwgZm9yY2VBc3NpZ24pIHtcbiAgICBmb3IgKHZhciBuYW1lIGluIG1hcCkge1xuICAgICAgICBpZiAoT2JqZWN0UHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobWFwLCBuYW1lKSkge1xuICAgICAgICAgIGRlZmluZVByb3BlcnR5KG9iamVjdCwgbmFtZSwgbWFwW25hbWVdLCBmb3JjZUFzc2lnbik7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG52YXIgdG9PYmplY3QgPSBmdW5jdGlvbiAobykge1xuICAgIGlmIChvID09IG51bGwpIHsgLy8gdGhpcyBtYXRjaGVzIGJvdGggbnVsbCBhbmQgdW5kZWZpbmVkXG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJjYW4ndCBjb252ZXJ0IFwiICsgbyArICcgdG8gb2JqZWN0Jyk7XG4gICAgfVxuICAgIHJldHVybiBPYmplY3Qobyk7XG59O1xuXG4vL1xuLy8gVXRpbFxuLy8gPT09PT09XG4vL1xuXG4vLyBFUzUgOS40XG4vLyBodHRwOi8vZXM1LmdpdGh1Yi5jb20vI3g5LjRcbi8vIGh0dHA6Ly9qc3BlcmYuY29tL3RvLWludGVnZXJcblxuZnVuY3Rpb24gdG9JbnRlZ2VyKG51bSkge1xuICAgIHZhciBuID0gK251bTtcbiAgICBpZiAobiAhPT0gbikgeyAvLyBpc05hTlxuICAgICAgICBuID0gMDtcbiAgICB9IGVsc2UgaWYgKG4gIT09IDAgJiYgbiAhPT0gKDEgLyAwKSAmJiBuICE9PSAtKDEgLyAwKSkge1xuICAgICAgICBuID0gKG4gPiAwIHx8IC0xKSAqIE1hdGguZmxvb3IoTWF0aC5hYnMobikpO1xuICAgIH1cbiAgICByZXR1cm4gbjtcbn1cblxuZnVuY3Rpb24gVG9VaW50MzIoeCkge1xuICAgIHJldHVybiB4ID4+PiAwO1xufVxuXG4vL1xuLy8gRnVuY3Rpb25cbi8vID09PT09PT09XG4vL1xuXG4vLyBFUy01IDE1LjMuNC41XG4vLyBodHRwOi8vZXM1LmdpdGh1Yi5jb20vI3gxNS4zLjQuNVxuXG5mdW5jdGlvbiBFbXB0eSgpIHt9XG5cbmRlZmluZVByb3BlcnRpZXMoRnVuY3Rpb25Qcm90b3R5cGUsIHtcbiAgICBiaW5kOiBmdW5jdGlvbiBiaW5kKHRoYXQpIHsgLy8gLmxlbmd0aCBpcyAxXG4gICAgICAgIC8vIDEuIExldCBUYXJnZXQgYmUgdGhlIHRoaXMgdmFsdWUuXG4gICAgICAgIHZhciB0YXJnZXQgPSB0aGlzO1xuICAgICAgICAvLyAyLiBJZiBJc0NhbGxhYmxlKFRhcmdldCkgaXMgZmFsc2UsIHRocm93IGEgVHlwZUVycm9yIGV4Y2VwdGlvbi5cbiAgICAgICAgaWYgKCFpc0Z1bmN0aW9uKHRhcmdldCkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0Z1bmN0aW9uLnByb3RvdHlwZS5iaW5kIGNhbGxlZCBvbiBpbmNvbXBhdGlibGUgJyArIHRhcmdldCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gMy4gTGV0IEEgYmUgYSBuZXcgKHBvc3NpYmx5IGVtcHR5KSBpbnRlcm5hbCBsaXN0IG9mIGFsbCBvZiB0aGVcbiAgICAgICAgLy8gICBhcmd1bWVudCB2YWx1ZXMgcHJvdmlkZWQgYWZ0ZXIgdGhpc0FyZyAoYXJnMSwgYXJnMiBldGMpLCBpbiBvcmRlci5cbiAgICAgICAgLy8gWFhYIHNsaWNlZEFyZ3Mgd2lsbCBzdGFuZCBpbiBmb3IgXCJBXCIgaWYgdXNlZFxuICAgICAgICB2YXIgYXJncyA9IGFycmF5X3NsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTsgLy8gZm9yIG5vcm1hbCBjYWxsXG4gICAgICAgIC8vIDQuIExldCBGIGJlIGEgbmV3IG5hdGl2ZSBFQ01BU2NyaXB0IG9iamVjdC5cbiAgICAgICAgLy8gMTEuIFNldCB0aGUgW1tQcm90b3R5cGVdXSBpbnRlcm5hbCBwcm9wZXJ0eSBvZiBGIHRvIHRoZSBzdGFuZGFyZFxuICAgICAgICAvLyAgIGJ1aWx0LWluIEZ1bmN0aW9uIHByb3RvdHlwZSBvYmplY3QgYXMgc3BlY2lmaWVkIGluIDE1LjMuMy4xLlxuICAgICAgICAvLyAxMi4gU2V0IHRoZSBbW0NhbGxdXSBpbnRlcm5hbCBwcm9wZXJ0eSBvZiBGIGFzIGRlc2NyaWJlZCBpblxuICAgICAgICAvLyAgIDE1LjMuNC41LjEuXG4gICAgICAgIC8vIDEzLiBTZXQgdGhlIFtbQ29uc3RydWN0XV0gaW50ZXJuYWwgcHJvcGVydHkgb2YgRiBhcyBkZXNjcmliZWQgaW5cbiAgICAgICAgLy8gICAxNS4zLjQuNS4yLlxuICAgICAgICAvLyAxNC4gU2V0IHRoZSBbW0hhc0luc3RhbmNlXV0gaW50ZXJuYWwgcHJvcGVydHkgb2YgRiBhcyBkZXNjcmliZWQgaW5cbiAgICAgICAgLy8gICAxNS4zLjQuNS4zLlxuICAgICAgICB2YXIgYmluZGVyID0gZnVuY3Rpb24gKCkge1xuXG4gICAgICAgICAgICBpZiAodGhpcyBpbnN0YW5jZW9mIGJvdW5kKSB7XG4gICAgICAgICAgICAgICAgLy8gMTUuMy40LjUuMiBbW0NvbnN0cnVjdF1dXG4gICAgICAgICAgICAgICAgLy8gV2hlbiB0aGUgW1tDb25zdHJ1Y3RdXSBpbnRlcm5hbCBtZXRob2Qgb2YgYSBmdW5jdGlvbiBvYmplY3QsXG4gICAgICAgICAgICAgICAgLy8gRiB0aGF0IHdhcyBjcmVhdGVkIHVzaW5nIHRoZSBiaW5kIGZ1bmN0aW9uIGlzIGNhbGxlZCB3aXRoIGFcbiAgICAgICAgICAgICAgICAvLyBsaXN0IG9mIGFyZ3VtZW50cyBFeHRyYUFyZ3MsIHRoZSBmb2xsb3dpbmcgc3RlcHMgYXJlIHRha2VuOlxuICAgICAgICAgICAgICAgIC8vIDEuIExldCB0YXJnZXQgYmUgdGhlIHZhbHVlIG9mIEYncyBbW1RhcmdldEZ1bmN0aW9uXV1cbiAgICAgICAgICAgICAgICAvLyAgIGludGVybmFsIHByb3BlcnR5LlxuICAgICAgICAgICAgICAgIC8vIDIuIElmIHRhcmdldCBoYXMgbm8gW1tDb25zdHJ1Y3RdXSBpbnRlcm5hbCBtZXRob2QsIGFcbiAgICAgICAgICAgICAgICAvLyAgIFR5cGVFcnJvciBleGNlcHRpb24gaXMgdGhyb3duLlxuICAgICAgICAgICAgICAgIC8vIDMuIExldCBib3VuZEFyZ3MgYmUgdGhlIHZhbHVlIG9mIEYncyBbW0JvdW5kQXJnc11dIGludGVybmFsXG4gICAgICAgICAgICAgICAgLy8gICBwcm9wZXJ0eS5cbiAgICAgICAgICAgICAgICAvLyA0LiBMZXQgYXJncyBiZSBhIG5ldyBsaXN0IGNvbnRhaW5pbmcgdGhlIHNhbWUgdmFsdWVzIGFzIHRoZVxuICAgICAgICAgICAgICAgIC8vICAgbGlzdCBib3VuZEFyZ3MgaW4gdGhlIHNhbWUgb3JkZXIgZm9sbG93ZWQgYnkgdGhlIHNhbWVcbiAgICAgICAgICAgICAgICAvLyAgIHZhbHVlcyBhcyB0aGUgbGlzdCBFeHRyYUFyZ3MgaW4gdGhlIHNhbWUgb3JkZXIuXG4gICAgICAgICAgICAgICAgLy8gNS4gUmV0dXJuIHRoZSByZXN1bHQgb2YgY2FsbGluZyB0aGUgW1tDb25zdHJ1Y3RdXSBpbnRlcm5hbFxuICAgICAgICAgICAgICAgIC8vICAgbWV0aG9kIG9mIHRhcmdldCBwcm92aWRpbmcgYXJncyBhcyB0aGUgYXJndW1lbnRzLlxuXG4gICAgICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHRhcmdldC5hcHBseShcbiAgICAgICAgICAgICAgICAgICAgdGhpcyxcbiAgICAgICAgICAgICAgICAgICAgYXJncy5jb25jYXQoYXJyYXlfc2xpY2UuY2FsbChhcmd1bWVudHMpKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgaWYgKE9iamVjdChyZXN1bHQpID09PSByZXN1bHQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG5cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gMTUuMy40LjUuMSBbW0NhbGxdXVxuICAgICAgICAgICAgICAgIC8vIFdoZW4gdGhlIFtbQ2FsbF1dIGludGVybmFsIG1ldGhvZCBvZiBhIGZ1bmN0aW9uIG9iamVjdCwgRixcbiAgICAgICAgICAgICAgICAvLyB3aGljaCB3YXMgY3JlYXRlZCB1c2luZyB0aGUgYmluZCBmdW5jdGlvbiBpcyBjYWxsZWQgd2l0aCBhXG4gICAgICAgICAgICAgICAgLy8gdGhpcyB2YWx1ZSBhbmQgYSBsaXN0IG9mIGFyZ3VtZW50cyBFeHRyYUFyZ3MsIHRoZSBmb2xsb3dpbmdcbiAgICAgICAgICAgICAgICAvLyBzdGVwcyBhcmUgdGFrZW46XG4gICAgICAgICAgICAgICAgLy8gMS4gTGV0IGJvdW5kQXJncyBiZSB0aGUgdmFsdWUgb2YgRidzIFtbQm91bmRBcmdzXV0gaW50ZXJuYWxcbiAgICAgICAgICAgICAgICAvLyAgIHByb3BlcnR5LlxuICAgICAgICAgICAgICAgIC8vIDIuIExldCBib3VuZFRoaXMgYmUgdGhlIHZhbHVlIG9mIEYncyBbW0JvdW5kVGhpc11dIGludGVybmFsXG4gICAgICAgICAgICAgICAgLy8gICBwcm9wZXJ0eS5cbiAgICAgICAgICAgICAgICAvLyAzLiBMZXQgdGFyZ2V0IGJlIHRoZSB2YWx1ZSBvZiBGJ3MgW1tUYXJnZXRGdW5jdGlvbl1dIGludGVybmFsXG4gICAgICAgICAgICAgICAgLy8gICBwcm9wZXJ0eS5cbiAgICAgICAgICAgICAgICAvLyA0LiBMZXQgYXJncyBiZSBhIG5ldyBsaXN0IGNvbnRhaW5pbmcgdGhlIHNhbWUgdmFsdWVzIGFzIHRoZVxuICAgICAgICAgICAgICAgIC8vICAgbGlzdCBib3VuZEFyZ3MgaW4gdGhlIHNhbWUgb3JkZXIgZm9sbG93ZWQgYnkgdGhlIHNhbWVcbiAgICAgICAgICAgICAgICAvLyAgIHZhbHVlcyBhcyB0aGUgbGlzdCBFeHRyYUFyZ3MgaW4gdGhlIHNhbWUgb3JkZXIuXG4gICAgICAgICAgICAgICAgLy8gNS4gUmV0dXJuIHRoZSByZXN1bHQgb2YgY2FsbGluZyB0aGUgW1tDYWxsXV0gaW50ZXJuYWwgbWV0aG9kXG4gICAgICAgICAgICAgICAgLy8gICBvZiB0YXJnZXQgcHJvdmlkaW5nIGJvdW5kVGhpcyBhcyB0aGUgdGhpcyB2YWx1ZSBhbmRcbiAgICAgICAgICAgICAgICAvLyAgIHByb3ZpZGluZyBhcmdzIGFzIHRoZSBhcmd1bWVudHMuXG5cbiAgICAgICAgICAgICAgICAvLyBlcXVpdjogdGFyZ2V0LmNhbGwodGhpcywgLi4uYm91bmRBcmdzLCAuLi5hcmdzKVxuICAgICAgICAgICAgICAgIHJldHVybiB0YXJnZXQuYXBwbHkoXG4gICAgICAgICAgICAgICAgICAgIHRoYXQsXG4gICAgICAgICAgICAgICAgICAgIGFyZ3MuY29uY2F0KGFycmF5X3NsaWNlLmNhbGwoYXJndW1lbnRzKSlcbiAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgfTtcblxuICAgICAgICAvLyAxNS4gSWYgdGhlIFtbQ2xhc3NdXSBpbnRlcm5hbCBwcm9wZXJ0eSBvZiBUYXJnZXQgaXMgXCJGdW5jdGlvblwiLCB0aGVuXG4gICAgICAgIC8vICAgICBhLiBMZXQgTCBiZSB0aGUgbGVuZ3RoIHByb3BlcnR5IG9mIFRhcmdldCBtaW51cyB0aGUgbGVuZ3RoIG9mIEEuXG4gICAgICAgIC8vICAgICBiLiBTZXQgdGhlIGxlbmd0aCBvd24gcHJvcGVydHkgb2YgRiB0byBlaXRoZXIgMCBvciBMLCB3aGljaGV2ZXIgaXNcbiAgICAgICAgLy8gICAgICAgbGFyZ2VyLlxuICAgICAgICAvLyAxNi4gRWxzZSBzZXQgdGhlIGxlbmd0aCBvd24gcHJvcGVydHkgb2YgRiB0byAwLlxuXG4gICAgICAgIHZhciBib3VuZExlbmd0aCA9IE1hdGgubWF4KDAsIHRhcmdldC5sZW5ndGggLSBhcmdzLmxlbmd0aCk7XG5cbiAgICAgICAgLy8gMTcuIFNldCB0aGUgYXR0cmlidXRlcyBvZiB0aGUgbGVuZ3RoIG93biBwcm9wZXJ0eSBvZiBGIHRvIHRoZSB2YWx1ZXNcbiAgICAgICAgLy8gICBzcGVjaWZpZWQgaW4gMTUuMy41LjEuXG4gICAgICAgIHZhciBib3VuZEFyZ3MgPSBbXTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib3VuZExlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBib3VuZEFyZ3MucHVzaCgnJCcgKyBpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFhYWCBCdWlsZCBhIGR5bmFtaWMgZnVuY3Rpb24gd2l0aCBkZXNpcmVkIGFtb3VudCBvZiBhcmd1bWVudHMgaXMgdGhlIG9ubHlcbiAgICAgICAgLy8gd2F5IHRvIHNldCB0aGUgbGVuZ3RoIHByb3BlcnR5IG9mIGEgZnVuY3Rpb24uXG4gICAgICAgIC8vIEluIGVudmlyb25tZW50cyB3aGVyZSBDb250ZW50IFNlY3VyaXR5IFBvbGljaWVzIGVuYWJsZWQgKENocm9tZSBleHRlbnNpb25zLFxuICAgICAgICAvLyBmb3IgZXguKSBhbGwgdXNlIG9mIGV2YWwgb3IgRnVuY3Rpb24gY29zdHJ1Y3RvciB0aHJvd3MgYW4gZXhjZXB0aW9uLlxuICAgICAgICAvLyBIb3dldmVyIGluIGFsbCBvZiB0aGVzZSBlbnZpcm9ubWVudHMgRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQgZXhpc3RzXG4gICAgICAgIC8vIGFuZCBzbyB0aGlzIGNvZGUgd2lsbCBuZXZlciBiZSBleGVjdXRlZC5cbiAgICAgICAgdmFyIGJvdW5kID0gRnVuY3Rpb24oJ2JpbmRlcicsICdyZXR1cm4gZnVuY3Rpb24gKCcgKyBib3VuZEFyZ3Muam9pbignLCcpICsgJyl7IHJldHVybiBiaW5kZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKTsgfScpKGJpbmRlcik7XG5cbiAgICAgICAgaWYgKHRhcmdldC5wcm90b3R5cGUpIHtcbiAgICAgICAgICAgIEVtcHR5LnByb3RvdHlwZSA9IHRhcmdldC5wcm90b3R5cGU7XG4gICAgICAgICAgICBib3VuZC5wcm90b3R5cGUgPSBuZXcgRW1wdHkoKTtcbiAgICAgICAgICAgIC8vIENsZWFuIHVwIGRhbmdsaW5nIHJlZmVyZW5jZXMuXG4gICAgICAgICAgICBFbXB0eS5wcm90b3R5cGUgPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVE9ET1xuICAgICAgICAvLyAxOC4gU2V0IHRoZSBbW0V4dGVuc2libGVdXSBpbnRlcm5hbCBwcm9wZXJ0eSBvZiBGIHRvIHRydWUuXG5cbiAgICAgICAgLy8gVE9ET1xuICAgICAgICAvLyAxOS4gTGV0IHRocm93ZXIgYmUgdGhlIFtbVGhyb3dUeXBlRXJyb3JdXSBmdW5jdGlvbiBPYmplY3QgKDEzLjIuMykuXG4gICAgICAgIC8vIDIwLiBDYWxsIHRoZSBbW0RlZmluZU93blByb3BlcnR5XV0gaW50ZXJuYWwgbWV0aG9kIG9mIEYgd2l0aFxuICAgICAgICAvLyAgIGFyZ3VtZW50cyBcImNhbGxlclwiLCBQcm9wZXJ0eURlc2NyaXB0b3Ige1tbR2V0XV06IHRocm93ZXIsIFtbU2V0XV06XG4gICAgICAgIC8vICAgdGhyb3dlciwgW1tFbnVtZXJhYmxlXV06IGZhbHNlLCBbW0NvbmZpZ3VyYWJsZV1dOiBmYWxzZX0sIGFuZFxuICAgICAgICAvLyAgIGZhbHNlLlxuICAgICAgICAvLyAyMS4gQ2FsbCB0aGUgW1tEZWZpbmVPd25Qcm9wZXJ0eV1dIGludGVybmFsIG1ldGhvZCBvZiBGIHdpdGhcbiAgICAgICAgLy8gICBhcmd1bWVudHMgXCJhcmd1bWVudHNcIiwgUHJvcGVydHlEZXNjcmlwdG9yIHtbW0dldF1dOiB0aHJvd2VyLFxuICAgICAgICAvLyAgIFtbU2V0XV06IHRocm93ZXIsIFtbRW51bWVyYWJsZV1dOiBmYWxzZSwgW1tDb25maWd1cmFibGVdXTogZmFsc2V9LFxuICAgICAgICAvLyAgIGFuZCBmYWxzZS5cblxuICAgICAgICAvLyBUT0RPXG4gICAgICAgIC8vIE5PVEUgRnVuY3Rpb24gb2JqZWN0cyBjcmVhdGVkIHVzaW5nIEZ1bmN0aW9uLnByb3RvdHlwZS5iaW5kIGRvIG5vdFxuICAgICAgICAvLyBoYXZlIGEgcHJvdG90eXBlIHByb3BlcnR5IG9yIHRoZSBbW0NvZGVdXSwgW1tGb3JtYWxQYXJhbWV0ZXJzXV0sIGFuZFxuICAgICAgICAvLyBbW1Njb3BlXV0gaW50ZXJuYWwgcHJvcGVydGllcy5cbiAgICAgICAgLy8gWFhYIGNhbid0IGRlbGV0ZSBwcm90b3R5cGUgaW4gcHVyZS1qcy5cblxuICAgICAgICAvLyAyMi4gUmV0dXJuIEYuXG4gICAgICAgIHJldHVybiBib3VuZDtcbiAgICB9XG59KTtcblxuLy9cbi8vIEFycmF5XG4vLyA9PT09PVxuLy9cblxuLy8gRVM1IDE1LjQuMy4yXG4vLyBodHRwOi8vZXM1LmdpdGh1Yi5jb20vI3gxNS40LjMuMlxuLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4vSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvaXNBcnJheVxuZGVmaW5lUHJvcGVydGllcyhBcnJheSwgeyBpc0FycmF5OiBpc0FycmF5IH0pO1xuXG5cbnZhciBib3hlZFN0cmluZyA9IE9iamVjdCgnYScpO1xudmFyIHNwbGl0U3RyaW5nID0gYm94ZWRTdHJpbmdbMF0gIT09ICdhJyB8fCAhKDAgaW4gYm94ZWRTdHJpbmcpO1xuXG52YXIgcHJvcGVybHlCb3hlc0NvbnRleHQgPSBmdW5jdGlvbiBwcm9wZXJseUJveGVkKG1ldGhvZCkge1xuICAgIC8vIENoZWNrIG5vZGUgMC42LjIxIGJ1ZyB3aGVyZSB0aGlyZCBwYXJhbWV0ZXIgaXMgbm90IGJveGVkXG4gICAgdmFyIHByb3Blcmx5Qm94ZXNOb25TdHJpY3QgPSB0cnVlO1xuICAgIHZhciBwcm9wZXJseUJveGVzU3RyaWN0ID0gdHJ1ZTtcbiAgICBpZiAobWV0aG9kKSB7XG4gICAgICAgIG1ldGhvZC5jYWxsKCdmb28nLCBmdW5jdGlvbiAoXywgX18sIGNvbnRleHQpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgY29udGV4dCAhPT0gJ29iamVjdCcpIHsgcHJvcGVybHlCb3hlc05vblN0cmljdCA9IGZhbHNlOyB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIG1ldGhvZC5jYWxsKFsxXSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJ3VzZSBzdHJpY3QnO1xuICAgICAgICAgICAgcHJvcGVybHlCb3hlc1N0cmljdCA9IHR5cGVvZiB0aGlzID09PSAnc3RyaW5nJztcbiAgICAgICAgfSwgJ3gnKTtcbiAgICB9XG4gICAgcmV0dXJuICEhbWV0aG9kICYmIHByb3Blcmx5Qm94ZXNOb25TdHJpY3QgJiYgcHJvcGVybHlCb3hlc1N0cmljdDtcbn07XG5cbmRlZmluZVByb3BlcnRpZXMoQXJyYXlQcm90b3R5cGUsIHtcbiAgICBmb3JFYWNoOiBmdW5jdGlvbiBmb3JFYWNoKGZ1biAvKiwgdGhpc3AqLykge1xuICAgICAgICB2YXIgb2JqZWN0ID0gdG9PYmplY3QodGhpcyksXG4gICAgICAgICAgICBzZWxmID0gc3BsaXRTdHJpbmcgJiYgaXNTdHJpbmcodGhpcykgPyB0aGlzLnNwbGl0KCcnKSA6IG9iamVjdCxcbiAgICAgICAgICAgIHRoaXNwID0gYXJndW1lbnRzWzFdLFxuICAgICAgICAgICAgaSA9IC0xLFxuICAgICAgICAgICAgbGVuZ3RoID0gc2VsZi5sZW5ndGggPj4+IDA7XG5cbiAgICAgICAgLy8gSWYgbm8gY2FsbGJhY2sgZnVuY3Rpb24gb3IgaWYgY2FsbGJhY2sgaXMgbm90IGEgY2FsbGFibGUgZnVuY3Rpb25cbiAgICAgICAgaWYgKCFpc0Z1bmN0aW9uKGZ1bikpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoKTsgLy8gVE9ETyBtZXNzYWdlXG4gICAgICAgIH1cblxuICAgICAgICB3aGlsZSAoKytpIDwgbGVuZ3RoKSB7XG4gICAgICAgICAgICBpZiAoaSBpbiBzZWxmKSB7XG4gICAgICAgICAgICAgICAgLy8gSW52b2tlIHRoZSBjYWxsYmFjayBmdW5jdGlvbiB3aXRoIGNhbGwsIHBhc3NpbmcgYXJndW1lbnRzOlxuICAgICAgICAgICAgICAgIC8vIGNvbnRleHQsIHByb3BlcnR5IHZhbHVlLCBwcm9wZXJ0eSBrZXksIHRoaXNBcmcgb2JqZWN0XG4gICAgICAgICAgICAgICAgLy8gY29udGV4dFxuICAgICAgICAgICAgICAgIGZ1bi5jYWxsKHRoaXNwLCBzZWxmW2ldLCBpLCBvYmplY3QpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufSwgIXByb3Blcmx5Qm94ZXNDb250ZXh0KEFycmF5UHJvdG90eXBlLmZvckVhY2gpKTtcblxuLy8gRVM1IDE1LjQuNC4xNFxuLy8gaHR0cDovL2VzNS5naXRodWIuY29tLyN4MTUuNC40LjE0XG4vLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9BcnJheS9pbmRleE9mXG52YXIgaGFzRmlyZWZveDJJbmRleE9mQnVnID0gQXJyYXkucHJvdG90eXBlLmluZGV4T2YgJiYgWzAsIDFdLmluZGV4T2YoMSwgMikgIT09IC0xO1xuZGVmaW5lUHJvcGVydGllcyhBcnJheVByb3RvdHlwZSwge1xuICAgIGluZGV4T2Y6IGZ1bmN0aW9uIGluZGV4T2Yoc291Z2h0IC8qLCBmcm9tSW5kZXggKi8gKSB7XG4gICAgICAgIHZhciBzZWxmID0gc3BsaXRTdHJpbmcgJiYgaXNTdHJpbmcodGhpcykgPyB0aGlzLnNwbGl0KCcnKSA6IHRvT2JqZWN0KHRoaXMpLFxuICAgICAgICAgICAgbGVuZ3RoID0gc2VsZi5sZW5ndGggPj4+IDA7XG5cbiAgICAgICAgaWYgKCFsZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBpID0gMDtcbiAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICBpID0gdG9JbnRlZ2VyKGFyZ3VtZW50c1sxXSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBoYW5kbGUgbmVnYXRpdmUgaW5kaWNlc1xuICAgICAgICBpID0gaSA+PSAwID8gaSA6IE1hdGgubWF4KDAsIGxlbmd0aCArIGkpO1xuICAgICAgICBmb3IgKDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoaSBpbiBzZWxmICYmIHNlbGZbaV0gPT09IHNvdWdodCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiAtMTtcbiAgICB9XG59LCBoYXNGaXJlZm94MkluZGV4T2ZCdWcpO1xuXG4vL1xuLy8gU3RyaW5nXG4vLyA9PT09PT1cbi8vXG5cbi8vIEVTNSAxNS41LjQuMTRcbi8vIGh0dHA6Ly9lczUuZ2l0aHViLmNvbS8jeDE1LjUuNC4xNFxuXG4vLyBbYnVnZml4LCBJRSBsdCA5LCBmaXJlZm94IDQsIEtvbnF1ZXJvciwgT3BlcmEsIG9ic2N1cmUgYnJvd3NlcnNdXG4vLyBNYW55IGJyb3dzZXJzIGRvIG5vdCBzcGxpdCBwcm9wZXJseSB3aXRoIHJlZ3VsYXIgZXhwcmVzc2lvbnMgb3IgdGhleVxuLy8gZG8gbm90IHBlcmZvcm0gdGhlIHNwbGl0IGNvcnJlY3RseSB1bmRlciBvYnNjdXJlIGNvbmRpdGlvbnMuXG4vLyBTZWUgaHR0cDovL2Jsb2cuc3RldmVubGV2aXRoYW4uY29tL2FyY2hpdmVzL2Nyb3NzLWJyb3dzZXItc3BsaXRcbi8vIEkndmUgdGVzdGVkIGluIG1hbnkgYnJvd3NlcnMgYW5kIHRoaXMgc2VlbXMgdG8gY292ZXIgdGhlIGRldmlhbnQgb25lczpcbi8vICAgICdhYicuc3BsaXQoLyg/OmFiKSovKSBzaG91bGQgYmUgW1wiXCIsIFwiXCJdLCBub3QgW1wiXCJdXG4vLyAgICAnLicuc3BsaXQoLyguPykoLj8pLykgc2hvdWxkIGJlIFtcIlwiLCBcIi5cIiwgXCJcIiwgXCJcIl0sIG5vdCBbXCJcIiwgXCJcIl1cbi8vICAgICd0ZXNzdCcuc3BsaXQoLyhzKSovKSBzaG91bGQgYmUgW1widFwiLCB1bmRlZmluZWQsIFwiZVwiLCBcInNcIiwgXCJ0XCJdLCBub3Rcbi8vICAgICAgIFt1bmRlZmluZWQsIFwidFwiLCB1bmRlZmluZWQsIFwiZVwiLCAuLi5dXG4vLyAgICAnJy5zcGxpdCgvLj8vKSBzaG91bGQgYmUgW10sIG5vdCBbXCJcIl1cbi8vICAgICcuJy5zcGxpdCgvKCkoKS8pIHNob3VsZCBiZSBbXCIuXCJdLCBub3QgW1wiXCIsIFwiXCIsIFwiLlwiXVxuXG52YXIgc3RyaW5nX3NwbGl0ID0gU3RyaW5nUHJvdG90eXBlLnNwbGl0O1xuaWYgKFxuICAgICdhYicuc3BsaXQoLyg/OmFiKSovKS5sZW5ndGggIT09IDIgfHxcbiAgICAnLicuc3BsaXQoLyguPykoLj8pLykubGVuZ3RoICE9PSA0IHx8XG4gICAgJ3Rlc3N0Jy5zcGxpdCgvKHMpKi8pWzFdID09PSAndCcgfHxcbiAgICAndGVzdCcuc3BsaXQoLyg/OikvLCAtMSkubGVuZ3RoICE9PSA0IHx8XG4gICAgJycuc3BsaXQoLy4/LykubGVuZ3RoIHx8XG4gICAgJy4nLnNwbGl0KC8oKSgpLykubGVuZ3RoID4gMVxuKSB7XG4gICAgKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGNvbXBsaWFudEV4ZWNOcGNnID0gLygpPz8vLmV4ZWMoJycpWzFdID09PSB2b2lkIDA7IC8vIE5QQ0c6IG5vbnBhcnRpY2lwYXRpbmcgY2FwdHVyaW5nIGdyb3VwXG5cbiAgICAgICAgU3RyaW5nUHJvdG90eXBlLnNwbGl0ID0gZnVuY3Rpb24gKHNlcGFyYXRvciwgbGltaXQpIHtcbiAgICAgICAgICAgIHZhciBzdHJpbmcgPSB0aGlzO1xuICAgICAgICAgICAgaWYgKHNlcGFyYXRvciA9PT0gdm9pZCAwICYmIGxpbWl0ID09PSAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJZiBgc2VwYXJhdG9yYCBpcyBub3QgYSByZWdleCwgdXNlIG5hdGl2ZSBzcGxpdFxuICAgICAgICAgICAgaWYgKF90b1N0cmluZy5jYWxsKHNlcGFyYXRvcikgIT09ICdbb2JqZWN0IFJlZ0V4cF0nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHN0cmluZ19zcGxpdC5jYWxsKHRoaXMsIHNlcGFyYXRvciwgbGltaXQpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgb3V0cHV0ID0gW10sXG4gICAgICAgICAgICAgICAgZmxhZ3MgPSAoc2VwYXJhdG9yLmlnbm9yZUNhc2UgPyAnaScgOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgKHNlcGFyYXRvci5tdWx0aWxpbmUgID8gJ20nIDogJycpICtcbiAgICAgICAgICAgICAgICAgICAgICAgIChzZXBhcmF0b3IuZXh0ZW5kZWQgICA/ICd4JyA6ICcnKSArIC8vIFByb3Bvc2VkIGZvciBFUzZcbiAgICAgICAgICAgICAgICAgICAgICAgIChzZXBhcmF0b3Iuc3RpY2t5ICAgICA/ICd5JyA6ICcnKSwgLy8gRmlyZWZveCAzK1xuICAgICAgICAgICAgICAgIGxhc3RMYXN0SW5kZXggPSAwLFxuICAgICAgICAgICAgICAgIC8vIE1ha2UgYGdsb2JhbGAgYW5kIGF2b2lkIGBsYXN0SW5kZXhgIGlzc3VlcyBieSB3b3JraW5nIHdpdGggYSBjb3B5XG4gICAgICAgICAgICAgICAgc2VwYXJhdG9yMiwgbWF0Y2gsIGxhc3RJbmRleCwgbGFzdExlbmd0aDtcbiAgICAgICAgICAgIHNlcGFyYXRvciA9IG5ldyBSZWdFeHAoc2VwYXJhdG9yLnNvdXJjZSwgZmxhZ3MgKyAnZycpO1xuICAgICAgICAgICAgc3RyaW5nICs9ICcnOyAvLyBUeXBlLWNvbnZlcnRcbiAgICAgICAgICAgIGlmICghY29tcGxpYW50RXhlY05wY2cpIHtcbiAgICAgICAgICAgICAgICAvLyBEb2Vzbid0IG5lZWQgZmxhZ3MgZ3ksIGJ1dCB0aGV5IGRvbid0IGh1cnRcbiAgICAgICAgICAgICAgICBzZXBhcmF0b3IyID0gbmV3IFJlZ0V4cCgnXicgKyBzZXBhcmF0b3Iuc291cmNlICsgJyQoPyFcXFxccyknLCBmbGFncyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvKiBWYWx1ZXMgZm9yIGBsaW1pdGAsIHBlciB0aGUgc3BlYzpcbiAgICAgICAgICAgICAqIElmIHVuZGVmaW5lZDogNDI5NDk2NzI5NSAvLyBNYXRoLnBvdygyLCAzMikgLSAxXG4gICAgICAgICAgICAgKiBJZiAwLCBJbmZpbml0eSwgb3IgTmFOOiAwXG4gICAgICAgICAgICAgKiBJZiBwb3NpdGl2ZSBudW1iZXI6IGxpbWl0ID0gTWF0aC5mbG9vcihsaW1pdCk7IGlmIChsaW1pdCA+IDQyOTQ5NjcyOTUpIGxpbWl0IC09IDQyOTQ5NjcyOTY7XG4gICAgICAgICAgICAgKiBJZiBuZWdhdGl2ZSBudW1iZXI6IDQyOTQ5NjcyOTYgLSBNYXRoLmZsb29yKE1hdGguYWJzKGxpbWl0KSlcbiAgICAgICAgICAgICAqIElmIG90aGVyOiBUeXBlLWNvbnZlcnQsIHRoZW4gdXNlIHRoZSBhYm92ZSBydWxlc1xuICAgICAgICAgICAgICovXG4gICAgICAgICAgICBsaW1pdCA9IGxpbWl0ID09PSB2b2lkIDAgP1xuICAgICAgICAgICAgICAgIC0xID4+PiAwIDogLy8gTWF0aC5wb3coMiwgMzIpIC0gMVxuICAgICAgICAgICAgICAgIFRvVWludDMyKGxpbWl0KTtcbiAgICAgICAgICAgIHdoaWxlIChtYXRjaCA9IHNlcGFyYXRvci5leGVjKHN0cmluZykpIHtcbiAgICAgICAgICAgICAgICAvLyBgc2VwYXJhdG9yLmxhc3RJbmRleGAgaXMgbm90IHJlbGlhYmxlIGNyb3NzLWJyb3dzZXJcbiAgICAgICAgICAgICAgICBsYXN0SW5kZXggPSBtYXRjaC5pbmRleCArIG1hdGNoWzBdLmxlbmd0aDtcbiAgICAgICAgICAgICAgICBpZiAobGFzdEluZGV4ID4gbGFzdExhc3RJbmRleCkge1xuICAgICAgICAgICAgICAgICAgICBvdXRwdXQucHVzaChzdHJpbmcuc2xpY2UobGFzdExhc3RJbmRleCwgbWF0Y2guaW5kZXgpKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gRml4IGJyb3dzZXJzIHdob3NlIGBleGVjYCBtZXRob2RzIGRvbid0IGNvbnNpc3RlbnRseSByZXR1cm4gYHVuZGVmaW5lZGAgZm9yXG4gICAgICAgICAgICAgICAgICAgIC8vIG5vbnBhcnRpY2lwYXRpbmcgY2FwdHVyaW5nIGdyb3Vwc1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWNvbXBsaWFudEV4ZWNOcGNnICYmIG1hdGNoLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoWzBdLnJlcGxhY2Uoc2VwYXJhdG9yMiwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYXJndW1lbnRzLmxlbmd0aCAtIDI7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoYXJndW1lbnRzW2ldID09PSB2b2lkIDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoW2ldID0gdm9pZCAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKG1hdGNoLmxlbmd0aCA+IDEgJiYgbWF0Y2guaW5kZXggPCBzdHJpbmcubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBBcnJheVByb3RvdHlwZS5wdXNoLmFwcGx5KG91dHB1dCwgbWF0Y2guc2xpY2UoMSkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGxhc3RMZW5ndGggPSBtYXRjaFswXS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIGxhc3RMYXN0SW5kZXggPSBsYXN0SW5kZXg7XG4gICAgICAgICAgICAgICAgICAgIGlmIChvdXRwdXQubGVuZ3RoID49IGxpbWl0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoc2VwYXJhdG9yLmxhc3RJbmRleCA9PT0gbWF0Y2guaW5kZXgpIHtcbiAgICAgICAgICAgICAgICAgICAgc2VwYXJhdG9yLmxhc3RJbmRleCsrOyAvLyBBdm9pZCBhbiBpbmZpbml0ZSBsb29wXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGxhc3RMYXN0SW5kZXggPT09IHN0cmluZy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBpZiAobGFzdExlbmd0aCB8fCAhc2VwYXJhdG9yLnRlc3QoJycpKSB7XG4gICAgICAgICAgICAgICAgICAgIG91dHB1dC5wdXNoKCcnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG91dHB1dC5wdXNoKHN0cmluZy5zbGljZShsYXN0TGFzdEluZGV4KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gb3V0cHV0Lmxlbmd0aCA+IGxpbWl0ID8gb3V0cHV0LnNsaWNlKDAsIGxpbWl0KSA6IG91dHB1dDtcbiAgICAgICAgfTtcbiAgICB9KCkpO1xuXG4vLyBbYnVnZml4LCBjaHJvbWVdXG4vLyBJZiBzZXBhcmF0b3IgaXMgdW5kZWZpbmVkLCB0aGVuIHRoZSByZXN1bHQgYXJyYXkgY29udGFpbnMganVzdCBvbmUgU3RyaW5nLFxuLy8gd2hpY2ggaXMgdGhlIHRoaXMgdmFsdWUgKGNvbnZlcnRlZCB0byBhIFN0cmluZykuIElmIGxpbWl0IGlzIG5vdCB1bmRlZmluZWQsXG4vLyB0aGVuIHRoZSBvdXRwdXQgYXJyYXkgaXMgdHJ1bmNhdGVkIHNvIHRoYXQgaXQgY29udGFpbnMgbm8gbW9yZSB0aGFuIGxpbWl0XG4vLyBlbGVtZW50cy5cbi8vIFwiMFwiLnNwbGl0KHVuZGVmaW5lZCwgMCkgLT4gW11cbn0gZWxzZSBpZiAoJzAnLnNwbGl0KHZvaWQgMCwgMCkubGVuZ3RoKSB7XG4gICAgU3RyaW5nUHJvdG90eXBlLnNwbGl0ID0gZnVuY3Rpb24gc3BsaXQoc2VwYXJhdG9yLCBsaW1pdCkge1xuICAgICAgICBpZiAoc2VwYXJhdG9yID09PSB2b2lkIDAgJiYgbGltaXQgPT09IDApIHsgcmV0dXJuIFtdOyB9XG4gICAgICAgIHJldHVybiBzdHJpbmdfc3BsaXQuY2FsbCh0aGlzLCBzZXBhcmF0b3IsIGxpbWl0KTtcbiAgICB9O1xufVxuXG4vLyBFUzUgMTUuNS40LjIwXG4vLyB3aGl0ZXNwYWNlIGZyb206IGh0dHA6Ly9lczUuZ2l0aHViLmlvLyN4MTUuNS40LjIwXG52YXIgd3MgPSAnXFx4MDlcXHgwQVxceDBCXFx4MENcXHgwRFxceDIwXFx4QTBcXHUxNjgwXFx1MTgwRVxcdTIwMDBcXHUyMDAxXFx1MjAwMlxcdTIwMDMnICtcbiAgICAnXFx1MjAwNFxcdTIwMDVcXHUyMDA2XFx1MjAwN1xcdTIwMDhcXHUyMDA5XFx1MjAwQVxcdTIwMkZcXHUyMDVGXFx1MzAwMFxcdTIwMjgnICtcbiAgICAnXFx1MjAyOVxcdUZFRkYnO1xudmFyIHplcm9XaWR0aCA9ICdcXHUyMDBiJztcbnZhciB3c1JlZ2V4Q2hhcnMgPSAnWycgKyB3cyArICddJztcbnZhciB0cmltQmVnaW5SZWdleHAgPSBuZXcgUmVnRXhwKCdeJyArIHdzUmVnZXhDaGFycyArIHdzUmVnZXhDaGFycyArICcqJyk7XG52YXIgdHJpbUVuZFJlZ2V4cCA9IG5ldyBSZWdFeHAod3NSZWdleENoYXJzICsgd3NSZWdleENoYXJzICsgJyokJyk7XG52YXIgaGFzVHJpbVdoaXRlc3BhY2VCdWcgPSBTdHJpbmdQcm90b3R5cGUudHJpbSAmJiAod3MudHJpbSgpIHx8ICF6ZXJvV2lkdGgudHJpbSgpKTtcbmRlZmluZVByb3BlcnRpZXMoU3RyaW5nUHJvdG90eXBlLCB7XG4gICAgLy8gaHR0cDovL2Jsb2cuc3RldmVubGV2aXRoYW4uY29tL2FyY2hpdmVzL2Zhc3Rlci10cmltLWphdmFzY3JpcHRcbiAgICAvLyBodHRwOi8vcGVyZmVjdGlvbmtpbGxzLmNvbS93aGl0ZXNwYWNlLWRldmlhdGlvbnMvXG4gICAgdHJpbTogZnVuY3Rpb24gdHJpbSgpIHtcbiAgICAgICAgaWYgKHRoaXMgPT09IHZvaWQgMCB8fCB0aGlzID09PSBudWxsKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiY2FuJ3QgY29udmVydCBcIiArIHRoaXMgKyAnIHRvIG9iamVjdCcpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBTdHJpbmcodGhpcykucmVwbGFjZSh0cmltQmVnaW5SZWdleHAsICcnKS5yZXBsYWNlKHRyaW1FbmRSZWdleHAsICcnKTtcbiAgICB9XG59LCBoYXNUcmltV2hpdGVzcGFjZUJ1Zyk7XG5cbi8vIEVDTUEtMjYyLCAzcmQgQi4yLjNcbi8vIE5vdCBhbiBFQ01BU2NyaXB0IHN0YW5kYXJkLCBhbHRob3VnaCBFQ01BU2NyaXB0IDNyZCBFZGl0aW9uIGhhcyBhXG4vLyBub24tbm9ybWF0aXZlIHNlY3Rpb24gc3VnZ2VzdGluZyB1bmlmb3JtIHNlbWFudGljcyBhbmQgaXQgc2hvdWxkIGJlXG4vLyBub3JtYWxpemVkIGFjcm9zcyBhbGwgYnJvd3NlcnNcbi8vIFtidWdmaXgsIElFIGx0IDldIElFIDwgOSBzdWJzdHIoKSB3aXRoIG5lZ2F0aXZlIHZhbHVlIG5vdCB3b3JraW5nIGluIElFXG52YXIgc3RyaW5nX3N1YnN0ciA9IFN0cmluZ1Byb3RvdHlwZS5zdWJzdHI7XG52YXIgaGFzTmVnYXRpdmVTdWJzdHJCdWcgPSAnJy5zdWJzdHIgJiYgJzBiJy5zdWJzdHIoLTEpICE9PSAnYic7XG5kZWZpbmVQcm9wZXJ0aWVzKFN0cmluZ1Byb3RvdHlwZSwge1xuICAgIHN1YnN0cjogZnVuY3Rpb24gc3Vic3RyKHN0YXJ0LCBsZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuIHN0cmluZ19zdWJzdHIuY2FsbChcbiAgICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgICBzdGFydCA8IDAgPyAoKHN0YXJ0ID0gdGhpcy5sZW5ndGggKyBzdGFydCkgPCAwID8gMCA6IHN0YXJ0KSA6IHN0YXJ0LFxuICAgICAgICAgICAgbGVuZ3RoXG4gICAgICAgICk7XG4gICAgfVxufSwgaGFzTmVnYXRpdmVTdWJzdHJCdWcpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFtcbiAgLy8gc3RyZWFtaW5nIHRyYW5zcG9ydHNcbiAgcmVxdWlyZSgnLi90cmFuc3BvcnQvd2Vic29ja2V0JylcbiwgcmVxdWlyZSgnLi90cmFuc3BvcnQveGhyLXN0cmVhbWluZycpXG4sIHJlcXVpcmUoJy4vdHJhbnNwb3J0L3hkci1zdHJlYW1pbmcnKVxuLCByZXF1aXJlKCcuL3RyYW5zcG9ydC9ldmVudHNvdXJjZScpXG4sIHJlcXVpcmUoJy4vdHJhbnNwb3J0L2xpYi9pZnJhbWUtd3JhcCcpKHJlcXVpcmUoJy4vdHJhbnNwb3J0L2V2ZW50c291cmNlJykpXG5cbiAgLy8gcG9sbGluZyB0cmFuc3BvcnRzXG4sIHJlcXVpcmUoJy4vdHJhbnNwb3J0L2h0bWxmaWxlJylcbiwgcmVxdWlyZSgnLi90cmFuc3BvcnQvbGliL2lmcmFtZS13cmFwJykocmVxdWlyZSgnLi90cmFuc3BvcnQvaHRtbGZpbGUnKSlcbiwgcmVxdWlyZSgnLi90cmFuc3BvcnQveGhyLXBvbGxpbmcnKVxuLCByZXF1aXJlKCcuL3RyYW5zcG9ydC94ZHItcG9sbGluZycpXG4sIHJlcXVpcmUoJy4vdHJhbnNwb3J0L2xpYi9pZnJhbWUtd3JhcCcpKHJlcXVpcmUoJy4vdHJhbnNwb3J0L3hoci1wb2xsaW5nJykpXG4sIHJlcXVpcmUoJy4vdHJhbnNwb3J0L2pzb25wLXBvbGxpbmcnKVxuXTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlclxuICAsIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIHV0aWxzID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvZXZlbnQnKVxuICAsIHVybFV0aWxzID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvdXJsJylcbiAgLCBYSFIgPSBnbG9iYWwuWE1MSHR0cFJlcXVlc3RcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OmJyb3dzZXI6eGhyJyk7XG59XG5cbmZ1bmN0aW9uIEFic3RyYWN0WEhST2JqZWN0KG1ldGhvZCwgdXJsLCBwYXlsb2FkLCBvcHRzKSB7XG4gIGRlYnVnKG1ldGhvZCwgdXJsKTtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICBFdmVudEVtaXR0ZXIuY2FsbCh0aGlzKTtcblxuICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICBzZWxmLl9zdGFydChtZXRob2QsIHVybCwgcGF5bG9hZCwgb3B0cyk7XG4gIH0sIDApO1xufVxuXG5pbmhlcml0cyhBYnN0cmFjdFhIUk9iamVjdCwgRXZlbnRFbWl0dGVyKTtcblxuQWJzdHJhY3RYSFJPYmplY3QucHJvdG90eXBlLl9zdGFydCA9IGZ1bmN0aW9uKG1ldGhvZCwgdXJsLCBwYXlsb2FkLCBvcHRzKSB7XG4gIHZhciBzZWxmID0gdGhpcztcblxuICB0cnkge1xuICAgIHRoaXMueGhyID0gbmV3IFhIUigpO1xuICB9IGNhdGNoICh4KSB7XG4gICAgLy8gaW50ZW50aW9uYWxseSBlbXB0eVxuICB9XG5cbiAgaWYgKCF0aGlzLnhocikge1xuICAgIGRlYnVnKCdubyB4aHInKTtcbiAgICB0aGlzLmVtaXQoJ2ZpbmlzaCcsIDAsICdubyB4aHIgc3VwcG9ydCcpO1xuICAgIHRoaXMuX2NsZWFudXAoKTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBzZXZlcmFsIGJyb3dzZXJzIGNhY2hlIFBPU1RzXG4gIHVybCA9IHVybFV0aWxzLmFkZFF1ZXJ5KHVybCwgJ3Q9JyArICgrbmV3IERhdGUoKSkpO1xuXG4gIC8vIEV4cGxvcmVyIHRlbmRzIHRvIGtlZXAgY29ubmVjdGlvbiBvcGVuLCBldmVuIGFmdGVyIHRoZVxuICAvLyB0YWIgZ2V0cyBjbG9zZWQ6IGh0dHA6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzUyODBcbiAgdGhpcy51bmxvYWRSZWYgPSB1dGlscy51bmxvYWRBZGQoZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ3VubG9hZCBjbGVhbnVwJyk7XG4gICAgc2VsZi5fY2xlYW51cCh0cnVlKTtcbiAgfSk7XG4gIHRyeSB7XG4gICAgdGhpcy54aHIub3BlbihtZXRob2QsIHVybCwgdHJ1ZSk7XG4gICAgaWYgKHRoaXMudGltZW91dCAmJiAndGltZW91dCcgaW4gdGhpcy54aHIpIHtcbiAgICAgIHRoaXMueGhyLnRpbWVvdXQgPSB0aGlzLnRpbWVvdXQ7XG4gICAgICB0aGlzLnhoci5vbnRpbWVvdXQgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgZGVidWcoJ3hociB0aW1lb3V0Jyk7XG4gICAgICAgIHNlbGYuZW1pdCgnZmluaXNoJywgMCwgJycpO1xuICAgICAgICBzZWxmLl9jbGVhbnVwKGZhbHNlKTtcbiAgICAgIH07XG4gICAgfVxuICB9IGNhdGNoIChlKSB7XG4gICAgZGVidWcoJ2V4Y2VwdGlvbicsIGUpO1xuICAgIC8vIElFIHJhaXNlcyBhbiBleGNlcHRpb24gb24gd3JvbmcgcG9ydC5cbiAgICB0aGlzLmVtaXQoJ2ZpbmlzaCcsIDAsICcnKTtcbiAgICB0aGlzLl9jbGVhbnVwKGZhbHNlKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoKCFvcHRzIHx8ICFvcHRzLm5vQ3JlZGVudGlhbHMpICYmIEFic3RyYWN0WEhST2JqZWN0LnN1cHBvcnRzQ09SUykge1xuICAgIGRlYnVnKCd3aXRoQ3JlZGVudGlhbHMnKTtcbiAgICAvLyBNb3ppbGxhIGRvY3Mgc2F5cyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi9YTUxIdHRwUmVxdWVzdCA6XG4gICAgLy8gXCJUaGlzIG5ldmVyIGFmZmVjdHMgc2FtZS1zaXRlIHJlcXVlc3RzLlwiXG5cbiAgICB0aGlzLnhoci53aXRoQ3JlZGVudGlhbHMgPSAndHJ1ZSc7XG4gIH1cbiAgaWYgKG9wdHMgJiYgb3B0cy5oZWFkZXJzKSB7XG4gICAgZm9yICh2YXIga2V5IGluIG9wdHMuaGVhZGVycykge1xuICAgICAgdGhpcy54aHIuc2V0UmVxdWVzdEhlYWRlcihrZXksIG9wdHMuaGVhZGVyc1trZXldKTtcbiAgICB9XG4gIH1cblxuICB0aGlzLnhoci5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICBpZiAoc2VsZi54aHIpIHtcbiAgICAgIHZhciB4ID0gc2VsZi54aHI7XG4gICAgICB2YXIgdGV4dCwgc3RhdHVzO1xuICAgICAgZGVidWcoJ3JlYWR5U3RhdGUnLCB4LnJlYWR5U3RhdGUpO1xuICAgICAgc3dpdGNoICh4LnJlYWR5U3RhdGUpIHtcbiAgICAgIGNhc2UgMzpcbiAgICAgICAgLy8gSUUgZG9lc24ndCBsaWtlIHBlZWtpbmcgaW50byByZXNwb25zZVRleHQgb3Igc3RhdHVzXG4gICAgICAgIC8vIG9uIE1pY3Jvc29mdC5YTUxIVFRQIGFuZCByZWFkeXN0YXRlPTNcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBzdGF0dXMgPSB4LnN0YXR1cztcbiAgICAgICAgICB0ZXh0ID0geC5yZXNwb25zZVRleHQ7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAvLyBpbnRlbnRpb25hbGx5IGVtcHR5XG4gICAgICAgIH1cbiAgICAgICAgZGVidWcoJ3N0YXR1cycsIHN0YXR1cyk7XG4gICAgICAgIC8vIElFIHJldHVybnMgMTIyMyBmb3IgMjA0OiBodHRwOi8vYnVncy5qcXVlcnkuY29tL3RpY2tldC8xNDUwXG4gICAgICAgIGlmIChzdGF0dXMgPT09IDEyMjMpIHtcbiAgICAgICAgICBzdGF0dXMgPSAyMDQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJRSBkb2VzIHJldHVybiByZWFkeXN0YXRlID09IDMgZm9yIDQwNCBhbnN3ZXJzLlxuICAgICAgICBpZiAoc3RhdHVzID09PSAyMDAgJiYgdGV4dCAmJiB0ZXh0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBkZWJ1ZygnY2h1bmsnKTtcbiAgICAgICAgICBzZWxmLmVtaXQoJ2NodW5rJywgc3RhdHVzLCB0ZXh0KTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgNDpcbiAgICAgICAgc3RhdHVzID0geC5zdGF0dXM7XG4gICAgICAgIGRlYnVnKCdzdGF0dXMnLCBzdGF0dXMpO1xuICAgICAgICAvLyBJRSByZXR1cm5zIDEyMjMgZm9yIDIwNDogaHR0cDovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvMTQ1MFxuICAgICAgICBpZiAoc3RhdHVzID09PSAxMjIzKSB7XG4gICAgICAgICAgc3RhdHVzID0gMjA0O1xuICAgICAgICB9XG4gICAgICAgIC8vIElFIHJldHVybnMgdGhpcyBmb3IgYSBiYWQgcG9ydFxuICAgICAgICAvLyBodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tL2VuLXVzL2xpYnJhcnkvd2luZG93cy9kZXNrdG9wL2FhMzgzNzcwKHY9dnMuODUpLmFzcHhcbiAgICAgICAgaWYgKHN0YXR1cyA9PT0gMTIwMDUgfHwgc3RhdHVzID09PSAxMjAyOSkge1xuICAgICAgICAgIHN0YXR1cyA9IDA7XG4gICAgICAgIH1cblxuICAgICAgICBkZWJ1ZygnZmluaXNoJywgc3RhdHVzLCB4LnJlc3BvbnNlVGV4dCk7XG4gICAgICAgIHNlbGYuZW1pdCgnZmluaXNoJywgc3RhdHVzLCB4LnJlc3BvbnNlVGV4dCk7XG4gICAgICAgIHNlbGYuX2NsZWFudXAoZmFsc2UpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgdHJ5IHtcbiAgICBzZWxmLnhoci5zZW5kKHBheWxvYWQpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgc2VsZi5lbWl0KCdmaW5pc2gnLCAwLCAnJyk7XG4gICAgc2VsZi5fY2xlYW51cChmYWxzZSk7XG4gIH1cbn07XG5cbkFic3RyYWN0WEhST2JqZWN0LnByb3RvdHlwZS5fY2xlYW51cCA9IGZ1bmN0aW9uKGFib3J0KSB7XG4gIGRlYnVnKCdjbGVhbnVwJyk7XG4gIGlmICghdGhpcy54aHIpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgdXRpbHMudW5sb2FkRGVsKHRoaXMudW5sb2FkUmVmKTtcblxuICAvLyBJRSBuZWVkcyB0aGlzIGZpZWxkIHRvIGJlIGEgZnVuY3Rpb25cbiAgdGhpcy54aHIub25yZWFkeXN0YXRlY2hhbmdlID0gZnVuY3Rpb24oKSB7fTtcbiAgaWYgKHRoaXMueGhyLm9udGltZW91dCkge1xuICAgIHRoaXMueGhyLm9udGltZW91dCA9IG51bGw7XG4gIH1cblxuICBpZiAoYWJvcnQpIHtcbiAgICB0cnkge1xuICAgICAgdGhpcy54aHIuYWJvcnQoKTtcbiAgICB9IGNhdGNoICh4KSB7XG4gICAgICAvLyBpbnRlbnRpb25hbGx5IGVtcHR5XG4gICAgfVxuICB9XG4gIHRoaXMudW5sb2FkUmVmID0gdGhpcy54aHIgPSBudWxsO1xufTtcblxuQWJzdHJhY3RYSFJPYmplY3QucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdjbG9zZScpO1xuICB0aGlzLl9jbGVhbnVwKHRydWUpO1xufTtcblxuQWJzdHJhY3RYSFJPYmplY3QuZW5hYmxlZCA9ICEhWEhSO1xuLy8gb3ZlcnJpZGUgWE1MSHR0cFJlcXVlc3QgZm9yIElFNi83XG4vLyBvYmZ1c2NhdGUgdG8gYXZvaWQgZmlyZXdhbGxzXG52YXIgYXhvID0gWydBY3RpdmUnXS5jb25jYXQoJ09iamVjdCcpLmpvaW4oJ1gnKTtcbmlmICghQWJzdHJhY3RYSFJPYmplY3QuZW5hYmxlZCAmJiAoYXhvIGluIGdsb2JhbCkpIHtcbiAgZGVidWcoJ292ZXJyaWRpbmcgeG1saHR0cHJlcXVlc3QnKTtcbiAgWEhSID0gZnVuY3Rpb24oKSB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBuZXcgZ2xvYmFsW2F4b10oJ01pY3Jvc29mdC5YTUxIVFRQJyk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9O1xuICBBYnN0cmFjdFhIUk9iamVjdC5lbmFibGVkID0gISFuZXcgWEhSKCk7XG59XG5cbnZhciBjb3JzID0gZmFsc2U7XG50cnkge1xuICBjb3JzID0gJ3dpdGhDcmVkZW50aWFscycgaW4gbmV3IFhIUigpO1xufSBjYXRjaCAoaWdub3JlZCkge1xuICAvLyBpbnRlbnRpb25hbGx5IGVtcHR5XG59XG5cbkFic3RyYWN0WEhST2JqZWN0LnN1cHBvcnRzQ09SUyA9IGNvcnM7XG5cbm1vZHVsZS5leHBvcnRzID0gQWJzdHJhY3RYSFJPYmplY3Q7XG4iLCJtb2R1bGUuZXhwb3J0cyA9IGdsb2JhbC5FdmVudFNvdXJjZTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIERyaXZlciA9IGdsb2JhbC5XZWJTb2NrZXQgfHwgZ2xvYmFsLk1veldlYlNvY2tldDtcbmlmIChEcml2ZXIpIHtcblx0bW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBXZWJTb2NrZXRCcm93c2VyRHJpdmVyKHVybCkge1xuXHRcdHJldHVybiBuZXcgRHJpdmVyKHVybCk7XG5cdH07XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBBamF4QmFzZWRUcmFuc3BvcnQgPSByZXF1aXJlKCcuL2xpYi9hamF4LWJhc2VkJylcbiAgLCBFdmVudFNvdXJjZVJlY2VpdmVyID0gcmVxdWlyZSgnLi9yZWNlaXZlci9ldmVudHNvdXJjZScpXG4gICwgWEhSQ29yc09iamVjdCA9IHJlcXVpcmUoJy4vc2VuZGVyL3hoci1jb3JzJylcbiAgLCBFdmVudFNvdXJjZURyaXZlciA9IHJlcXVpcmUoJ2V2ZW50c291cmNlJylcbiAgO1xuXG5mdW5jdGlvbiBFdmVudFNvdXJjZVRyYW5zcG9ydCh0cmFuc1VybCkge1xuICBpZiAoIUV2ZW50U291cmNlVHJhbnNwb3J0LmVuYWJsZWQoKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignVHJhbnNwb3J0IGNyZWF0ZWQgd2hlbiBkaXNhYmxlZCcpO1xuICB9XG5cbiAgQWpheEJhc2VkVHJhbnNwb3J0LmNhbGwodGhpcywgdHJhbnNVcmwsICcvZXZlbnRzb3VyY2UnLCBFdmVudFNvdXJjZVJlY2VpdmVyLCBYSFJDb3JzT2JqZWN0KTtcbn1cblxuaW5oZXJpdHMoRXZlbnRTb3VyY2VUcmFuc3BvcnQsIEFqYXhCYXNlZFRyYW5zcG9ydCk7XG5cbkV2ZW50U291cmNlVHJhbnNwb3J0LmVuYWJsZWQgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuICEhRXZlbnRTb3VyY2VEcml2ZXI7XG59O1xuXG5FdmVudFNvdXJjZVRyYW5zcG9ydC50cmFuc3BvcnROYW1lID0gJ2V2ZW50c291cmNlJztcbkV2ZW50U291cmNlVHJhbnNwb3J0LnJvdW5kVHJpcHMgPSAyO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50U291cmNlVHJhbnNwb3J0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgSHRtbGZpbGVSZWNlaXZlciA9IHJlcXVpcmUoJy4vcmVjZWl2ZXIvaHRtbGZpbGUnKVxuICAsIFhIUkxvY2FsT2JqZWN0ID0gcmVxdWlyZSgnLi9zZW5kZXIveGhyLWxvY2FsJylcbiAgLCBBamF4QmFzZWRUcmFuc3BvcnQgPSByZXF1aXJlKCcuL2xpYi9hamF4LWJhc2VkJylcbiAgO1xuXG5mdW5jdGlvbiBIdG1sRmlsZVRyYW5zcG9ydCh0cmFuc1VybCkge1xuICBpZiAoIUh0bWxmaWxlUmVjZWl2ZXIuZW5hYmxlZCkge1xuICAgIHRocm93IG5ldyBFcnJvcignVHJhbnNwb3J0IGNyZWF0ZWQgd2hlbiBkaXNhYmxlZCcpO1xuICB9XG4gIEFqYXhCYXNlZFRyYW5zcG9ydC5jYWxsKHRoaXMsIHRyYW5zVXJsLCAnL2h0bWxmaWxlJywgSHRtbGZpbGVSZWNlaXZlciwgWEhSTG9jYWxPYmplY3QpO1xufVxuXG5pbmhlcml0cyhIdG1sRmlsZVRyYW5zcG9ydCwgQWpheEJhc2VkVHJhbnNwb3J0KTtcblxuSHRtbEZpbGVUcmFuc3BvcnQuZW5hYmxlZCA9IGZ1bmN0aW9uKGluZm8pIHtcbiAgcmV0dXJuIEh0bWxmaWxlUmVjZWl2ZXIuZW5hYmxlZCAmJiBpbmZvLnNhbWVPcmlnaW47XG59O1xuXG5IdG1sRmlsZVRyYW5zcG9ydC50cmFuc3BvcnROYW1lID0gJ2h0bWxmaWxlJztcbkh0bWxGaWxlVHJhbnNwb3J0LnJvdW5kVHJpcHMgPSAyO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEh0bWxGaWxlVHJhbnNwb3J0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyBGZXcgY29vbCB0cmFuc3BvcnRzIGRvIHdvcmsgb25seSBmb3Igc2FtZS1vcmlnaW4uIEluIG9yZGVyIHRvIG1ha2Vcbi8vIHRoZW0gd29yayBjcm9zcy1kb21haW4gd2Ugc2hhbGwgdXNlIGlmcmFtZSwgc2VydmVkIGZyb20gdGhlXG4vLyByZW1vdGUgZG9tYWluLiBOZXcgYnJvd3NlcnMgaGF2ZSBjYXBhYmlsaXRpZXMgdG8gY29tbXVuaWNhdGUgd2l0aFxuLy8gY3Jvc3MgZG9tYWluIGlmcmFtZSB1c2luZyBwb3N0TWVzc2FnZSgpLiBJbiBJRSBpdCB3YXMgaW1wbGVtZW50ZWRcbi8vIGZyb20gSUUgOCssIGJ1dCBvZiBjb3Vyc2UsIElFIGdvdCBzb21lIGRldGFpbHMgd3Jvbmc6XG4vLyAgICBodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tL2VuLXVzL2xpYnJhcnkvY2MxOTcwMTUodj1WUy44NSkuYXNweFxuLy8gICAgaHR0cDovL3N0ZXZlc291ZGVycy5jb20vbWlzYy90ZXN0LXBvc3RtZXNzYWdlLnBocFxuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgSlNPTjMgPSByZXF1aXJlKCdqc29uMycpXG4gICwgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gICwgdmVyc2lvbiA9IHJlcXVpcmUoJy4uL3ZlcnNpb24nKVxuICAsIHVybFV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXJsJylcbiAgLCBpZnJhbWVVdGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL2lmcmFtZScpXG4gICwgZXZlbnRVdGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL2V2ZW50JylcbiAgLCByYW5kb20gPSByZXF1aXJlKCcuLi91dGlscy9yYW5kb20nKVxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6dHJhbnNwb3J0OmlmcmFtZScpO1xufVxuXG5mdW5jdGlvbiBJZnJhbWVUcmFuc3BvcnQodHJhbnNwb3J0LCB0cmFuc1VybCwgYmFzZVVybCkge1xuICBpZiAoIUlmcmFtZVRyYW5zcG9ydC5lbmFibGVkKCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1RyYW5zcG9ydCBjcmVhdGVkIHdoZW4gZGlzYWJsZWQnKTtcbiAgfVxuICBFdmVudEVtaXR0ZXIuY2FsbCh0aGlzKTtcblxuICB2YXIgc2VsZiA9IHRoaXM7XG4gIHRoaXMub3JpZ2luID0gdXJsVXRpbHMuZ2V0T3JpZ2luKGJhc2VVcmwpO1xuICB0aGlzLmJhc2VVcmwgPSBiYXNlVXJsO1xuICB0aGlzLnRyYW5zVXJsID0gdHJhbnNVcmw7XG4gIHRoaXMudHJhbnNwb3J0ID0gdHJhbnNwb3J0O1xuICB0aGlzLndpbmRvd0lkID0gcmFuZG9tLnN0cmluZyg4KTtcblxuICB2YXIgaWZyYW1lVXJsID0gdXJsVXRpbHMuYWRkUGF0aChiYXNlVXJsLCAnL2lmcmFtZS5odG1sJykgKyAnIycgKyB0aGlzLndpbmRvd0lkO1xuICBkZWJ1Zyh0cmFuc3BvcnQsIHRyYW5zVXJsLCBpZnJhbWVVcmwpO1xuXG4gIHRoaXMuaWZyYW1lT2JqID0gaWZyYW1lVXRpbHMuY3JlYXRlSWZyYW1lKGlmcmFtZVVybCwgZnVuY3Rpb24ocikge1xuICAgIGRlYnVnKCdlcnIgY2FsbGJhY2snKTtcbiAgICBzZWxmLmVtaXQoJ2Nsb3NlJywgMTAwNiwgJ1VuYWJsZSB0byBsb2FkIGFuIGlmcmFtZSAoJyArIHIgKyAnKScpO1xuICAgIHNlbGYuY2xvc2UoKTtcbiAgfSk7XG5cbiAgdGhpcy5vbm1lc3NhZ2VDYWxsYmFjayA9IHRoaXMuX21lc3NhZ2UuYmluZCh0aGlzKTtcbiAgZXZlbnRVdGlscy5hdHRhY2hFdmVudCgnbWVzc2FnZScsIHRoaXMub25tZXNzYWdlQ2FsbGJhY2spO1xufVxuXG5pbmhlcml0cyhJZnJhbWVUcmFuc3BvcnQsIEV2ZW50RW1pdHRlcik7XG5cbklmcmFtZVRyYW5zcG9ydC5wcm90b3R5cGUuY2xvc2UgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ2Nsb3NlJyk7XG4gIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gIGlmICh0aGlzLmlmcmFtZU9iaikge1xuICAgIGV2ZW50VXRpbHMuZGV0YWNoRXZlbnQoJ21lc3NhZ2UnLCB0aGlzLm9ubWVzc2FnZUNhbGxiYWNrKTtcbiAgICB0cnkge1xuICAgICAgLy8gV2hlbiB0aGUgaWZyYW1lIGlzIG5vdCBsb2FkZWQsIElFIHJhaXNlcyBhbiBleGNlcHRpb25cbiAgICAgIC8vIG9uICdjb250ZW50V2luZG93Jy5cbiAgICAgIHRoaXMucG9zdE1lc3NhZ2UoJ2MnKTtcbiAgICB9IGNhdGNoICh4KSB7XG4gICAgICAvLyBpbnRlbnRpb25hbGx5IGVtcHR5XG4gICAgfVxuICAgIHRoaXMuaWZyYW1lT2JqLmNsZWFudXAoKTtcbiAgICB0aGlzLmlmcmFtZU9iaiA9IG51bGw7XG4gICAgdGhpcy5vbm1lc3NhZ2VDYWxsYmFjayA9IHRoaXMuaWZyYW1lT2JqID0gbnVsbDtcbiAgfVxufTtcblxuSWZyYW1lVHJhbnNwb3J0LnByb3RvdHlwZS5fbWVzc2FnZSA9IGZ1bmN0aW9uKGUpIHtcbiAgZGVidWcoJ21lc3NhZ2UnLCBlLmRhdGEpO1xuICBpZiAoIXVybFV0aWxzLmlzT3JpZ2luRXF1YWwoZS5vcmlnaW4sIHRoaXMub3JpZ2luKSkge1xuICAgIGRlYnVnKCdub3Qgc2FtZSBvcmlnaW4nLCBlLm9yaWdpbiwgdGhpcy5vcmlnaW4pO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHZhciBpZnJhbWVNZXNzYWdlO1xuICB0cnkge1xuICAgIGlmcmFtZU1lc3NhZ2UgPSBKU09OMy5wYXJzZShlLmRhdGEpO1xuICB9IGNhdGNoIChpZ25vcmVkKSB7XG4gICAgZGVidWcoJ2JhZCBqc29uJywgZS5kYXRhKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoaWZyYW1lTWVzc2FnZS53aW5kb3dJZCAhPT0gdGhpcy53aW5kb3dJZCkge1xuICAgIGRlYnVnKCdtaXNtYXRjaGVkIHdpbmRvdyBpZCcsIGlmcmFtZU1lc3NhZ2Uud2luZG93SWQsIHRoaXMud2luZG93SWQpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHN3aXRjaCAoaWZyYW1lTWVzc2FnZS50eXBlKSB7XG4gIGNhc2UgJ3MnOlxuICAgIHRoaXMuaWZyYW1lT2JqLmxvYWRlZCgpO1xuICAgIC8vIHdpbmRvdyBnbG9iYWwgZGVwZW5kZW5jeVxuICAgIHRoaXMucG9zdE1lc3NhZ2UoJ3MnLCBKU09OMy5zdHJpbmdpZnkoW1xuICAgICAgdmVyc2lvblxuICAgICwgdGhpcy50cmFuc3BvcnRcbiAgICAsIHRoaXMudHJhbnNVcmxcbiAgICAsIHRoaXMuYmFzZVVybFxuICAgIF0pKTtcbiAgICBicmVhaztcbiAgY2FzZSAndCc6XG4gICAgdGhpcy5lbWl0KCdtZXNzYWdlJywgaWZyYW1lTWVzc2FnZS5kYXRhKTtcbiAgICBicmVhaztcbiAgY2FzZSAnYyc6XG4gICAgdmFyIGNkYXRhO1xuICAgIHRyeSB7XG4gICAgICBjZGF0YSA9IEpTT04zLnBhcnNlKGlmcmFtZU1lc3NhZ2UuZGF0YSk7XG4gICAgfSBjYXRjaCAoaWdub3JlZCkge1xuICAgICAgZGVidWcoJ2JhZCBqc29uJywgaWZyYW1lTWVzc2FnZS5kYXRhKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5lbWl0KCdjbG9zZScsIGNkYXRhWzBdLCBjZGF0YVsxXSk7XG4gICAgdGhpcy5jbG9zZSgpO1xuICAgIGJyZWFrO1xuICB9XG59O1xuXG5JZnJhbWVUcmFuc3BvcnQucHJvdG90eXBlLnBvc3RNZXNzYWdlID0gZnVuY3Rpb24odHlwZSwgZGF0YSkge1xuICBkZWJ1ZygncG9zdE1lc3NhZ2UnLCB0eXBlLCBkYXRhKTtcbiAgdGhpcy5pZnJhbWVPYmoucG9zdChKU09OMy5zdHJpbmdpZnkoe1xuICAgIHdpbmRvd0lkOiB0aGlzLndpbmRvd0lkXG4gICwgdHlwZTogdHlwZVxuICAsIGRhdGE6IGRhdGEgfHwgJydcbiAgfSksIHRoaXMub3JpZ2luKTtcbn07XG5cbklmcmFtZVRyYW5zcG9ydC5wcm90b3R5cGUuc2VuZCA9IGZ1bmN0aW9uKG1lc3NhZ2UpIHtcbiAgZGVidWcoJ3NlbmQnLCBtZXNzYWdlKTtcbiAgdGhpcy5wb3N0TWVzc2FnZSgnbScsIG1lc3NhZ2UpO1xufTtcblxuSWZyYW1lVHJhbnNwb3J0LmVuYWJsZWQgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIGlmcmFtZVV0aWxzLmlmcmFtZUVuYWJsZWQ7XG59O1xuXG5JZnJhbWVUcmFuc3BvcnQudHJhbnNwb3J0TmFtZSA9ICdpZnJhbWUnO1xuSWZyYW1lVHJhbnNwb3J0LnJvdW5kVHJpcHMgPSAyO1xuXG5tb2R1bGUuZXhwb3J0cyA9IElmcmFtZVRyYW5zcG9ydDtcbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gVGhlIHNpbXBsZXN0IGFuZCBtb3N0IHJvYnVzdCB0cmFuc3BvcnQsIHVzaW5nIHRoZSB3ZWxsLWtub3cgY3Jvc3Ncbi8vIGRvbWFpbiBoYWNrIC0gSlNPTlAuIFRoaXMgdHJhbnNwb3J0IGlzIHF1aXRlIGluZWZmaWNpZW50IC0gb25lXG4vLyBtZXNzYWdlIGNvdWxkIHVzZSB1cCB0byBvbmUgaHR0cCByZXF1ZXN0LiBCdXQgYXQgbGVhc3QgaXQgd29ya3MgYWxtb3N0XG4vLyBldmVyeXdoZXJlLlxuLy8gS25vd24gbGltaXRhdGlvbnM6XG4vLyAgIG8geW91IHdpbGwgZ2V0IGEgc3Bpbm5pbmcgY3Vyc29yXG4vLyAgIG8gZm9yIEtvbnF1ZXJvciBhIGR1bWIgdGltZXIgaXMgbmVlZGVkIHRvIGRldGVjdCBlcnJvcnNcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIFNlbmRlclJlY2VpdmVyID0gcmVxdWlyZSgnLi9saWIvc2VuZGVyLXJlY2VpdmVyJylcbiAgLCBKc29ucFJlY2VpdmVyID0gcmVxdWlyZSgnLi9yZWNlaXZlci9qc29ucCcpXG4gICwganNvbnBTZW5kZXIgPSByZXF1aXJlKCcuL3NlbmRlci9qc29ucCcpXG4gIDtcblxuZnVuY3Rpb24gSnNvblBUcmFuc3BvcnQodHJhbnNVcmwpIHtcbiAgaWYgKCFKc29uUFRyYW5zcG9ydC5lbmFibGVkKCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1RyYW5zcG9ydCBjcmVhdGVkIHdoZW4gZGlzYWJsZWQnKTtcbiAgfVxuICBTZW5kZXJSZWNlaXZlci5jYWxsKHRoaXMsIHRyYW5zVXJsLCAnL2pzb25wJywganNvbnBTZW5kZXIsIEpzb25wUmVjZWl2ZXIpO1xufVxuXG5pbmhlcml0cyhKc29uUFRyYW5zcG9ydCwgU2VuZGVyUmVjZWl2ZXIpO1xuXG5Kc29uUFRyYW5zcG9ydC5lbmFibGVkID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiAhIWdsb2JhbC5kb2N1bWVudDtcbn07XG5cbkpzb25QVHJhbnNwb3J0LnRyYW5zcG9ydE5hbWUgPSAnanNvbnAtcG9sbGluZyc7XG5Kc29uUFRyYW5zcG9ydC5yb3VuZFRyaXBzID0gMTtcbkpzb25QVHJhbnNwb3J0Lm5lZWRCb2R5ID0gdHJ1ZTtcblxubW9kdWxlLmV4cG9ydHMgPSBKc29uUFRyYW5zcG9ydDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIHVybFV0aWxzID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvdXJsJylcbiAgLCBTZW5kZXJSZWNlaXZlciA9IHJlcXVpcmUoJy4vc2VuZGVyLXJlY2VpdmVyJylcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OmFqYXgtYmFzZWQnKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlQWpheFNlbmRlcihBamF4T2JqZWN0KSB7XG4gIHJldHVybiBmdW5jdGlvbih1cmwsIHBheWxvYWQsIGNhbGxiYWNrKSB7XG4gICAgZGVidWcoJ2NyZWF0ZSBhamF4IHNlbmRlcicsIHVybCwgcGF5bG9hZCk7XG4gICAgdmFyIG9wdCA9IHt9O1xuICAgIGlmICh0eXBlb2YgcGF5bG9hZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgIG9wdC5oZWFkZXJzID0geydDb250ZW50LXR5cGUnOiAndGV4dC9wbGFpbid9O1xuICAgIH1cbiAgICB2YXIgYWpheFVybCA9IHVybFV0aWxzLmFkZFBhdGgodXJsLCAnL3hocl9zZW5kJyk7XG4gICAgdmFyIHhvID0gbmV3IEFqYXhPYmplY3QoJ1BPU1QnLCBhamF4VXJsLCBwYXlsb2FkLCBvcHQpO1xuICAgIHhvLm9uY2UoJ2ZpbmlzaCcsIGZ1bmN0aW9uKHN0YXR1cykge1xuICAgICAgZGVidWcoJ2ZpbmlzaCcsIHN0YXR1cyk7XG4gICAgICB4byA9IG51bGw7XG5cbiAgICAgIGlmIChzdGF0dXMgIT09IDIwMCAmJiBzdGF0dXMgIT09IDIwNCkge1xuICAgICAgICByZXR1cm4gY2FsbGJhY2sobmV3IEVycm9yKCdodHRwIHN0YXR1cyAnICsgc3RhdHVzKSk7XG4gICAgICB9XG4gICAgICBjYWxsYmFjaygpO1xuICAgIH0pO1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIGRlYnVnKCdhYm9ydCcpO1xuICAgICAgeG8uY2xvc2UoKTtcbiAgICAgIHhvID0gbnVsbDtcblxuICAgICAgdmFyIGVyciA9IG5ldyBFcnJvcignQWJvcnRlZCcpO1xuICAgICAgZXJyLmNvZGUgPSAxMDAwO1xuICAgICAgY2FsbGJhY2soZXJyKTtcbiAgICB9O1xuICB9O1xufVxuXG5mdW5jdGlvbiBBamF4QmFzZWRUcmFuc3BvcnQodHJhbnNVcmwsIHVybFN1ZmZpeCwgUmVjZWl2ZXIsIEFqYXhPYmplY3QpIHtcbiAgU2VuZGVyUmVjZWl2ZXIuY2FsbCh0aGlzLCB0cmFuc1VybCwgdXJsU3VmZml4LCBjcmVhdGVBamF4U2VuZGVyKEFqYXhPYmplY3QpLCBSZWNlaXZlciwgQWpheE9iamVjdCk7XG59XG5cbmluaGVyaXRzKEFqYXhCYXNlZFRyYW5zcG9ydCwgU2VuZGVyUmVjZWl2ZXIpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEFqYXhCYXNlZFRyYW5zcG9ydDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlclxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6YnVmZmVyZWQtc2VuZGVyJyk7XG59XG5cbmZ1bmN0aW9uIEJ1ZmZlcmVkU2VuZGVyKHVybCwgc2VuZGVyKSB7XG4gIGRlYnVnKHVybCk7XG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuICB0aGlzLnNlbmRCdWZmZXIgPSBbXTtcbiAgdGhpcy5zZW5kZXIgPSBzZW5kZXI7XG4gIHRoaXMudXJsID0gdXJsO1xufVxuXG5pbmhlcml0cyhCdWZmZXJlZFNlbmRlciwgRXZlbnRFbWl0dGVyKTtcblxuQnVmZmVyZWRTZW5kZXIucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbihtZXNzYWdlKSB7XG4gIGRlYnVnKCdzZW5kJywgbWVzc2FnZSk7XG4gIHRoaXMuc2VuZEJ1ZmZlci5wdXNoKG1lc3NhZ2UpO1xuICBpZiAoIXRoaXMuc2VuZFN0b3ApIHtcbiAgICB0aGlzLnNlbmRTY2hlZHVsZSgpO1xuICB9XG59O1xuXG4vLyBGb3IgcG9sbGluZyB0cmFuc3BvcnRzIGluIGEgc2l0dWF0aW9uIHdoZW4gaW4gdGhlIG1lc3NhZ2UgY2FsbGJhY2ssXG4vLyBuZXcgbWVzc2FnZSBpcyBiZWluZyBzZW5kLiBJZiB0aGUgc2VuZGluZyBjb25uZWN0aW9uIHdhcyBzdGFydGVkXG4vLyBiZWZvcmUgcmVjZWl2aW5nIG9uZSwgaXQgaXMgcG9zc2libGUgdG8gc2F0dXJhdGUgdGhlIG5ldHdvcmsgYW5kXG4vLyB0aW1lb3V0IGR1ZSB0byB0aGUgbGFjayBvZiByZWNlaXZpbmcgc29ja2V0LiBUbyBhdm9pZCB0aGF0IHdlIGRlbGF5XG4vLyBzZW5kaW5nIG1lc3NhZ2VzIGJ5IHNvbWUgc21hbGwgdGltZSwgaW4gb3JkZXIgdG8gbGV0IHJlY2VpdmluZ1xuLy8gY29ubmVjdGlvbiBiZSBzdGFydGVkIGJlZm9yZWhhbmQuIFRoaXMgaXMgb25seSBhIGhhbGZtZWFzdXJlIGFuZFxuLy8gZG9lcyBub3QgZml4IHRoZSBiaWcgcHJvYmxlbSwgYnV0IGl0IGRvZXMgbWFrZSB0aGUgdGVzdHMgZ28gbW9yZVxuLy8gc3RhYmxlIG9uIHNsb3cgbmV0d29ya3MuXG5CdWZmZXJlZFNlbmRlci5wcm90b3R5cGUuc2VuZFNjaGVkdWxlV2FpdCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1Zygnc2VuZFNjaGVkdWxlV2FpdCcpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIHZhciB0cmVmO1xuICB0aGlzLnNlbmRTdG9wID0gZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ3NlbmRTdG9wJyk7XG4gICAgc2VsZi5zZW5kU3RvcCA9IG51bGw7XG4gICAgY2xlYXJUaW1lb3V0KHRyZWYpO1xuICB9O1xuICB0cmVmID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICBkZWJ1ZygndGltZW91dCcpO1xuICAgIHNlbGYuc2VuZFN0b3AgPSBudWxsO1xuICAgIHNlbGYuc2VuZFNjaGVkdWxlKCk7XG4gIH0sIDI1KTtcbn07XG5cbkJ1ZmZlcmVkU2VuZGVyLnByb3RvdHlwZS5zZW5kU2NoZWR1bGUgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ3NlbmRTY2hlZHVsZScsIHRoaXMuc2VuZEJ1ZmZlci5sZW5ndGgpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIGlmICh0aGlzLnNlbmRCdWZmZXIubGVuZ3RoID4gMCkge1xuICAgIHZhciBwYXlsb2FkID0gJ1snICsgdGhpcy5zZW5kQnVmZmVyLmpvaW4oJywnKSArICddJztcbiAgICB0aGlzLnNlbmRTdG9wID0gdGhpcy5zZW5kZXIodGhpcy51cmwsIHBheWxvYWQsIGZ1bmN0aW9uKGVycikge1xuICAgICAgc2VsZi5zZW5kU3RvcCA9IG51bGw7XG4gICAgICBpZiAoZXJyKSB7XG4gICAgICAgIGRlYnVnKCdlcnJvcicsIGVycik7XG4gICAgICAgIHNlbGYuZW1pdCgnY2xvc2UnLCBlcnIuY29kZSB8fCAxMDA2LCAnU2VuZGluZyBlcnJvcjogJyArIGVycik7XG4gICAgICAgIHNlbGYuX2NsZWFudXAoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHNlbGYuc2VuZFNjaGVkdWxlV2FpdCgpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHRoaXMuc2VuZEJ1ZmZlciA9IFtdO1xuICB9XG59O1xuXG5CdWZmZXJlZFNlbmRlci5wcm90b3R5cGUuX2NsZWFudXAgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ19jbGVhbnVwJyk7XG4gIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG59O1xuXG5CdWZmZXJlZFNlbmRlci5wcm90b3R5cGUuc3RvcCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1Zygnc3RvcCcpO1xuICB0aGlzLl9jbGVhbnVwKCk7XG4gIGlmICh0aGlzLnNlbmRTdG9wKSB7XG4gICAgdGhpcy5zZW5kU3RvcCgpO1xuICAgIHRoaXMuc2VuZFN0b3AgPSBudWxsO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEJ1ZmZlcmVkU2VuZGVyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgSWZyYW1lVHJhbnNwb3J0ID0gcmVxdWlyZSgnLi4vaWZyYW1lJylcbiAgLCBvYmplY3RVdGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzL29iamVjdCcpXG4gIDtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbih0cmFuc3BvcnQpIHtcblxuICBmdW5jdGlvbiBJZnJhbWVXcmFwVHJhbnNwb3J0KHRyYW5zVXJsLCBiYXNlVXJsKSB7XG4gICAgSWZyYW1lVHJhbnNwb3J0LmNhbGwodGhpcywgdHJhbnNwb3J0LnRyYW5zcG9ydE5hbWUsIHRyYW5zVXJsLCBiYXNlVXJsKTtcbiAgfVxuXG4gIGluaGVyaXRzKElmcmFtZVdyYXBUcmFuc3BvcnQsIElmcmFtZVRyYW5zcG9ydCk7XG5cbiAgSWZyYW1lV3JhcFRyYW5zcG9ydC5lbmFibGVkID0gZnVuY3Rpb24odXJsLCBpbmZvKSB7XG4gICAgaWYgKCFnbG9iYWwuZG9jdW1lbnQpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB2YXIgaWZyYW1lSW5mbyA9IG9iamVjdFV0aWxzLmV4dGVuZCh7fSwgaW5mbyk7XG4gICAgaWZyYW1lSW5mby5zYW1lT3JpZ2luID0gdHJ1ZTtcbiAgICByZXR1cm4gdHJhbnNwb3J0LmVuYWJsZWQoaWZyYW1lSW5mbykgJiYgSWZyYW1lVHJhbnNwb3J0LmVuYWJsZWQoKTtcbiAgfTtcblxuICBJZnJhbWVXcmFwVHJhbnNwb3J0LnRyYW5zcG9ydE5hbWUgPSAnaWZyYW1lLScgKyB0cmFuc3BvcnQudHJhbnNwb3J0TmFtZTtcbiAgSWZyYW1lV3JhcFRyYW5zcG9ydC5uZWVkQm9keSA9IHRydWU7XG4gIElmcmFtZVdyYXBUcmFuc3BvcnQucm91bmRUcmlwcyA9IElmcmFtZVRyYW5zcG9ydC5yb3VuZFRyaXBzICsgdHJhbnNwb3J0LnJvdW5kVHJpcHMgLSAxOyAvLyBodG1sLCBqYXZhc2NyaXB0ICgyKSArIHRyYW5zcG9ydCAtIG5vIENPUlMgKDEpXG5cbiAgSWZyYW1lV3JhcFRyYW5zcG9ydC5mYWNhZGVUcmFuc3BvcnQgPSB0cmFuc3BvcnQ7XG5cbiAgcmV0dXJuIElmcmFtZVdyYXBUcmFuc3BvcnQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDpwb2xsaW5nJyk7XG59XG5cbmZ1bmN0aW9uIFBvbGxpbmcoUmVjZWl2ZXIsIHJlY2VpdmVVcmwsIEFqYXhPYmplY3QpIHtcbiAgZGVidWcocmVjZWl2ZVVybCk7XG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuICB0aGlzLlJlY2VpdmVyID0gUmVjZWl2ZXI7XG4gIHRoaXMucmVjZWl2ZVVybCA9IHJlY2VpdmVVcmw7XG4gIHRoaXMuQWpheE9iamVjdCA9IEFqYXhPYmplY3Q7XG4gIHRoaXMuX3NjaGVkdWxlUmVjZWl2ZXIoKTtcbn1cblxuaW5oZXJpdHMoUG9sbGluZywgRXZlbnRFbWl0dGVyKTtcblxuUG9sbGluZy5wcm90b3R5cGUuX3NjaGVkdWxlUmVjZWl2ZXIgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ19zY2hlZHVsZVJlY2VpdmVyJyk7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgdmFyIHBvbGwgPSB0aGlzLnBvbGwgPSBuZXcgdGhpcy5SZWNlaXZlcih0aGlzLnJlY2VpdmVVcmwsIHRoaXMuQWpheE9iamVjdCk7XG5cbiAgcG9sbC5vbignbWVzc2FnZScsIGZ1bmN0aW9uKG1zZykge1xuICAgIGRlYnVnKCdtZXNzYWdlJywgbXNnKTtcbiAgICBzZWxmLmVtaXQoJ21lc3NhZ2UnLCBtc2cpO1xuICB9KTtcblxuICBwb2xsLm9uY2UoJ2Nsb3NlJywgZnVuY3Rpb24oY29kZSwgcmVhc29uKSB7XG4gICAgZGVidWcoJ2Nsb3NlJywgY29kZSwgcmVhc29uLCBzZWxmLnBvbGxJc0Nsb3NpbmcpO1xuICAgIHNlbGYucG9sbCA9IHBvbGwgPSBudWxsO1xuXG4gICAgaWYgKCFzZWxmLnBvbGxJc0Nsb3NpbmcpIHtcbiAgICAgIGlmIChyZWFzb24gPT09ICduZXR3b3JrJykge1xuICAgICAgICBzZWxmLl9zY2hlZHVsZVJlY2VpdmVyKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzZWxmLmVtaXQoJ2Nsb3NlJywgY29kZSB8fCAxMDA2LCByZWFzb24pO1xuICAgICAgICBzZWxmLnJlbW92ZUFsbExpc3RlbmVycygpO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG59O1xuXG5Qb2xsaW5nLnByb3RvdHlwZS5hYm9ydCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnYWJvcnQnKTtcbiAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgdGhpcy5wb2xsSXNDbG9zaW5nID0gdHJ1ZTtcbiAgaWYgKHRoaXMucG9sbCkge1xuICAgIHRoaXMucG9sbC5hYm9ydCgpO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFBvbGxpbmc7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCB1cmxVdGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzL3VybCcpXG4gICwgQnVmZmVyZWRTZW5kZXIgPSByZXF1aXJlKCcuL2J1ZmZlcmVkLXNlbmRlcicpXG4gICwgUG9sbGluZyA9IHJlcXVpcmUoJy4vcG9sbGluZycpXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDpzZW5kZXItcmVjZWl2ZXInKTtcbn1cblxuZnVuY3Rpb24gU2VuZGVyUmVjZWl2ZXIodHJhbnNVcmwsIHVybFN1ZmZpeCwgc2VuZGVyRnVuYywgUmVjZWl2ZXIsIEFqYXhPYmplY3QpIHtcbiAgdmFyIHBvbGxVcmwgPSB1cmxVdGlscy5hZGRQYXRoKHRyYW5zVXJsLCB1cmxTdWZmaXgpO1xuICBkZWJ1Zyhwb2xsVXJsKTtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICBCdWZmZXJlZFNlbmRlci5jYWxsKHRoaXMsIHRyYW5zVXJsLCBzZW5kZXJGdW5jKTtcblxuICB0aGlzLnBvbGwgPSBuZXcgUG9sbGluZyhSZWNlaXZlciwgcG9sbFVybCwgQWpheE9iamVjdCk7XG4gIHRoaXMucG9sbC5vbignbWVzc2FnZScsIGZ1bmN0aW9uKG1zZykge1xuICAgIGRlYnVnKCdwb2xsIG1lc3NhZ2UnLCBtc2cpO1xuICAgIHNlbGYuZW1pdCgnbWVzc2FnZScsIG1zZyk7XG4gIH0pO1xuICB0aGlzLnBvbGwub25jZSgnY2xvc2UnLCBmdW5jdGlvbihjb2RlLCByZWFzb24pIHtcbiAgICBkZWJ1ZygncG9sbCBjbG9zZScsIGNvZGUsIHJlYXNvbik7XG4gICAgc2VsZi5wb2xsID0gbnVsbDtcbiAgICBzZWxmLmVtaXQoJ2Nsb3NlJywgY29kZSwgcmVhc29uKTtcbiAgICBzZWxmLmNsb3NlKCk7XG4gIH0pO1xufVxuXG5pbmhlcml0cyhTZW5kZXJSZWNlaXZlciwgQnVmZmVyZWRTZW5kZXIpO1xuXG5TZW5kZXJSZWNlaXZlci5wcm90b3R5cGUuY2xvc2UgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ2Nsb3NlJyk7XG4gIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gIGlmICh0aGlzLnBvbGwpIHtcbiAgICB0aGlzLnBvbGwuYWJvcnQoKTtcbiAgICB0aGlzLnBvbGwgPSBudWxsO1xuICB9XG4gIHRoaXMuc3RvcCgpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTZW5kZXJSZWNlaXZlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlclxuICAsIEV2ZW50U291cmNlRHJpdmVyID0gcmVxdWlyZSgnZXZlbnRzb3VyY2UnKVxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6cmVjZWl2ZXI6ZXZlbnRzb3VyY2UnKTtcbn1cblxuZnVuY3Rpb24gRXZlbnRTb3VyY2VSZWNlaXZlcih1cmwpIHtcbiAgZGVidWcodXJsKTtcbiAgRXZlbnRFbWl0dGVyLmNhbGwodGhpcyk7XG5cbiAgdmFyIHNlbGYgPSB0aGlzO1xuICB2YXIgZXMgPSB0aGlzLmVzID0gbmV3IEV2ZW50U291cmNlRHJpdmVyKHVybCk7XG4gIGVzLm9ubWVzc2FnZSA9IGZ1bmN0aW9uKGUpIHtcbiAgICBkZWJ1ZygnbWVzc2FnZScsIGUuZGF0YSk7XG4gICAgc2VsZi5lbWl0KCdtZXNzYWdlJywgZGVjb2RlVVJJKGUuZGF0YSkpO1xuICB9O1xuICBlcy5vbmVycm9yID0gZnVuY3Rpb24oZSkge1xuICAgIGRlYnVnKCdlcnJvcicsIGVzLnJlYWR5U3RhdGUsIGUpO1xuICAgIC8vIEVTIG9uIHJlY29ubmVjdGlvbiBoYXMgcmVhZHlTdGF0ZSA9IDAgb3IgMS5cbiAgICAvLyBvbiBuZXR3b3JrIGVycm9yIGl0J3MgQ0xPU0VEID0gMlxuICAgIHZhciByZWFzb24gPSAoZXMucmVhZHlTdGF0ZSAhPT0gMiA/ICduZXR3b3JrJyA6ICdwZXJtYW5lbnQnKTtcbiAgICBzZWxmLl9jbGVhbnVwKCk7XG4gICAgc2VsZi5fY2xvc2UocmVhc29uKTtcbiAgfTtcbn1cblxuaW5oZXJpdHMoRXZlbnRTb3VyY2VSZWNlaXZlciwgRXZlbnRFbWl0dGVyKTtcblxuRXZlbnRTb3VyY2VSZWNlaXZlci5wcm90b3R5cGUuYWJvcnQgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ2Fib3J0Jyk7XG4gIHRoaXMuX2NsZWFudXAoKTtcbiAgdGhpcy5fY2xvc2UoJ3VzZXInKTtcbn07XG5cbkV2ZW50U291cmNlUmVjZWl2ZXIucHJvdG90eXBlLl9jbGVhbnVwID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdjbGVhbnVwJyk7XG4gIHZhciBlcyA9IHRoaXMuZXM7XG4gIGlmIChlcykge1xuICAgIGVzLm9ubWVzc2FnZSA9IGVzLm9uZXJyb3IgPSBudWxsO1xuICAgIGVzLmNsb3NlKCk7XG4gICAgdGhpcy5lcyA9IG51bGw7XG4gIH1cbn07XG5cbkV2ZW50U291cmNlUmVjZWl2ZXIucHJvdG90eXBlLl9jbG9zZSA9IGZ1bmN0aW9uKHJlYXNvbikge1xuICBkZWJ1ZygnY2xvc2UnLCByZWFzb24pO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIC8vIFNhZmFyaSBhbmQgY2hyb21lIDwgMTUgY3Jhc2ggaWYgd2UgY2xvc2Ugd2luZG93IGJlZm9yZVxuICAvLyB3YWl0aW5nIGZvciBFUyBjbGVhbnVwLiBTZWU6XG4gIC8vIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD04OTE1NVxuICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgIHNlbGYuZW1pdCgnY2xvc2UnLCBudWxsLCByZWFzb24pO1xuICAgIHNlbGYucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gIH0sIDIwMCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50U291cmNlUmVjZWl2ZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBpZnJhbWVVdGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzL2lmcmFtZScpXG4gICwgdXJsVXRpbHMgPSByZXF1aXJlKCcuLi8uLi91dGlscy91cmwnKVxuICAsIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlclxuICAsIHJhbmRvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzL3JhbmRvbScpXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDpyZWNlaXZlcjpodG1sZmlsZScpO1xufVxuXG5mdW5jdGlvbiBIdG1sZmlsZVJlY2VpdmVyKHVybCkge1xuICBkZWJ1Zyh1cmwpO1xuICBFdmVudEVtaXR0ZXIuY2FsbCh0aGlzKTtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICBpZnJhbWVVdGlscy5wb2xsdXRlR2xvYmFsTmFtZXNwYWNlKCk7XG5cbiAgdGhpcy5pZCA9ICdhJyArIHJhbmRvbS5zdHJpbmcoNik7XG4gIHVybCA9IHVybFV0aWxzLmFkZFF1ZXJ5KHVybCwgJ2M9JyArIGRlY29kZVVSSUNvbXBvbmVudChpZnJhbWVVdGlscy5XUHJlZml4ICsgJy4nICsgdGhpcy5pZCkpO1xuXG4gIGRlYnVnKCd1c2luZyBodG1sZmlsZScsIEh0bWxmaWxlUmVjZWl2ZXIuaHRtbGZpbGVFbmFibGVkKTtcbiAgdmFyIGNvbnN0cnVjdEZ1bmMgPSBIdG1sZmlsZVJlY2VpdmVyLmh0bWxmaWxlRW5hYmxlZCA/XG4gICAgICBpZnJhbWVVdGlscy5jcmVhdGVIdG1sZmlsZSA6IGlmcmFtZVV0aWxzLmNyZWF0ZUlmcmFtZTtcblxuICBnbG9iYWxbaWZyYW1lVXRpbHMuV1ByZWZpeF1bdGhpcy5pZF0gPSB7XG4gICAgc3RhcnQ6IGZ1bmN0aW9uKCkge1xuICAgICAgZGVidWcoJ3N0YXJ0Jyk7XG4gICAgICBzZWxmLmlmcmFtZU9iai5sb2FkZWQoKTtcbiAgICB9XG4gICwgbWVzc2FnZTogZnVuY3Rpb24oZGF0YSkge1xuICAgICAgZGVidWcoJ21lc3NhZ2UnLCBkYXRhKTtcbiAgICAgIHNlbGYuZW1pdCgnbWVzc2FnZScsIGRhdGEpO1xuICAgIH1cbiAgLCBzdG9wOiBmdW5jdGlvbigpIHtcbiAgICAgIGRlYnVnKCdzdG9wJyk7XG4gICAgICBzZWxmLl9jbGVhbnVwKCk7XG4gICAgICBzZWxmLl9jbG9zZSgnbmV0d29yaycpO1xuICAgIH1cbiAgfTtcbiAgdGhpcy5pZnJhbWVPYmogPSBjb25zdHJ1Y3RGdW5jKHVybCwgZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ2NhbGxiYWNrJyk7XG4gICAgc2VsZi5fY2xlYW51cCgpO1xuICAgIHNlbGYuX2Nsb3NlKCdwZXJtYW5lbnQnKTtcbiAgfSk7XG59XG5cbmluaGVyaXRzKEh0bWxmaWxlUmVjZWl2ZXIsIEV2ZW50RW1pdHRlcik7XG5cbkh0bWxmaWxlUmVjZWl2ZXIucHJvdG90eXBlLmFib3J0ID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdhYm9ydCcpO1xuICB0aGlzLl9jbGVhbnVwKCk7XG4gIHRoaXMuX2Nsb3NlKCd1c2VyJyk7XG59O1xuXG5IdG1sZmlsZVJlY2VpdmVyLnByb3RvdHlwZS5fY2xlYW51cCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnX2NsZWFudXAnKTtcbiAgaWYgKHRoaXMuaWZyYW1lT2JqKSB7XG4gICAgdGhpcy5pZnJhbWVPYmouY2xlYW51cCgpO1xuICAgIHRoaXMuaWZyYW1lT2JqID0gbnVsbDtcbiAgfVxuICBkZWxldGUgZ2xvYmFsW2lmcmFtZVV0aWxzLldQcmVmaXhdW3RoaXMuaWRdO1xufTtcblxuSHRtbGZpbGVSZWNlaXZlci5wcm90b3R5cGUuX2Nsb3NlID0gZnVuY3Rpb24ocmVhc29uKSB7XG4gIGRlYnVnKCdfY2xvc2UnLCByZWFzb24pO1xuICB0aGlzLmVtaXQoJ2Nsb3NlJywgbnVsbCwgcmVhc29uKTtcbiAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbn07XG5cbkh0bWxmaWxlUmVjZWl2ZXIuaHRtbGZpbGVFbmFibGVkID0gZmFsc2U7XG5cbi8vIG9iZnVzY2F0ZSB0byBhdm9pZCBmaXJld2FsbHNcbnZhciBheG8gPSBbJ0FjdGl2ZSddLmNvbmNhdCgnT2JqZWN0Jykuam9pbignWCcpO1xuaWYgKGF4byBpbiBnbG9iYWwpIHtcbiAgdHJ5IHtcbiAgICBIdG1sZmlsZVJlY2VpdmVyLmh0bWxmaWxlRW5hYmxlZCA9ICEhbmV3IGdsb2JhbFtheG9dKCdodG1sZmlsZScpO1xuICB9IGNhdGNoICh4KSB7XG4gICAgLy8gaW50ZW50aW9uYWxseSBlbXB0eVxuICB9XG59XG5cbkh0bWxmaWxlUmVjZWl2ZXIuZW5hYmxlZCA9IEh0bWxmaWxlUmVjZWl2ZXIuaHRtbGZpbGVFbmFibGVkIHx8IGlmcmFtZVV0aWxzLmlmcmFtZUVuYWJsZWQ7XG5cbm1vZHVsZS5leHBvcnRzID0gSHRtbGZpbGVSZWNlaXZlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvaWZyYW1lJylcbiAgLCByYW5kb20gPSByZXF1aXJlKCcuLi8uLi91dGlscy9yYW5kb20nKVxuICAsIGJyb3dzZXIgPSByZXF1aXJlKCcuLi8uLi91dGlscy9icm93c2VyJylcbiAgLCB1cmxVdGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzL3VybCcpXG4gICwgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDpyZWNlaXZlcjpqc29ucCcpO1xufVxuXG5mdW5jdGlvbiBKc29ucFJlY2VpdmVyKHVybCkge1xuICBkZWJ1Zyh1cmwpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuXG4gIHV0aWxzLnBvbGx1dGVHbG9iYWxOYW1lc3BhY2UoKTtcblxuICB0aGlzLmlkID0gJ2EnICsgcmFuZG9tLnN0cmluZyg2KTtcbiAgdmFyIHVybFdpdGhJZCA9IHVybFV0aWxzLmFkZFF1ZXJ5KHVybCwgJ2M9JyArIGVuY29kZVVSSUNvbXBvbmVudCh1dGlscy5XUHJlZml4ICsgJy4nICsgdGhpcy5pZCkpO1xuXG4gIGdsb2JhbFt1dGlscy5XUHJlZml4XVt0aGlzLmlkXSA9IHRoaXMuX2NhbGxiYWNrLmJpbmQodGhpcyk7XG4gIHRoaXMuX2NyZWF0ZVNjcmlwdCh1cmxXaXRoSWQpO1xuXG4gIC8vIEZhbGxiYWNrIG1vc3RseSBmb3IgS29ucXVlcm9yIC0gc3R1cGlkIHRpbWVyLCAzNSBzZWNvbmRzIHNoYWxsIGJlIHBsZW50eS5cbiAgdGhpcy50aW1lb3V0SWQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgIGRlYnVnKCd0aW1lb3V0Jyk7XG4gICAgc2VsZi5fYWJvcnQobmV3IEVycm9yKCdKU09OUCBzY3JpcHQgbG9hZGVkIGFibm9ybWFsbHkgKHRpbWVvdXQpJykpO1xuICB9LCBKc29ucFJlY2VpdmVyLnRpbWVvdXQpO1xufVxuXG5pbmhlcml0cyhKc29ucFJlY2VpdmVyLCBFdmVudEVtaXR0ZXIpO1xuXG5Kc29ucFJlY2VpdmVyLnByb3RvdHlwZS5hYm9ydCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnYWJvcnQnKTtcbiAgaWYgKGdsb2JhbFt1dGlscy5XUHJlZml4XVt0aGlzLmlkXSkge1xuICAgIHZhciBlcnIgPSBuZXcgRXJyb3IoJ0pTT05QIHVzZXIgYWJvcnRlZCByZWFkJyk7XG4gICAgZXJyLmNvZGUgPSAxMDAwO1xuICAgIHRoaXMuX2Fib3J0KGVycik7XG4gIH1cbn07XG5cbkpzb25wUmVjZWl2ZXIudGltZW91dCA9IDM1MDAwO1xuSnNvbnBSZWNlaXZlci5zY3JpcHRFcnJvclRpbWVvdXQgPSAxMDAwO1xuXG5Kc29ucFJlY2VpdmVyLnByb3RvdHlwZS5fY2FsbGJhY2sgPSBmdW5jdGlvbihkYXRhKSB7XG4gIGRlYnVnKCdfY2FsbGJhY2snLCBkYXRhKTtcbiAgdGhpcy5fY2xlYW51cCgpO1xuXG4gIGlmICh0aGlzLmFib3J0aW5nKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKGRhdGEpIHtcbiAgICBkZWJ1ZygnbWVzc2FnZScsIGRhdGEpO1xuICAgIHRoaXMuZW1pdCgnbWVzc2FnZScsIGRhdGEpO1xuICB9XG4gIHRoaXMuZW1pdCgnY2xvc2UnLCBudWxsLCAnbmV0d29yaycpO1xuICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygpO1xufTtcblxuSnNvbnBSZWNlaXZlci5wcm90b3R5cGUuX2Fib3J0ID0gZnVuY3Rpb24oZXJyKSB7XG4gIGRlYnVnKCdfYWJvcnQnLCBlcnIpO1xuICB0aGlzLl9jbGVhbnVwKCk7XG4gIHRoaXMuYWJvcnRpbmcgPSB0cnVlO1xuICB0aGlzLmVtaXQoJ2Nsb3NlJywgZXJyLmNvZGUsIGVyci5tZXNzYWdlKTtcbiAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbn07XG5cbkpzb25wUmVjZWl2ZXIucHJvdG90eXBlLl9jbGVhbnVwID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdfY2xlYW51cCcpO1xuICBjbGVhclRpbWVvdXQodGhpcy50aW1lb3V0SWQpO1xuICBpZiAodGhpcy5zY3JpcHQyKSB7XG4gICAgdGhpcy5zY3JpcHQyLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodGhpcy5zY3JpcHQyKTtcbiAgICB0aGlzLnNjcmlwdDIgPSBudWxsO1xuICB9XG4gIGlmICh0aGlzLnNjcmlwdCkge1xuICAgIHZhciBzY3JpcHQgPSB0aGlzLnNjcmlwdDtcbiAgICAvLyBVbmZvcnR1bmF0ZWx5LCB5b3UgY2FuJ3QgcmVhbGx5IGFib3J0IHNjcmlwdCBsb2FkaW5nIG9mXG4gICAgLy8gdGhlIHNjcmlwdC5cbiAgICBzY3JpcHQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChzY3JpcHQpO1xuICAgIHNjcmlwdC5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBzY3JpcHQub25lcnJvciA9XG4gICAgICAgIHNjcmlwdC5vbmxvYWQgPSBzY3JpcHQub25jbGljayA9IG51bGw7XG4gICAgdGhpcy5zY3JpcHQgPSBudWxsO1xuICB9XG4gIGRlbGV0ZSBnbG9iYWxbdXRpbHMuV1ByZWZpeF1bdGhpcy5pZF07XG59O1xuXG5Kc29ucFJlY2VpdmVyLnByb3RvdHlwZS5fc2NyaXB0RXJyb3IgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ19zY3JpcHRFcnJvcicpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIGlmICh0aGlzLmVycm9yVGltZXIpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICB0aGlzLmVycm9yVGltZXIgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgIGlmICghc2VsZi5sb2FkZWRPa2F5KSB7XG4gICAgICBzZWxmLl9hYm9ydChuZXcgRXJyb3IoJ0pTT05QIHNjcmlwdCBsb2FkZWQgYWJub3JtYWxseSAob25lcnJvciknKSk7XG4gICAgfVxuICB9LCBKc29ucFJlY2VpdmVyLnNjcmlwdEVycm9yVGltZW91dCk7XG59O1xuXG5Kc29ucFJlY2VpdmVyLnByb3RvdHlwZS5fY3JlYXRlU2NyaXB0ID0gZnVuY3Rpb24odXJsKSB7XG4gIGRlYnVnKCdfY3JlYXRlU2NyaXB0JywgdXJsKTtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICB2YXIgc2NyaXB0ID0gdGhpcy5zY3JpcHQgPSBnbG9iYWwuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7XG4gIHZhciBzY3JpcHQyOyAgLy8gT3BlcmEgc3luY2hyb25vdXMgbG9hZCB0cmljay5cblxuICBzY3JpcHQuaWQgPSAnYScgKyByYW5kb20uc3RyaW5nKDgpO1xuICBzY3JpcHQuc3JjID0gdXJsO1xuICBzY3JpcHQudHlwZSA9ICd0ZXh0L2phdmFzY3JpcHQnO1xuICBzY3JpcHQuY2hhcnNldCA9ICdVVEYtOCc7XG4gIHNjcmlwdC5vbmVycm9yID0gdGhpcy5fc2NyaXB0RXJyb3IuYmluZCh0aGlzKTtcbiAgc2NyaXB0Lm9ubG9hZCA9IGZ1bmN0aW9uKCkge1xuICAgIGRlYnVnKCdvbmxvYWQnKTtcbiAgICBzZWxmLl9hYm9ydChuZXcgRXJyb3IoJ0pTT05QIHNjcmlwdCBsb2FkZWQgYWJub3JtYWxseSAob25sb2FkKScpKTtcbiAgfTtcblxuICAvLyBJRTkgZmlyZXMgJ2Vycm9yJyBldmVudCBhZnRlciBvbnJlYWR5c3RhdGVjaGFuZ2Ugb3IgYmVmb3JlLCBpbiByYW5kb20gb3JkZXIuXG4gIC8vIFVzZSBsb2FkZWRPa2F5IHRvIGRldGVybWluZSBpZiBhY3R1YWxseSBlcnJvcmVkXG4gIHNjcmlwdC5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICBkZWJ1Zygnb25yZWFkeXN0YXRlY2hhbmdlJywgc2NyaXB0LnJlYWR5U3RhdGUpO1xuICAgIGlmICgvbG9hZGVkfGNsb3NlZC8udGVzdChzY3JpcHQucmVhZHlTdGF0ZSkpIHtcbiAgICAgIGlmIChzY3JpcHQgJiYgc2NyaXB0Lmh0bWxGb3IgJiYgc2NyaXB0Lm9uY2xpY2spIHtcbiAgICAgICAgc2VsZi5sb2FkZWRPa2F5ID0gdHJ1ZTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAvLyBJbiBJRSwgYWN0dWFsbHkgZXhlY3V0ZSB0aGUgc2NyaXB0LlxuICAgICAgICAgIHNjcmlwdC5vbmNsaWNrKCk7XG4gICAgICAgIH0gY2F0Y2ggKHgpIHtcbiAgICAgICAgICAvLyBpbnRlbnRpb25hbGx5IGVtcHR5XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmIChzY3JpcHQpIHtcbiAgICAgICAgc2VsZi5fYWJvcnQobmV3IEVycm9yKCdKU09OUCBzY3JpcHQgbG9hZGVkIGFibm9ybWFsbHkgKG9ucmVhZHlzdGF0ZWNoYW5nZSknKSk7XG4gICAgICB9XG4gICAgfVxuICB9O1xuICAvLyBJRTogZXZlbnQvaHRtbEZvci9vbmNsaWNrIHRyaWNrLlxuICAvLyBPbmUgY2FuJ3QgcmVseSBvbiBwcm9wZXIgb3JkZXIgZm9yIG9ucmVhZHlzdGF0ZWNoYW5nZS4gSW4gb3JkZXIgdG9cbiAgLy8gbWFrZSBzdXJlLCBzZXQgYSAnaHRtbEZvcicgYW5kICdldmVudCcgcHJvcGVydGllcywgc28gdGhhdFxuICAvLyBzY3JpcHQgY29kZSB3aWxsIGJlIGluc3RhbGxlZCBhcyAnb25jbGljaycgaGFuZGxlciBmb3IgdGhlXG4gIC8vIHNjcmlwdCBvYmplY3QuIExhdGVyLCBvbnJlYWR5c3RhdGVjaGFuZ2UsIG1hbnVhbGx5IGV4ZWN1dGUgdGhpc1xuICAvLyBjb2RlLiBGRiBhbmQgQ2hyb21lIGRvZXNuJ3Qgd29yayB3aXRoICdldmVudCcgYW5kICdodG1sRm9yJ1xuICAvLyBzZXQuIEZvciByZWZlcmVuY2Ugc2VlOlxuICAvLyAgIGh0dHA6Ly9qYXVib3VyZy5uZXQvMjAxMC8wNy9sb2FkaW5nLXNjcmlwdC1hcy1vbmNsaWNrLWhhbmRsZXItb2YuaHRtbFxuICAvLyBBbHNvLCByZWFkIG9uIHRoYXQgYWJvdXQgc2NyaXB0IG9yZGVyaW5nOlxuICAvLyAgIGh0dHA6Ly93aWtpLndoYXR3Zy5vcmcvd2lraS9EeW5hbWljX1NjcmlwdF9FeGVjdXRpb25fT3JkZXJcbiAgaWYgKHR5cGVvZiBzY3JpcHQuYXN5bmMgPT09ICd1bmRlZmluZWQnICYmIGdsb2JhbC5kb2N1bWVudC5hdHRhY2hFdmVudCkge1xuICAgIC8vIEFjY29yZGluZyB0byBtb3ppbGxhIGRvY3MsIGluIHJlY2VudCBicm93c2VycyBzY3JpcHQuYXN5bmMgZGVmYXVsdHNcbiAgICAvLyB0byAndHJ1ZScsIHNvIHdlIG1heSB1c2UgaXQgdG8gZGV0ZWN0IGEgZ29vZCBicm93c2VyOlxuICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuL0hUTUwvRWxlbWVudC9zY3JpcHRcbiAgICBpZiAoIWJyb3dzZXIuaXNPcGVyYSgpKSB7XG4gICAgICAvLyBOYWl2ZWx5IGFzc3VtZSB3ZSdyZSBpbiBJRVxuICAgICAgdHJ5IHtcbiAgICAgICAgc2NyaXB0Lmh0bWxGb3IgPSBzY3JpcHQuaWQ7XG4gICAgICAgIHNjcmlwdC5ldmVudCA9ICdvbmNsaWNrJztcbiAgICAgIH0gY2F0Y2ggKHgpIHtcbiAgICAgICAgLy8gaW50ZW50aW9uYWxseSBlbXB0eVxuICAgICAgfVxuICAgICAgc2NyaXB0LmFzeW5jID0gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gT3BlcmEsIHNlY29uZCBzeW5jIHNjcmlwdCBoYWNrXG4gICAgICBzY3JpcHQyID0gdGhpcy5zY3JpcHQyID0gZ2xvYmFsLmRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpO1xuICAgICAgc2NyaXB0Mi50ZXh0ID0gXCJ0cnl7dmFyIGEgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnXCIgKyBzY3JpcHQuaWQgKyBcIicpOyBpZihhKWEub25lcnJvcigpO31jYXRjaCh4KXt9O1wiO1xuICAgICAgc2NyaXB0LmFzeW5jID0gc2NyaXB0Mi5hc3luYyA9IGZhbHNlO1xuICAgIH1cbiAgfVxuICBpZiAodHlwZW9mIHNjcmlwdC5hc3luYyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBzY3JpcHQuYXN5bmMgPSB0cnVlO1xuICB9XG5cbiAgdmFyIGhlYWQgPSBnbG9iYWwuZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2hlYWQnKVswXTtcbiAgaGVhZC5pbnNlcnRCZWZvcmUoc2NyaXB0LCBoZWFkLmZpcnN0Q2hpbGQpO1xuICBpZiAoc2NyaXB0Mikge1xuICAgIGhlYWQuaW5zZXJ0QmVmb3JlKHNjcmlwdDIsIGhlYWQuZmlyc3RDaGlsZCk7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSnNvbnBSZWNlaXZlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlclxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6cmVjZWl2ZXI6eGhyJyk7XG59XG5cbmZ1bmN0aW9uIFhoclJlY2VpdmVyKHVybCwgQWpheE9iamVjdCkge1xuICBkZWJ1Zyh1cmwpO1xuICBFdmVudEVtaXR0ZXIuY2FsbCh0aGlzKTtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gIHRoaXMuYnVmZmVyUG9zaXRpb24gPSAwO1xuXG4gIHRoaXMueG8gPSBuZXcgQWpheE9iamVjdCgnUE9TVCcsIHVybCwgbnVsbCk7XG4gIHRoaXMueG8ub24oJ2NodW5rJywgdGhpcy5fY2h1bmtIYW5kbGVyLmJpbmQodGhpcykpO1xuICB0aGlzLnhvLm9uY2UoJ2ZpbmlzaCcsIGZ1bmN0aW9uKHN0YXR1cywgdGV4dCkge1xuICAgIGRlYnVnKCdmaW5pc2gnLCBzdGF0dXMsIHRleHQpO1xuICAgIHNlbGYuX2NodW5rSGFuZGxlcihzdGF0dXMsIHRleHQpO1xuICAgIHNlbGYueG8gPSBudWxsO1xuICAgIHZhciByZWFzb24gPSBzdGF0dXMgPT09IDIwMCA/ICduZXR3b3JrJyA6ICdwZXJtYW5lbnQnO1xuICAgIGRlYnVnKCdjbG9zZScsIHJlYXNvbik7XG4gICAgc2VsZi5lbWl0KCdjbG9zZScsIG51bGwsIHJlYXNvbik7XG4gICAgc2VsZi5fY2xlYW51cCgpO1xuICB9KTtcbn1cblxuaW5oZXJpdHMoWGhyUmVjZWl2ZXIsIEV2ZW50RW1pdHRlcik7XG5cblhoclJlY2VpdmVyLnByb3RvdHlwZS5fY2h1bmtIYW5kbGVyID0gZnVuY3Rpb24oc3RhdHVzLCB0ZXh0KSB7XG4gIGRlYnVnKCdfY2h1bmtIYW5kbGVyJywgc3RhdHVzKTtcbiAgaWYgKHN0YXR1cyAhPT0gMjAwIHx8ICF0ZXh0KSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgZm9yICh2YXIgaWR4ID0gLTE7IDsgdGhpcy5idWZmZXJQb3NpdGlvbiArPSBpZHggKyAxKSB7XG4gICAgdmFyIGJ1ZiA9IHRleHQuc2xpY2UodGhpcy5idWZmZXJQb3NpdGlvbik7XG4gICAgaWR4ID0gYnVmLmluZGV4T2YoJ1xcbicpO1xuICAgIGlmIChpZHggPT09IC0xKSB7XG4gICAgICBicmVhaztcbiAgICB9XG4gICAgdmFyIG1zZyA9IGJ1Zi5zbGljZSgwLCBpZHgpO1xuICAgIGlmIChtc2cpIHtcbiAgICAgIGRlYnVnKCdtZXNzYWdlJywgbXNnKTtcbiAgICAgIHRoaXMuZW1pdCgnbWVzc2FnZScsIG1zZyk7XG4gICAgfVxuICB9XG59O1xuXG5YaHJSZWNlaXZlci5wcm90b3R5cGUuX2NsZWFudXAgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ19jbGVhbnVwJyk7XG4gIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG59O1xuXG5YaHJSZWNlaXZlci5wcm90b3R5cGUuYWJvcnQgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ2Fib3J0Jyk7XG4gIGlmICh0aGlzLnhvKSB7XG4gICAgdGhpcy54by5jbG9zZSgpO1xuICAgIGRlYnVnKCdjbG9zZScpO1xuICAgIHRoaXMuZW1pdCgnY2xvc2UnLCBudWxsLCAndXNlcicpO1xuICAgIHRoaXMueG8gPSBudWxsO1xuICB9XG4gIHRoaXMuX2NsZWFudXAoKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gWGhyUmVjZWl2ZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciByYW5kb20gPSByZXF1aXJlKCcuLi8uLi91dGlscy9yYW5kb20nKVxuICAsIHVybFV0aWxzID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvdXJsJylcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OnNlbmRlcjpqc29ucCcpO1xufVxuXG52YXIgZm9ybSwgYXJlYTtcblxuZnVuY3Rpb24gY3JlYXRlSWZyYW1lKGlkKSB7XG4gIGRlYnVnKCdjcmVhdGVJZnJhbWUnLCBpZCk7XG4gIHRyeSB7XG4gICAgLy8gaWU2IGR5bmFtaWMgaWZyYW1lcyB3aXRoIHRhcmdldD1cIlwiIHN1cHBvcnQgKHRoYW5rcyBDaHJpcyBMYW1iYWNoZXIpXG4gICAgcmV0dXJuIGdsb2JhbC5kb2N1bWVudC5jcmVhdGVFbGVtZW50KCc8aWZyYW1lIG5hbWU9XCInICsgaWQgKyAnXCI+Jyk7XG4gIH0gY2F0Y2ggKHgpIHtcbiAgICB2YXIgaWZyYW1lID0gZ2xvYmFsLmRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lmcmFtZScpO1xuICAgIGlmcmFtZS5uYW1lID0gaWQ7XG4gICAgcmV0dXJuIGlmcmFtZTtcbiAgfVxufVxuXG5mdW5jdGlvbiBjcmVhdGVGb3JtKCkge1xuICBkZWJ1ZygnY3JlYXRlRm9ybScpO1xuICBmb3JtID0gZ2xvYmFsLmRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2Zvcm0nKTtcbiAgZm9ybS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICBmb3JtLnN0eWxlLnBvc2l0aW9uID0gJ2Fic29sdXRlJztcbiAgZm9ybS5tZXRob2QgPSAnUE9TVCc7XG4gIGZvcm0uZW5jdHlwZSA9ICdhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQnO1xuICBmb3JtLmFjY2VwdENoYXJzZXQgPSAnVVRGLTgnO1xuXG4gIGFyZWEgPSBnbG9iYWwuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndGV4dGFyZWEnKTtcbiAgYXJlYS5uYW1lID0gJ2QnO1xuICBmb3JtLmFwcGVuZENoaWxkKGFyZWEpO1xuXG4gIGdsb2JhbC5kb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGZvcm0pO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKHVybCwgcGF5bG9hZCwgY2FsbGJhY2spIHtcbiAgZGVidWcodXJsLCBwYXlsb2FkKTtcbiAgaWYgKCFmb3JtKSB7XG4gICAgY3JlYXRlRm9ybSgpO1xuICB9XG4gIHZhciBpZCA9ICdhJyArIHJhbmRvbS5zdHJpbmcoOCk7XG4gIGZvcm0udGFyZ2V0ID0gaWQ7XG4gIGZvcm0uYWN0aW9uID0gdXJsVXRpbHMuYWRkUXVlcnkodXJsVXRpbHMuYWRkUGF0aCh1cmwsICcvanNvbnBfc2VuZCcpLCAnaT0nICsgaWQpO1xuXG4gIHZhciBpZnJhbWUgPSBjcmVhdGVJZnJhbWUoaWQpO1xuICBpZnJhbWUuaWQgPSBpZDtcbiAgaWZyYW1lLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gIGZvcm0uYXBwZW5kQ2hpbGQoaWZyYW1lKTtcblxuICB0cnkge1xuICAgIGFyZWEudmFsdWUgPSBwYXlsb2FkO1xuICB9IGNhdGNoIChlKSB7XG4gICAgLy8gc2VyaW91c2x5IGJyb2tlbiBicm93c2VycyBnZXQgaGVyZVxuICB9XG4gIGZvcm0uc3VibWl0KCk7XG5cbiAgdmFyIGNvbXBsZXRlZCA9IGZ1bmN0aW9uKGVycikge1xuICAgIGRlYnVnKCdjb21wbGV0ZWQnLCBpZCwgZXJyKTtcbiAgICBpZiAoIWlmcmFtZS5vbmVycm9yKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmcmFtZS5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBpZnJhbWUub25lcnJvciA9IGlmcmFtZS5vbmxvYWQgPSBudWxsO1xuICAgIC8vIE9wZXJhIG1pbmkgZG9lc24ndCBsaWtlIGlmIHdlIEdDIGlmcmFtZVxuICAgIC8vIGltbWVkaWF0ZWx5LCB0aHVzIHRoaXMgdGltZW91dC5cbiAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgZGVidWcoJ2NsZWFuaW5nIHVwJywgaWQpO1xuICAgICAgaWZyYW1lLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoaWZyYW1lKTtcbiAgICAgIGlmcmFtZSA9IG51bGw7XG4gICAgfSwgNTAwKTtcbiAgICBhcmVhLnZhbHVlID0gJyc7XG4gICAgLy8gSXQgaXMgbm90IHBvc3NpYmxlIHRvIGRldGVjdCBpZiB0aGUgaWZyYW1lIHN1Y2NlZWRlZCBvclxuICAgIC8vIGZhaWxlZCB0byBzdWJtaXQgb3VyIGZvcm0uXG4gICAgY2FsbGJhY2soZXJyKTtcbiAgfTtcbiAgaWZyYW1lLm9uZXJyb3IgPSBmdW5jdGlvbigpIHtcbiAgICBkZWJ1Zygnb25lcnJvcicsIGlkKTtcbiAgICBjb21wbGV0ZWQoKTtcbiAgfTtcbiAgaWZyYW1lLm9ubG9hZCA9IGZ1bmN0aW9uKCkge1xuICAgIGRlYnVnKCdvbmxvYWQnLCBpZCk7XG4gICAgY29tcGxldGVkKCk7XG4gIH07XG4gIGlmcmFtZS5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbihlKSB7XG4gICAgZGVidWcoJ29ucmVhZHlzdGF0ZWNoYW5nZScsIGlkLCBpZnJhbWUucmVhZHlTdGF0ZSwgZSk7XG4gICAgaWYgKGlmcmFtZS5yZWFkeVN0YXRlID09PSAnY29tcGxldGUnKSB7XG4gICAgICBjb21wbGV0ZWQoKTtcbiAgICB9XG4gIH07XG4gIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICBkZWJ1ZygnYWJvcnRlZCcsIGlkKTtcbiAgICBjb21wbGV0ZWQobmV3IEVycm9yKCdBYm9ydGVkJykpO1xuICB9O1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlclxuICAsIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIGV2ZW50VXRpbHMgPSByZXF1aXJlKCcuLi8uLi91dGlscy9ldmVudCcpXG4gICwgYnJvd3NlciA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzL2Jyb3dzZXInKVxuICAsIHVybFV0aWxzID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvdXJsJylcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OnNlbmRlcjp4ZHInKTtcbn1cblxuLy8gUmVmZXJlbmNlczpcbi8vICAgaHR0cDovL2FqYXhpYW4uY29tL2FyY2hpdmVzLzEwMC1saW5lLWFqYXgtd3JhcHBlclxuLy8gICBodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tL2VuLXVzL2xpYnJhcnkvY2MyODgwNjAodj1WUy44NSkuYXNweFxuXG5mdW5jdGlvbiBYRFJPYmplY3QobWV0aG9kLCB1cmwsIHBheWxvYWQpIHtcbiAgZGVidWcobWV0aG9kLCB1cmwpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuXG4gIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgc2VsZi5fc3RhcnQobWV0aG9kLCB1cmwsIHBheWxvYWQpO1xuICB9LCAwKTtcbn1cblxuaW5oZXJpdHMoWERST2JqZWN0LCBFdmVudEVtaXR0ZXIpO1xuXG5YRFJPYmplY3QucHJvdG90eXBlLl9zdGFydCA9IGZ1bmN0aW9uKG1ldGhvZCwgdXJsLCBwYXlsb2FkKSB7XG4gIGRlYnVnKCdfc3RhcnQnKTtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICB2YXIgeGRyID0gbmV3IGdsb2JhbC5YRG9tYWluUmVxdWVzdCgpO1xuICAvLyBJRSBjYWNoZXMgZXZlbiBQT1NUc1xuICB1cmwgPSB1cmxVdGlscy5hZGRRdWVyeSh1cmwsICd0PScgKyAoK25ldyBEYXRlKCkpKTtcblxuICB4ZHIub25lcnJvciA9IGZ1bmN0aW9uKCkge1xuICAgIGRlYnVnKCdvbmVycm9yJyk7XG4gICAgc2VsZi5fZXJyb3IoKTtcbiAgfTtcbiAgeGRyLm9udGltZW91dCA9IGZ1bmN0aW9uKCkge1xuICAgIGRlYnVnKCdvbnRpbWVvdXQnKTtcbiAgICBzZWxmLl9lcnJvcigpO1xuICB9O1xuICB4ZHIub25wcm9ncmVzcyA9IGZ1bmN0aW9uKCkge1xuICAgIGRlYnVnKCdwcm9ncmVzcycsIHhkci5yZXNwb25zZVRleHQpO1xuICAgIHNlbGYuZW1pdCgnY2h1bmsnLCAyMDAsIHhkci5yZXNwb25zZVRleHQpO1xuICB9O1xuICB4ZHIub25sb2FkID0gZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ2xvYWQnKTtcbiAgICBzZWxmLmVtaXQoJ2ZpbmlzaCcsIDIwMCwgeGRyLnJlc3BvbnNlVGV4dCk7XG4gICAgc2VsZi5fY2xlYW51cChmYWxzZSk7XG4gIH07XG4gIHRoaXMueGRyID0geGRyO1xuICB0aGlzLnVubG9hZFJlZiA9IGV2ZW50VXRpbHMudW5sb2FkQWRkKGZ1bmN0aW9uKCkge1xuICAgIHNlbGYuX2NsZWFudXAodHJ1ZSk7XG4gIH0pO1xuICB0cnkge1xuICAgIC8vIEZhaWxzIHdpdGggQWNjZXNzRGVuaWVkIGlmIHBvcnQgbnVtYmVyIGlzIGJvZ3VzXG4gICAgdGhpcy54ZHIub3BlbihtZXRob2QsIHVybCk7XG4gICAgaWYgKHRoaXMudGltZW91dCkge1xuICAgICAgdGhpcy54ZHIudGltZW91dCA9IHRoaXMudGltZW91dDtcbiAgICB9XG4gICAgdGhpcy54ZHIuc2VuZChwYXlsb2FkKTtcbiAgfSBjYXRjaCAoeCkge1xuICAgIHRoaXMuX2Vycm9yKCk7XG4gIH1cbn07XG5cblhEUk9iamVjdC5wcm90b3R5cGUuX2Vycm9yID0gZnVuY3Rpb24oKSB7XG4gIHRoaXMuZW1pdCgnZmluaXNoJywgMCwgJycpO1xuICB0aGlzLl9jbGVhbnVwKGZhbHNlKTtcbn07XG5cblhEUk9iamVjdC5wcm90b3R5cGUuX2NsZWFudXAgPSBmdW5jdGlvbihhYm9ydCkge1xuICBkZWJ1ZygnY2xlYW51cCcsIGFib3J0KTtcbiAgaWYgKCF0aGlzLnhkcikge1xuICAgIHJldHVybjtcbiAgfVxuICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygpO1xuICBldmVudFV0aWxzLnVubG9hZERlbCh0aGlzLnVubG9hZFJlZik7XG5cbiAgdGhpcy54ZHIub250aW1lb3V0ID0gdGhpcy54ZHIub25lcnJvciA9IHRoaXMueGRyLm9ucHJvZ3Jlc3MgPSB0aGlzLnhkci5vbmxvYWQgPSBudWxsO1xuICBpZiAoYWJvcnQpIHtcbiAgICB0cnkge1xuICAgICAgdGhpcy54ZHIuYWJvcnQoKTtcbiAgICB9IGNhdGNoICh4KSB7XG4gICAgICAvLyBpbnRlbnRpb25hbGx5IGVtcHR5XG4gICAgfVxuICB9XG4gIHRoaXMudW5sb2FkUmVmID0gdGhpcy54ZHIgPSBudWxsO1xufTtcblxuWERST2JqZWN0LnByb3RvdHlwZS5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnY2xvc2UnKTtcbiAgdGhpcy5fY2xlYW51cCh0cnVlKTtcbn07XG5cbi8vIElFIDgvOSBpZiB0aGUgcmVxdWVzdCB0YXJnZXQgdXNlcyB0aGUgc2FtZSBzY2hlbWUgLSAjNzlcblhEUk9iamVjdC5lbmFibGVkID0gISEoZ2xvYmFsLlhEb21haW5SZXF1ZXN0ICYmIGJyb3dzZXIuaGFzRG9tYWluKCkpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFhEUk9iamVjdDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIFhockRyaXZlciA9IHJlcXVpcmUoJy4uL2RyaXZlci94aHInKVxuICA7XG5cbmZ1bmN0aW9uIFhIUkNvcnNPYmplY3QobWV0aG9kLCB1cmwsIHBheWxvYWQsIG9wdHMpIHtcbiAgWGhyRHJpdmVyLmNhbGwodGhpcywgbWV0aG9kLCB1cmwsIHBheWxvYWQsIG9wdHMpO1xufVxuXG5pbmhlcml0cyhYSFJDb3JzT2JqZWN0LCBYaHJEcml2ZXIpO1xuXG5YSFJDb3JzT2JqZWN0LmVuYWJsZWQgPSBYaHJEcml2ZXIuZW5hYmxlZCAmJiBYaHJEcml2ZXIuc3VwcG9ydHNDT1JTO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFhIUkNvcnNPYmplY3Q7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCdldmVudHMnKS5FdmVudEVtaXR0ZXJcbiAgLCBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgO1xuXG5mdW5jdGlvbiBYSFJGYWtlKC8qIG1ldGhvZCwgdXJsLCBwYXlsb2FkLCBvcHRzICovKSB7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgRXZlbnRFbWl0dGVyLmNhbGwodGhpcyk7XG5cbiAgdGhpcy50byA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgc2VsZi5lbWl0KCdmaW5pc2gnLCAyMDAsICd7fScpO1xuICB9LCBYSFJGYWtlLnRpbWVvdXQpO1xufVxuXG5pbmhlcml0cyhYSFJGYWtlLCBFdmVudEVtaXR0ZXIpO1xuXG5YSFJGYWtlLnByb3RvdHlwZS5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICBjbGVhclRpbWVvdXQodGhpcy50byk7XG59O1xuXG5YSFJGYWtlLnRpbWVvdXQgPSAyMDAwO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFhIUkZha2U7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBYaHJEcml2ZXIgPSByZXF1aXJlKCcuLi9kcml2ZXIveGhyJylcbiAgO1xuXG5mdW5jdGlvbiBYSFJMb2NhbE9iamVjdChtZXRob2QsIHVybCwgcGF5bG9hZCAvKiwgb3B0cyAqLykge1xuICBYaHJEcml2ZXIuY2FsbCh0aGlzLCBtZXRob2QsIHVybCwgcGF5bG9hZCwge1xuICAgIG5vQ3JlZGVudGlhbHM6IHRydWVcbiAgfSk7XG59XG5cbmluaGVyaXRzKFhIUkxvY2FsT2JqZWN0LCBYaHJEcml2ZXIpO1xuXG5YSFJMb2NhbE9iamVjdC5lbmFibGVkID0gWGhyRHJpdmVyLmVuYWJsZWQ7XG5cbm1vZHVsZS5leHBvcnRzID0gWEhSTG9jYWxPYmplY3Q7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL2V2ZW50JylcbiAgLCB1cmxVdGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3VybCcpXG4gICwgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gICwgV2Vic29ja2V0RHJpdmVyID0gcmVxdWlyZSgnLi9kcml2ZXIvd2Vic29ja2V0JylcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OndlYnNvY2tldCcpO1xufVxuXG5mdW5jdGlvbiBXZWJTb2NrZXRUcmFuc3BvcnQodHJhbnNVcmwsIGlnbm9yZSwgb3B0aW9ucykge1xuICBpZiAoIVdlYlNvY2tldFRyYW5zcG9ydC5lbmFibGVkKCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1RyYW5zcG9ydCBjcmVhdGVkIHdoZW4gZGlzYWJsZWQnKTtcbiAgfVxuXG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuICBkZWJ1ZygnY29uc3RydWN0b3InLCB0cmFuc1VybCk7XG5cbiAgdmFyIHNlbGYgPSB0aGlzO1xuICB2YXIgdXJsID0gdXJsVXRpbHMuYWRkUGF0aCh0cmFuc1VybCwgJy93ZWJzb2NrZXQnKTtcbiAgaWYgKHVybC5zbGljZSgwLCA1KSA9PT0gJ2h0dHBzJykge1xuICAgIHVybCA9ICd3c3MnICsgdXJsLnNsaWNlKDUpO1xuICB9IGVsc2Uge1xuICAgIHVybCA9ICd3cycgKyB1cmwuc2xpY2UoNCk7XG4gIH1cbiAgdGhpcy51cmwgPSB1cmw7XG5cbiAgdGhpcy53cyA9IG5ldyBXZWJzb2NrZXREcml2ZXIodGhpcy51cmwsIFtdLCBvcHRpb25zKTtcbiAgdGhpcy53cy5vbm1lc3NhZ2UgPSBmdW5jdGlvbihlKSB7XG4gICAgZGVidWcoJ21lc3NhZ2UgZXZlbnQnLCBlLmRhdGEpO1xuICAgIHNlbGYuZW1pdCgnbWVzc2FnZScsIGUuZGF0YSk7XG4gIH07XG4gIC8vIEZpcmVmb3ggaGFzIGFuIGludGVyZXN0aW5nIGJ1Zy4gSWYgYSB3ZWJzb2NrZXQgY29ubmVjdGlvbiBpc1xuICAvLyBjcmVhdGVkIGFmdGVyIG9udW5sb2FkLCBpdCBzdGF5cyBhbGl2ZSBldmVuIHdoZW4gdXNlclxuICAvLyBuYXZpZ2F0ZXMgYXdheSBmcm9tIHRoZSBwYWdlLiBJbiBzdWNoIHNpdHVhdGlvbiBsZXQncyBsaWUgLVxuICAvLyBsZXQncyBub3Qgb3BlbiB0aGUgd3MgY29ubmVjdGlvbiBhdCBhbGwuIFNlZTpcbiAgLy8gaHR0cHM6Ly9naXRodWIuY29tL3NvY2tqcy9zb2NranMtY2xpZW50L2lzc3Vlcy8yOFxuICAvLyBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD02OTYwODVcbiAgdGhpcy51bmxvYWRSZWYgPSB1dGlscy51bmxvYWRBZGQoZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ3VubG9hZCcpO1xuICAgIHNlbGYud3MuY2xvc2UoKTtcbiAgfSk7XG4gIHRoaXMud3Mub25jbG9zZSA9IGZ1bmN0aW9uKGUpIHtcbiAgICBkZWJ1ZygnY2xvc2UgZXZlbnQnLCBlLmNvZGUsIGUucmVhc29uKTtcbiAgICBzZWxmLmVtaXQoJ2Nsb3NlJywgZS5jb2RlLCBlLnJlYXNvbik7XG4gICAgc2VsZi5fY2xlYW51cCgpO1xuICB9O1xuICB0aGlzLndzLm9uZXJyb3IgPSBmdW5jdGlvbihlKSB7XG4gICAgZGVidWcoJ2Vycm9yIGV2ZW50JywgZSk7XG4gICAgc2VsZi5lbWl0KCdjbG9zZScsIDEwMDYsICdXZWJTb2NrZXQgY29ubmVjdGlvbiBicm9rZW4nKTtcbiAgICBzZWxmLl9jbGVhbnVwKCk7XG4gIH07XG59XG5cbmluaGVyaXRzKFdlYlNvY2tldFRyYW5zcG9ydCwgRXZlbnRFbWl0dGVyKTtcblxuV2ViU29ja2V0VHJhbnNwb3J0LnByb3RvdHlwZS5zZW5kID0gZnVuY3Rpb24oZGF0YSkge1xuICB2YXIgbXNnID0gJ1snICsgZGF0YSArICddJztcbiAgZGVidWcoJ3NlbmQnLCBtc2cpO1xuICB0aGlzLndzLnNlbmQobXNnKTtcbn07XG5cbldlYlNvY2tldFRyYW5zcG9ydC5wcm90b3R5cGUuY2xvc2UgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ2Nsb3NlJyk7XG4gIGlmICh0aGlzLndzKSB7XG4gICAgdGhpcy53cy5jbG9zZSgpO1xuICB9XG4gIHRoaXMuX2NsZWFudXAoKTtcbn07XG5cbldlYlNvY2tldFRyYW5zcG9ydC5wcm90b3R5cGUuX2NsZWFudXAgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ19jbGVhbnVwJyk7XG4gIHZhciB3cyA9IHRoaXMud3M7XG4gIGlmICh3cykge1xuICAgIHdzLm9ubWVzc2FnZSA9IHdzLm9uY2xvc2UgPSB3cy5vbmVycm9yID0gbnVsbDtcbiAgfVxuICB1dGlscy51bmxvYWREZWwodGhpcy51bmxvYWRSZWYpO1xuICB0aGlzLnVubG9hZFJlZiA9IHRoaXMud3MgPSBudWxsO1xuICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygpO1xufTtcblxuV2ViU29ja2V0VHJhbnNwb3J0LmVuYWJsZWQgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ2VuYWJsZWQnKTtcbiAgcmV0dXJuICEhV2Vic29ja2V0RHJpdmVyO1xufTtcbldlYlNvY2tldFRyYW5zcG9ydC50cmFuc3BvcnROYW1lID0gJ3dlYnNvY2tldCc7XG5cbi8vIEluIHRoZW9yeSwgd3Mgc2hvdWxkIHJlcXVpcmUgMSByb3VuZCB0cmlwLiBCdXQgaW4gY2hyb21lLCB0aGlzIGlzXG4vLyBub3QgdmVyeSBzdGFibGUgb3ZlciBTU0wuIE1vc3QgbGlrZWx5IGEgd3MgY29ubmVjdGlvbiByZXF1aXJlcyBhXG4vLyBzZXBhcmF0ZSBTU0wgY29ubmVjdGlvbiwgaW4gd2hpY2ggY2FzZSAyIHJvdW5kIHRyaXBzIGFyZSBhblxuLy8gYWJzb2x1dGUgbWludW11bS5cbldlYlNvY2tldFRyYW5zcG9ydC5yb3VuZFRyaXBzID0gMjtcblxubW9kdWxlLmV4cG9ydHMgPSBXZWJTb2NrZXRUcmFuc3BvcnQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBBamF4QmFzZWRUcmFuc3BvcnQgPSByZXF1aXJlKCcuL2xpYi9hamF4LWJhc2VkJylcbiAgLCBYZHJTdHJlYW1pbmdUcmFuc3BvcnQgPSByZXF1aXJlKCcuL3hkci1zdHJlYW1pbmcnKVxuICAsIFhoclJlY2VpdmVyID0gcmVxdWlyZSgnLi9yZWNlaXZlci94aHInKVxuICAsIFhEUk9iamVjdCA9IHJlcXVpcmUoJy4vc2VuZGVyL3hkcicpXG4gIDtcblxuZnVuY3Rpb24gWGRyUG9sbGluZ1RyYW5zcG9ydCh0cmFuc1VybCkge1xuICBpZiAoIVhEUk9iamVjdC5lbmFibGVkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdUcmFuc3BvcnQgY3JlYXRlZCB3aGVuIGRpc2FibGVkJyk7XG4gIH1cbiAgQWpheEJhc2VkVHJhbnNwb3J0LmNhbGwodGhpcywgdHJhbnNVcmwsICcveGhyJywgWGhyUmVjZWl2ZXIsIFhEUk9iamVjdCk7XG59XG5cbmluaGVyaXRzKFhkclBvbGxpbmdUcmFuc3BvcnQsIEFqYXhCYXNlZFRyYW5zcG9ydCk7XG5cblhkclBvbGxpbmdUcmFuc3BvcnQuZW5hYmxlZCA9IFhkclN0cmVhbWluZ1RyYW5zcG9ydC5lbmFibGVkO1xuWGRyUG9sbGluZ1RyYW5zcG9ydC50cmFuc3BvcnROYW1lID0gJ3hkci1wb2xsaW5nJztcblhkclBvbGxpbmdUcmFuc3BvcnQucm91bmRUcmlwcyA9IDI7IC8vIHByZWZsaWdodCwgYWpheFxuXG5tb2R1bGUuZXhwb3J0cyA9IFhkclBvbGxpbmdUcmFuc3BvcnQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBBamF4QmFzZWRUcmFuc3BvcnQgPSByZXF1aXJlKCcuL2xpYi9hamF4LWJhc2VkJylcbiAgLCBYaHJSZWNlaXZlciA9IHJlcXVpcmUoJy4vcmVjZWl2ZXIveGhyJylcbiAgLCBYRFJPYmplY3QgPSByZXF1aXJlKCcuL3NlbmRlci94ZHInKVxuICA7XG5cbi8vIEFjY29yZGluZyB0bzpcbi8vICAgaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xNjQxNTA3L2RldGVjdC1icm93c2VyLXN1cHBvcnQtZm9yLWNyb3NzLWRvbWFpbi14bWxodHRwcmVxdWVzdHNcbi8vICAgaHR0cDovL2hhY2tzLm1vemlsbGEub3JnLzIwMDkvMDcvY3Jvc3Mtc2l0ZS14bWxodHRwcmVxdWVzdC13aXRoLWNvcnMvXG5cbmZ1bmN0aW9uIFhkclN0cmVhbWluZ1RyYW5zcG9ydCh0cmFuc1VybCkge1xuICBpZiAoIVhEUk9iamVjdC5lbmFibGVkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdUcmFuc3BvcnQgY3JlYXRlZCB3aGVuIGRpc2FibGVkJyk7XG4gIH1cbiAgQWpheEJhc2VkVHJhbnNwb3J0LmNhbGwodGhpcywgdHJhbnNVcmwsICcveGhyX3N0cmVhbWluZycsIFhoclJlY2VpdmVyLCBYRFJPYmplY3QpO1xufVxuXG5pbmhlcml0cyhYZHJTdHJlYW1pbmdUcmFuc3BvcnQsIEFqYXhCYXNlZFRyYW5zcG9ydCk7XG5cblhkclN0cmVhbWluZ1RyYW5zcG9ydC5lbmFibGVkID0gZnVuY3Rpb24oaW5mbykge1xuICBpZiAoaW5mby5jb29raWVfbmVlZGVkIHx8IGluZm8ubnVsbE9yaWdpbikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICByZXR1cm4gWERST2JqZWN0LmVuYWJsZWQgJiYgaW5mby5zYW1lU2NoZW1lO1xufTtcblxuWGRyU3RyZWFtaW5nVHJhbnNwb3J0LnRyYW5zcG9ydE5hbWUgPSAneGRyLXN0cmVhbWluZyc7XG5YZHJTdHJlYW1pbmdUcmFuc3BvcnQucm91bmRUcmlwcyA9IDI7IC8vIHByZWZsaWdodCwgYWpheFxuXG5tb2R1bGUuZXhwb3J0cyA9IFhkclN0cmVhbWluZ1RyYW5zcG9ydDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEFqYXhCYXNlZFRyYW5zcG9ydCA9IHJlcXVpcmUoJy4vbGliL2FqYXgtYmFzZWQnKVxuICAsIFhoclJlY2VpdmVyID0gcmVxdWlyZSgnLi9yZWNlaXZlci94aHInKVxuICAsIFhIUkNvcnNPYmplY3QgPSByZXF1aXJlKCcuL3NlbmRlci94aHItY29ycycpXG4gICwgWEhSTG9jYWxPYmplY3QgPSByZXF1aXJlKCcuL3NlbmRlci94aHItbG9jYWwnKVxuICA7XG5cbmZ1bmN0aW9uIFhoclBvbGxpbmdUcmFuc3BvcnQodHJhbnNVcmwpIHtcbiAgaWYgKCFYSFJMb2NhbE9iamVjdC5lbmFibGVkICYmICFYSFJDb3JzT2JqZWN0LmVuYWJsZWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1RyYW5zcG9ydCBjcmVhdGVkIHdoZW4gZGlzYWJsZWQnKTtcbiAgfVxuICBBamF4QmFzZWRUcmFuc3BvcnQuY2FsbCh0aGlzLCB0cmFuc1VybCwgJy94aHInLCBYaHJSZWNlaXZlciwgWEhSQ29yc09iamVjdCk7XG59XG5cbmluaGVyaXRzKFhoclBvbGxpbmdUcmFuc3BvcnQsIEFqYXhCYXNlZFRyYW5zcG9ydCk7XG5cblhoclBvbGxpbmdUcmFuc3BvcnQuZW5hYmxlZCA9IGZ1bmN0aW9uKGluZm8pIHtcbiAgaWYgKGluZm8ubnVsbE9yaWdpbikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGlmIChYSFJMb2NhbE9iamVjdC5lbmFibGVkICYmIGluZm8uc2FtZU9yaWdpbikge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIHJldHVybiBYSFJDb3JzT2JqZWN0LmVuYWJsZWQ7XG59O1xuXG5YaHJQb2xsaW5nVHJhbnNwb3J0LnRyYW5zcG9ydE5hbWUgPSAneGhyLXBvbGxpbmcnO1xuWGhyUG9sbGluZ1RyYW5zcG9ydC5yb3VuZFRyaXBzID0gMjsgLy8gcHJlZmxpZ2h0LCBhamF4XG5cbm1vZHVsZS5leHBvcnRzID0gWGhyUG9sbGluZ1RyYW5zcG9ydDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEFqYXhCYXNlZFRyYW5zcG9ydCA9IHJlcXVpcmUoJy4vbGliL2FqYXgtYmFzZWQnKVxuICAsIFhoclJlY2VpdmVyID0gcmVxdWlyZSgnLi9yZWNlaXZlci94aHInKVxuICAsIFhIUkNvcnNPYmplY3QgPSByZXF1aXJlKCcuL3NlbmRlci94aHItY29ycycpXG4gICwgWEhSTG9jYWxPYmplY3QgPSByZXF1aXJlKCcuL3NlbmRlci94aHItbG9jYWwnKVxuICAsIGJyb3dzZXIgPSByZXF1aXJlKCcuLi91dGlscy9icm93c2VyJylcbiAgO1xuXG5mdW5jdGlvbiBYaHJTdHJlYW1pbmdUcmFuc3BvcnQodHJhbnNVcmwpIHtcbiAgaWYgKCFYSFJMb2NhbE9iamVjdC5lbmFibGVkICYmICFYSFJDb3JzT2JqZWN0LmVuYWJsZWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1RyYW5zcG9ydCBjcmVhdGVkIHdoZW4gZGlzYWJsZWQnKTtcbiAgfVxuICBBamF4QmFzZWRUcmFuc3BvcnQuY2FsbCh0aGlzLCB0cmFuc1VybCwgJy94aHJfc3RyZWFtaW5nJywgWGhyUmVjZWl2ZXIsIFhIUkNvcnNPYmplY3QpO1xufVxuXG5pbmhlcml0cyhYaHJTdHJlYW1pbmdUcmFuc3BvcnQsIEFqYXhCYXNlZFRyYW5zcG9ydCk7XG5cblhoclN0cmVhbWluZ1RyYW5zcG9ydC5lbmFibGVkID0gZnVuY3Rpb24oaW5mbykge1xuICBpZiAoaW5mby5udWxsT3JpZ2luKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIC8vIE9wZXJhIGRvZXNuJ3Qgc3VwcG9ydCB4aHItc3RyZWFtaW5nICM2MFxuICAvLyBCdXQgaXQgbWlnaHQgYmUgYWJsZSB0byAjOTJcbiAgaWYgKGJyb3dzZXIuaXNPcGVyYSgpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcmV0dXJuIFhIUkNvcnNPYmplY3QuZW5hYmxlZDtcbn07XG5cblhoclN0cmVhbWluZ1RyYW5zcG9ydC50cmFuc3BvcnROYW1lID0gJ3hoci1zdHJlYW1pbmcnO1xuWGhyU3RyZWFtaW5nVHJhbnNwb3J0LnJvdW5kVHJpcHMgPSAyOyAvLyBwcmVmbGlnaHQsIGFqYXhcblxuLy8gU2FmYXJpIGdldHMgY29uZnVzZWQgd2hlbiBhIHN0cmVhbWluZyBhamF4IHJlcXVlc3QgaXMgc3RhcnRlZFxuLy8gYmVmb3JlIG9ubG9hZC4gVGhpcyBjYXVzZXMgdGhlIGxvYWQgaW5kaWNhdG9yIHRvIHNwaW4gaW5kZWZpbmV0ZWx5LlxuLy8gT25seSByZXF1aXJlIGJvZHkgd2hlbiB1c2VkIGluIGEgYnJvd3NlclxuWGhyU3RyZWFtaW5nVHJhbnNwb3J0Lm5lZWRCb2R5ID0gISFnbG9iYWwuZG9jdW1lbnQ7XG5cbm1vZHVsZS5leHBvcnRzID0gWGhyU3RyZWFtaW5nVHJhbnNwb3J0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5pZiAoZ2xvYmFsLmNyeXB0byAmJiBnbG9iYWwuY3J5cHRvLmdldFJhbmRvbVZhbHVlcykge1xuICBtb2R1bGUuZXhwb3J0cy5yYW5kb21CeXRlcyA9IGZ1bmN0aW9uKGxlbmd0aCkge1xuICAgIHZhciBieXRlcyA9IG5ldyBVaW50OEFycmF5KGxlbmd0aCk7XG4gICAgZ2xvYmFsLmNyeXB0by5nZXRSYW5kb21WYWx1ZXMoYnl0ZXMpO1xuICAgIHJldHVybiBieXRlcztcbiAgfTtcbn0gZWxzZSB7XG4gIG1vZHVsZS5leHBvcnRzLnJhbmRvbUJ5dGVzID0gZnVuY3Rpb24obGVuZ3RoKSB7XG4gICAgdmFyIGJ5dGVzID0gbmV3IEFycmF5KGxlbmd0aCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgYnl0ZXNbaV0gPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAyNTYpO1xuICAgIH1cbiAgICByZXR1cm4gYnl0ZXM7XG4gIH07XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBpc09wZXJhOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gZ2xvYmFsLm5hdmlnYXRvciAmJlxuICAgICAgL29wZXJhL2kudGVzdChnbG9iYWwubmF2aWdhdG9yLnVzZXJBZ2VudCk7XG4gIH1cblxuLCBpc0tvbnF1ZXJvcjogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIGdsb2JhbC5uYXZpZ2F0b3IgJiZcbiAgICAgIC9rb25xdWVyb3IvaS50ZXN0KGdsb2JhbC5uYXZpZ2F0b3IudXNlckFnZW50KTtcbiAgfVxuXG4gIC8vICMxODcgd3JhcCBkb2N1bWVudC5kb21haW4gaW4gdHJ5L2NhdGNoIGJlY2F1c2Ugb2YgV1A4IGZyb20gZmlsZTovLy9cbiwgaGFzRG9tYWluOiBmdW5jdGlvbiAoKSB7XG4gICAgLy8gbm9uLWJyb3dzZXIgY2xpZW50IGFsd2F5cyBoYXMgYSBkb21haW5cbiAgICBpZiAoIWdsb2JhbC5kb2N1bWVudCkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiAhIWdsb2JhbC5kb2N1bWVudC5kb21haW47XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIEpTT04zID0gcmVxdWlyZSgnanNvbjMnKTtcblxuLy8gU29tZSBleHRyYSBjaGFyYWN0ZXJzIHRoYXQgQ2hyb21lIGdldHMgd3JvbmcsIGFuZCBzdWJzdGl0dXRlcyB3aXRoXG4vLyBzb21ldGhpbmcgZWxzZSBvbiB0aGUgd2lyZS5cbnZhciBleHRyYUVzY2FwYWJsZSA9IC9bXFx4MDAtXFx4MWZcXHVkODAwLVxcdWRmZmZcXHVmZmZlXFx1ZmZmZlxcdTAzMDAtXFx1MDMzM1xcdTAzM2QtXFx1MDM0NlxcdTAzNGEtXFx1MDM0Y1xcdTAzNTAtXFx1MDM1MlxcdTAzNTctXFx1MDM1OFxcdTAzNWMtXFx1MDM2MlxcdTAzNzRcXHUwMzdlXFx1MDM4N1xcdTA1OTEtXFx1MDVhZlxcdTA1YzRcXHUwNjEwLVxcdTA2MTdcXHUwNjUzLVxcdTA2NTRcXHUwNjU3LVxcdTA2NWJcXHUwNjVkLVxcdTA2NWVcXHUwNmRmLVxcdTA2ZTJcXHUwNmViLVxcdTA2ZWNcXHUwNzMwXFx1MDczMi1cXHUwNzMzXFx1MDczNS1cXHUwNzM2XFx1MDczYVxcdTA3M2RcXHUwNzNmLVxcdTA3NDFcXHUwNzQzXFx1MDc0NVxcdTA3NDdcXHUwN2ViLVxcdTA3ZjFcXHUwOTUxXFx1MDk1OC1cXHUwOTVmXFx1MDlkYy1cXHUwOWRkXFx1MDlkZlxcdTBhMzNcXHUwYTM2XFx1MGE1OS1cXHUwYTViXFx1MGE1ZVxcdTBiNWMtXFx1MGI1ZFxcdTBlMzgtXFx1MGUzOVxcdTBmNDNcXHUwZjRkXFx1MGY1MlxcdTBmNTdcXHUwZjVjXFx1MGY2OVxcdTBmNzItXFx1MGY3NlxcdTBmNzhcXHUwZjgwLVxcdTBmODNcXHUwZjkzXFx1MGY5ZFxcdTBmYTJcXHUwZmE3XFx1MGZhY1xcdTBmYjlcXHUxOTM5LVxcdTE5M2FcXHUxYTE3XFx1MWI2YlxcdTFjZGEtXFx1MWNkYlxcdTFkYzAtXFx1MWRjZlxcdTFkZmNcXHUxZGZlXFx1MWY3MVxcdTFmNzNcXHUxZjc1XFx1MWY3N1xcdTFmNzlcXHUxZjdiXFx1MWY3ZFxcdTFmYmJcXHUxZmJlXFx1MWZjOVxcdTFmY2JcXHUxZmQzXFx1MWZkYlxcdTFmZTNcXHUxZmViXFx1MWZlZS1cXHUxZmVmXFx1MWZmOVxcdTFmZmJcXHUxZmZkXFx1MjAwMC1cXHUyMDAxXFx1MjBkMC1cXHUyMGQxXFx1MjBkNC1cXHUyMGQ3XFx1MjBlNy1cXHUyMGU5XFx1MjEyNlxcdTIxMmEtXFx1MjEyYlxcdTIzMjktXFx1MjMyYVxcdTJhZGNcXHUzMDJiLVxcdTMwMmNcXHVhYWIyLVxcdWFhYjNcXHVmOTAwLVxcdWZhMGRcXHVmYTEwXFx1ZmExMlxcdWZhMTUtXFx1ZmExZVxcdWZhMjBcXHVmYTIyXFx1ZmEyNS1cXHVmYTI2XFx1ZmEyYS1cXHVmYTJkXFx1ZmEzMC1cXHVmYTZkXFx1ZmE3MC1cXHVmYWQ5XFx1ZmIxZFxcdWZiMWZcXHVmYjJhLVxcdWZiMzZcXHVmYjM4LVxcdWZiM2NcXHVmYjNlXFx1ZmI0MC1cXHVmYjQxXFx1ZmI0My1cXHVmYjQ0XFx1ZmI0Ni1cXHVmYjRlXFx1ZmZmMC1cXHVmZmZmXS9nXG4gICwgZXh0cmFMb29rdXA7XG5cbi8vIFRoaXMgbWF5IGJlIHF1aXRlIHNsb3csIHNvIGxldCdzIGRlbGF5IHVudGlsIHVzZXIgYWN0dWFsbHkgdXNlcyBiYWRcbi8vIGNoYXJhY3RlcnMuXG52YXIgdW5yb2xsTG9va3VwID0gZnVuY3Rpb24oZXNjYXBhYmxlKSB7XG4gIHZhciBpO1xuICB2YXIgdW5yb2xsZWQgPSB7fTtcbiAgdmFyIGMgPSBbXTtcbiAgZm9yIChpID0gMDsgaSA8IDY1NTM2OyBpKyspIHtcbiAgICBjLnB1c2goIFN0cmluZy5mcm9tQ2hhckNvZGUoaSkgKTtcbiAgfVxuICBlc2NhcGFibGUubGFzdEluZGV4ID0gMDtcbiAgYy5qb2luKCcnKS5yZXBsYWNlKGVzY2FwYWJsZSwgZnVuY3Rpb24oYSkge1xuICAgIHVucm9sbGVkWyBhIF0gPSAnXFxcXHUnICsgKCcwMDAwJyArIGEuY2hhckNvZGVBdCgwKS50b1N0cmluZygxNikpLnNsaWNlKC00KTtcbiAgICByZXR1cm4gJyc7XG4gIH0pO1xuICBlc2NhcGFibGUubGFzdEluZGV4ID0gMDtcbiAgcmV0dXJuIHVucm9sbGVkO1xufTtcblxuLy8gUXVvdGUgc3RyaW5nLCBhbHNvIHRha2luZyBjYXJlIG9mIHVuaWNvZGUgY2hhcmFjdGVycyB0aGF0IGJyb3dzZXJzXG4vLyBvZnRlbiBicmVhay4gRXNwZWNpYWxseSwgdGFrZSBjYXJlIG9mIHVuaWNvZGUgc3Vycm9nYXRlczpcbi8vIGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTWFwcGluZ19vZl9Vbmljb2RlX2NoYXJhY3RlcnMjU3Vycm9nYXRlc1xubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHF1b3RlOiBmdW5jdGlvbihzdHJpbmcpIHtcbiAgICB2YXIgcXVvdGVkID0gSlNPTjMuc3RyaW5naWZ5KHN0cmluZyk7XG5cbiAgICAvLyBJbiBtb3N0IGNhc2VzIHRoaXMgc2hvdWxkIGJlIHZlcnkgZmFzdCBhbmQgZ29vZCBlbm91Z2guXG4gICAgZXh0cmFFc2NhcGFibGUubGFzdEluZGV4ID0gMDtcbiAgICBpZiAoIWV4dHJhRXNjYXBhYmxlLnRlc3QocXVvdGVkKSkge1xuICAgICAgcmV0dXJuIHF1b3RlZDtcbiAgICB9XG5cbiAgICBpZiAoIWV4dHJhTG9va3VwKSB7XG4gICAgICBleHRyYUxvb2t1cCA9IHVucm9sbExvb2t1cChleHRyYUVzY2FwYWJsZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHF1b3RlZC5yZXBsYWNlKGV4dHJhRXNjYXBhYmxlLCBmdW5jdGlvbihhKSB7XG4gICAgICByZXR1cm4gZXh0cmFMb29rdXBbYV07XG4gICAgfSk7XG4gIH1cbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciByYW5kb20gPSByZXF1aXJlKCcuL3JhbmRvbScpO1xuXG52YXIgb25VbmxvYWQgPSB7fVxuICAsIGFmdGVyVW5sb2FkID0gZmFsc2VcbiAgICAvLyBkZXRlY3QgZ29vZ2xlIGNocm9tZSBwYWNrYWdlZCBhcHBzIGJlY2F1c2UgdGhleSBkb24ndCBhbGxvdyB0aGUgJ3VubG9hZCcgZXZlbnRcbiAgLCBpc0Nocm9tZVBhY2thZ2VkQXBwID0gZ2xvYmFsLmNocm9tZSAmJiBnbG9iYWwuY2hyb21lLmFwcCAmJiBnbG9iYWwuY2hyb21lLmFwcC5ydW50aW1lXG4gIDtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGF0dGFjaEV2ZW50OiBmdW5jdGlvbihldmVudCwgbGlzdGVuZXIpIHtcbiAgICBpZiAodHlwZW9mIGdsb2JhbC5hZGRFdmVudExpc3RlbmVyICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgZ2xvYmFsLmFkZEV2ZW50TGlzdGVuZXIoZXZlbnQsIGxpc3RlbmVyLCBmYWxzZSk7XG4gICAgfSBlbHNlIGlmIChnbG9iYWwuZG9jdW1lbnQgJiYgZ2xvYmFsLmF0dGFjaEV2ZW50KSB7XG4gICAgICAvLyBJRSBxdWlya3MuXG4gICAgICAvLyBBY2NvcmRpbmcgdG86IGh0dHA6Ly9zdGV2ZXNvdWRlcnMuY29tL21pc2MvdGVzdC1wb3N0bWVzc2FnZS5waHBcbiAgICAgIC8vIHRoZSBtZXNzYWdlIGdldHMgZGVsaXZlcmVkIG9ubHkgdG8gJ2RvY3VtZW50Jywgbm90ICd3aW5kb3cnLlxuICAgICAgZ2xvYmFsLmRvY3VtZW50LmF0dGFjaEV2ZW50KCdvbicgKyBldmVudCwgbGlzdGVuZXIpO1xuICAgICAgLy8gSSBnZXQgJ3dpbmRvdycgZm9yIGllOC5cbiAgICAgIGdsb2JhbC5hdHRhY2hFdmVudCgnb24nICsgZXZlbnQsIGxpc3RlbmVyKTtcbiAgICB9XG4gIH1cblxuLCBkZXRhY2hFdmVudDogZnVuY3Rpb24oZXZlbnQsIGxpc3RlbmVyKSB7XG4gICAgaWYgKHR5cGVvZiBnbG9iYWwuYWRkRXZlbnRMaXN0ZW5lciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIGdsb2JhbC5yZW1vdmVFdmVudExpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lciwgZmFsc2UpO1xuICAgIH0gZWxzZSBpZiAoZ2xvYmFsLmRvY3VtZW50ICYmIGdsb2JhbC5kZXRhY2hFdmVudCkge1xuICAgICAgZ2xvYmFsLmRvY3VtZW50LmRldGFjaEV2ZW50KCdvbicgKyBldmVudCwgbGlzdGVuZXIpO1xuICAgICAgZ2xvYmFsLmRldGFjaEV2ZW50KCdvbicgKyBldmVudCwgbGlzdGVuZXIpO1xuICAgIH1cbiAgfVxuXG4sIHVubG9hZEFkZDogZnVuY3Rpb24obGlzdGVuZXIpIHtcbiAgICBpZiAoaXNDaHJvbWVQYWNrYWdlZEFwcCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgdmFyIHJlZiA9IHJhbmRvbS5zdHJpbmcoOCk7XG4gICAgb25VbmxvYWRbcmVmXSA9IGxpc3RlbmVyO1xuICAgIGlmIChhZnRlclVubG9hZCkge1xuICAgICAgc2V0VGltZW91dCh0aGlzLnRyaWdnZXJVbmxvYWRDYWxsYmFja3MsIDApO1xuICAgIH1cbiAgICByZXR1cm4gcmVmO1xuICB9XG5cbiwgdW5sb2FkRGVsOiBmdW5jdGlvbihyZWYpIHtcbiAgICBpZiAocmVmIGluIG9uVW5sb2FkKSB7XG4gICAgICBkZWxldGUgb25VbmxvYWRbcmVmXTtcbiAgICB9XG4gIH1cblxuLCB0cmlnZ2VyVW5sb2FkQ2FsbGJhY2tzOiBmdW5jdGlvbigpIHtcbiAgICBmb3IgKHZhciByZWYgaW4gb25VbmxvYWQpIHtcbiAgICAgIG9uVW5sb2FkW3JlZl0oKTtcbiAgICAgIGRlbGV0ZSBvblVubG9hZFtyZWZdO1xuICAgIH1cbiAgfVxufTtcblxudmFyIHVubG9hZFRyaWdnZXJlZCA9IGZ1bmN0aW9uKCkge1xuICBpZiAoYWZ0ZXJVbmxvYWQpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgYWZ0ZXJVbmxvYWQgPSB0cnVlO1xuICBtb2R1bGUuZXhwb3J0cy50cmlnZ2VyVW5sb2FkQ2FsbGJhY2tzKCk7XG59O1xuXG4vLyAndW5sb2FkJyBhbG9uZSBpcyBub3QgcmVsaWFibGUgaW4gb3BlcmEgd2l0aGluIGFuIGlmcmFtZSwgYnV0IHdlXG4vLyBjYW4ndCB1c2UgYGJlZm9yZXVubG9hZGAgYXMgSUUgZmlyZXMgaXQgb24gamF2YXNjcmlwdDogbGlua3MuXG5pZiAoIWlzQ2hyb21lUGFja2FnZWRBcHApIHtcbiAgbW9kdWxlLmV4cG9ydHMuYXR0YWNoRXZlbnQoJ3VubG9hZCcsIHVubG9hZFRyaWdnZXJlZCk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBldmVudFV0aWxzID0gcmVxdWlyZSgnLi9ldmVudCcpXG4gICwgSlNPTjMgPSByZXF1aXJlKCdqc29uMycpXG4gICwgYnJvd3NlciA9IHJlcXVpcmUoJy4vYnJvd3NlcicpXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDp1dGlsczppZnJhbWUnKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIFdQcmVmaXg6ICdfanAnXG4sIGN1cnJlbnRXaW5kb3dJZDogbnVsbFxuXG4sIHBvbGx1dGVHbG9iYWxOYW1lc3BhY2U6IGZ1bmN0aW9uKCkge1xuICAgIGlmICghKG1vZHVsZS5leHBvcnRzLldQcmVmaXggaW4gZ2xvYmFsKSkge1xuICAgICAgZ2xvYmFsW21vZHVsZS5leHBvcnRzLldQcmVmaXhdID0ge307XG4gICAgfVxuICB9XG5cbiwgcG9zdE1lc3NhZ2U6IGZ1bmN0aW9uKHR5cGUsIGRhdGEpIHtcbiAgICBpZiAoZ2xvYmFsLnBhcmVudCAhPT0gZ2xvYmFsKSB7XG4gICAgICBnbG9iYWwucGFyZW50LnBvc3RNZXNzYWdlKEpTT04zLnN0cmluZ2lmeSh7XG4gICAgICAgIHdpbmRvd0lkOiBtb2R1bGUuZXhwb3J0cy5jdXJyZW50V2luZG93SWRcbiAgICAgICwgdHlwZTogdHlwZVxuICAgICAgLCBkYXRhOiBkYXRhIHx8ICcnXG4gICAgICB9KSwgJyonKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZGVidWcoJ0Nhbm5vdCBwb3N0TWVzc2FnZSwgbm8gcGFyZW50IHdpbmRvdy4nLCB0eXBlLCBkYXRhKTtcbiAgICB9XG4gIH1cblxuLCBjcmVhdGVJZnJhbWU6IGZ1bmN0aW9uKGlmcmFtZVVybCwgZXJyb3JDYWxsYmFjaykge1xuICAgIHZhciBpZnJhbWUgPSBnbG9iYWwuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaWZyYW1lJyk7XG4gICAgdmFyIHRyZWYsIHVubG9hZFJlZjtcbiAgICB2YXIgdW5hdHRhY2ggPSBmdW5jdGlvbigpIHtcbiAgICAgIGRlYnVnKCd1bmF0dGFjaCcpO1xuICAgICAgY2xlYXJUaW1lb3V0KHRyZWYpO1xuICAgICAgLy8gRXhwbG9yZXIgaGFkIHByb2JsZW1zIHdpdGggdGhhdC5cbiAgICAgIHRyeSB7XG4gICAgICAgIGlmcmFtZS5vbmxvYWQgPSBudWxsO1xuICAgICAgfSBjYXRjaCAoeCkge1xuICAgICAgICAvLyBpbnRlbnRpb25hbGx5IGVtcHR5XG4gICAgICB9XG4gICAgICBpZnJhbWUub25lcnJvciA9IG51bGw7XG4gICAgfTtcbiAgICB2YXIgY2xlYW51cCA9IGZ1bmN0aW9uKCkge1xuICAgICAgZGVidWcoJ2NsZWFudXAnKTtcbiAgICAgIGlmIChpZnJhbWUpIHtcbiAgICAgICAgdW5hdHRhY2goKTtcbiAgICAgICAgLy8gVGhpcyB0aW1lb3V0IG1ha2VzIGNocm9tZSBmaXJlIG9uYmVmb3JldW5sb2FkIGV2ZW50XG4gICAgICAgIC8vIHdpdGhpbiBpZnJhbWUuIFdpdGhvdXQgdGhlIHRpbWVvdXQgaXQgZ29lcyBzdHJhaWdodCB0b1xuICAgICAgICAvLyBvbnVubG9hZC5cbiAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICBpZiAoaWZyYW1lKSB7XG4gICAgICAgICAgICBpZnJhbWUucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChpZnJhbWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZnJhbWUgPSBudWxsO1xuICAgICAgICB9LCAwKTtcbiAgICAgICAgZXZlbnRVdGlscy51bmxvYWREZWwodW5sb2FkUmVmKTtcbiAgICAgIH1cbiAgICB9O1xuICAgIHZhciBvbmVycm9yID0gZnVuY3Rpb24oZXJyKSB7XG4gICAgICBkZWJ1Zygnb25lcnJvcicsIGVycik7XG4gICAgICBpZiAoaWZyYW1lKSB7XG4gICAgICAgIGNsZWFudXAoKTtcbiAgICAgICAgZXJyb3JDYWxsYmFjayhlcnIpO1xuICAgICAgfVxuICAgIH07XG4gICAgdmFyIHBvc3QgPSBmdW5jdGlvbihtc2csIG9yaWdpbikge1xuICAgICAgZGVidWcoJ3Bvc3QnLCBtc2csIG9yaWdpbik7XG4gICAgICB0cnkge1xuICAgICAgICAvLyBXaGVuIHRoZSBpZnJhbWUgaXMgbm90IGxvYWRlZCwgSUUgcmFpc2VzIGFuIGV4Y2VwdGlvblxuICAgICAgICAvLyBvbiAnY29udGVudFdpbmRvdycuXG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgaWYgKGlmcmFtZSAmJiBpZnJhbWUuY29udGVudFdpbmRvdykge1xuICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cucG9zdE1lc3NhZ2UobXNnLCBvcmlnaW4pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwgMCk7XG4gICAgICB9IGNhdGNoICh4KSB7XG4gICAgICAgIC8vIGludGVudGlvbmFsbHkgZW1wdHlcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgaWZyYW1lLnNyYyA9IGlmcmFtZVVybDtcbiAgICBpZnJhbWUuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICBpZnJhbWUuc3R5bGUucG9zaXRpb24gPSAnYWJzb2x1dGUnO1xuICAgIGlmcmFtZS5vbmVycm9yID0gZnVuY3Rpb24oKSB7XG4gICAgICBvbmVycm9yKCdvbmVycm9yJyk7XG4gICAgfTtcbiAgICBpZnJhbWUub25sb2FkID0gZnVuY3Rpb24oKSB7XG4gICAgICBkZWJ1Zygnb25sb2FkJyk7XG4gICAgICAvLyBgb25sb2FkYCBpcyB0cmlnZ2VyZWQgYmVmb3JlIHNjcmlwdHMgb24gdGhlIGlmcmFtZSBhcmVcbiAgICAgIC8vIGV4ZWN1dGVkLiBHaXZlIGl0IGZldyBzZWNvbmRzIHRvIGFjdHVhbGx5IGxvYWQgc3R1ZmYuXG4gICAgICBjbGVhclRpbWVvdXQodHJlZik7XG4gICAgICB0cmVmID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgb25lcnJvcignb25sb2FkIHRpbWVvdXQnKTtcbiAgICAgIH0sIDIwMDApO1xuICAgIH07XG4gICAgZ2xvYmFsLmRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoaWZyYW1lKTtcbiAgICB0cmVmID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgIG9uZXJyb3IoJ3RpbWVvdXQnKTtcbiAgICB9LCAxNTAwMCk7XG4gICAgdW5sb2FkUmVmID0gZXZlbnRVdGlscy51bmxvYWRBZGQoY2xlYW51cCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHBvc3Q6IHBvc3RcbiAgICAsIGNsZWFudXA6IGNsZWFudXBcbiAgICAsIGxvYWRlZDogdW5hdHRhY2hcbiAgICB9O1xuICB9XG5cbi8qIGpzaGludCB1bmRlZjogZmFsc2UsIG5ld2NhcDogZmFsc2UgKi9cbi8qIGVzbGludCBuby11bmRlZjogMCwgbmV3LWNhcDogMCAqL1xuLCBjcmVhdGVIdG1sZmlsZTogZnVuY3Rpb24oaWZyYW1lVXJsLCBlcnJvckNhbGxiYWNrKSB7XG4gICAgdmFyIGF4byA9IFsnQWN0aXZlJ10uY29uY2F0KCdPYmplY3QnKS5qb2luKCdYJyk7XG4gICAgdmFyIGRvYyA9IG5ldyBnbG9iYWxbYXhvXSgnaHRtbGZpbGUnKTtcbiAgICB2YXIgdHJlZiwgdW5sb2FkUmVmO1xuICAgIHZhciBpZnJhbWU7XG4gICAgdmFyIHVuYXR0YWNoID0gZnVuY3Rpb24oKSB7XG4gICAgICBjbGVhclRpbWVvdXQodHJlZik7XG4gICAgICBpZnJhbWUub25lcnJvciA9IG51bGw7XG4gICAgfTtcbiAgICB2YXIgY2xlYW51cCA9IGZ1bmN0aW9uKCkge1xuICAgICAgaWYgKGRvYykge1xuICAgICAgICB1bmF0dGFjaCgpO1xuICAgICAgICBldmVudFV0aWxzLnVubG9hZERlbCh1bmxvYWRSZWYpO1xuICAgICAgICBpZnJhbWUucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChpZnJhbWUpO1xuICAgICAgICBpZnJhbWUgPSBkb2MgPSBudWxsO1xuICAgICAgICBDb2xsZWN0R2FyYmFnZSgpO1xuICAgICAgfVxuICAgIH07XG4gICAgdmFyIG9uZXJyb3IgPSBmdW5jdGlvbihyKSB7XG4gICAgICBkZWJ1Zygnb25lcnJvcicsIHIpO1xuICAgICAgaWYgKGRvYykge1xuICAgICAgICBjbGVhbnVwKCk7XG4gICAgICAgIGVycm9yQ2FsbGJhY2socik7XG4gICAgICB9XG4gICAgfTtcbiAgICB2YXIgcG9zdCA9IGZ1bmN0aW9uKG1zZywgb3JpZ2luKSB7XG4gICAgICB0cnkge1xuICAgICAgICAvLyBXaGVuIHRoZSBpZnJhbWUgaXMgbm90IGxvYWRlZCwgSUUgcmFpc2VzIGFuIGV4Y2VwdGlvblxuICAgICAgICAvLyBvbiAnY29udGVudFdpbmRvdycuXG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgaWYgKGlmcmFtZSAmJiBpZnJhbWUuY29udGVudFdpbmRvdykge1xuICAgICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5wb3N0TWVzc2FnZShtc2csIG9yaWdpbik7XG4gICAgICAgICAgfVxuICAgICAgICB9LCAwKTtcbiAgICAgIH0gY2F0Y2ggKHgpIHtcbiAgICAgICAgLy8gaW50ZW50aW9uYWxseSBlbXB0eVxuICAgICAgfVxuICAgIH07XG5cbiAgICBkb2Mub3BlbigpO1xuICAgIGRvYy53cml0ZSgnPGh0bWw+PHMnICsgJ2NyaXB0PicgK1xuICAgICAgICAgICAgICAnZG9jdW1lbnQuZG9tYWluPVwiJyArIGdsb2JhbC5kb2N1bWVudC5kb21haW4gKyAnXCI7JyArXG4gICAgICAgICAgICAgICc8L3MnICsgJ2NyaXB0PjwvaHRtbD4nKTtcbiAgICBkb2MuY2xvc2UoKTtcbiAgICBkb2MucGFyZW50V2luZG93W21vZHVsZS5leHBvcnRzLldQcmVmaXhdID0gZ2xvYmFsW21vZHVsZS5leHBvcnRzLldQcmVmaXhdO1xuICAgIHZhciBjID0gZG9jLmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgIGRvYy5ib2R5LmFwcGVuZENoaWxkKGMpO1xuICAgIGlmcmFtZSA9IGRvYy5jcmVhdGVFbGVtZW50KCdpZnJhbWUnKTtcbiAgICBjLmFwcGVuZENoaWxkKGlmcmFtZSk7XG4gICAgaWZyYW1lLnNyYyA9IGlmcmFtZVVybDtcbiAgICBpZnJhbWUub25lcnJvciA9IGZ1bmN0aW9uKCkge1xuICAgICAgb25lcnJvcignb25lcnJvcicpO1xuICAgIH07XG4gICAgdHJlZiA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICBvbmVycm9yKCd0aW1lb3V0Jyk7XG4gICAgfSwgMTUwMDApO1xuICAgIHVubG9hZFJlZiA9IGV2ZW50VXRpbHMudW5sb2FkQWRkKGNsZWFudXApO1xuICAgIHJldHVybiB7XG4gICAgICBwb3N0OiBwb3N0XG4gICAgLCBjbGVhbnVwOiBjbGVhbnVwXG4gICAgLCBsb2FkZWQ6IHVuYXR0YWNoXG4gICAgfTtcbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMuaWZyYW1lRW5hYmxlZCA9IGZhbHNlO1xuaWYgKGdsb2JhbC5kb2N1bWVudCkge1xuICAvLyBwb3N0TWVzc2FnZSBtaXNiZWhhdmVzIGluIGtvbnF1ZXJvciA0LjYuNSAtIHRoZSBtZXNzYWdlcyBhcmUgZGVsaXZlcmVkIHdpdGhcbiAgLy8gaHVnZSBkZWxheSwgb3Igbm90IGF0IGFsbC5cbiAgbW9kdWxlLmV4cG9ydHMuaWZyYW1lRW5hYmxlZCA9ICh0eXBlb2YgZ2xvYmFsLnBvc3RNZXNzYWdlID09PSAnZnVuY3Rpb24nIHx8XG4gICAgdHlwZW9mIGdsb2JhbC5wb3N0TWVzc2FnZSA9PT0gJ29iamVjdCcpICYmICghYnJvd3Nlci5pc0tvbnF1ZXJvcigpKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGxvZ09iamVjdCA9IHt9O1xuWydsb2cnLCAnZGVidWcnLCAnd2FybiddLmZvckVhY2goZnVuY3Rpb24gKGxldmVsKSB7XG4gIHZhciBsZXZlbEV4aXN0cztcblxuICB0cnkge1xuICAgIGxldmVsRXhpc3RzID0gZ2xvYmFsLmNvbnNvbGUgJiYgZ2xvYmFsLmNvbnNvbGVbbGV2ZWxdICYmIGdsb2JhbC5jb25zb2xlW2xldmVsXS5hcHBseTtcbiAgfSBjYXRjaChlKSB7XG4gICAgLy8gZG8gbm90aGluZ1xuICB9XG5cbiAgbG9nT2JqZWN0W2xldmVsXSA9IGxldmVsRXhpc3RzID8gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBnbG9iYWwuY29uc29sZVtsZXZlbF0uYXBwbHkoZ2xvYmFsLmNvbnNvbGUsIGFyZ3VtZW50cyk7XG4gIH0gOiAobGV2ZWwgPT09ICdsb2cnID8gZnVuY3Rpb24gKCkge30gOiBsb2dPYmplY3QubG9nKTtcbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGxvZ09iamVjdDtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGlzT2JqZWN0OiBmdW5jdGlvbihvYmopIHtcbiAgICB2YXIgdHlwZSA9IHR5cGVvZiBvYmo7XG4gICAgcmV0dXJuIHR5cGUgPT09ICdmdW5jdGlvbicgfHwgdHlwZSA9PT0gJ29iamVjdCcgJiYgISFvYmo7XG4gIH1cblxuLCBleHRlbmQ6IGZ1bmN0aW9uKG9iaikge1xuICAgIGlmICghdGhpcy5pc09iamVjdChvYmopKSB7XG4gICAgICByZXR1cm4gb2JqO1xuICAgIH1cbiAgICB2YXIgc291cmNlLCBwcm9wO1xuICAgIGZvciAodmFyIGkgPSAxLCBsZW5ndGggPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHNvdXJjZSA9IGFyZ3VtZW50c1tpXTtcbiAgICAgIGZvciAocHJvcCBpbiBzb3VyY2UpIHtcbiAgICAgICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzb3VyY2UsIHByb3ApKSB7XG4gICAgICAgICAgb2JqW3Byb3BdID0gc291cmNlW3Byb3BdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBvYmo7XG4gIH1cbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qIGdsb2JhbCBjcnlwdG86dHJ1ZSAqL1xudmFyIGNyeXB0byA9IHJlcXVpcmUoJ2NyeXB0bycpO1xuXG4vLyBUaGlzIHN0cmluZyBoYXMgbGVuZ3RoIDMyLCBhIHBvd2VyIG9mIDIsIHNvIHRoZSBtb2R1bHVzIGRvZXNuJ3QgaW50cm9kdWNlIGFcbi8vIGJpYXMuXG52YXIgX3JhbmRvbVN0cmluZ0NoYXJzID0gJ2FiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Jztcbm1vZHVsZS5leHBvcnRzID0ge1xuICBzdHJpbmc6IGZ1bmN0aW9uKGxlbmd0aCkge1xuICAgIHZhciBtYXggPSBfcmFuZG9tU3RyaW5nQ2hhcnMubGVuZ3RoO1xuICAgIHZhciBieXRlcyA9IGNyeXB0by5yYW5kb21CeXRlcyhsZW5ndGgpO1xuICAgIHZhciByZXQgPSBbXTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICByZXQucHVzaChfcmFuZG9tU3RyaW5nQ2hhcnMuc3Vic3RyKGJ5dGVzW2ldICUgbWF4LCAxKSk7XG4gICAgfVxuICAgIHJldHVybiByZXQuam9pbignJyk7XG4gIH1cblxuLCBudW1iZXI6IGZ1bmN0aW9uKG1heCkge1xuICAgIHJldHVybiBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBtYXgpO1xuICB9XG5cbiwgbnVtYmVyU3RyaW5nOiBmdW5jdGlvbihtYXgpIHtcbiAgICB2YXIgdCA9ICgnJyArIChtYXggLSAxKSkubGVuZ3RoO1xuICAgIHZhciBwID0gbmV3IEFycmF5KHQgKyAxKS5qb2luKCcwJyk7XG4gICAgcmV0dXJuIChwICsgdGhpcy5udW1iZXIobWF4KSkuc2xpY2UoLXQpO1xuICB9XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OnV0aWxzOnRyYW5zcG9ydCcpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKGF2YWlsYWJsZVRyYW5zcG9ydHMpIHtcbiAgcmV0dXJuIHtcbiAgICBmaWx0ZXJUb0VuYWJsZWQ6IGZ1bmN0aW9uKHRyYW5zcG9ydHNXaGl0ZWxpc3QsIGluZm8pIHtcbiAgICAgIHZhciB0cmFuc3BvcnRzID0ge1xuICAgICAgICBtYWluOiBbXVxuICAgICAgLCBmYWNhZGU6IFtdXG4gICAgICB9O1xuICAgICAgaWYgKCF0cmFuc3BvcnRzV2hpdGVsaXN0KSB7XG4gICAgICAgIHRyYW5zcG9ydHNXaGl0ZWxpc3QgPSBbXTtcbiAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHRyYW5zcG9ydHNXaGl0ZWxpc3QgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIHRyYW5zcG9ydHNXaGl0ZWxpc3QgPSBbdHJhbnNwb3J0c1doaXRlbGlzdF07XG4gICAgICB9XG5cbiAgICAgIGF2YWlsYWJsZVRyYW5zcG9ydHMuZm9yRWFjaChmdW5jdGlvbih0cmFucykge1xuICAgICAgICBpZiAoIXRyYW5zKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRyYW5zLnRyYW5zcG9ydE5hbWUgPT09ICd3ZWJzb2NrZXQnICYmIGluZm8ud2Vic29ja2V0ID09PSBmYWxzZSkge1xuICAgICAgICAgIGRlYnVnKCdkaXNhYmxlZCBmcm9tIHNlcnZlcicsICd3ZWJzb2NrZXQnKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHJhbnNwb3J0c1doaXRlbGlzdC5sZW5ndGggJiZcbiAgICAgICAgICAgIHRyYW5zcG9ydHNXaGl0ZWxpc3QuaW5kZXhPZih0cmFucy50cmFuc3BvcnROYW1lKSA9PT0gLTEpIHtcbiAgICAgICAgICBkZWJ1Zygnbm90IGluIHdoaXRlbGlzdCcsIHRyYW5zLnRyYW5zcG9ydE5hbWUpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0cmFucy5lbmFibGVkKGluZm8pKSB7XG4gICAgICAgICAgZGVidWcoJ2VuYWJsZWQnLCB0cmFucy50cmFuc3BvcnROYW1lKTtcbiAgICAgICAgICB0cmFuc3BvcnRzLm1haW4ucHVzaCh0cmFucyk7XG4gICAgICAgICAgaWYgKHRyYW5zLmZhY2FkZVRyYW5zcG9ydCkge1xuICAgICAgICAgICAgdHJhbnNwb3J0cy5mYWNhZGUucHVzaCh0cmFucy5mYWNhZGVUcmFuc3BvcnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBkZWJ1ZygnZGlzYWJsZWQnLCB0cmFucy50cmFuc3BvcnROYW1lKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICByZXR1cm4gdHJhbnNwb3J0cztcbiAgICB9XG4gIH07XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgVVJMID0gcmVxdWlyZSgndXJsLXBhcnNlJyk7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6dXRpbHM6dXJsJyk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBnZXRPcmlnaW46IGZ1bmN0aW9uKHVybCkge1xuICAgIGlmICghdXJsKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICB2YXIgcCA9IG5ldyBVUkwodXJsKTtcbiAgICBpZiAocC5wcm90b2NvbCA9PT0gJ2ZpbGU6Jykge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgdmFyIHBvcnQgPSBwLnBvcnQ7XG4gICAgaWYgKCFwb3J0KSB7XG4gICAgICBwb3J0ID0gKHAucHJvdG9jb2wgPT09ICdodHRwczonKSA/ICc0NDMnIDogJzgwJztcbiAgICB9XG5cbiAgICByZXR1cm4gcC5wcm90b2NvbCArICcvLycgKyBwLmhvc3RuYW1lICsgJzonICsgcG9ydDtcbiAgfVxuXG4sIGlzT3JpZ2luRXF1YWw6IGZ1bmN0aW9uKGEsIGIpIHtcbiAgICB2YXIgcmVzID0gdGhpcy5nZXRPcmlnaW4oYSkgPT09IHRoaXMuZ2V0T3JpZ2luKGIpO1xuICAgIGRlYnVnKCdzYW1lJywgYSwgYiwgcmVzKTtcbiAgICByZXR1cm4gcmVzO1xuICB9XG5cbiwgaXNTY2hlbWVFcXVhbDogZnVuY3Rpb24oYSwgYikge1xuICAgIHJldHVybiAoYS5zcGxpdCgnOicpWzBdID09PSBiLnNwbGl0KCc6JylbMF0pO1xuICB9XG5cbiwgYWRkUGF0aDogZnVuY3Rpb24gKHVybCwgcGF0aCkge1xuICAgIHZhciBxcyA9IHVybC5zcGxpdCgnPycpO1xuICAgIHJldHVybiBxc1swXSArIHBhdGggKyAocXNbMV0gPyAnPycgKyBxc1sxXSA6ICcnKTtcbiAgfVxuXG4sIGFkZFF1ZXJ5OiBmdW5jdGlvbiAodXJsLCBxKSB7XG4gICAgcmV0dXJuIHVybCArICh1cmwuaW5kZXhPZignPycpID09PSAtMSA/ICgnPycgKyBxKSA6ICgnJicgKyBxKSk7XG4gIH1cbn07XG4iLCJtb2R1bGUuZXhwb3J0cyA9ICcxLjEuMSc7XG4iLCIvKipcbiAqIFVBUGFyc2VyLmpzIHYwLjcuMTJcbiAqIExpZ2h0d2VpZ2h0IEphdmFTY3JpcHQtYmFzZWQgVXNlci1BZ2VudCBzdHJpbmcgcGFyc2VyXG4gKiBodHRwczovL2dpdGh1Yi5jb20vZmFpc2FsbWFuL3VhLXBhcnNlci1qc1xuICpcbiAqIENvcHlyaWdodCDCqSAyMDEyLTIwMTYgRmFpc2FsIFNhbG1hbiA8Znl6bG1hbkBnbWFpbC5jb20+XG4gKiBEdWFsIGxpY2Vuc2VkIHVuZGVyIEdQTHYyICYgTUlUXG4gKi9cblxuKGZ1bmN0aW9uICh3aW5kb3csIHVuZGVmaW5lZCkge1xuXG4gICAgJ3VzZSBzdHJpY3QnO1xuXG4gICAgLy8vLy8vLy8vLy8vLy9cbiAgICAvLyBDb25zdGFudHNcbiAgICAvLy8vLy8vLy8vLy8vXG5cblxuICAgIHZhciBMSUJWRVJTSU9OICA9ICcwLjcuMTInLFxuICAgICAgICBFTVBUWSAgICAgICA9ICcnLFxuICAgICAgICBVTktOT1dOICAgICA9ICc/JyxcbiAgICAgICAgRlVOQ19UWVBFICAgPSAnZnVuY3Rpb24nLFxuICAgICAgICBVTkRFRl9UWVBFICA9ICd1bmRlZmluZWQnLFxuICAgICAgICBPQkpfVFlQRSAgICA9ICdvYmplY3QnLFxuICAgICAgICBTVFJfVFlQRSAgICA9ICdzdHJpbmcnLFxuICAgICAgICBNQUpPUiAgICAgICA9ICdtYWpvcicsIC8vIGRlcHJlY2F0ZWRcbiAgICAgICAgTU9ERUwgICAgICAgPSAnbW9kZWwnLFxuICAgICAgICBOQU1FICAgICAgICA9ICduYW1lJyxcbiAgICAgICAgVFlQRSAgICAgICAgPSAndHlwZScsXG4gICAgICAgIFZFTkRPUiAgICAgID0gJ3ZlbmRvcicsXG4gICAgICAgIFZFUlNJT04gICAgID0gJ3ZlcnNpb24nLFxuICAgICAgICBBUkNISVRFQ1RVUkU9ICdhcmNoaXRlY3R1cmUnLFxuICAgICAgICBDT05TT0xFICAgICA9ICdjb25zb2xlJyxcbiAgICAgICAgTU9CSUxFICAgICAgPSAnbW9iaWxlJyxcbiAgICAgICAgVEFCTEVUICAgICAgPSAndGFibGV0JyxcbiAgICAgICAgU01BUlRUViAgICAgPSAnc21hcnR0dicsXG4gICAgICAgIFdFQVJBQkxFICAgID0gJ3dlYXJhYmxlJyxcbiAgICAgICAgRU1CRURERUQgICAgPSAnZW1iZWRkZWQnO1xuXG5cbiAgICAvLy8vLy8vLy8vL1xuICAgIC8vIEhlbHBlclxuICAgIC8vLy8vLy8vLy9cblxuXG4gICAgdmFyIHV0aWwgPSB7XG4gICAgICAgIGV4dGVuZCA6IGZ1bmN0aW9uIChyZWdleGVzLCBleHRlbnNpb25zKSB7XG4gICAgICAgICAgICB2YXIgbWFyZ2VkUmVnZXhlcyA9IHt9O1xuICAgICAgICAgICAgZm9yICh2YXIgaSBpbiByZWdleGVzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGV4dGVuc2lvbnNbaV0gJiYgZXh0ZW5zaW9uc1tpXS5sZW5ndGggJSAyID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIG1hcmdlZFJlZ2V4ZXNbaV0gPSBleHRlbnNpb25zW2ldLmNvbmNhdChyZWdleGVzW2ldKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBtYXJnZWRSZWdleGVzW2ldID0gcmVnZXhlc1tpXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gbWFyZ2VkUmVnZXhlcztcbiAgICAgICAgfSxcbiAgICAgICAgaGFzIDogZnVuY3Rpb24gKHN0cjEsIHN0cjIpIHtcbiAgICAgICAgICBpZiAodHlwZW9mIHN0cjEgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBzdHIyLnRvTG93ZXJDYXNlKCkuaW5kZXhPZihzdHIxLnRvTG93ZXJDYXNlKCkpICE9PSAtMTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgbG93ZXJpemUgOiBmdW5jdGlvbiAoc3RyKSB7XG4gICAgICAgICAgICByZXR1cm4gc3RyLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIH0sXG4gICAgICAgIG1ham9yIDogZnVuY3Rpb24gKHZlcnNpb24pIHtcbiAgICAgICAgICAgIHJldHVybiB0eXBlb2YodmVyc2lvbikgPT09IFNUUl9UWVBFID8gdmVyc2lvbi5yZXBsYWNlKC9bXlxcZFxcLl0vZywnJykuc3BsaXQoXCIuXCIpWzBdIDogdW5kZWZpbmVkO1xuICAgICAgICB9LFxuICAgICAgICB0cmltIDogZnVuY3Rpb24gKHN0cikge1xuICAgICAgICAgIHJldHVybiBzdHIucmVwbGFjZSgvXltcXHNcXHVGRUZGXFx4QTBdK3xbXFxzXFx1RkVGRlxceEEwXSskL2csICcnKTtcbiAgICAgICAgfVxuICAgIH07XG5cblxuICAgIC8vLy8vLy8vLy8vLy8vL1xuICAgIC8vIE1hcCBoZWxwZXJcbiAgICAvLy8vLy8vLy8vLy8vL1xuXG5cbiAgICB2YXIgbWFwcGVyID0ge1xuXG4gICAgICAgIHJneCA6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICAgICAgdmFyIHJlc3VsdCwgaSA9IDAsIGosIGssIHAsIHEsIG1hdGNoZXMsIG1hdGNoLCBhcmdzID0gYXJndW1lbnRzO1xuXG4gICAgICAgICAgICAvLyBsb29wIHRocm91Z2ggYWxsIHJlZ2V4ZXMgbWFwc1xuICAgICAgICAgICAgd2hpbGUgKGkgPCBhcmdzLmxlbmd0aCAmJiAhbWF0Y2hlcykge1xuXG4gICAgICAgICAgICAgICAgdmFyIHJlZ2V4ID0gYXJnc1tpXSwgICAgICAgLy8gZXZlbiBzZXF1ZW5jZSAoMCwyLDQsLi4pXG4gICAgICAgICAgICAgICAgICAgIHByb3BzID0gYXJnc1tpICsgMV07ICAgLy8gb2RkIHNlcXVlbmNlICgxLDMsNSwuLilcblxuICAgICAgICAgICAgICAgIC8vIGNvbnN0cnVjdCBvYmplY3QgYmFyZWJvbmVzXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiByZXN1bHQgPT09IFVOREVGX1RZUEUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0ge307XG4gICAgICAgICAgICAgICAgICAgIGZvciAocCBpbiBwcm9wcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHByb3BzLmhhc093blByb3BlcnR5KHApKXtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBxID0gcHJvcHNbcF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBxID09PSBPQkpfVFlQRSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRbcVswXV0gPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0W3FdID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIHRyeSBtYXRjaGluZyB1YXN0cmluZyB3aXRoIHJlZ2V4ZXNcbiAgICAgICAgICAgICAgICBqID0gayA9IDA7XG4gICAgICAgICAgICAgICAgd2hpbGUgKGogPCByZWdleC5sZW5ndGggJiYgIW1hdGNoZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgbWF0Y2hlcyA9IHJlZ2V4W2orK10uZXhlYyh0aGlzLmdldFVBKCkpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoISFtYXRjaGVzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKHAgPSAwOyBwIDwgcHJvcHMubGVuZ3RoOyBwKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaCA9IG1hdGNoZXNbKytrXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBxID0gcHJvcHNbcF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2hlY2sgaWYgZ2l2ZW4gcHJvcGVydHkgaXMgYWN0dWFsbHkgYXJyYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHEgPT09IE9CSl9UWVBFICYmIHEubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocS5sZW5ndGggPT0gMikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBxWzFdID09IEZVTkNfVFlQRSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFzc2lnbiBtb2RpZmllZCBtYXRjaFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdFtxWzBdXSA9IHFbMV0uY2FsbCh0aGlzLCBtYXRjaCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFzc2lnbiBnaXZlbiB2YWx1ZSwgaWdub3JlIHJlZ2V4IG1hdGNoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0W3FbMF1dID0gcVsxXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChxLmxlbmd0aCA9PSAzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjaGVjayB3aGV0aGVyIGZ1bmN0aW9uIG9yIHJlZ2V4XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHFbMV0gPT09IEZVTkNfVFlQRSAmJiAhKHFbMV0uZXhlYyAmJiBxWzFdLnRlc3QpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2FsbCBmdW5jdGlvbiAodXN1YWxseSBzdHJpbmcgbWFwcGVyKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdFtxWzBdXSA9IG1hdGNoID8gcVsxXS5jYWxsKHRoaXMsIG1hdGNoLCBxWzJdKSA6IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc2FuaXRpemUgbWF0Y2ggdXNpbmcgZ2l2ZW4gcmVnZXhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRbcVswXV0gPSBtYXRjaCA/IG1hdGNoLnJlcGxhY2UocVsxXSwgcVsyXSkgOiB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocS5sZW5ndGggPT0gNCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdFtxWzBdXSA9IG1hdGNoID8gcVszXS5jYWxsKHRoaXMsIG1hdGNoLnJlcGxhY2UocVsxXSwgcVsyXSkpIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0W3FdID0gbWF0Y2ggPyBtYXRjaCA6IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaSArPSAyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSxcblxuICAgICAgICBzdHIgOiBmdW5jdGlvbiAoc3RyLCBtYXApIHtcblxuICAgICAgICAgICAgZm9yICh2YXIgaSBpbiBtYXApIHtcbiAgICAgICAgICAgICAgICAvLyBjaGVjayBpZiBhcnJheVxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgbWFwW2ldID09PSBPQkpfVFlQRSAmJiBtYXBbaV0ubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IG1hcFtpXS5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHV0aWwuaGFzKG1hcFtpXVtqXSwgc3RyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAoaSA9PT0gVU5LTk9XTikgPyB1bmRlZmluZWQgOiBpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICh1dGlsLmhhcyhtYXBbaV0sIHN0cikpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChpID09PSBVTktOT1dOKSA/IHVuZGVmaW5lZCA6IGk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHN0cjtcbiAgICAgICAgfVxuICAgIH07XG5cblxuICAgIC8vLy8vLy8vLy8vLy8vL1xuICAgIC8vIFN0cmluZyBtYXBcbiAgICAvLy8vLy8vLy8vLy8vL1xuXG5cbiAgICB2YXIgbWFwcyA9IHtcblxuICAgICAgICBicm93c2VyIDoge1xuICAgICAgICAgICAgb2xkc2FmYXJpIDoge1xuICAgICAgICAgICAgICAgIHZlcnNpb24gOiB7XG4gICAgICAgICAgICAgICAgICAgICcxLjAnICAgOiAnLzgnLFxuICAgICAgICAgICAgICAgICAgICAnMS4yJyAgIDogJy8xJyxcbiAgICAgICAgICAgICAgICAgICAgJzEuMycgICA6ICcvMycsXG4gICAgICAgICAgICAgICAgICAgICcyLjAnICAgOiAnLzQxMicsXG4gICAgICAgICAgICAgICAgICAgICcyLjAuMicgOiAnLzQxNicsXG4gICAgICAgICAgICAgICAgICAgICcyLjAuMycgOiAnLzQxNycsXG4gICAgICAgICAgICAgICAgICAgICcyLjAuNCcgOiAnLzQxOScsXG4gICAgICAgICAgICAgICAgICAgICc/JyAgICAgOiAnLydcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgZGV2aWNlIDoge1xuICAgICAgICAgICAgYW1hem9uIDoge1xuICAgICAgICAgICAgICAgIG1vZGVsIDoge1xuICAgICAgICAgICAgICAgICAgICAnRmlyZSBQaG9uZScgOiBbJ1NEJywgJ0tGJ11cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgc3ByaW50IDoge1xuICAgICAgICAgICAgICAgIG1vZGVsIDoge1xuICAgICAgICAgICAgICAgICAgICAnRXZvIFNoaWZ0IDRHJyA6ICc3MzczS1QnXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB2ZW5kb3IgOiB7XG4gICAgICAgICAgICAgICAgICAgICdIVEMnICAgICAgIDogJ0FQQScsXG4gICAgICAgICAgICAgICAgICAgICdTcHJpbnQnICAgIDogJ1NwcmludCdcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgb3MgOiB7XG4gICAgICAgICAgICB3aW5kb3dzIDoge1xuICAgICAgICAgICAgICAgIHZlcnNpb24gOiB7XG4gICAgICAgICAgICAgICAgICAgICdNRScgICAgICAgIDogJzQuOTAnLFxuICAgICAgICAgICAgICAgICAgICAnTlQgMy4xMScgICA6ICdOVDMuNTEnLFxuICAgICAgICAgICAgICAgICAgICAnTlQgNC4wJyAgICA6ICdOVDQuMCcsXG4gICAgICAgICAgICAgICAgICAgICcyMDAwJyAgICAgIDogJ05UIDUuMCcsXG4gICAgICAgICAgICAgICAgICAgICdYUCcgICAgICAgIDogWydOVCA1LjEnLCAnTlQgNS4yJ10sXG4gICAgICAgICAgICAgICAgICAgICdWaXN0YScgICAgIDogJ05UIDYuMCcsXG4gICAgICAgICAgICAgICAgICAgICc3JyAgICAgICAgIDogJ05UIDYuMScsXG4gICAgICAgICAgICAgICAgICAgICc4JyAgICAgICAgIDogJ05UIDYuMicsXG4gICAgICAgICAgICAgICAgICAgICc4LjEnICAgICAgIDogJ05UIDYuMycsXG4gICAgICAgICAgICAgICAgICAgICcxMCcgICAgICAgIDogWydOVCA2LjQnLCAnTlQgMTAuMCddLFxuICAgICAgICAgICAgICAgICAgICAnUlQnICAgICAgICA6ICdBUk0nXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcblxuXG4gICAgLy8vLy8vLy8vLy8vLy9cbiAgICAvLyBSZWdleCBtYXBcbiAgICAvLy8vLy8vLy8vLy8vXG5cblxuICAgIHZhciByZWdleGVzID0ge1xuXG4gICAgICAgIGJyb3dzZXIgOiBbW1xuXG4gICAgICAgICAgICAvLyBQcmVzdG8gYmFzZWRcbiAgICAgICAgICAgIC8ob3BlcmFcXHNtaW5pKVxcLyhbXFx3XFwuLV0rKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9wZXJhIE1pbmlcbiAgICAgICAgICAgIC8ob3BlcmFcXHNbbW9iaWxldGFiXSspLit2ZXJzaW9uXFwvKFtcXHdcXC4tXSspL2ksICAgICAgICAgICAgICAgICAgICAgIC8vIE9wZXJhIE1vYmkvVGFibGV0XG4gICAgICAgICAgICAvKG9wZXJhKS4rdmVyc2lvblxcLyhbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9wZXJhID4gOS44MFxuICAgICAgICAgICAgLyhvcGVyYSlbXFwvXFxzXSsoW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BlcmEgPCA5LjgwXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhvcGlvcylbXFwvXFxzXSsoW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BlcmEgbWluaSBvbiBpcGhvbmUgPj0gOC4wXG4gICAgICAgICAgICBdLCBbW05BTUUsICdPcGVyYSBNaW5pJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC9cXHMob3ByKVxcLyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9wZXJhIFdlYmtpdFxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnT3BlcmEnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLy8gTWl4ZWRcbiAgICAgICAgICAgIC8oa2luZGxlKVxcLyhbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gS2luZGxlXG4gICAgICAgICAgICAvKGx1bmFzY2FwZXxtYXh0aG9ufG5ldGZyb250fGphc21pbmV8YmxhemVyKVtcXC9cXHNdPyhbXFx3XFwuXSspKi9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBMdW5hc2NhcGUvTWF4dGhvbi9OZXRmcm9udC9KYXNtaW5lL0JsYXplclxuXG4gICAgICAgICAgICAvLyBUcmlkZW50IGJhc2VkXG4gICAgICAgICAgICAvKGF2YW50XFxzfGllbW9iaWxlfHNsaW18YmFpZHUpKD86YnJvd3Nlcik/W1xcL1xcc10/KFtcXHdcXC5dKikvaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQXZhbnQvSUVNb2JpbGUvU2xpbUJyb3dzZXIvQmFpZHVcbiAgICAgICAgICAgIC8oPzptc3xcXCgpKGllKVxccyhbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEludGVybmV0IEV4cGxvcmVyXG5cbiAgICAgICAgICAgIC8vIFdlYmtpdC9LSFRNTCBiYXNlZFxuICAgICAgICAgICAgLyhyZWtvbnEpXFwvKFtcXHdcXC5dKykqL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBSZWtvbnFcbiAgICAgICAgICAgIC8oY2hyb21pdW18ZmxvY2t8cm9ja21lbHR8bWlkb3JpfGVwaXBoYW55fHNpbGt8c2t5ZmlyZXxvdmlicm93c2VyfGJvbHR8aXJvbnx2aXZhbGRpfGlyaWRpdW18cGhhbnRvbWpzKVxcLyhbXFx3XFwuLV0rKS9pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIENocm9taXVtL0Zsb2NrL1JvY2tNZWx0L01pZG9yaS9FcGlwaGFueS9TaWxrL1NreWZpcmUvQm9sdC9Jcm9uL0lyaWRpdW0vUGhhbnRvbUpTXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyh0cmlkZW50KS4rcnZbOlxcc10oW1xcd1xcLl0rKS4rbGlrZVxcc2dlY2tvL2kgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSUUxMVxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnSUUnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhlZGdlKVxcLygoXFxkKyk/W1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTWljcm9zb2Z0IEVkZ2VcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKHlhYnJvd3NlcilcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFlhbmRleFxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnWWFuZGV4J10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oY29tb2RvX2RyYWdvbilcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ29tb2RvIERyYWdvblxuICAgICAgICAgICAgXSwgW1tOQU1FLCAvXy9nLCAnICddLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKG1pY3JvbWVzc2VuZ2VyKVxcLyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFdlQ2hhdFxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnV2VDaGF0J10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC94aWFvbWlcXC9taXVpYnJvd3NlclxcLyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1JVUkgQnJvd3NlclxuICAgICAgICAgICAgXSwgW1ZFUlNJT04sIFtOQU1FLCAnTUlVSSBCcm93c2VyJ11dLCBbXG5cbiAgICAgICAgICAgIC9cXHN3dlxcKS4rKGNocm9tZSlcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDaHJvbWUgV2ViVmlld1xuICAgICAgICAgICAgXSwgW1tOQU1FLCAvKC4rKS8sICckMSBXZWJWaWV3J10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLitzYW1zdW5nYnJvd3NlclxcLyhbXFx3XFwuXSspL2ksXG4gICAgICAgICAgICAvYW5kcm9pZC4rdmVyc2lvblxcLyhbXFx3XFwuXSspXFxzKyg/Om1vYmlsZVxccz9zYWZhcml8c2FmYXJpKSovaSAgICAgICAgLy8gQW5kcm9pZCBCcm93c2VyXG4gICAgICAgICAgICBdLCBbVkVSU0lPTiwgW05BTUUsICdBbmRyb2lkIEJyb3dzZXInXV0sIFtcblxuICAgICAgICAgICAgLyhjaHJvbWV8b21uaXdlYnxhcm9yYXxbdGl6ZW5va2FdezV9XFxzP2Jyb3dzZXIpXFwvdj8oW1xcd1xcLl0rKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDaHJvbWUvT21uaVdlYi9Bcm9yYS9UaXplbi9Ob2tpYVxuICAgICAgICAgICAgLyhxcWJyb3dzZXIpW1xcL1xcc10/KFtcXHdcXC5dKykvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBRUUJyb3dzZXJcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKHVjXFxzP2Jyb3dzZXIpW1xcL1xcc10/KFtcXHdcXC5dKykvaSxcbiAgICAgICAgICAgIC91Y3dlYi4rKHVjYnJvd3NlcilbXFwvXFxzXT8oW1xcd1xcLl0rKS9pLFxuICAgICAgICAgICAgL2p1Yy4rKHVjd2ViKVtcXC9cXHNdPyhbXFx3XFwuXSspL2lcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVUNCcm93c2VyXG4gICAgICAgICAgICBdLCBbW05BTUUsICdVQ0Jyb3dzZXInXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhkb2xmaW4pXFwvKFtcXHdcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBEb2xwaGluXG4gICAgICAgICAgICBdLCBbW05BTUUsICdEb2xwaGluJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oKD86YW5kcm9pZC4rKWNybW98Y3Jpb3MpXFwvKFtcXHdcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2hyb21lIGZvciBBbmRyb2lkL2lPU1xuICAgICAgICAgICAgXSwgW1tOQU1FLCAnQ2hyb21lJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC87ZmJhdlxcLyhbXFx3XFwuXSspOy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRmFjZWJvb2sgQXBwIGZvciBpT1NcbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBbTkFNRSwgJ0ZhY2Vib29rJ11dLCBbXG5cbiAgICAgICAgICAgIC9meGlvc1xcLyhbXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRmlyZWZveCBmb3IgaU9TXG4gICAgICAgICAgICBdLCBbVkVSU0lPTiwgW05BTUUsICdGaXJlZm94J11dLCBbXG5cbiAgICAgICAgICAgIC92ZXJzaW9uXFwvKFtcXHdcXC5dKykuKz9tb2JpbGVcXC9cXHcrXFxzKHNhZmFyaSkvaSAgICAgICAgICAgICAgICAgICAgICAgLy8gTW9iaWxlIFNhZmFyaVxuICAgICAgICAgICAgXSwgW1ZFUlNJT04sIFtOQU1FLCAnTW9iaWxlIFNhZmFyaSddXSwgW1xuXG4gICAgICAgICAgICAvdmVyc2lvblxcLyhbXFx3XFwuXSspLis/KG1vYmlsZVxccz9zYWZhcml8c2FmYXJpKS9pICAgICAgICAgICAgICAgICAgICAvLyBTYWZhcmkgJiBTYWZhcmkgTW9iaWxlXG4gICAgICAgICAgICBdLCBbVkVSU0lPTiwgTkFNRV0sIFtcblxuICAgICAgICAgICAgL3dlYmtpdC4rPyhtb2JpbGVcXHM/c2FmYXJpfHNhZmFyaSkoXFwvW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgLy8gU2FmYXJpIDwgMy4wXG4gICAgICAgICAgICBdLCBbTkFNRSwgW1ZFUlNJT04sIG1hcHBlci5zdHIsIG1hcHMuYnJvd3Nlci5vbGRzYWZhcmkudmVyc2lvbl1dLCBbXG5cbiAgICAgICAgICAgIC8oa29ucXVlcm9yKVxcLyhbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gS29ucXVlcm9yXG4gICAgICAgICAgICAvKHdlYmtpdHxraHRtbClcXC8oW1xcd1xcLl0rKS9pXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLy8gR2Vja28gYmFzZWRcbiAgICAgICAgICAgIC8obmF2aWdhdG9yfG5ldHNjYXBlKVxcLyhbXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTmV0c2NhcGVcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ05ldHNjYXBlJ10sIFZFUlNJT05dLCBbXG4gICAgICAgICAgICAvKHN3aWZ0Zm94KS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFN3aWZ0Zm94XG4gICAgICAgICAgICAvKGljZWRyYWdvbnxpY2V3ZWFzZWx8Y2FtaW5vfGNoaW1lcmF8ZmVubmVjfG1hZW1vXFxzYnJvd3NlcnxtaW5pbW98Y29ua2Vyb3IpW1xcL1xcc10/KFtcXHdcXC5cXCtdKykvaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWNlRHJhZ29uL0ljZXdlYXNlbC9DYW1pbm8vQ2hpbWVyYS9GZW5uZWMvTWFlbW8vTWluaW1vL0Nvbmtlcm9yXG4gICAgICAgICAgICAvKGZpcmVmb3h8c2VhbW9ua2V5fGstbWVsZW9ufGljZWNhdHxpY2VhcGV8ZmlyZWJpcmR8cGhvZW5peClcXC8oW1xcd1xcLi1dKykvaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRmlyZWZveC9TZWFNb25rZXkvSy1NZWxlb24vSWNlQ2F0L0ljZUFwZS9GaXJlYmlyZC9QaG9lbml4XG4gICAgICAgICAgICAvKG1vemlsbGEpXFwvKFtcXHdcXC5dKykuK3J2XFw6LitnZWNrb1xcL1xcZCsvaSwgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1vemlsbGFcblxuICAgICAgICAgICAgLy8gT3RoZXJcbiAgICAgICAgICAgIC8ocG9sYXJpc3xseW54fGRpbGxvfGljYWJ8ZG9yaXN8YW1heWF8dzNtfG5ldHN1cmZ8c2xlaXBuaXIpW1xcL1xcc10/KFtcXHdcXC5dKykvaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUG9sYXJpcy9MeW54L0RpbGxvL2lDYWIvRG9yaXMvQW1heWEvdzNtL05ldFN1cmYvU2xlaXBuaXJcbiAgICAgICAgICAgIC8obGlua3MpXFxzXFwoKFtcXHdcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExpbmtzXG4gICAgICAgICAgICAvKGdvYnJvd3NlcilcXC8/KFtcXHdcXC5dKykqL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdvQnJvd3NlclxuICAgICAgICAgICAgLyhpY2VcXHM/YnJvd3NlcilcXC92PyhbXFx3XFwuX10rKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSUNFIEJyb3dzZXJcbiAgICAgICAgICAgIC8obW9zYWljKVtcXC9cXHNdKFtcXHdcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1vc2FpY1xuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dXG5cbiAgICAgICAgICAgIC8qIC8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgICAgICAgICAgLy8gTWVkaWEgcGxheWVycyBCRUdJTlxuICAgICAgICAgICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbiAgICAgICAgICAgICwgW1xuXG4gICAgICAgICAgICAvKGFwcGxlKD86Y29yZW1lZGlhfCkpXFwvKChcXGQrKVtcXHdcXC5fXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHZW5lcmljIEFwcGxlIENvcmVNZWRpYVxuICAgICAgICAgICAgLyhjb3JlbWVkaWEpIHYoKFxcZCspW1xcd1xcLl9dKykvaVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oYXF1YWx1bmd8bHlzc25hfGJzcGxheWVyKVxcLygoXFxkKyk/W1xcd1xcLi1dKykvaSAgICAgICAgICAgICAgICAgICAgIC8vIEFxdWFsdW5nL0x5c3NuYS9CU1BsYXllclxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oYXJlc3xvc3Nwcm94eSlcXHMoKFxcZCspW1xcd1xcLi1dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFyZXMvT1NTUHJveHlcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKGF1ZGFjaW91c3xhdWRpbXVzaWNzdHJlYW18YW1hcm9rfGJhc3N8Y29yZXxkYWx2aWt8Z25vbWVtcGxheWVyfG11c2ljIG9uIGNvbnNvbGV8bnNwbGF5ZXJ8cHNwLWludGVybmV0cmFkaW9wbGF5ZXJ8dmlkZW9zKVxcLygoXFxkKylbXFx3XFwuLV0rKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBdWRhY2lvdXMvQXVkaU11c2ljU3RyZWFtL0FtYXJvay9CQVNTL09wZW5DT1JFL0RhbHZpay9Hbm9tZU1wbGF5ZXIvTW9DXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5TUGxheWVyL1BTUC1JbnRlcm5ldFJhZGlvUGxheWVyL1ZpZGVvc1xuICAgICAgICAgICAgLyhjbGVtZW50aW5lfG11c2ljIHBsYXllciBkYWVtb24pXFxzKChcXGQrKVtcXHdcXC4tXSspL2ksICAgICAgICAgICAgICAgLy8gQ2xlbWVudGluZS9NUERcbiAgICAgICAgICAgIC8obGcgcGxheWVyfG5leHBsYXllcilcXHMoKFxcZCspW1xcZFxcLl0rKS9pLFxuICAgICAgICAgICAgL3BsYXllclxcLyhuZXhwbGF5ZXJ8bGcgcGxheWVyKVxccygoXFxkKylbXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgIC8vIE5leFBsYXllci9MRyBQbGF5ZXJcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuICAgICAgICAgICAgLyhuZXhwbGF5ZXIpXFxzKChcXGQrKVtcXHdcXC4tXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTmV4cGxheWVyXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhmbHJwKVxcLygoXFxkKylbXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRmxpcCBQbGF5ZXJcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ0ZsaXAgUGxheWVyJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oZnN0cmVhbXxuYXRpdmVob3N0fHF1ZXJ5c2Vla3NwaWRlcnxpYS1hcmNoaXZlcnxmYWNlYm9va2V4dGVybmFsaGl0KS9pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZTdHJlYW0vTmF0aXZlSG9zdC9RdWVyeVNlZWtTcGlkZXIvSUEgQXJjaGl2ZXIvZmFjZWJvb2tleHRlcm5hbGhpdFxuICAgICAgICAgICAgXSwgW05BTUVdLCBbXG5cbiAgICAgICAgICAgIC8oZ3N0cmVhbWVyKSBzb3VwaHR0cHNyYyAoPzpcXChbXlxcKV0rXFwpKXswLDF9IGxpYnNvdXBcXC8oKFxcZCspW1xcd1xcLi1dKykvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHc3RyZWFtZXJcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKGh0YyBzdHJlYW1pbmcgcGxheWVyKVxcc1tcXHdfXStcXHNcXC9cXHMoKFxcZCspW1xcZFxcLl0rKS9pLCAgICAgICAgICAgICAgLy8gSFRDIFN0cmVhbWluZyBQbGF5ZXJcbiAgICAgICAgICAgIC8oamF2YXxweXRob24tdXJsbGlifHB5dGhvbi1yZXF1ZXN0c3x3Z2V0fGxpYmN1cmwpXFwvKChcXGQrKVtcXHdcXC4tX10rKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBKYXZhL3VybGxpYi9yZXF1ZXN0cy93Z2V0L2NVUkxcbiAgICAgICAgICAgIC8obGF2ZikoKFxcZCspW1xcZFxcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTGF2ZiAoRkZNUEVHKVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oaHRjX29uZV9zKVxcLygoXFxkKylbXFxkXFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEhUQyBPbmUgU1xuICAgICAgICAgICAgXSwgW1tOQU1FLCAvXy9nLCAnICddLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKG1wbGF5ZXIpKD86XFxzfFxcLykoPzooPzpzaGVycHlhLSl7MCwxfXN2bikoPzotfFxccykoclxcZCsoPzotXFxkK1tcXHdcXC4tXSspezAsMX0pL2lcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTVBsYXllciBTVk5cbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKG1wbGF5ZXIpKD86XFxzfFxcL3xbdW5rb3ctXSspKChcXGQrKVtcXHdcXC4tXSspL2kgICAgICAgICAgICAgICAgICAgICAgLy8gTVBsYXllclxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8obXBsYXllcikvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTVBsYXllciAobm8gb3RoZXIgaW5mbylcbiAgICAgICAgICAgIC8oeW91cm11emUpL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gWW91ck11emVcbiAgICAgICAgICAgIC8obWVkaWEgcGxheWVyIGNsYXNzaWN8bmVybyBzaG93dGltZSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTWVkaWEgUGxheWVyIENsYXNzaWMvTmVybyBTaG93VGltZVxuICAgICAgICAgICAgXSwgW05BTUVdLCBbXG5cbiAgICAgICAgICAgIC8obmVybyAoPzpob21lfHNjb3V0KSlcXC8oKFxcZCspW1xcd1xcLi1dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5lcm8gSG9tZS9OZXJvIFNjb3V0XG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhub2tpYVxcZCspXFwvKChcXGQrKVtcXHdcXC4tXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5va2lhXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgL1xccyhzb25nYmlyZClcXC8oKFxcZCspW1xcd1xcLi1dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvbmdiaXJkL1BoaWxpcHMtU29uZ2JpcmRcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKHdpbmFtcCkzIHZlcnNpb24gKChcXGQrKVtcXHdcXC4tXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFdpbmFtcFxuICAgICAgICAgICAgLyh3aW5hbXApXFxzKChcXGQrKVtcXHdcXC4tXSspL2ksXG4gICAgICAgICAgICAvKHdpbmFtcCltcGVnXFwvKChcXGQrKVtcXHdcXC4tXSspL2lcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKG9jbXMtYm90fHRhcGlucmFkaW98dHVuZWluIHJhZGlvfHVua25vd258d2luYW1wfGlubGlnaHQgcmFkaW8pL2kgIC8vIE9DTVMtYm90L3RhcCBpbiByYWRpby90dW5laW4vdW5rbm93bi93aW5hbXAgKG5vIG90aGVyIGluZm8pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlubGlnaHQgcmFkaW9cbiAgICAgICAgICAgIF0sIFtOQU1FXSwgW1xuXG4gICAgICAgICAgICAvKHF1aWNrdGltZXxybWF8cmFkaW9hcHB8cmFkaW9jbGllbnRhcHBsaWNhdGlvbnxzb3VuZHRhcHx0b3RlbXxzdGFnZWZyaWdodHxzdHJlYW1pdW0pXFwvKChcXGQrKVtcXHdcXC4tXSspL2lcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUXVpY2tUaW1lL1JlYWxNZWRpYS9SYWRpb0FwcC9SYWRpb0NsaWVudEFwcGxpY2F0aW9uL1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTb3VuZFRhcC9Ub3RlbS9TdGFnZWZyaWdodC9TdHJlYW1pdW1cbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKHNtcCkoKFxcZCspW1xcZFxcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNNUFxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8odmxjKSBtZWRpYSBwbGF5ZXIgLSB2ZXJzaW9uICgoXFxkKylbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgLy8gVkxDIFZpZGVvbGFuXG4gICAgICAgICAgICAvKHZsYylcXC8oKFxcZCspW1xcd1xcLi1dKykvaSxcbiAgICAgICAgICAgIC8oeGJtY3xndmZzfHhpbmV8eG1tc3xpcmFwcClcXC8oKFxcZCspW1xcd1xcLi1dKykvaSwgICAgICAgICAgICAgICAgICAgIC8vIFhCTUMvZ3Zmcy9YaW5lL1hNTVMvaXJhcHBcbiAgICAgICAgICAgIC8oZm9vYmFyMjAwMClcXC8oKFxcZCspW1xcZFxcLl0rKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZvb2JhcjIwMDBcbiAgICAgICAgICAgIC8oaXR1bmVzKVxcLygoXFxkKylbXFxkXFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlUdW5lc1xuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8od21wbGF5ZXIpXFwvKChcXGQrKVtcXHdcXC4tXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFdpbmRvd3MgTWVkaWEgUGxheWVyXG4gICAgICAgICAgICAvKHdpbmRvd3MtbWVkaWEtcGxheWVyKVxcLygoXFxkKylbXFx3XFwuLV0rKS9pXG4gICAgICAgICAgICBdLCBbW05BTUUsIC8tL2csICcgJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC93aW5kb3dzXFwvKChcXGQrKVtcXHdcXC4tXSspIHVwbnBcXC9bXFxkXFwuXSsgZGxuYWRvY1xcL1tcXGRcXC5dKyAoaG9tZSBtZWRpYSBzZXJ2ZXIpL2lcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2luZG93cyBNZWRpYSBTZXJ2ZXJcbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBbTkFNRSwgJ1dpbmRvd3MnXV0sIFtcblxuICAgICAgICAgICAgLyhjb21cXC5yaXNldXByYWRpb2FsYXJtKVxcLygoXFxkKylbXFxkXFwuXSopL2kgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJpc2VVUCBSYWRpbyBBbGFybVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8ocmFkLmlvKVxccygoXFxkKylbXFxkXFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJhZC5pb1xuICAgICAgICAgICAgLyhyYWRpby4oPzpkZXxhdHxmcikpXFxzKChcXGQrKVtcXGRcXC5dKykvaVxuICAgICAgICAgICAgXSwgW1tOQU1FLCAncmFkLmlvJ10sIFZFUlNJT05dXG5cbiAgICAgICAgICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cbiAgICAgICAgICAgIC8vIE1lZGlhIHBsYXllcnMgRU5EXG4gICAgICAgICAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLyovXG5cbiAgICAgICAgXSxcblxuICAgICAgICBjcHUgOiBbW1xuXG4gICAgICAgICAgICAvKD86KGFtZHx4KD86KD86ODZ8NjQpW18tXSk/fHdvd3x3aW4pNjQpWztcXCldL2kgICAgICAgICAgICAgICAgICAgICAvLyBBTUQ2NFxuICAgICAgICAgICAgXSwgW1tBUkNISVRFQ1RVUkUsICdhbWQ2NCddXSwgW1xuXG4gICAgICAgICAgICAvKGlhMzIoPz07KSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElBMzIgKHF1aWNrdGltZSlcbiAgICAgICAgICAgIF0sIFtbQVJDSElURUNUVVJFLCB1dGlsLmxvd2VyaXplXV0sIFtcblxuICAgICAgICAgICAgLygoPzppWzM0Nl18eCk4NilbO1xcKV0vaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSUEzMlxuICAgICAgICAgICAgXSwgW1tBUkNISVRFQ1RVUkUsICdpYTMyJ11dLCBbXG5cbiAgICAgICAgICAgIC8vIFBvY2tldFBDIG1pc3Rha2VubHkgaWRlbnRpZmllZCBhcyBQb3dlclBDXG4gICAgICAgICAgICAvd2luZG93c1xccyhjZXxtb2JpbGUpO1xcc3BwYzsvaVxuICAgICAgICAgICAgXSwgW1tBUkNISVRFQ1RVUkUsICdhcm0nXV0sIFtcblxuICAgICAgICAgICAgLygoPzpwcGN8cG93ZXJwYykoPzo2NCk/KSg/Olxcc21hY3w7fFxcKSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBvd2VyUENcbiAgICAgICAgICAgIF0sIFtbQVJDSElURUNUVVJFLCAvb3dlci8sICcnLCB1dGlsLmxvd2VyaXplXV0sIFtcblxuICAgICAgICAgICAgLyhzdW40XFx3KVs7XFwpXS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNQQVJDXG4gICAgICAgICAgICBdLCBbW0FSQ0hJVEVDVFVSRSwgJ3NwYXJjJ11dLCBbXG5cbiAgICAgICAgICAgIC8oKD86YXZyMzJ8aWE2NCg/PTspKXw2OGsoPz1cXCkpfGFybSg/OjY0fCg/PXZcXGQrOykpfCg/PWF0bWVsXFxzKWF2cnwoPzppcml4fG1pcHN8c3BhcmMpKD86NjQpPyg/PTspfHBhLXJpc2MpL2lcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSUE2NCwgNjhLLCBBUk0vNjQsIEFWUi8zMiwgSVJJWC82NCwgTUlQUy82NCwgU1BBUkMvNjQsIFBBLVJJU0NcbiAgICAgICAgICAgIF0sIFtbQVJDSElURUNUVVJFLCB1dGlsLmxvd2VyaXplXV1cbiAgICAgICAgXSxcblxuICAgICAgICBkZXZpY2UgOiBbW1xuXG4gICAgICAgICAgICAvXFwoKGlwYWR8cGxheWJvb2spO1tcXHdcXHNcXCk7LV0rKHJpbXxhcHBsZSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpUGFkL1BsYXlCb29rXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFZFTkRPUiwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hcHBsZWNvcmVtZWRpYVxcL1tcXHdcXC5dKyBcXCgoaXBhZCkvICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlQYWRcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0FwcGxlJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuXG4gICAgICAgICAgICAvKGFwcGxlXFxzezAsMX10dikvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBcHBsZSBUVlxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ0FwcGxlIFRWJ10sIFtWRU5ET1IsICdBcHBsZSddXSwgW1xuXG4gICAgICAgICAgICAvKGFyY2hvcylcXHMoZ2FtZXBhZDI/KS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBcmNob3NcbiAgICAgICAgICAgIC8oaHApLisodG91Y2hwYWQpL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSFAgVG91Y2hQYWRcbiAgICAgICAgICAgIC8oaHApLisodGFibGV0KS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSFAgVGFibGV0XG4gICAgICAgICAgICAvKGtpbmRsZSlcXC8oW1xcd1xcLl0rKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEtpbmRsZVxuICAgICAgICAgICAgL1xccyhub29rKVtcXHdcXHNdK2J1aWxkXFwvKFxcdyspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5vb2tcbiAgICAgICAgICAgIC8oZGVsbClcXHMoc3RyZWFba3ByXFxzXFxkXSpbXFxka29dKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIERlbGwgU3RyZWFrXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC8oa2ZbQS16XSspXFxzYnVpbGRcXC9bXFx3XFwuXSsuKnNpbGtcXC8vaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBLaW5kbGUgRmlyZSBIRFxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnQW1hem9uJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuICAgICAgICAgICAgLyhzZHxrZilbMDM0OWhpam9yc3R1d10rXFxzYnVpbGRcXC9bXFx3XFwuXSsuKnNpbGtcXC8vaSAgICAgICAgICAgICAgICAgIC8vIEZpcmUgUGhvbmVcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsIG1hcHBlci5zdHIsIG1hcHMuZGV2aWNlLmFtYXpvbi5tb2RlbF0sIFtWRU5ET1IsICdBbWF6b24nXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC9cXCgoaXBbaG9uZWR8XFxzXFx3Kl0rKTsuKyhhcHBsZSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaVBvZC9pUGhvbmVcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgVkVORE9SLCBbVFlQRSwgTU9CSUxFXV0sIFtcbiAgICAgICAgICAgIC9cXCgoaXBbaG9uZWR8XFxzXFx3Kl0rKTsvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaVBvZC9pUGhvbmVcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0FwcGxlJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKGJsYWNrYmVycnkpW1xccy1dPyhcXHcrKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQmxhY2tCZXJyeVxuICAgICAgICAgICAgLyhibGFja2JlcnJ5fGJlbnF8cGFsbSg/PVxcLSl8c29ueWVyaWNzc29ufGFjZXJ8YXN1c3xkZWxsfGh1YXdlaXxtZWl6dXxtb3Rvcm9sYXxwb2x5dHJvbilbXFxzXy1dPyhbXFx3LV0rKSovaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQmVuUS9QYWxtL1NvbnktRXJpY3Nzb24vQWNlci9Bc3VzL0RlbGwvSHVhd2VpL01laXp1L01vdG9yb2xhL1BvbHl0cm9uXG4gICAgICAgICAgICAvKGhwKVxccyhbXFx3XFxzXStcXHcpL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIUCBpUEFRXG4gICAgICAgICAgICAvKGFzdXMpLT8oXFx3KykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBc3VzXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvXFwoYmIxMDtcXHMoXFx3KykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEJsYWNrQmVycnkgMTBcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0JsYWNrQmVycnknXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFzdXMgVGFibGV0c1xuICAgICAgICAgICAgL2FuZHJvaWQuKyh0cmFuc2ZvW3ByaW1lXFxzXXs0LDEwfVxcc1xcdyt8ZWVlcGN8c2xpZGVyXFxzXFx3K3xuZXh1cyA3fHBhZGZvbmUpL2lcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0FzdXMnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC8oc29ueSlcXHModGFibGV0XFxzW3BzXSlcXHNidWlsZFxcLy9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTb255XG4gICAgICAgICAgICAvKHNvbnkpPyg/OnNncC4rKVxcc2J1aWxkXFwvL2lcbiAgICAgICAgICAgIF0sIFtbVkVORE9SLCAnU29ueSddLCBbTU9ERUwsICdYcGVyaWEgVGFibGV0J10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuICAgICAgICAgICAgLyg/OnNvbnkpPyg/Oig/Oig/OmN8ZClcXGR7NH0pfCg/OnNvWy1sXS4rKSlcXHNidWlsZFxcLy9pXG4gICAgICAgICAgICBdLCBbW1ZFTkRPUiwgJ1NvbnknXSwgW01PREVMLCAnWHBlcmlhIFBob25lJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvXFxzKG91eWEpXFxzL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3V5YVxuICAgICAgICAgICAgLyhuaW50ZW5kbylcXHMoW3dpZHMzdV0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTmludGVuZG9cbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIE1PREVMLCBbVFlQRSwgQ09OU09MRV1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLis7XFxzKHNoaWVsZClcXHNidWlsZC9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOdmlkaWFcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ052aWRpYSddLCBbVFlQRSwgQ09OU09MRV1dLCBbXG5cbiAgICAgICAgICAgIC8ocGxheXN0YXRpb25cXHNbMzRwb3J0YWJsZXZpXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBsYXlzdGF0aW9uXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdTb255J10sIFtUWVBFLCBDT05TT0xFXV0sIFtcblxuICAgICAgICAgICAgLyhzcHJpbnRcXHMoXFx3KykpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNwcmludCBQaG9uZXNcbiAgICAgICAgICAgIF0sIFtbVkVORE9SLCBtYXBwZXIuc3RyLCBtYXBzLmRldmljZS5zcHJpbnQudmVuZG9yXSwgW01PREVMLCBtYXBwZXIuc3RyLCBtYXBzLmRldmljZS5zcHJpbnQubW9kZWxdLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgLyhsZW5vdm8pXFxzPyhTKD86NTAwMHw2MDAwKSsoPzpbLV1bXFx3K10pKS9pICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExlbm92byB0YWJsZXRzXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC8oaHRjKVs7X1xccy1dKyhbXFx3XFxzXSsoPz1cXCkpfFxcdyspKi9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIVENcbiAgICAgICAgICAgIC8oenRlKS0oXFx3KykqL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFpURVxuICAgICAgICAgICAgLyhhbGNhdGVsfGdlZWtzcGhvbmV8aHVhd2VpfGxlbm92b3xuZXhpYW58cGFuYXNvbmljfCg/PTtcXHMpc29ueSlbX1xccy1dPyhbXFx3LV0rKSovaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBbGNhdGVsL0dlZWtzUGhvbmUvSHVhd2VpL0xlbm92by9OZXhpYW4vUGFuYXNvbmljL1NvbnlcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIFtNT0RFTCwgL18vZywgJyAnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8obmV4dXNcXHM5KS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEhUQyBOZXh1cyA5XG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdIVEMnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC8obmV4dXNcXHM2cCkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEh1YXdlaSBOZXh1cyA2UFxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnSHVhd2VpJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKG1pY3Jvc29mdCk7XFxzKGx1bWlhW1xcc1xcd10rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1pY3Jvc29mdCBMdW1pYVxuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgTU9ERUwsIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvW1xcc1xcKDtdKHhib3goPzpcXHNvbmUpPylbXFxzXFwpO10vaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTWljcm9zb2Z0IFhib3hcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ01pY3Jvc29mdCddLCBbVFlQRSwgQ09OU09MRV1dLCBbXG4gICAgICAgICAgICAvKGtpblxcLltvbmV0d117M30pL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNaWNyb3NvZnQgS2luXG4gICAgICAgICAgICBdLCBbW01PREVMLCAvXFwuL2csICcgJ10sIFtWRU5ET1IsICdNaWNyb3NvZnQnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTW90b3JvbGFcbiAgICAgICAgICAgIC9cXHMobWlsZXN0b25lfGRyb2lkKD86WzItNHhdfFxccyg/OmJpb25pY3x4Mnxwcm98cmF6cikpPyg6P1xcczRnKT8pW1xcd1xcc10rYnVpbGRcXC8vaSxcbiAgICAgICAgICAgIC9tb3RbXFxzLV0/KFxcdyspKi9pLFxuICAgICAgICAgICAgLyhYVFxcZHszLDR9KSBidWlsZFxcLy9pLFxuICAgICAgICAgICAgLyhuZXh1c1xcczYpL2lcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ01vdG9yb2xhJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgL2FuZHJvaWQuK1xccyhtejYwXFxkfHhvb21bXFxzMl17MCwyfSlcXHNidWlsZFxcLy9pXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdNb3Rvcm9sYSddLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgL2hiYnR2XFwvXFxkK1xcLlxcZCtcXC5cXGQrXFxzK1xcKFtcXHdcXHNdKjtcXHMqKFxcd1teO10qKTsoW147XSopL2kgICAgICAgICAgICAvLyBIYmJUViBkZXZpY2VzXG4gICAgICAgICAgICBdLCBbW1ZFTkRPUiwgdXRpbC50cmltXSwgW01PREVMLCB1dGlsLnRyaW1dLCBbVFlQRSwgU01BUlRUVl1dLCBbXG5cbiAgICAgICAgICAgIC9oYmJ0di4rbWFwbGU7KFxcZCspL2lcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsIC9eLywgJ1NtYXJ0VFYnXSwgW1ZFTkRPUiwgJ1NhbXN1bmcnXSwgW1RZUEUsIFNNQVJUVFZdXSwgW1xuXG4gICAgICAgICAgICAvXFwoZHR2W1xcKTtdLisoYXF1b3MpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2hhcnBcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ1NoYXJwJ10sIFtUWVBFLCBTTUFSVFRWXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuKygoc2NoLWlbODldMFxcZHxzaHctbTM4MHN8Z3QtcFxcZHs0fXxndC1uXFxkK3xzZ2gtdDhbNTZdOXxuZXh1cyAxMCkpL2ksXG4gICAgICAgICAgICAvKChTTS1UXFx3KykpL2lcbiAgICAgICAgICAgIF0sIFtbVkVORE9SLCAnU2Ftc3VuZyddLCBNT0RFTCwgW1RZUEUsIFRBQkxFVF1dLCBbICAgICAgICAgICAgICAgICAgLy8gU2Ftc3VuZ1xuICAgICAgICAgICAgL3NtYXJ0LXR2Lisoc2Ftc3VuZykvaVxuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgW1RZUEUsIFNNQVJUVFZdLCBNT0RFTF0sIFtcbiAgICAgICAgICAgIC8oKHNbY2dwXWgtXFx3K3xndC1cXHcrfGdhbGF4eVxcc25leHVzfHNtLVxcd1tcXHdcXGRdKykpL2ksXG4gICAgICAgICAgICAvKHNhbVtzdW5nXSopW1xccy1dKihcXHcrLT9bXFx3LV0qKSovaSxcbiAgICAgICAgICAgIC9zZWMtKChzZ2hcXHcrKSkvaVxuICAgICAgICAgICAgXSwgW1tWRU5ET1IsICdTYW1zdW5nJ10sIE1PREVMLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgL3NpZS0oXFx3KykqL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2llbWVuc1xuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnU2llbWVucyddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgLyhtYWVtb3xub2tpYSkuKihuOTAwfGx1bWlhXFxzXFxkKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5va2lhXG4gICAgICAgICAgICAvKG5va2lhKVtcXHNfLV0/KFtcXHctXSspKi9pXG4gICAgICAgICAgICBdLCBbW1ZFTkRPUiwgJ05va2lhJ10sIE1PREVMLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWRcXHMzXFwuW1xcc1xcdzstXXsxMH0oYVxcZHszfSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFjZXJcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0FjZXInXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkXFxzM1xcLltcXHNcXHc7LV17MTB9KGxnPyktKFswNmN2OV17Myw0fSkvaSAgICAgICAgICAgICAgICAgICAgIC8vIExHIFRhYmxldFxuICAgICAgICAgICAgXSwgW1tWRU5ET1IsICdMRyddLCBNT0RFTCwgW1RZUEUsIFRBQkxFVF1dLCBbXG4gICAgICAgICAgICAvKGxnKSBuZXRjYXN0XFwudHYvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBMRyBTbWFydFRWXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIFNNQVJUVFZdXSwgW1xuICAgICAgICAgICAgLyhuZXh1c1xcc1s0NV0pL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTEdcbiAgICAgICAgICAgIC9sZ1tlO1xcc1xcLy1dKyhcXHcrKSovaVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnTEcnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLisoaWRlYXRhYlthLXowLTlcXC1cXHNdKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBMZW5vdm9cbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0xlbm92byddLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgL2xpbnV4Oy4rKChqb2xsYSkpOy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBKb2xsYVxuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgTU9ERUwsIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKChwZWJibGUpKWFwcFxcL1tcXGRcXC5dK1xccy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQZWJibGVcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIE1PREVMLCBbVFlQRSwgV0VBUkFCTEVdXSwgW1xuXG4gICAgICAgICAgICAvYW5kcm9pZC4rO1xccyhnbGFzcylcXHNcXGQvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdvb2dsZSBHbGFzc1xuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnR29vZ2xlJ10sIFtUWVBFLCBXRUFSQUJMRV1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLisoXFx3KylcXHMrYnVpbGRcXC9obVxcMS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFhpYW9taSBIb25nbWkgJ251bWVyaWMnIG1vZGVsc1xuICAgICAgICAgICAgL2FuZHJvaWQuKyhobVtcXHNcXC1fXSpub3RlP1tcXHNfXSooPzpcXGRcXHcpPylcXHMrYnVpbGQvaSwgICAgICAgICAgICAgICAvLyBYaWFvbWkgSG9uZ21pXG4gICAgICAgICAgICAvYW5kcm9pZC4rKG1pW1xcc1xcLV9dKig/Om9uZXxvbmVbXFxzX11wbHVzfG5vdGUgbHRlKT9bXFxzX10qKD86XFxkXFx3KT8pXFxzK2J1aWxkL2kgICAgLy8gWGlhb21pIE1pXG4gICAgICAgICAgICBdLCBbW01PREVMLCAvXy9nLCAnICddLCBbVkVORE9SLCAnWGlhb21pJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvYW5kcm9pZC4rYTAwMCgxKVxccytidWlsZC9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPbmVQbHVzXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdPbmVQbHVzJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvXFxzKHRhYmxldClbO1xcL10vaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVW5pZGVudGlmaWFibGUgVGFibGV0XG4gICAgICAgICAgICAvXFxzKG1vYmlsZSkoPzpbO1xcL118XFxzc2FmYXJpKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVuaWRlbnRpZmlhYmxlIE1vYmlsZVxuICAgICAgICAgICAgXSwgW1tUWVBFLCB1dGlsLmxvd2VyaXplXSwgVkVORE9SLCBNT0RFTF1cblxuICAgICAgICAgICAgLyovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgICAgICAgICAgLy8gVE9ETzogbW92ZSB0byBzdHJpbmcgbWFwXG4gICAgICAgICAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbiAgICAgICAgICAgIC8oQzY2MDMpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU29ueSBYcGVyaWEgWiBDNjYwM1xuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ1hwZXJpYSBaIEM2NjAzJ10sIFtWRU5ET1IsICdTb255J10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgLyhDNjkwMykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTb255IFhwZXJpYSBaIDFcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdYcGVyaWEgWiAxJ10sIFtWRU5ET1IsICdTb255J10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKFNNLUc5MDBbRnxIXSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNhbXN1bmcgR2FsYXh5IFM1XG4gICAgICAgICAgICBdLCBbW01PREVMLCAnR2FsYXh5IFM1J10sIFtWRU5ET1IsICdTYW1zdW5nJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgLyhTTS1HNzEwMikvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTYW1zdW5nIEdhbGF4eSBHcmFuZCAyXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnR2FsYXh5IEdyYW5kIDInXSwgW1ZFTkRPUiwgJ1NhbXN1bmcnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKFNNLUc1MzBIKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNhbXN1bmcgR2FsYXh5IEdyYW5kIFByaW1lXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnR2FsYXh5IEdyYW5kIFByaW1lJ10sIFtWRU5ET1IsICdTYW1zdW5nJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgLyhTTS1HMzEzSFopL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTYW1zdW5nIEdhbGF4eSBWXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnR2FsYXh5IFYnXSwgW1ZFTkRPUiwgJ1NhbXN1bmcnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKFNNLVQ4MDUpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNhbXN1bmcgR2FsYXh5IFRhYiBTIDEwLjVcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdHYWxheHkgVGFiIFMgMTAuNSddLCBbVkVORE9SLCAnU2Ftc3VuZyddLCBbVFlQRSwgVEFCTEVUXV0sIFtcbiAgICAgICAgICAgIC8oU00tRzgwMEYpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2Ftc3VuZyBHYWxheHkgUzUgTWluaVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ0dhbGF4eSBTNSBNaW5pJ10sIFtWRU5ET1IsICdTYW1zdW5nJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgLyhTTS1UMzExKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTYW1zdW5nIEdhbGF4eSBUYWIgMyA4LjBcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdHYWxheHkgVGFiIDMgOC4wJ10sIFtWRU5ET1IsICdTYW1zdW5nJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuXG4gICAgICAgICAgICAvKFIxMDAxKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9wcG8gUjEwMDFcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ09QUE8nXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKFg5MDA2KS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9wcG8gRmluZCA3YVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ0ZpbmQgN2EnXSwgW1ZFTkRPUiwgJ09wcG8nXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKFIyMDAxKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9wcG8gWU9ZTyBSMjAwMVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ1lveW8gUjIwMDEnXSwgW1ZFTkRPUiwgJ09wcG8nXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKFI4MTUpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9wcG8gQ2xvdmVyIFI4MTVcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdDbG92ZXIgUjgxNSddLCBbVkVORE9SLCAnT3BwbyddLCBbVFlQRSwgTU9CSUxFXV0sIFtcbiAgICAgICAgICAgICAvKFU3MDcpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BwbyBGaW5kIFdheSBTXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnRmluZCBXYXkgUyddLCBbVkVORE9SLCAnT3BwbyddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgLyhUM0MpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBZHZhbiBWYW5kcm9pZCBUM0NcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0FkdmFuJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuICAgICAgICAgICAgLyhBRFZBTiBUMUpcXCspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWR2YW4gVmFuZHJvaWQgVDFKK1xuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ1ZhbmRyb2lkIFQxSisnXSwgW1ZFTkRPUiwgJ0FkdmFuJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuICAgICAgICAgICAgLyhBRFZBTiBTNEEpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBZHZhbiBWYW5kcm9pZCBTNEFcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdWYW5kcm9pZCBTNEEnXSwgW1ZFTkRPUiwgJ0FkdmFuJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKFY5NzJNKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFpURSBWOTcyTVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnWlRFJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKGktbW9iaWxlKVxccyhJUVxcc1tcXGRcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpLW1vYmlsZSBJUVxuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgTU9ERUwsIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgLyhJUTYuMykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpLW1vYmlsZSBJUSBJUSA2LjNcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdJUSA2LjMnXSwgW1ZFTkRPUiwgJ2ktbW9iaWxlJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgLyhpLW1vYmlsZSlcXHMoaS1zdHlsZVxcc1tcXGRcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaS1tb2JpbGUgaS1TVFlMRVxuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgTU9ERUwsIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgLyhpLVNUWUxFMi4xKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpLW1vYmlsZSBpLVNUWUxFIDIuMVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ2ktU1RZTEUgMi4xJ10sIFtWRU5ET1IsICdpLW1vYmlsZSddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgLyhtb2JpaXN0YXIgdG91Y2ggTEFJIDUxMikvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBtb2JpaXN0YXIgdG91Y2ggTEFJIDUxMlxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ1RvdWNoIExBSSA1MTInXSwgW1ZFTkRPUiwgJ21vYmlpc3RhciddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgLy8vLy8vLy8vLy8vL1xuICAgICAgICAgICAgLy8gRU5EIFRPRE9cbiAgICAgICAgICAgIC8vLy8vLy8vLy8vKi9cblxuICAgICAgICBdLFxuXG4gICAgICAgIGVuZ2luZSA6IFtbXG5cbiAgICAgICAgICAgIC93aW5kb3dzLitcXHNlZGdlXFwvKFtcXHdcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEVkZ2VIVE1MXG4gICAgICAgICAgICBdLCBbVkVSU0lPTiwgW05BTUUsICdFZGdlSFRNTCddXSwgW1xuXG4gICAgICAgICAgICAvKHByZXN0bylcXC8oW1xcd1xcLl0rKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFByZXN0b1xuICAgICAgICAgICAgLyh3ZWJraXR8dHJpZGVudHxuZXRmcm9udHxuZXRzdXJmfGFtYXlhfGx5bnh8dzNtKVxcLyhbXFx3XFwuXSspL2ksICAgICAvLyBXZWJLaXQvVHJpZGVudC9OZXRGcm9udC9OZXRTdXJmL0FtYXlhL0x5bngvdzNtXG4gICAgICAgICAgICAvKGtodG1sfHRhc21hbnxsaW5rcylbXFwvXFxzXVxcKD8oW1xcd1xcLl0rKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gS0hUTUwvVGFzbWFuL0xpbmtzXG4gICAgICAgICAgICAvKGljYWIpW1xcL1xcc10oWzIzXVxcLltcXGRcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaUNhYlxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC9ydlxcOihbXFx3XFwuXSspLiooZ2Vja28pL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR2Vja29cbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBOQU1FXVxuICAgICAgICBdLFxuXG4gICAgICAgIG9zIDogW1tcblxuICAgICAgICAgICAgLy8gV2luZG93cyBiYXNlZFxuICAgICAgICAgICAgL21pY3Jvc29mdFxccyh3aW5kb3dzKVxccyh2aXN0YXx4cCkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFdpbmRvd3MgKGlUdW5lcylcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuICAgICAgICAgICAgLyh3aW5kb3dzKVxcc250XFxzNlxcLjI7XFxzKGFybSkvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2luZG93cyBSVFxuICAgICAgICAgICAgLyh3aW5kb3dzXFxzcGhvbmUoPzpcXHNvcykqKVtcXHNcXC9dPyhbXFxkXFwuXFxzXStcXHcpKi9pLCAgICAgICAgICAgICAgICAgIC8vIFdpbmRvd3MgUGhvbmVcbiAgICAgICAgICAgIC8od2luZG93c1xcc21vYmlsZXx3aW5kb3dzKVtcXHNcXC9dPyhbbnRjZVxcZFxcLlxcc10rXFx3KS9pXG4gICAgICAgICAgICBdLCBbTkFNRSwgW1ZFUlNJT04sIG1hcHBlci5zdHIsIG1hcHMub3Mud2luZG93cy52ZXJzaW9uXV0sIFtcbiAgICAgICAgICAgIC8od2luKD89M3w5fG4pfHdpblxcczl4XFxzKShbbnRcXGRcXC5dKykvaVxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnV2luZG93cyddLCBbVkVSU0lPTiwgbWFwcGVyLnN0ciwgbWFwcy5vcy53aW5kb3dzLnZlcnNpb25dXSwgW1xuXG4gICAgICAgICAgICAvLyBNb2JpbGUvRW1iZWRkZWQgT1NcbiAgICAgICAgICAgIC9cXCgoYmIpKDEwKTsvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEJsYWNrQmVycnkgMTBcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ0JsYWNrQmVycnknXSwgVkVSU0lPTl0sIFtcbiAgICAgICAgICAgIC8oYmxhY2tiZXJyeSlcXHcqXFwvPyhbXFx3XFwuXSspKi9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEJsYWNrYmVycnlcbiAgICAgICAgICAgIC8odGl6ZW4pW1xcL1xcc10oW1xcd1xcLl0rKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRpemVuXG4gICAgICAgICAgICAvKGFuZHJvaWR8d2Vib3N8cGFsbVxcc29zfHFueHxiYWRhfHJpbVxcc3RhYmxldFxcc29zfG1lZWdvfGNvbnRpa2kpW1xcL1xccy1dPyhbXFx3XFwuXSspKi9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBbmRyb2lkL1dlYk9TL1BhbG0vUU5YL0JhZGEvUklNL01lZUdvL0NvbnRpa2lcbiAgICAgICAgICAgIC9saW51eDsuKyhzYWlsZmlzaCk7L2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2FpbGZpc2ggT1NcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuICAgICAgICAgICAgLyhzeW1iaWFuXFxzP29zfHN5bWJvc3xzNjAoPz07KSlbXFwvXFxzLV0/KFtcXHdcXC5dKykqL2kgICAgICAgICAgICAgICAgIC8vIFN5bWJpYW5cbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ1N5bWJpYW4nXSwgVkVSU0lPTl0sIFtcbiAgICAgICAgICAgIC9cXCgoc2VyaWVzNDApOy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNlcmllcyA0MFxuICAgICAgICAgICAgXSwgW05BTUVdLCBbXG4gICAgICAgICAgICAvbW96aWxsYS4rXFwobW9iaWxlOy4rZ2Vja28uK2ZpcmVmb3gvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGaXJlZm94IE9TXG4gICAgICAgICAgICBdLCBbW05BTUUsICdGaXJlZm94IE9TJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8vIENvbnNvbGVcbiAgICAgICAgICAgIC8obmludGVuZG98cGxheXN0YXRpb24pXFxzKFt3aWRzMzRwb3J0YWJsZXZ1XSspL2ksICAgICAgICAgICAgICAgICAgIC8vIE5pbnRlbmRvL1BsYXlzdGF0aW9uXG5cbiAgICAgICAgICAgIC8vIEdOVS9MaW51eCBiYXNlZFxuICAgICAgICAgICAgLyhtaW50KVtcXC9cXHNcXChdPyhcXHcrKSovaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTWludFxuICAgICAgICAgICAgLyhtYWdlaWF8dmVjdG9ybGludXgpWztcXHNdL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTWFnZWlhL1ZlY3RvckxpbnV4XG4gICAgICAgICAgICAvKGpvbGl8W2t4bG5dP3VidW50dXxkZWJpYW58W29wZW5dKnN1c2V8Z2VudG9vfCg/PVxccylhcmNofHNsYWNrd2FyZXxmZWRvcmF8bWFuZHJpdmF8Y2VudG9zfHBjbGludXhvc3xyZWRoYXR8emVud2Fsa3xsaW5wdXMpW1xcL1xccy1dPyg/IWNocm9tKShbXFx3XFwuLV0rKSovaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSm9saS9VYnVudHUvRGViaWFuL1NVU0UvR2VudG9vL0FyY2gvU2xhY2t3YXJlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZlZG9yYS9NYW5kcml2YS9DZW50T1MvUENMaW51eE9TL1JlZEhhdC9aZW53YWxrL0xpbnB1c1xuICAgICAgICAgICAgLyhodXJkfGxpbnV4KVxccz8oW1xcd1xcLl0rKSovaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIdXJkL0xpbnV4XG4gICAgICAgICAgICAvKGdudSlcXHM/KFtcXHdcXC5dKykqL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdOVVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oY3JvcylcXHNbXFx3XStcXHMoW1xcd1xcLl0rXFx3KS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2hyb21pdW0gT1NcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ0Nocm9taXVtIE9TJ10sIFZFUlNJT05dLFtcblxuICAgICAgICAgICAgLy8gU29sYXJpc1xuICAgICAgICAgICAgLyhzdW5vcylcXHM/KFtcXHdcXC5dK1xcZCkqL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU29sYXJpc1xuICAgICAgICAgICAgXSwgW1tOQU1FLCAnU29sYXJpcyddLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvLyBCU0QgYmFzZWRcbiAgICAgICAgICAgIC9cXHMoW2ZyZW50b3BjLV17MCw0fWJzZHxkcmFnb25mbHkpXFxzPyhbXFx3XFwuXSspKi9pICAgICAgICAgICAgICAgICAgIC8vIEZyZWVCU0QvTmV0QlNEL09wZW5CU0QvUEMtQlNEL0RyYWdvbkZseVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLFtcblxuICAgICAgICAgICAgLyhoYWlrdSlcXHMoXFx3KykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSGFpa3VcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSxbXG5cbiAgICAgICAgICAgIC8oaXBbaG9uZWFkXSspKD86Lipvc1xccyhbXFx3XSspKlxcc2xpa2VcXHNtYWN8O1xcc29wZXJhKS9pICAgICAgICAgICAgICAvLyBpT1NcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ2lPUyddLCBbVkVSU0lPTiwgL18vZywgJy4nXV0sIFtcblxuICAgICAgICAgICAgLyhtYWNcXHNvc1xcc3gpXFxzPyhbXFx3XFxzXFwuXStcXHcpKi9pLFxuICAgICAgICAgICAgLyhtYWNpbnRvc2h8bWFjKD89X3Bvd2VycGMpXFxzKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTWFjIE9TXG4gICAgICAgICAgICBdLCBbW05BTUUsICdNYWMgT1MnXSwgW1ZFUlNJT04sIC9fL2csICcuJ11dLCBbXG5cbiAgICAgICAgICAgIC8vIE90aGVyXG4gICAgICAgICAgICAvKCg/Om9wZW4pP3NvbGFyaXMpW1xcL1xccy1dPyhbXFx3XFwuXSspKi9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTb2xhcmlzXG4gICAgICAgICAgICAvKGFpeClcXHMoKFxcZCkoPz1cXC58XFwpfFxccylbXFx3XFwuXSopKi9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBSVhcbiAgICAgICAgICAgIC8ocGxhblxcczl8bWluaXh8YmVvc3xvc1xcLzJ8YW1pZ2Fvc3xtb3JwaG9zfHJpc2NcXHNvc3xvcGVudm1zKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQbGFuOS9NaW5peC9CZU9TL09TMi9BbWlnYU9TL01vcnBoT1MvUklTQ09TL09wZW5WTVNcbiAgICAgICAgICAgIC8odW5peClcXHM/KFtcXHdcXC5dKykqL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVU5JWFxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dXG4gICAgICAgIF1cbiAgICB9O1xuXG5cbiAgICAvLy8vLy8vLy8vLy8vLy8vL1xuICAgIC8vIENvbnN0cnVjdG9yXG4gICAgLy8vLy8vLy8vLy8vLy8vL1xuXG5cbiAgICB2YXIgVUFQYXJzZXIgPSBmdW5jdGlvbiAodWFzdHJpbmcsIGV4dGVuc2lvbnMpIHtcblxuICAgICAgICBpZiAoISh0aGlzIGluc3RhbmNlb2YgVUFQYXJzZXIpKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFVBUGFyc2VyKHVhc3RyaW5nLCBleHRlbnNpb25zKS5nZXRSZXN1bHQoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB1YSA9IHVhc3RyaW5nIHx8ICgod2luZG93ICYmIHdpbmRvdy5uYXZpZ2F0b3IgJiYgd2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQpID8gd2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQgOiBFTVBUWSk7XG4gICAgICAgIHZhciByZ3htYXAgPSBleHRlbnNpb25zID8gdXRpbC5leHRlbmQocmVnZXhlcywgZXh0ZW5zaW9ucykgOiByZWdleGVzO1xuXG4gICAgICAgIHRoaXMuZ2V0QnJvd3NlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBicm93c2VyID0gbWFwcGVyLnJneC5hcHBseSh0aGlzLCByZ3htYXAuYnJvd3Nlcik7XG4gICAgICAgICAgICBicm93c2VyLm1ham9yID0gdXRpbC5tYWpvcihicm93c2VyLnZlcnNpb24pO1xuICAgICAgICAgICAgcmV0dXJuIGJyb3dzZXI7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZ2V0Q1BVID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIG1hcHBlci5yZ3guYXBwbHkodGhpcywgcmd4bWFwLmNwdSk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZ2V0RGV2aWNlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIG1hcHBlci5yZ3guYXBwbHkodGhpcywgcmd4bWFwLmRldmljZSk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZ2V0RW5naW5lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIG1hcHBlci5yZ3guYXBwbHkodGhpcywgcmd4bWFwLmVuZ2luZSk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZ2V0T1MgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gbWFwcGVyLnJneC5hcHBseSh0aGlzLCByZ3htYXAub3MpO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmdldFJlc3VsdCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB1YSAgICAgIDogdGhpcy5nZXRVQSgpLFxuICAgICAgICAgICAgICAgIGJyb3dzZXIgOiB0aGlzLmdldEJyb3dzZXIoKSxcbiAgICAgICAgICAgICAgICBlbmdpbmUgIDogdGhpcy5nZXRFbmdpbmUoKSxcbiAgICAgICAgICAgICAgICBvcyAgICAgIDogdGhpcy5nZXRPUygpLFxuICAgICAgICAgICAgICAgIGRldmljZSAgOiB0aGlzLmdldERldmljZSgpLFxuICAgICAgICAgICAgICAgIGNwdSAgICAgOiB0aGlzLmdldENQVSgpXG4gICAgICAgICAgICB9O1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmdldFVBID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHVhO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLnNldFVBID0gZnVuY3Rpb24gKHVhc3RyaW5nKSB7XG4gICAgICAgICAgICB1YSA9IHVhc3RyaW5nO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICBVQVBhcnNlci5WRVJTSU9OID0gTElCVkVSU0lPTjtcbiAgICBVQVBhcnNlci5CUk9XU0VSID0ge1xuICAgICAgICBOQU1FICAgIDogTkFNRSxcbiAgICAgICAgTUFKT1IgICA6IE1BSk9SLCAvLyBkZXByZWNhdGVkXG4gICAgICAgIFZFUlNJT04gOiBWRVJTSU9OXG4gICAgfTtcbiAgICBVQVBhcnNlci5DUFUgPSB7XG4gICAgICAgIEFSQ0hJVEVDVFVSRSA6IEFSQ0hJVEVDVFVSRVxuICAgIH07XG4gICAgVUFQYXJzZXIuREVWSUNFID0ge1xuICAgICAgICBNT0RFTCAgIDogTU9ERUwsXG4gICAgICAgIFZFTkRPUiAgOiBWRU5ET1IsXG4gICAgICAgIFRZUEUgICAgOiBUWVBFLFxuICAgICAgICBDT05TT0xFIDogQ09OU09MRSxcbiAgICAgICAgTU9CSUxFICA6IE1PQklMRSxcbiAgICAgICAgU01BUlRUViA6IFNNQVJUVFYsXG4gICAgICAgIFRBQkxFVCAgOiBUQUJMRVQsXG4gICAgICAgIFdFQVJBQkxFOiBXRUFSQUJMRSxcbiAgICAgICAgRU1CRURERUQ6IEVNQkVEREVEXG4gICAgfTtcbiAgICBVQVBhcnNlci5FTkdJTkUgPSB7XG4gICAgICAgIE5BTUUgICAgOiBOQU1FLFxuICAgICAgICBWRVJTSU9OIDogVkVSU0lPTlxuICAgIH07XG4gICAgVUFQYXJzZXIuT1MgPSB7XG4gICAgICAgIE5BTUUgICAgOiBOQU1FLFxuICAgICAgICBWRVJTSU9OIDogVkVSU0lPTlxuICAgIH07XG5cblxuICAgIC8vLy8vLy8vLy8vXG4gICAgLy8gRXhwb3J0XG4gICAgLy8vLy8vLy8vL1xuXG5cbiAgICAvLyBjaGVjayBqcyBlbnZpcm9ubWVudFxuICAgIGlmICh0eXBlb2YoZXhwb3J0cykgIT09IFVOREVGX1RZUEUpIHtcbiAgICAgICAgLy8gbm9kZWpzIGVudlxuICAgICAgICBpZiAodHlwZW9mIG1vZHVsZSAhPT0gVU5ERUZfVFlQRSAmJiBtb2R1bGUuZXhwb3J0cykge1xuICAgICAgICAgICAgZXhwb3J0cyA9IG1vZHVsZS5leHBvcnRzID0gVUFQYXJzZXI7XG4gICAgICAgIH1cbiAgICAgICAgZXhwb3J0cy5VQVBhcnNlciA9IFVBUGFyc2VyO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIHJlcXVpcmVqcyBlbnYgKG9wdGlvbmFsKVxuICAgICAgICBpZiAodHlwZW9mKGRlZmluZSkgPT09IEZVTkNfVFlQRSAmJiBkZWZpbmUuYW1kKSB7XG4gICAgICAgICAgICBkZWZpbmUoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBVQVBhcnNlcjtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gYnJvd3NlciBlbnZcbiAgICAgICAgICAgIHdpbmRvdy5VQVBhcnNlciA9IFVBUGFyc2VyO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8galF1ZXJ5L1plcHRvIHNwZWNpZmljIChvcHRpb25hbClcbiAgICAvLyBOb3RlOlxuICAgIC8vICAgSW4gQU1EIGVudiB0aGUgZ2xvYmFsIHNjb3BlIHNob3VsZCBiZSBrZXB0IGNsZWFuLCBidXQgalF1ZXJ5IGlzIGFuIGV4Y2VwdGlvbi5cbiAgICAvLyAgIGpRdWVyeSBhbHdheXMgZXhwb3J0cyB0byBnbG9iYWwgc2NvcGUsIHVubGVzcyBqUXVlcnkubm9Db25mbGljdCh0cnVlKSBpcyB1c2VkLFxuICAgIC8vICAgYW5kIHdlIHNob3VsZCBjYXRjaCB0aGF0LlxuICAgIHZhciAkID0gd2luZG93LmpRdWVyeSB8fCB3aW5kb3cuWmVwdG87XG4gICAgaWYgKHR5cGVvZiAkICE9PSBVTkRFRl9UWVBFKSB7XG4gICAgICAgIHZhciBwYXJzZXIgPSBuZXcgVUFQYXJzZXIoKTtcbiAgICAgICAgJC51YSA9IHBhcnNlci5nZXRSZXN1bHQoKTtcbiAgICAgICAgJC51YS5nZXQgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJzZXIuZ2V0VUEoKTtcbiAgICAgICAgfTtcbiAgICAgICAgJC51YS5zZXQgPSBmdW5jdGlvbiAodWFzdHJpbmcpIHtcbiAgICAgICAgICAgIHBhcnNlci5zZXRVQSh1YXN0cmluZyk7XG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gcGFyc2VyLmdldFJlc3VsdCgpO1xuICAgICAgICAgICAgZm9yICh2YXIgcHJvcCBpbiByZXN1bHQpIHtcbiAgICAgICAgICAgICAgICAkLnVhW3Byb3BdID0gcmVzdWx0W3Byb3BdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgIH1cblxufSkodHlwZW9mIHdpbmRvdyA9PT0gJ29iamVjdCcgPyB3aW5kb3cgOiB0aGlzKTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHJlcXVpcmVkID0gcmVxdWlyZSgncmVxdWlyZXMtcG9ydCcpXG4gICwgcXMgPSByZXF1aXJlKCdxdWVyeXN0cmluZ2lmeScpXG4gICwgcHJvdG9jb2xyZSA9IC9eKFthLXpdW2EtejAtOS4rLV0qOik/KFxcL1xcLyk/KFtcXFNcXHNdKikvaVxuICAsIHNsYXNoZXMgPSAvXltBLVphLXpdW0EtWmEtejAtOSstLl0qOlxcL1xcLy87XG5cbi8qKlxuICogVGhlc2UgYXJlIHRoZSBwYXJzZSBydWxlcyBmb3IgdGhlIFVSTCBwYXJzZXIsIGl0IGluZm9ybXMgdGhlIHBhcnNlclxuICogYWJvdXQ6XG4gKlxuICogMC4gVGhlIGNoYXIgaXQgTmVlZHMgdG8gcGFyc2UsIGlmIGl0J3MgYSBzdHJpbmcgaXQgc2hvdWxkIGJlIGRvbmUgdXNpbmdcbiAqICAgIGluZGV4T2YsIFJlZ0V4cCB1c2luZyBleGVjIGFuZCBOYU4gbWVhbnMgc2V0IGFzIGN1cnJlbnQgdmFsdWUuXG4gKiAxLiBUaGUgcHJvcGVydHkgd2Ugc2hvdWxkIHNldCB3aGVuIHBhcnNpbmcgdGhpcyB2YWx1ZS5cbiAqIDIuIEluZGljYXRpb24gaWYgaXQncyBiYWNrd2FyZHMgb3IgZm9yd2FyZCBwYXJzaW5nLCB3aGVuIHNldCBhcyBudW1iZXIgaXQnc1xuICogICAgdGhlIHZhbHVlIG9mIGV4dHJhIGNoYXJzIHRoYXQgc2hvdWxkIGJlIHNwbGl0IG9mZi5cbiAqIDMuIEluaGVyaXQgZnJvbSBsb2NhdGlvbiBpZiBub24gZXhpc3RpbmcgaW4gdGhlIHBhcnNlci5cbiAqIDQuIGB0b0xvd2VyQ2FzZWAgdGhlIHJlc3VsdGluZyB2YWx1ZS5cbiAqL1xudmFyIHJ1bGVzID0gW1xuICBbJyMnLCAnaGFzaCddLCAgICAgICAgICAgICAgICAgICAgICAgIC8vIEV4dHJhY3QgZnJvbSB0aGUgYmFjay5cbiAgWyc/JywgJ3F1ZXJ5J10sICAgICAgICAgICAgICAgICAgICAgICAvLyBFeHRyYWN0IGZyb20gdGhlIGJhY2suXG4gIFsnLycsICdwYXRobmFtZSddLCAgICAgICAgICAgICAgICAgICAgLy8gRXh0cmFjdCBmcm9tIHRoZSBiYWNrLlxuICBbJ0AnLCAnYXV0aCcsIDFdLCAgICAgICAgICAgICAgICAgICAgIC8vIEV4dHJhY3QgZnJvbSB0aGUgZnJvbnQuXG4gIFtOYU4sICdob3N0JywgdW5kZWZpbmVkLCAxLCAxXSwgICAgICAgLy8gU2V0IGxlZnQgb3ZlciB2YWx1ZS5cbiAgWy86KFxcZCspJC8sICdwb3J0JywgdW5kZWZpbmVkLCAxXSwgICAgLy8gUmVnRXhwIHRoZSBiYWNrLlxuICBbTmFOLCAnaG9zdG5hbWUnLCB1bmRlZmluZWQsIDEsIDFdICAgIC8vIFNldCBsZWZ0IG92ZXIuXG5dO1xuXG4vKipcbiAqIFRoZXNlIHByb3BlcnRpZXMgc2hvdWxkIG5vdCBiZSBjb3BpZWQgb3IgaW5oZXJpdGVkIGZyb20uIFRoaXMgaXMgb25seSBuZWVkZWRcbiAqIGZvciBhbGwgbm9uIGJsb2IgVVJMJ3MgYXMgYSBibG9iIFVSTCBkb2VzIG5vdCBpbmNsdWRlIGEgaGFzaCwgb25seSB0aGVcbiAqIG9yaWdpbi5cbiAqXG4gKiBAdHlwZSB7T2JqZWN0fVxuICogQHByaXZhdGVcbiAqL1xudmFyIGlnbm9yZSA9IHsgaGFzaDogMSwgcXVlcnk6IDEgfTtcblxuLyoqXG4gKiBUaGUgbG9jYXRpb24gb2JqZWN0IGRpZmZlcnMgd2hlbiB5b3VyIGNvZGUgaXMgbG9hZGVkIHRocm91Z2ggYSBub3JtYWwgcGFnZSxcbiAqIFdvcmtlciBvciB0aHJvdWdoIGEgd29ya2VyIHVzaW5nIGEgYmxvYi4gQW5kIHdpdGggdGhlIGJsb2JibGUgYmVnaW5zIHRoZVxuICogdHJvdWJsZSBhcyB0aGUgbG9jYXRpb24gb2JqZWN0IHdpbGwgY29udGFpbiB0aGUgVVJMIG9mIHRoZSBibG9iLCBub3QgdGhlXG4gKiBsb2NhdGlvbiBvZiB0aGUgcGFnZSB3aGVyZSBvdXIgY29kZSBpcyBsb2FkZWQgaW4uIFRoZSBhY3R1YWwgb3JpZ2luIGlzXG4gKiBlbmNvZGVkIGluIHRoZSBgcGF0aG5hbWVgIHNvIHdlIGNhbiB0aGFua2Z1bGx5IGdlbmVyYXRlIGEgZ29vZCBcImRlZmF1bHRcIlxuICogbG9jYXRpb24gZnJvbSBpdCBzbyB3ZSBjYW4gZ2VuZXJhdGUgcHJvcGVyIHJlbGF0aXZlIFVSTCdzIGFnYWluLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gbG9jIE9wdGlvbmFsIGRlZmF1bHQgbG9jYXRpb24gb2JqZWN0LlxuICogQHJldHVybnMge09iamVjdH0gbG9sY2F0aW9uIG9iamVjdC5cbiAqIEBhcGkgcHVibGljXG4gKi9cbmZ1bmN0aW9uIGxvbGNhdGlvbihsb2MpIHtcbiAgbG9jID0gbG9jIHx8IGdsb2JhbC5sb2NhdGlvbiB8fCB7fTtcblxuICB2YXIgZmluYWxkZXN0aW5hdGlvbiA9IHt9XG4gICAgLCB0eXBlID0gdHlwZW9mIGxvY1xuICAgICwga2V5O1xuXG4gIGlmICgnYmxvYjonID09PSBsb2MucHJvdG9jb2wpIHtcbiAgICBmaW5hbGRlc3RpbmF0aW9uID0gbmV3IFVSTCh1bmVzY2FwZShsb2MucGF0aG5hbWUpLCB7fSk7XG4gIH0gZWxzZSBpZiAoJ3N0cmluZycgPT09IHR5cGUpIHtcbiAgICBmaW5hbGRlc3RpbmF0aW9uID0gbmV3IFVSTChsb2MsIHt9KTtcbiAgICBmb3IgKGtleSBpbiBpZ25vcmUpIGRlbGV0ZSBmaW5hbGRlc3RpbmF0aW9uW2tleV07XG4gIH0gZWxzZSBpZiAoJ29iamVjdCcgPT09IHR5cGUpIHtcbiAgICBmb3IgKGtleSBpbiBsb2MpIHtcbiAgICAgIGlmIChrZXkgaW4gaWdub3JlKSBjb250aW51ZTtcbiAgICAgIGZpbmFsZGVzdGluYXRpb25ba2V5XSA9IGxvY1trZXldO1xuICAgIH1cblxuICAgIGlmIChmaW5hbGRlc3RpbmF0aW9uLnNsYXNoZXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgZmluYWxkZXN0aW5hdGlvbi5zbGFzaGVzID0gc2xhc2hlcy50ZXN0KGxvYy5ocmVmKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gZmluYWxkZXN0aW5hdGlvbjtcbn1cblxuLyoqXG4gKiBAdHlwZWRlZiBQcm90b2NvbEV4dHJhY3RcbiAqIEB0eXBlIE9iamVjdFxuICogQHByb3BlcnR5IHtTdHJpbmd9IHByb3RvY29sIFByb3RvY29sIG1hdGNoZWQgaW4gdGhlIFVSTCwgaW4gbG93ZXJjYXNlLlxuICogQHByb3BlcnR5IHtCb29sZWFufSBzbGFzaGVzIGB0cnVlYCBpZiBwcm90b2NvbCBpcyBmb2xsb3dlZCBieSBcIi8vXCIsIGVsc2UgYGZhbHNlYC5cbiAqIEBwcm9wZXJ0eSB7U3RyaW5nfSByZXN0IFJlc3Qgb2YgdGhlIFVSTCB0aGF0IGlzIG5vdCBwYXJ0IG9mIHRoZSBwcm90b2NvbC5cbiAqL1xuXG4vKipcbiAqIEV4dHJhY3QgcHJvdG9jb2wgaW5mb3JtYXRpb24gZnJvbSBhIFVSTCB3aXRoL3dpdGhvdXQgZG91YmxlIHNsYXNoIChcIi8vXCIpLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBhZGRyZXNzIFVSTCB3ZSB3YW50IHRvIGV4dHJhY3QgZnJvbS5cbiAqIEByZXR1cm4ge1Byb3RvY29sRXh0cmFjdH0gRXh0cmFjdGVkIGluZm9ybWF0aW9uLlxuICogQGFwaSBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGV4dHJhY3RQcm90b2NvbChhZGRyZXNzKSB7XG4gIHZhciBtYXRjaCA9IHByb3RvY29scmUuZXhlYyhhZGRyZXNzKTtcblxuICByZXR1cm4ge1xuICAgIHByb3RvY29sOiBtYXRjaFsxXSA/IG1hdGNoWzFdLnRvTG93ZXJDYXNlKCkgOiAnJyxcbiAgICBzbGFzaGVzOiAhIW1hdGNoWzJdLFxuICAgIHJlc3Q6IG1hdGNoWzNdXG4gIH07XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhIHJlbGF0aXZlIFVSTCBwYXRobmFtZSBhZ2FpbnN0IGEgYmFzZSBVUkwgcGF0aG5hbWUuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHJlbGF0aXZlIFBhdGhuYW1lIG9mIHRoZSByZWxhdGl2ZSBVUkwuXG4gKiBAcGFyYW0ge1N0cmluZ30gYmFzZSBQYXRobmFtZSBvZiB0aGUgYmFzZSBVUkwuXG4gKiBAcmV0dXJuIHtTdHJpbmd9IFJlc29sdmVkIHBhdGhuYW1lLlxuICogQGFwaSBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIHJlc29sdmUocmVsYXRpdmUsIGJhc2UpIHtcbiAgdmFyIHBhdGggPSAoYmFzZSB8fCAnLycpLnNwbGl0KCcvJykuc2xpY2UoMCwgLTEpLmNvbmNhdChyZWxhdGl2ZS5zcGxpdCgnLycpKVxuICAgICwgaSA9IHBhdGgubGVuZ3RoXG4gICAgLCBsYXN0ID0gcGF0aFtpIC0gMV1cbiAgICAsIHVuc2hpZnQgPSBmYWxzZVxuICAgICwgdXAgPSAwO1xuXG4gIHdoaWxlIChpLS0pIHtcbiAgICBpZiAocGF0aFtpXSA9PT0gJy4nKSB7XG4gICAgICBwYXRoLnNwbGljZShpLCAxKTtcbiAgICB9IGVsc2UgaWYgKHBhdGhbaV0gPT09ICcuLicpIHtcbiAgICAgIHBhdGguc3BsaWNlKGksIDEpO1xuICAgICAgdXArKztcbiAgICB9IGVsc2UgaWYgKHVwKSB7XG4gICAgICBpZiAoaSA9PT0gMCkgdW5zaGlmdCA9IHRydWU7XG4gICAgICBwYXRoLnNwbGljZShpLCAxKTtcbiAgICAgIHVwLS07XG4gICAgfVxuICB9XG5cbiAgaWYgKHVuc2hpZnQpIHBhdGgudW5zaGlmdCgnJyk7XG4gIGlmIChsYXN0ID09PSAnLicgfHwgbGFzdCA9PT0gJy4uJykgcGF0aC5wdXNoKCcnKTtcblxuICByZXR1cm4gcGF0aC5qb2luKCcvJyk7XG59XG5cbi8qKlxuICogVGhlIGFjdHVhbCBVUkwgaW5zdGFuY2UuIEluc3RlYWQgb2YgcmV0dXJuaW5nIGFuIG9iamVjdCB3ZSd2ZSBvcHRlZC1pbiB0b1xuICogY3JlYXRlIGFuIGFjdHVhbCBjb25zdHJ1Y3RvciBhcyBpdCdzIG11Y2ggbW9yZSBtZW1vcnkgZWZmaWNpZW50IGFuZFxuICogZmFzdGVyIGFuZCBpdCBwbGVhc2VzIG15IE9DRC5cbiAqXG4gKiBAY29uc3RydWN0b3JcbiAqIEBwYXJhbSB7U3RyaW5nfSBhZGRyZXNzIFVSTCB3ZSB3YW50IHRvIHBhcnNlLlxuICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBsb2NhdGlvbiBMb2NhdGlvbiBkZWZhdWx0cyBmb3IgcmVsYXRpdmUgcGF0aHMuXG4gKiBAcGFyYW0ge0Jvb2xlYW58RnVuY3Rpb259IHBhcnNlciBQYXJzZXIgZm9yIHRoZSBxdWVyeSBzdHJpbmcuXG4gKiBAYXBpIHB1YmxpY1xuICovXG5mdW5jdGlvbiBVUkwoYWRkcmVzcywgbG9jYXRpb24sIHBhcnNlcikge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgVVJMKSkge1xuICAgIHJldHVybiBuZXcgVVJMKGFkZHJlc3MsIGxvY2F0aW9uLCBwYXJzZXIpO1xuICB9XG5cbiAgdmFyIHJlbGF0aXZlLCBleHRyYWN0ZWQsIHBhcnNlLCBpbnN0cnVjdGlvbiwgaW5kZXgsIGtleVxuICAgICwgaW5zdHJ1Y3Rpb25zID0gcnVsZXMuc2xpY2UoKVxuICAgICwgdHlwZSA9IHR5cGVvZiBsb2NhdGlvblxuICAgICwgdXJsID0gdGhpc1xuICAgICwgaSA9IDA7XG5cbiAgLy9cbiAgLy8gVGhlIGZvbGxvd2luZyBpZiBzdGF0ZW1lbnRzIGFsbG93cyB0aGlzIG1vZHVsZSB0d28gaGF2ZSBjb21wYXRpYmlsaXR5IHdpdGhcbiAgLy8gMiBkaWZmZXJlbnQgQVBJOlxuICAvL1xuICAvLyAxLiBOb2RlLmpzJ3MgYHVybC5wYXJzZWAgYXBpIHdoaWNoIGFjY2VwdHMgYSBVUkwsIGJvb2xlYW4gYXMgYXJndW1lbnRzXG4gIC8vICAgIHdoZXJlIHRoZSBib29sZWFuIGluZGljYXRlcyB0aGF0IHRoZSBxdWVyeSBzdHJpbmcgc2hvdWxkIGFsc28gYmUgcGFyc2VkLlxuICAvL1xuICAvLyAyLiBUaGUgYFVSTGAgaW50ZXJmYWNlIG9mIHRoZSBicm93c2VyIHdoaWNoIGFjY2VwdHMgYSBVUkwsIG9iamVjdCBhc1xuICAvLyAgICBhcmd1bWVudHMuIFRoZSBzdXBwbGllZCBvYmplY3Qgd2lsbCBiZSB1c2VkIGFzIGRlZmF1bHQgdmFsdWVzIC8gZmFsbC1iYWNrXG4gIC8vICAgIGZvciByZWxhdGl2ZSBwYXRocy5cbiAgLy9cbiAgaWYgKCdvYmplY3QnICE9PSB0eXBlICYmICdzdHJpbmcnICE9PSB0eXBlKSB7XG4gICAgcGFyc2VyID0gbG9jYXRpb247XG4gICAgbG9jYXRpb24gPSBudWxsO1xuICB9XG5cbiAgaWYgKHBhcnNlciAmJiAnZnVuY3Rpb24nICE9PSB0eXBlb2YgcGFyc2VyKSBwYXJzZXIgPSBxcy5wYXJzZTtcblxuICBsb2NhdGlvbiA9IGxvbGNhdGlvbihsb2NhdGlvbik7XG5cbiAgLy9cbiAgLy8gRXh0cmFjdCBwcm90b2NvbCBpbmZvcm1hdGlvbiBiZWZvcmUgcnVubmluZyB0aGUgaW5zdHJ1Y3Rpb25zLlxuICAvL1xuICBleHRyYWN0ZWQgPSBleHRyYWN0UHJvdG9jb2woYWRkcmVzcyB8fCAnJyk7XG4gIHJlbGF0aXZlID0gIWV4dHJhY3RlZC5wcm90b2NvbCAmJiAhZXh0cmFjdGVkLnNsYXNoZXM7XG4gIHVybC5zbGFzaGVzID0gZXh0cmFjdGVkLnNsYXNoZXMgfHwgcmVsYXRpdmUgJiYgbG9jYXRpb24uc2xhc2hlcztcbiAgdXJsLnByb3RvY29sID0gZXh0cmFjdGVkLnByb3RvY29sIHx8IGxvY2F0aW9uLnByb3RvY29sIHx8ICcnO1xuICBhZGRyZXNzID0gZXh0cmFjdGVkLnJlc3Q7XG5cbiAgLy9cbiAgLy8gV2hlbiB0aGUgYXV0aG9yaXR5IGNvbXBvbmVudCBpcyBhYnNlbnQgdGhlIFVSTCBzdGFydHMgd2l0aCBhIHBhdGhcbiAgLy8gY29tcG9uZW50LlxuICAvL1xuICBpZiAoIWV4dHJhY3RlZC5zbGFzaGVzKSBpbnN0cnVjdGlvbnNbMl0gPSBbLyguKikvLCAncGF0aG5hbWUnXTtcblxuICBmb3IgKDsgaSA8IGluc3RydWN0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgIGluc3RydWN0aW9uID0gaW5zdHJ1Y3Rpb25zW2ldO1xuICAgIHBhcnNlID0gaW5zdHJ1Y3Rpb25bMF07XG4gICAga2V5ID0gaW5zdHJ1Y3Rpb25bMV07XG5cbiAgICBpZiAocGFyc2UgIT09IHBhcnNlKSB7XG4gICAgICB1cmxba2V5XSA9IGFkZHJlc3M7XG4gICAgfSBlbHNlIGlmICgnc3RyaW5nJyA9PT0gdHlwZW9mIHBhcnNlKSB7XG4gICAgICBpZiAofihpbmRleCA9IGFkZHJlc3MuaW5kZXhPZihwYXJzZSkpKSB7XG4gICAgICAgIGlmICgnbnVtYmVyJyA9PT0gdHlwZW9mIGluc3RydWN0aW9uWzJdKSB7XG4gICAgICAgICAgdXJsW2tleV0gPSBhZGRyZXNzLnNsaWNlKDAsIGluZGV4KTtcbiAgICAgICAgICBhZGRyZXNzID0gYWRkcmVzcy5zbGljZShpbmRleCArIGluc3RydWN0aW9uWzJdKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB1cmxba2V5XSA9IGFkZHJlc3Muc2xpY2UoaW5kZXgpO1xuICAgICAgICAgIGFkZHJlc3MgPSBhZGRyZXNzLnNsaWNlKDAsIGluZGV4KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoKGluZGV4ID0gcGFyc2UuZXhlYyhhZGRyZXNzKSkpIHtcbiAgICAgIHVybFtrZXldID0gaW5kZXhbMV07XG4gICAgICBhZGRyZXNzID0gYWRkcmVzcy5zbGljZSgwLCBpbmRleC5pbmRleCk7XG4gICAgfVxuXG4gICAgdXJsW2tleV0gPSB1cmxba2V5XSB8fCAoXG4gICAgICByZWxhdGl2ZSAmJiBpbnN0cnVjdGlvblszXSA/IGxvY2F0aW9uW2tleV0gfHwgJycgOiAnJ1xuICAgICk7XG5cbiAgICAvL1xuICAgIC8vIEhvc3RuYW1lLCBob3N0IGFuZCBwcm90b2NvbCBzaG91bGQgYmUgbG93ZXJjYXNlZCBzbyB0aGV5IGNhbiBiZSB1c2VkIHRvXG4gICAgLy8gY3JlYXRlIGEgcHJvcGVyIGBvcmlnaW5gLlxuICAgIC8vXG4gICAgaWYgKGluc3RydWN0aW9uWzRdKSB1cmxba2V5XSA9IHVybFtrZXldLnRvTG93ZXJDYXNlKCk7XG4gIH1cblxuICAvL1xuICAvLyBBbHNvIHBhcnNlIHRoZSBzdXBwbGllZCBxdWVyeSBzdHJpbmcgaW4gdG8gYW4gb2JqZWN0LiBJZiB3ZSdyZSBzdXBwbGllZFxuICAvLyB3aXRoIGEgY3VzdG9tIHBhcnNlciBhcyBmdW5jdGlvbiB1c2UgdGhhdCBpbnN0ZWFkIG9mIHRoZSBkZWZhdWx0IGJ1aWxkLWluXG4gIC8vIHBhcnNlci5cbiAgLy9cbiAgaWYgKHBhcnNlcikgdXJsLnF1ZXJ5ID0gcGFyc2VyKHVybC5xdWVyeSk7XG5cbiAgLy9cbiAgLy8gSWYgdGhlIFVSTCBpcyByZWxhdGl2ZSwgcmVzb2x2ZSB0aGUgcGF0aG5hbWUgYWdhaW5zdCB0aGUgYmFzZSBVUkwuXG4gIC8vXG4gIGlmIChcbiAgICAgIHJlbGF0aXZlXG4gICAgJiYgbG9jYXRpb24uc2xhc2hlc1xuICAgICYmIHVybC5wYXRobmFtZS5jaGFyQXQoMCkgIT09ICcvJ1xuICAgICYmICh1cmwucGF0aG5hbWUgIT09ICcnIHx8IGxvY2F0aW9uLnBhdGhuYW1lICE9PSAnJylcbiAgKSB7XG4gICAgdXJsLnBhdGhuYW1lID0gcmVzb2x2ZSh1cmwucGF0aG5hbWUsIGxvY2F0aW9uLnBhdGhuYW1lKTtcbiAgfVxuXG4gIC8vXG4gIC8vIFdlIHNob3VsZCBub3QgYWRkIHBvcnQgbnVtYmVycyBpZiB0aGV5IGFyZSBhbHJlYWR5IHRoZSBkZWZhdWx0IHBvcnQgbnVtYmVyXG4gIC8vIGZvciBhIGdpdmVuIHByb3RvY29sLiBBcyB0aGUgaG9zdCBhbHNvIGNvbnRhaW5zIHRoZSBwb3J0IG51bWJlciB3ZSdyZSBnb2luZ1xuICAvLyBvdmVycmlkZSBpdCB3aXRoIHRoZSBob3N0bmFtZSB3aGljaCBjb250YWlucyBubyBwb3J0IG51bWJlci5cbiAgLy9cbiAgaWYgKCFyZXF1aXJlZCh1cmwucG9ydCwgdXJsLnByb3RvY29sKSkge1xuICAgIHVybC5ob3N0ID0gdXJsLmhvc3RuYW1lO1xuICAgIHVybC5wb3J0ID0gJyc7XG4gIH1cblxuICAvL1xuICAvLyBQYXJzZSBkb3duIHRoZSBgYXV0aGAgZm9yIHRoZSB1c2VybmFtZSBhbmQgcGFzc3dvcmQuXG4gIC8vXG4gIHVybC51c2VybmFtZSA9IHVybC5wYXNzd29yZCA9ICcnO1xuICBpZiAodXJsLmF1dGgpIHtcbiAgICBpbnN0cnVjdGlvbiA9IHVybC5hdXRoLnNwbGl0KCc6Jyk7XG4gICAgdXJsLnVzZXJuYW1lID0gaW5zdHJ1Y3Rpb25bMF0gfHwgJyc7XG4gICAgdXJsLnBhc3N3b3JkID0gaW5zdHJ1Y3Rpb25bMV0gfHwgJyc7XG4gIH1cblxuICB1cmwub3JpZ2luID0gdXJsLnByb3RvY29sICYmIHVybC5ob3N0ICYmIHVybC5wcm90b2NvbCAhPT0gJ2ZpbGU6J1xuICAgID8gdXJsLnByb3RvY29sICsnLy8nKyB1cmwuaG9zdFxuICAgIDogJ251bGwnO1xuXG4gIC8vXG4gIC8vIFRoZSBocmVmIGlzIGp1c3QgdGhlIGNvbXBpbGVkIHJlc3VsdC5cbiAgLy9cbiAgdXJsLmhyZWYgPSB1cmwudG9TdHJpbmcoKTtcbn1cblxuLyoqXG4gKiBUaGlzIGlzIGNvbnZlbmllbmNlIG1ldGhvZCBmb3IgY2hhbmdpbmcgcHJvcGVydGllcyBpbiB0aGUgVVJMIGluc3RhbmNlIHRvXG4gKiBpbnN1cmUgdGhhdCB0aGV5IGFsbCBwcm9wYWdhdGUgY29ycmVjdGx5LlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBwYXJ0ICAgICAgICAgIFByb3BlcnR5IHdlIG5lZWQgdG8gYWRqdXN0LlxuICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgICAgICAgICAgVGhlIG5ld2x5IGFzc2lnbmVkIHZhbHVlLlxuICogQHBhcmFtIHtCb29sZWFufEZ1bmN0aW9ufSBmbiAgV2hlbiBzZXR0aW5nIHRoZSBxdWVyeSwgaXQgd2lsbCBiZSB0aGUgZnVuY3Rpb25cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZWQgdG8gcGFyc2UgdGhlIHF1ZXJ5LlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV2hlbiBzZXR0aW5nIHRoZSBwcm90b2NvbCwgZG91YmxlIHNsYXNoIHdpbGwgYmVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZWQgZnJvbSB0aGUgZmluYWwgdXJsIGlmIGl0IGlzIHRydWUuXG4gKiBAcmV0dXJucyB7VVJMfVxuICogQGFwaSBwdWJsaWNcbiAqL1xuZnVuY3Rpb24gc2V0KHBhcnQsIHZhbHVlLCBmbikge1xuICB2YXIgdXJsID0gdGhpcztcblxuICBzd2l0Y2ggKHBhcnQpIHtcbiAgICBjYXNlICdxdWVyeSc6XG4gICAgICBpZiAoJ3N0cmluZycgPT09IHR5cGVvZiB2YWx1ZSAmJiB2YWx1ZS5sZW5ndGgpIHtcbiAgICAgICAgdmFsdWUgPSAoZm4gfHwgcXMucGFyc2UpKHZhbHVlKTtcbiAgICAgIH1cblxuICAgICAgdXJsW3BhcnRdID0gdmFsdWU7XG4gICAgICBicmVhaztcblxuICAgIGNhc2UgJ3BvcnQnOlxuICAgICAgdXJsW3BhcnRdID0gdmFsdWU7XG5cbiAgICAgIGlmICghcmVxdWlyZWQodmFsdWUsIHVybC5wcm90b2NvbCkpIHtcbiAgICAgICAgdXJsLmhvc3QgPSB1cmwuaG9zdG5hbWU7XG4gICAgICAgIHVybFtwYXJ0XSA9ICcnO1xuICAgICAgfSBlbHNlIGlmICh2YWx1ZSkge1xuICAgICAgICB1cmwuaG9zdCA9IHVybC5ob3N0bmFtZSArJzonKyB2YWx1ZTtcbiAgICAgIH1cblxuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlICdob3N0bmFtZSc6XG4gICAgICB1cmxbcGFydF0gPSB2YWx1ZTtcblxuICAgICAgaWYgKHVybC5wb3J0KSB2YWx1ZSArPSAnOicrIHVybC5wb3J0O1xuICAgICAgdXJsLmhvc3QgPSB2YWx1ZTtcbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSAnaG9zdCc6XG4gICAgICB1cmxbcGFydF0gPSB2YWx1ZTtcblxuICAgICAgaWYgKC86XFxkKyQvLnRlc3QodmFsdWUpKSB7XG4gICAgICAgIHZhbHVlID0gdmFsdWUuc3BsaXQoJzonKTtcbiAgICAgICAgdXJsLnBvcnQgPSB2YWx1ZS5wb3AoKTtcbiAgICAgICAgdXJsLmhvc3RuYW1lID0gdmFsdWUuam9pbignOicpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdXJsLmhvc3RuYW1lID0gdmFsdWU7XG4gICAgICAgIHVybC5wb3J0ID0gJyc7XG4gICAgICB9XG5cbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSAncHJvdG9jb2wnOlxuICAgICAgdXJsLnByb3RvY29sID0gdmFsdWUudG9Mb3dlckNhc2UoKTtcbiAgICAgIHVybC5zbGFzaGVzID0gIWZuO1xuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlICdwYXRobmFtZSc6XG4gICAgICB1cmwucGF0aG5hbWUgPSB2YWx1ZS5sZW5ndGggJiYgdmFsdWUuY2hhckF0KDApICE9PSAnLycgPyAnLycgKyB2YWx1ZSA6IHZhbHVlO1xuXG4gICAgICBicmVhaztcblxuICAgIGRlZmF1bHQ6XG4gICAgICB1cmxbcGFydF0gPSB2YWx1ZTtcbiAgfVxuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgcnVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgaW5zID0gcnVsZXNbaV07XG5cbiAgICBpZiAoaW5zWzRdKSB1cmxbaW5zWzFdXSA9IHVybFtpbnNbMV1dLnRvTG93ZXJDYXNlKCk7XG4gIH1cblxuICB1cmwub3JpZ2luID0gdXJsLnByb3RvY29sICYmIHVybC5ob3N0ICYmIHVybC5wcm90b2NvbCAhPT0gJ2ZpbGU6J1xuICAgID8gdXJsLnByb3RvY29sICsnLy8nKyB1cmwuaG9zdFxuICAgIDogJ251bGwnO1xuXG4gIHVybC5ocmVmID0gdXJsLnRvU3RyaW5nKCk7XG5cbiAgcmV0dXJuIHVybDtcbn1cblxuLyoqXG4gKiBUcmFuc2Zvcm0gdGhlIHByb3BlcnRpZXMgYmFjayBpbiB0byBhIHZhbGlkIGFuZCBmdWxsIFVSTCBzdHJpbmcuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gc3RyaW5naWZ5IE9wdGlvbmFsIHF1ZXJ5IHN0cmluZ2lmeSBmdW5jdGlvbi5cbiAqIEByZXR1cm5zIHtTdHJpbmd9XG4gKiBAYXBpIHB1YmxpY1xuICovXG5mdW5jdGlvbiB0b1N0cmluZyhzdHJpbmdpZnkpIHtcbiAgaWYgKCFzdHJpbmdpZnkgfHwgJ2Z1bmN0aW9uJyAhPT0gdHlwZW9mIHN0cmluZ2lmeSkgc3RyaW5naWZ5ID0gcXMuc3RyaW5naWZ5O1xuXG4gIHZhciBxdWVyeVxuICAgICwgdXJsID0gdGhpc1xuICAgICwgcHJvdG9jb2wgPSB1cmwucHJvdG9jb2w7XG5cbiAgaWYgKHByb3RvY29sICYmIHByb3RvY29sLmNoYXJBdChwcm90b2NvbC5sZW5ndGggLSAxKSAhPT0gJzonKSBwcm90b2NvbCArPSAnOic7XG5cbiAgdmFyIHJlc3VsdCA9IHByb3RvY29sICsgKHVybC5zbGFzaGVzID8gJy8vJyA6ICcnKTtcblxuICBpZiAodXJsLnVzZXJuYW1lKSB7XG4gICAgcmVzdWx0ICs9IHVybC51c2VybmFtZTtcbiAgICBpZiAodXJsLnBhc3N3b3JkKSByZXN1bHQgKz0gJzonKyB1cmwucGFzc3dvcmQ7XG4gICAgcmVzdWx0ICs9ICdAJztcbiAgfVxuXG4gIHJlc3VsdCArPSB1cmwuaG9zdCArIHVybC5wYXRobmFtZTtcblxuICBxdWVyeSA9ICdvYmplY3QnID09PSB0eXBlb2YgdXJsLnF1ZXJ5ID8gc3RyaW5naWZ5KHVybC5xdWVyeSkgOiB1cmwucXVlcnk7XG4gIGlmIChxdWVyeSkgcmVzdWx0ICs9ICc/JyAhPT0gcXVlcnkuY2hhckF0KDApID8gJz8nKyBxdWVyeSA6IHF1ZXJ5O1xuXG4gIGlmICh1cmwuaGFzaCkgcmVzdWx0ICs9IHVybC5oYXNoO1xuXG4gIHJldHVybiByZXN1bHQ7XG59XG5cblVSTC5wcm90b3R5cGUgPSB7IHNldDogc2V0LCB0b1N0cmluZzogdG9TdHJpbmcgfTtcblxuLy9cbi8vIEV4cG9zZSB0aGUgVVJMIHBhcnNlciBhbmQgc29tZSBhZGRpdGlvbmFsIHByb3BlcnRpZXMgdGhhdCBtaWdodCBiZSB1c2VmdWwgZm9yXG4vLyBvdGhlcnMgb3IgdGVzdGluZy5cbi8vXG5VUkwuZXh0cmFjdFByb3RvY29sID0gZXh0cmFjdFByb3RvY29sO1xuVVJMLmxvY2F0aW9uID0gbG9sY2F0aW9uO1xuVVJMLnFzID0gcXM7XG5cbm1vZHVsZS5leHBvcnRzID0gVVJMO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaGFzID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTtcblxuLyoqXG4gKiBEZWNvZGUgYSBVUkkgZW5jb2RlZCBzdHJpbmcuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IFRoZSBVUkkgZW5jb2RlZCBzdHJpbmcuXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBUaGUgZGVjb2RlZCBzdHJpbmcuXG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gZGVjb2RlKGlucHV0KSB7XG4gIHJldHVybiBkZWNvZGVVUklDb21wb25lbnQoaW5wdXQucmVwbGFjZSgvXFwrL2csICcgJykpO1xufVxuXG4vKipcbiAqIFNpbXBsZSBxdWVyeSBzdHJpbmcgcGFyc2VyLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBxdWVyeSBUaGUgcXVlcnkgc3RyaW5nIHRoYXQgbmVlZHMgdG8gYmUgcGFyc2VkLlxuICogQHJldHVybnMge09iamVjdH1cbiAqIEBhcGkgcHVibGljXG4gKi9cbmZ1bmN0aW9uIHF1ZXJ5c3RyaW5nKHF1ZXJ5KSB7XG4gIHZhciBwYXJzZXIgPSAvKFtePT8mXSspPT8oW14mXSopL2dcbiAgICAsIHJlc3VsdCA9IHt9XG4gICAgLCBwYXJ0O1xuXG4gIC8vXG4gIC8vIExpdHRsZSBuaWZ0eSBwYXJzaW5nIGhhY2ssIGxldmVyYWdlIHRoZSBmYWN0IHRoYXQgUmVnRXhwLmV4ZWMgaW5jcmVtZW50c1xuICAvLyB0aGUgbGFzdEluZGV4IHByb3BlcnR5IHNvIHdlIGNhbiBjb250aW51ZSBleGVjdXRpbmcgdGhpcyBsb29wIHVudGlsIHdlJ3ZlXG4gIC8vIHBhcnNlZCBhbGwgcmVzdWx0cy5cbiAgLy9cbiAgZm9yICg7XG4gICAgcGFydCA9IHBhcnNlci5leGVjKHF1ZXJ5KTtcbiAgICByZXN1bHRbZGVjb2RlKHBhcnRbMV0pXSA9IGRlY29kZShwYXJ0WzJdKVxuICApO1xuXG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogVHJhbnNmb3JtIGEgcXVlcnkgc3RyaW5nIHRvIGFuIG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqIE9iamVjdCB0aGF0IHNob3VsZCBiZSB0cmFuc2Zvcm1lZC5cbiAqIEBwYXJhbSB7U3RyaW5nfSBwcmVmaXggT3B0aW9uYWwgcHJlZml4LlxuICogQHJldHVybnMge1N0cmluZ31cbiAqIEBhcGkgcHVibGljXG4gKi9cbmZ1bmN0aW9uIHF1ZXJ5c3RyaW5naWZ5KG9iaiwgcHJlZml4KSB7XG4gIHByZWZpeCA9IHByZWZpeCB8fCAnJztcblxuICB2YXIgcGFpcnMgPSBbXTtcblxuICAvL1xuICAvLyBPcHRpb25hbGx5IHByZWZpeCB3aXRoIGEgJz8nIGlmIG5lZWRlZFxuICAvL1xuICBpZiAoJ3N0cmluZycgIT09IHR5cGVvZiBwcmVmaXgpIHByZWZpeCA9ICc/JztcblxuICBmb3IgKHZhciBrZXkgaW4gb2JqKSB7XG4gICAgaWYgKGhhcy5jYWxsKG9iaiwga2V5KSkge1xuICAgICAgcGFpcnMucHVzaChlbmNvZGVVUklDb21wb25lbnQoa2V5KSArJz0nKyBlbmNvZGVVUklDb21wb25lbnQob2JqW2tleV0pKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gcGFpcnMubGVuZ3RoID8gcHJlZml4ICsgcGFpcnMuam9pbignJicpIDogJyc7XG59XG5cbi8vXG4vLyBFeHBvc2UgdGhlIG1vZHVsZS5cbi8vXG5leHBvcnRzLnN0cmluZ2lmeSA9IHF1ZXJ5c3RyaW5naWZ5O1xuZXhwb3J0cy5wYXJzZSA9IHF1ZXJ5c3RyaW5nO1xuIiwiXG52YXIgcm5nO1xuXG52YXIgY3J5cHRvID0gZ2xvYmFsLmNyeXB0byB8fCBnbG9iYWwubXNDcnlwdG87IC8vIGZvciBJRSAxMVxuaWYgKGNyeXB0byAmJiBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKSB7XG4gIC8vIFdIQVRXRyBjcnlwdG8tYmFzZWQgUk5HIC0gaHR0cDovL3dpa2kud2hhdHdnLm9yZy93aWtpL0NyeXB0b1xuICAvLyBNb2RlcmF0ZWx5IGZhc3QsIGhpZ2ggcXVhbGl0eVxuICB2YXIgX3JuZHM4ID0gbmV3IFVpbnQ4QXJyYXkoMTYpO1xuICBybmcgPSBmdW5jdGlvbiB3aGF0d2dSTkcoKSB7XG4gICAgY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhfcm5kczgpO1xuICAgIHJldHVybiBfcm5kczg7XG4gIH07XG59XG5cbmlmICghcm5nKSB7XG4gIC8vIE1hdGgucmFuZG9tKCktYmFzZWQgKFJORylcbiAgLy9cbiAgLy8gSWYgYWxsIGVsc2UgZmFpbHMsIHVzZSBNYXRoLnJhbmRvbSgpLiAgSXQncyBmYXN0LCBidXQgaXMgb2YgdW5zcGVjaWZpZWRcbiAgLy8gcXVhbGl0eS5cbiAgdmFyICBfcm5kcyA9IG5ldyBBcnJheSgxNik7XG4gIHJuZyA9IGZ1bmN0aW9uKCkge1xuICAgIGZvciAodmFyIGkgPSAwLCByOyBpIDwgMTY7IGkrKykge1xuICAgICAgaWYgKChpICYgMHgwMykgPT09IDApIHIgPSBNYXRoLnJhbmRvbSgpICogMHgxMDAwMDAwMDA7XG4gICAgICBfcm5kc1tpXSA9IHIgPj4+ICgoaSAmIDB4MDMpIDw8IDMpICYgMHhmZjtcbiAgICB9XG5cbiAgICByZXR1cm4gX3JuZHM7XG4gIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gcm5nO1xuXG4iLCIvLyAgICAgdXVpZC5qc1xuLy9cbi8vICAgICBDb3B5cmlnaHQgKGMpIDIwMTAtMjAxMiBSb2JlcnQgS2llZmZlclxuLy8gICAgIE1JVCBMaWNlbnNlIC0gaHR0cDovL29wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL21pdC1saWNlbnNlLnBocFxuXG4vLyBVbmlxdWUgSUQgY3JlYXRpb24gcmVxdWlyZXMgYSBoaWdoIHF1YWxpdHkgcmFuZG9tICMgZ2VuZXJhdG9yLiAgV2UgZmVhdHVyZVxuLy8gZGV0ZWN0IHRvIGRldGVybWluZSB0aGUgYmVzdCBSTkcgc291cmNlLCBub3JtYWxpemluZyB0byBhIGZ1bmN0aW9uIHRoYXRcbi8vIHJldHVybnMgMTI4LWJpdHMgb2YgcmFuZG9tbmVzcywgc2luY2UgdGhhdCdzIHdoYXQncyB1c3VhbGx5IHJlcXVpcmVkXG52YXIgX3JuZyA9IHJlcXVpcmUoJy4vcm5nJyk7XG5cbi8vIE1hcHMgZm9yIG51bWJlciA8LT4gaGV4IHN0cmluZyBjb252ZXJzaW9uXG52YXIgX2J5dGVUb0hleCA9IFtdO1xudmFyIF9oZXhUb0J5dGUgPSB7fTtcbmZvciAodmFyIGkgPSAwOyBpIDwgMjU2OyBpKyspIHtcbiAgX2J5dGVUb0hleFtpXSA9IChpICsgMHgxMDApLnRvU3RyaW5nKDE2KS5zdWJzdHIoMSk7XG4gIF9oZXhUb0J5dGVbX2J5dGVUb0hleFtpXV0gPSBpO1xufVxuXG4vLyAqKmBwYXJzZSgpYCAtIFBhcnNlIGEgVVVJRCBpbnRvIGl0J3MgY29tcG9uZW50IGJ5dGVzKipcbmZ1bmN0aW9uIHBhcnNlKHMsIGJ1Ziwgb2Zmc2V0KSB7XG4gIHZhciBpID0gKGJ1ZiAmJiBvZmZzZXQpIHx8IDAsIGlpID0gMDtcblxuICBidWYgPSBidWYgfHwgW107XG4gIHMudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9bMC05YS1mXXsyfS9nLCBmdW5jdGlvbihvY3QpIHtcbiAgICBpZiAoaWkgPCAxNikgeyAvLyBEb24ndCBvdmVyZmxvdyFcbiAgICAgIGJ1ZltpICsgaWkrK10gPSBfaGV4VG9CeXRlW29jdF07XG4gICAgfVxuICB9KTtcblxuICAvLyBaZXJvIG91dCByZW1haW5pbmcgYnl0ZXMgaWYgc3RyaW5nIHdhcyBzaG9ydFxuICB3aGlsZSAoaWkgPCAxNikge1xuICAgIGJ1ZltpICsgaWkrK10gPSAwO1xuICB9XG5cbiAgcmV0dXJuIGJ1Zjtcbn1cblxuLy8gKipgdW5wYXJzZSgpYCAtIENvbnZlcnQgVVVJRCBieXRlIGFycmF5IChhbGEgcGFyc2UoKSkgaW50byBhIHN0cmluZyoqXG5mdW5jdGlvbiB1bnBhcnNlKGJ1Ziwgb2Zmc2V0KSB7XG4gIHZhciBpID0gb2Zmc2V0IHx8IDAsIGJ0aCA9IF9ieXRlVG9IZXg7XG4gIHJldHVybiAgYnRoW2J1ZltpKytdXSArIGJ0aFtidWZbaSsrXV0gK1xuICAgICAgICAgIGJ0aFtidWZbaSsrXV0gKyBidGhbYnVmW2krK11dICsgJy0nICtcbiAgICAgICAgICBidGhbYnVmW2krK11dICsgYnRoW2J1ZltpKytdXSArICctJyArXG4gICAgICAgICAgYnRoW2J1ZltpKytdXSArIGJ0aFtidWZbaSsrXV0gKyAnLScgK1xuICAgICAgICAgIGJ0aFtidWZbaSsrXV0gKyBidGhbYnVmW2krK11dICsgJy0nICtcbiAgICAgICAgICBidGhbYnVmW2krK11dICsgYnRoW2J1ZltpKytdXSArXG4gICAgICAgICAgYnRoW2J1ZltpKytdXSArIGJ0aFtidWZbaSsrXV0gK1xuICAgICAgICAgIGJ0aFtidWZbaSsrXV0gKyBidGhbYnVmW2krK11dO1xufVxuXG4vLyAqKmB2MSgpYCAtIEdlbmVyYXRlIHRpbWUtYmFzZWQgVVVJRCoqXG4vL1xuLy8gSW5zcGlyZWQgYnkgaHR0cHM6Ly9naXRodWIuY29tL0xpb3NLL1VVSUQuanNcbi8vIGFuZCBodHRwOi8vZG9jcy5weXRob24ub3JnL2xpYnJhcnkvdXVpZC5odG1sXG5cbi8vIHJhbmRvbSAjJ3Mgd2UgbmVlZCB0byBpbml0IG5vZGUgYW5kIGNsb2Nrc2VxXG52YXIgX3NlZWRCeXRlcyA9IF9ybmcoKTtcblxuLy8gUGVyIDQuNSwgY3JlYXRlIGFuZCA0OC1iaXQgbm9kZSBpZCwgKDQ3IHJhbmRvbSBiaXRzICsgbXVsdGljYXN0IGJpdCA9IDEpXG52YXIgX25vZGVJZCA9IFtcbiAgX3NlZWRCeXRlc1swXSB8IDB4MDEsXG4gIF9zZWVkQnl0ZXNbMV0sIF9zZWVkQnl0ZXNbMl0sIF9zZWVkQnl0ZXNbM10sIF9zZWVkQnl0ZXNbNF0sIF9zZWVkQnl0ZXNbNV1cbl07XG5cbi8vIFBlciA0LjIuMiwgcmFuZG9taXplICgxNCBiaXQpIGNsb2Nrc2VxXG52YXIgX2Nsb2Nrc2VxID0gKF9zZWVkQnl0ZXNbNl0gPDwgOCB8IF9zZWVkQnl0ZXNbN10pICYgMHgzZmZmO1xuXG4vLyBQcmV2aW91cyB1dWlkIGNyZWF0aW9uIHRpbWVcbnZhciBfbGFzdE1TZWNzID0gMCwgX2xhc3ROU2VjcyA9IDA7XG5cbi8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vYnJvb2ZhL25vZGUtdXVpZCBmb3IgQVBJIGRldGFpbHNcbmZ1bmN0aW9uIHYxKG9wdGlvbnMsIGJ1Ziwgb2Zmc2V0KSB7XG4gIHZhciBpID0gYnVmICYmIG9mZnNldCB8fCAwO1xuICB2YXIgYiA9IGJ1ZiB8fCBbXTtcblxuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICB2YXIgY2xvY2tzZXEgPSBvcHRpb25zLmNsb2Nrc2VxICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmNsb2Nrc2VxIDogX2Nsb2Nrc2VxO1xuXG4gIC8vIFVVSUQgdGltZXN0YW1wcyBhcmUgMTAwIG5hbm8tc2Vjb25kIHVuaXRzIHNpbmNlIHRoZSBHcmVnb3JpYW4gZXBvY2gsXG4gIC8vICgxNTgyLTEwLTE1IDAwOjAwKS4gIEpTTnVtYmVycyBhcmVuJ3QgcHJlY2lzZSBlbm91Z2ggZm9yIHRoaXMsIHNvXG4gIC8vIHRpbWUgaXMgaGFuZGxlZCBpbnRlcm5hbGx5IGFzICdtc2VjcycgKGludGVnZXIgbWlsbGlzZWNvbmRzKSBhbmQgJ25zZWNzJ1xuICAvLyAoMTAwLW5hbm9zZWNvbmRzIG9mZnNldCBmcm9tIG1zZWNzKSBzaW5jZSB1bml4IGVwb2NoLCAxOTcwLTAxLTAxIDAwOjAwLlxuICB2YXIgbXNlY3MgPSBvcHRpb25zLm1zZWNzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLm1zZWNzIDogbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgLy8gUGVyIDQuMi4xLjIsIHVzZSBjb3VudCBvZiB1dWlkJ3MgZ2VuZXJhdGVkIGR1cmluZyB0aGUgY3VycmVudCBjbG9ja1xuICAvLyBjeWNsZSB0byBzaW11bGF0ZSBoaWdoZXIgcmVzb2x1dGlvbiBjbG9ja1xuICB2YXIgbnNlY3MgPSBvcHRpb25zLm5zZWNzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLm5zZWNzIDogX2xhc3ROU2VjcyArIDE7XG5cbiAgLy8gVGltZSBzaW5jZSBsYXN0IHV1aWQgY3JlYXRpb24gKGluIG1zZWNzKVxuICB2YXIgZHQgPSAobXNlY3MgLSBfbGFzdE1TZWNzKSArIChuc2VjcyAtIF9sYXN0TlNlY3MpLzEwMDAwO1xuXG4gIC8vIFBlciA0LjIuMS4yLCBCdW1wIGNsb2Nrc2VxIG9uIGNsb2NrIHJlZ3Jlc3Npb25cbiAgaWYgKGR0IDwgMCAmJiBvcHRpb25zLmNsb2Nrc2VxID09PSB1bmRlZmluZWQpIHtcbiAgICBjbG9ja3NlcSA9IGNsb2Nrc2VxICsgMSAmIDB4M2ZmZjtcbiAgfVxuXG4gIC8vIFJlc2V0IG5zZWNzIGlmIGNsb2NrIHJlZ3Jlc3NlcyAobmV3IGNsb2Nrc2VxKSBvciB3ZSd2ZSBtb3ZlZCBvbnRvIGEgbmV3XG4gIC8vIHRpbWUgaW50ZXJ2YWxcbiAgaWYgKChkdCA8IDAgfHwgbXNlY3MgPiBfbGFzdE1TZWNzKSAmJiBvcHRpb25zLm5zZWNzID09PSB1bmRlZmluZWQpIHtcbiAgICBuc2VjcyA9IDA7XG4gIH1cblxuICAvLyBQZXIgNC4yLjEuMiBUaHJvdyBlcnJvciBpZiB0b28gbWFueSB1dWlkcyBhcmUgcmVxdWVzdGVkXG4gIGlmIChuc2VjcyA+PSAxMDAwMCkge1xuICAgIHRocm93IG5ldyBFcnJvcigndXVpZC52MSgpOiBDYW5cXCd0IGNyZWF0ZSBtb3JlIHRoYW4gMTBNIHV1aWRzL3NlYycpO1xuICB9XG5cbiAgX2xhc3RNU2VjcyA9IG1zZWNzO1xuICBfbGFzdE5TZWNzID0gbnNlY3M7XG4gIF9jbG9ja3NlcSA9IGNsb2Nrc2VxO1xuXG4gIC8vIFBlciA0LjEuNCAtIENvbnZlcnQgZnJvbSB1bml4IGVwb2NoIHRvIEdyZWdvcmlhbiBlcG9jaFxuICBtc2VjcyArPSAxMjIxOTI5MjgwMDAwMDtcblxuICAvLyBgdGltZV9sb3dgXG4gIHZhciB0bCA9ICgobXNlY3MgJiAweGZmZmZmZmYpICogMTAwMDAgKyBuc2VjcykgJSAweDEwMDAwMDAwMDtcbiAgYltpKytdID0gdGwgPj4+IDI0ICYgMHhmZjtcbiAgYltpKytdID0gdGwgPj4+IDE2ICYgMHhmZjtcbiAgYltpKytdID0gdGwgPj4+IDggJiAweGZmO1xuICBiW2krK10gPSB0bCAmIDB4ZmY7XG5cbiAgLy8gYHRpbWVfbWlkYFxuICB2YXIgdG1oID0gKG1zZWNzIC8gMHgxMDAwMDAwMDAgKiAxMDAwMCkgJiAweGZmZmZmZmY7XG4gIGJbaSsrXSA9IHRtaCA+Pj4gOCAmIDB4ZmY7XG4gIGJbaSsrXSA9IHRtaCAmIDB4ZmY7XG5cbiAgLy8gYHRpbWVfaGlnaF9hbmRfdmVyc2lvbmBcbiAgYltpKytdID0gdG1oID4+PiAyNCAmIDB4ZiB8IDB4MTA7IC8vIGluY2x1ZGUgdmVyc2lvblxuICBiW2krK10gPSB0bWggPj4+IDE2ICYgMHhmZjtcblxuICAvLyBgY2xvY2tfc2VxX2hpX2FuZF9yZXNlcnZlZGAgKFBlciA0LjIuMiAtIGluY2x1ZGUgdmFyaWFudClcbiAgYltpKytdID0gY2xvY2tzZXEgPj4+IDggfCAweDgwO1xuXG4gIC8vIGBjbG9ja19zZXFfbG93YFxuICBiW2krK10gPSBjbG9ja3NlcSAmIDB4ZmY7XG5cbiAgLy8gYG5vZGVgXG4gIHZhciBub2RlID0gb3B0aW9ucy5ub2RlIHx8IF9ub2RlSWQ7XG4gIGZvciAodmFyIG4gPSAwOyBuIDwgNjsgbisrKSB7XG4gICAgYltpICsgbl0gPSBub2RlW25dO1xuICB9XG5cbiAgcmV0dXJuIGJ1ZiA/IGJ1ZiA6IHVucGFyc2UoYik7XG59XG5cbi8vICoqYHY0KClgIC0gR2VuZXJhdGUgcmFuZG9tIFVVSUQqKlxuXG4vLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2Jyb29mYS9ub2RlLXV1aWQgZm9yIEFQSSBkZXRhaWxzXG5mdW5jdGlvbiB2NChvcHRpb25zLCBidWYsIG9mZnNldCkge1xuICAvLyBEZXByZWNhdGVkIC0gJ2Zvcm1hdCcgYXJndW1lbnQsIGFzIHN1cHBvcnRlZCBpbiB2MS4yXG4gIHZhciBpID0gYnVmICYmIG9mZnNldCB8fCAwO1xuXG4gIGlmICh0eXBlb2Yob3B0aW9ucykgPT0gJ3N0cmluZycpIHtcbiAgICBidWYgPSBvcHRpb25zID09ICdiaW5hcnknID8gbmV3IEFycmF5KDE2KSA6IG51bGw7XG4gICAgb3B0aW9ucyA9IG51bGw7XG4gIH1cbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgdmFyIHJuZHMgPSBvcHRpb25zLnJhbmRvbSB8fCAob3B0aW9ucy5ybmcgfHwgX3JuZykoKTtcblxuICAvLyBQZXIgNC40LCBzZXQgYml0cyBmb3IgdmVyc2lvbiBhbmQgYGNsb2NrX3NlcV9oaV9hbmRfcmVzZXJ2ZWRgXG4gIHJuZHNbNl0gPSAocm5kc1s2XSAmIDB4MGYpIHwgMHg0MDtcbiAgcm5kc1s4XSA9IChybmRzWzhdICYgMHgzZikgfCAweDgwO1xuXG4gIC8vIENvcHkgYnl0ZXMgdG8gYnVmZmVyLCBpZiBwcm92aWRlZFxuICBpZiAoYnVmKSB7XG4gICAgZm9yICh2YXIgaWkgPSAwOyBpaSA8IDE2OyBpaSsrKSB7XG4gICAgICBidWZbaSArIGlpXSA9IHJuZHNbaWldO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBidWYgfHwgdW5wYXJzZShybmRzKTtcbn1cblxuLy8gRXhwb3J0IHB1YmxpYyBBUElcbnZhciB1dWlkID0gdjQ7XG51dWlkLnYxID0gdjE7XG51dWlkLnY0ID0gdjQ7XG51dWlkLnBhcnNlID0gcGFyc2U7XG51dWlkLnVucGFyc2UgPSB1bnBhcnNlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHV1aWQ7XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgYWRhcHRlckZhY3RvcnkgPSByZXF1aXJlKCcuL2FkYXB0ZXJfZmFjdG9yeS5qcycpO1xubW9kdWxlLmV4cG9ydHMgPSBhZGFwdGVyRmFjdG9yeSh7d2luZG93OiBnbG9iYWwud2luZG93fSk7XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG4vLyBTaGltbWluZyBzdGFydHMgaGVyZS5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oZGVwZW5kZW5jaWVzKSB7XG4gIHZhciB3aW5kb3cgPSBkZXBlbmRlbmNpZXMgJiYgZGVwZW5kZW5jaWVzLndpbmRvdztcblxuICAvLyBVdGlscy5cbiAgdmFyIHV0aWxzID0gcmVxdWlyZSgnLi91dGlscycpO1xuICB2YXIgbG9nZ2luZyA9IHV0aWxzLmxvZztcbiAgdmFyIGJyb3dzZXJEZXRhaWxzID0gdXRpbHMuZGV0ZWN0QnJvd3Nlcih3aW5kb3cpO1xuXG4gIC8vIEV4cG9ydCB0byB0aGUgYWRhcHRlciBnbG9iYWwgb2JqZWN0IHZpc2libGUgaW4gdGhlIGJyb3dzZXIuXG4gIHZhciBhZGFwdGVyID0ge1xuICAgIGJyb3dzZXJEZXRhaWxzOiBicm93c2VyRGV0YWlscyxcbiAgICBleHRyYWN0VmVyc2lvbjogdXRpbHMuZXh0cmFjdFZlcnNpb24sXG4gICAgZGlzYWJsZUxvZzogdXRpbHMuZGlzYWJsZUxvZ1xuICB9O1xuXG4gIC8vIFVuY29tbWVudCB0aGUgbGluZSBiZWxvdyBpZiB5b3Ugd2FudCBsb2dnaW5nIHRvIG9jY3VyLCBpbmNsdWRpbmcgbG9nZ2luZ1xuICAvLyBmb3IgdGhlIHN3aXRjaCBzdGF0ZW1lbnQgYmVsb3cuIENhbiBhbHNvIGJlIHR1cm5lZCBvbiBpbiB0aGUgYnJvd3NlciB2aWFcbiAgLy8gYWRhcHRlci5kaXNhYmxlTG9nKGZhbHNlKSwgYnV0IHRoZW4gbG9nZ2luZyBmcm9tIHRoZSBzd2l0Y2ggc3RhdGVtZW50IGJlbG93XG4gIC8vIHdpbGwgbm90IGFwcGVhci5cbiAgLy8gcmVxdWlyZSgnLi91dGlscycpLmRpc2FibGVMb2coZmFsc2UpO1xuXG4gIC8vIEJyb3dzZXIgc2hpbXMuXG4gIHZhciBjaHJvbWVTaGltID0gcmVxdWlyZSgnLi9jaHJvbWUvY2hyb21lX3NoaW0nKSB8fCBudWxsO1xuICB2YXIgZWRnZVNoaW0gPSByZXF1aXJlKCcuL2VkZ2UvZWRnZV9zaGltJykgfHwgbnVsbDtcbiAgdmFyIGZpcmVmb3hTaGltID0gcmVxdWlyZSgnLi9maXJlZm94L2ZpcmVmb3hfc2hpbScpIHx8IG51bGw7XG4gIHZhciBzYWZhcmlTaGltID0gcmVxdWlyZSgnLi9zYWZhcmkvc2FmYXJpX3NoaW0nKSB8fCBudWxsO1xuXG4gIC8vIFNoaW0gYnJvd3NlciBpZiBmb3VuZC5cbiAgc3dpdGNoIChicm93c2VyRGV0YWlscy5icm93c2VyKSB7XG4gICAgY2FzZSAnY2hyb21lJzpcbiAgICAgIGlmICghY2hyb21lU2hpbSB8fCAhY2hyb21lU2hpbS5zaGltUGVlckNvbm5lY3Rpb24pIHtcbiAgICAgICAgbG9nZ2luZygnQ2hyb21lIHNoaW0gaXMgbm90IGluY2x1ZGVkIGluIHRoaXMgYWRhcHRlciByZWxlYXNlLicpO1xuICAgICAgICByZXR1cm4gYWRhcHRlcjtcbiAgICAgIH1cbiAgICAgIGxvZ2dpbmcoJ2FkYXB0ZXIuanMgc2hpbW1pbmcgY2hyb21lLicpO1xuICAgICAgLy8gRXhwb3J0IHRvIHRoZSBhZGFwdGVyIGdsb2JhbCBvYmplY3QgdmlzaWJsZSBpbiB0aGUgYnJvd3Nlci5cbiAgICAgIGFkYXB0ZXIuYnJvd3NlclNoaW0gPSBjaHJvbWVTaGltO1xuXG4gICAgICBjaHJvbWVTaGltLnNoaW1HZXRVc2VyTWVkaWEod2luZG93KTtcbiAgICAgIGNocm9tZVNoaW0uc2hpbU1lZGlhU3RyZWFtKHdpbmRvdyk7XG4gICAgICB1dGlscy5zaGltQ3JlYXRlT2JqZWN0VVJMKHdpbmRvdyk7XG4gICAgICBjaHJvbWVTaGltLnNoaW1Tb3VyY2VPYmplY3Qod2luZG93KTtcbiAgICAgIGNocm9tZVNoaW0uc2hpbVBlZXJDb25uZWN0aW9uKHdpbmRvdyk7XG4gICAgICBjaHJvbWVTaGltLnNoaW1PblRyYWNrKHdpbmRvdyk7XG4gICAgICBjaHJvbWVTaGltLnNoaW1HZXRTZW5kZXJzV2l0aER0bWYod2luZG93KTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgJ2ZpcmVmb3gnOlxuICAgICAgaWYgKCFmaXJlZm94U2hpbSB8fCAhZmlyZWZveFNoaW0uc2hpbVBlZXJDb25uZWN0aW9uKSB7XG4gICAgICAgIGxvZ2dpbmcoJ0ZpcmVmb3ggc2hpbSBpcyBub3QgaW5jbHVkZWQgaW4gdGhpcyBhZGFwdGVyIHJlbGVhc2UuJyk7XG4gICAgICAgIHJldHVybiBhZGFwdGVyO1xuICAgICAgfVxuICAgICAgbG9nZ2luZygnYWRhcHRlci5qcyBzaGltbWluZyBmaXJlZm94LicpO1xuICAgICAgLy8gRXhwb3J0IHRvIHRoZSBhZGFwdGVyIGdsb2JhbCBvYmplY3QgdmlzaWJsZSBpbiB0aGUgYnJvd3Nlci5cbiAgICAgIGFkYXB0ZXIuYnJvd3NlclNoaW0gPSBmaXJlZm94U2hpbTtcblxuICAgICAgZmlyZWZveFNoaW0uc2hpbUdldFVzZXJNZWRpYSh3aW5kb3cpO1xuICAgICAgdXRpbHMuc2hpbUNyZWF0ZU9iamVjdFVSTCh3aW5kb3cpO1xuICAgICAgZmlyZWZveFNoaW0uc2hpbVNvdXJjZU9iamVjdCh3aW5kb3cpO1xuICAgICAgZmlyZWZveFNoaW0uc2hpbVBlZXJDb25uZWN0aW9uKHdpbmRvdyk7XG4gICAgICBmaXJlZm94U2hpbS5zaGltT25UcmFjayh3aW5kb3cpO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAnZWRnZSc6XG4gICAgICBpZiAoIWVkZ2VTaGltIHx8ICFlZGdlU2hpbS5zaGltUGVlckNvbm5lY3Rpb24pIHtcbiAgICAgICAgbG9nZ2luZygnTVMgZWRnZSBzaGltIGlzIG5vdCBpbmNsdWRlZCBpbiB0aGlzIGFkYXB0ZXIgcmVsZWFzZS4nKTtcbiAgICAgICAgcmV0dXJuIGFkYXB0ZXI7XG4gICAgICB9XG4gICAgICBsb2dnaW5nKCdhZGFwdGVyLmpzIHNoaW1taW5nIGVkZ2UuJyk7XG4gICAgICAvLyBFeHBvcnQgdG8gdGhlIGFkYXB0ZXIgZ2xvYmFsIG9iamVjdCB2aXNpYmxlIGluIHRoZSBicm93c2VyLlxuICAgICAgYWRhcHRlci5icm93c2VyU2hpbSA9IGVkZ2VTaGltO1xuXG4gICAgICBlZGdlU2hpbS5zaGltR2V0VXNlck1lZGlhKHdpbmRvdyk7XG4gICAgICB1dGlscy5zaGltQ3JlYXRlT2JqZWN0VVJMKHdpbmRvdyk7XG4gICAgICBlZGdlU2hpbS5zaGltUGVlckNvbm5lY3Rpb24od2luZG93KTtcbiAgICAgIGVkZ2VTaGltLnNoaW1SZXBsYWNlVHJhY2sod2luZG93KTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgJ3NhZmFyaSc6XG4gICAgICBpZiAoIXNhZmFyaVNoaW0pIHtcbiAgICAgICAgbG9nZ2luZygnU2FmYXJpIHNoaW0gaXMgbm90IGluY2x1ZGVkIGluIHRoaXMgYWRhcHRlciByZWxlYXNlLicpO1xuICAgICAgICByZXR1cm4gYWRhcHRlcjtcbiAgICAgIH1cbiAgICAgIGxvZ2dpbmcoJ2FkYXB0ZXIuanMgc2hpbW1pbmcgc2FmYXJpLicpO1xuICAgICAgLy8gRXhwb3J0IHRvIHRoZSBhZGFwdGVyIGdsb2JhbCBvYmplY3QgdmlzaWJsZSBpbiB0aGUgYnJvd3Nlci5cbiAgICAgIGFkYXB0ZXIuYnJvd3NlclNoaW0gPSBzYWZhcmlTaGltO1xuXG4gICAgICBzYWZhcmlTaGltLnNoaW1DYWxsYmFja3NBUEkod2luZG93KTtcbiAgICAgIHNhZmFyaVNoaW0uc2hpbUFkZFN0cmVhbSh3aW5kb3cpO1xuICAgICAgc2FmYXJpU2hpbS5zaGltT25BZGRTdHJlYW0od2luZG93KTtcbiAgICAgIHNhZmFyaVNoaW0uc2hpbUdldFVzZXJNZWRpYSh3aW5kb3cpO1xuICAgICAgYnJlYWs7XG4gICAgZGVmYXVsdDpcbiAgICAgIGxvZ2dpbmcoJ1Vuc3VwcG9ydGVkIGJyb3dzZXIhJyk7XG4gICAgICBicmVhaztcbiAgfVxuXG4gIHJldHVybiBhZGFwdGVyO1xufTtcbiIsIlxuLypcbiAqICBDb3B5cmlnaHQgKGMpIDIwMTYgVGhlIFdlYlJUQyBwcm9qZWN0IGF1dGhvcnMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlIGxpY2Vuc2VcbiAqICB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGluIHRoZSByb290IG9mIHRoZSBzb3VyY2VcbiAqICB0cmVlLlxuICovXG4gLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy5qcycpO1xudmFyIGxvZ2dpbmcgPSB1dGlscy5sb2c7XG5cbnZhciBjaHJvbWVTaGltID0ge1xuICBzaGltTWVkaWFTdHJlYW06IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIHdpbmRvdy5NZWRpYVN0cmVhbSA9IHdpbmRvdy5NZWRpYVN0cmVhbSB8fCB3aW5kb3cud2Via2l0TWVkaWFTdHJlYW07XG4gIH0sXG5cbiAgc2hpbU9uVHJhY2s6IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAnb2JqZWN0JyAmJiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gJiYgISgnb250cmFjaycgaW5cbiAgICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZSkpIHtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLCAnb250cmFjaycsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5fb250cmFjaztcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbihmKSB7XG4gICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAgIGlmICh0aGlzLl9vbnRyYWNrKSB7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RyYWNrJywgdGhpcy5fb250cmFjayk7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2FkZHN0cmVhbScsIHRoaXMuX29udHJhY2twb2x5KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVyKCd0cmFjaycsIHRoaXMuX29udHJhY2sgPSBmKTtcbiAgICAgICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXIoJ2FkZHN0cmVhbScsIHRoaXMuX29udHJhY2twb2x5ID0gZnVuY3Rpb24oZSkge1xuICAgICAgICAgICAgLy8gb25hZGRzdHJlYW0gZG9lcyBub3QgZmlyZSB3aGVuIGEgdHJhY2sgaXMgYWRkZWQgdG8gYW4gZXhpc3RpbmdcbiAgICAgICAgICAgIC8vIHN0cmVhbS4gQnV0IHN0cmVhbS5vbmFkZHRyYWNrIGlzIGltcGxlbWVudGVkIHNvIHdlIHVzZSB0aGF0LlxuICAgICAgICAgICAgZS5zdHJlYW0uYWRkRXZlbnRMaXN0ZW5lcignYWRkdHJhY2snLCBmdW5jdGlvbih0ZSkge1xuICAgICAgICAgICAgICB2YXIgcmVjZWl2ZXI7XG4gICAgICAgICAgICAgIGlmICh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFJlY2VpdmVycykge1xuICAgICAgICAgICAgICAgIHJlY2VpdmVyID0gc2VsZi5nZXRSZWNlaXZlcnMoKS5maW5kKGZ1bmN0aW9uKHIpIHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiByLnRyYWNrLmlkID09PSB0ZS50cmFjay5pZDtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZWNlaXZlciA9IHt0cmFjazogdGUudHJhY2t9O1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KCd0cmFjaycpO1xuICAgICAgICAgICAgICBldmVudC50cmFjayA9IHRlLnRyYWNrO1xuICAgICAgICAgICAgICBldmVudC5yZWNlaXZlciA9IHJlY2VpdmVyO1xuICAgICAgICAgICAgICBldmVudC5zdHJlYW1zID0gW2Uuc3RyZWFtXTtcbiAgICAgICAgICAgICAgc2VsZi5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgZS5zdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbih0cmFjaykge1xuICAgICAgICAgICAgICB2YXIgcmVjZWl2ZXI7XG4gICAgICAgICAgICAgIGlmICh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFJlY2VpdmVycykge1xuICAgICAgICAgICAgICAgIHJlY2VpdmVyID0gc2VsZi5nZXRSZWNlaXZlcnMoKS5maW5kKGZ1bmN0aW9uKHIpIHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiByLnRyYWNrLmlkID09PSB0cmFjay5pZDtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZWNlaXZlciA9IHt0cmFjazogdHJhY2t9O1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHZhciBldmVudCA9IG5ldyBFdmVudCgndHJhY2snKTtcbiAgICAgICAgICAgICAgZXZlbnQudHJhY2sgPSB0cmFjaztcbiAgICAgICAgICAgICAgZXZlbnQucmVjZWl2ZXIgPSByZWNlaXZlcjtcbiAgICAgICAgICAgICAgZXZlbnQuc3RyZWFtcyA9IFtlLnN0cmVhbV07XG4gICAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfSxcblxuICBzaGltR2V0U2VuZGVyc1dpdGhEdG1mOiBmdW5jdGlvbih3aW5kb3cpIHtcbiAgICBpZiAodHlwZW9mIHdpbmRvdyA9PT0gJ29iamVjdCcgJiYgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uICYmXG4gICAgICAgICEoJ2dldFNlbmRlcnMnIGluIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUpICYmXG4gICAgICAgICdjcmVhdGVEVE1GU2VuZGVyJyBpbiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlKSB7XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFNlbmRlcnMgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3NlbmRlcnMgfHwgW107XG4gICAgICB9O1xuICAgICAgdmFyIG9yaWdBZGRTdHJlYW0gPSB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZFN0cmVhbTtcbiAgICAgIHZhciBvcmlnUmVtb3ZlU3RyZWFtID0gd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5yZW1vdmVTdHJlYW07XG5cbiAgICAgIGlmICghd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRUcmFjaykge1xuICAgICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZFRyYWNrID0gZnVuY3Rpb24odHJhY2ssIHN0cmVhbSkge1xuICAgICAgICAgIHZhciBwYyA9IHRoaXM7XG4gICAgICAgICAgaWYgKHBjLnNpZ25hbGluZ1N0YXRlID09PSAnY2xvc2VkJykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IERPTUV4Y2VwdGlvbihcbiAgICAgICAgICAgICAgJ1RoZSBSVENQZWVyQ29ubmVjdGlvblxcJ3Mgc2lnbmFsaW5nU3RhdGUgaXMgXFwnY2xvc2VkXFwnLicsXG4gICAgICAgICAgICAgICdJbnZhbGlkU3RhdGVFcnJvcicpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB2YXIgc3RyZWFtcyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgICBpZiAoc3RyZWFtcy5sZW5ndGggIT09IDEgfHxcbiAgICAgICAgICAgICAgIXN0cmVhbXNbMF0uZ2V0VHJhY2tzKCkuZmluZChmdW5jdGlvbih0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHQgPT09IHRyYWNrO1xuICAgICAgICAgICAgICB9KSkge1xuICAgICAgICAgICAgLy8gdGhpcyBpcyBub3QgZnVsbHkgY29ycmVjdCBidXQgYWxsIHdlIGNhbiBtYW5hZ2Ugd2l0aG91dFxuICAgICAgICAgICAgLy8gW1thc3NvY2lhdGVkIE1lZGlhU3RyZWFtc11dIGludGVybmFsIHNsb3QuXG4gICAgICAgICAgICB0aHJvdyBuZXcgRE9NRXhjZXB0aW9uKFxuICAgICAgICAgICAgICAnVGhlIGFkYXB0ZXIuanMgYWRkVHJhY2sgcG9seWZpbGwgb25seSBzdXBwb3J0cyBhIHNpbmdsZSAnICtcbiAgICAgICAgICAgICAgJyBzdHJlYW0gd2hpY2ggaXMgYXNzb2NpYXRlZCB3aXRoIHRoZSBzcGVjaWZpZWQgdHJhY2suJyxcbiAgICAgICAgICAgICAgJ05vdFN1cHBvcnRlZEVycm9yJyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcGMuX3NlbmRlcnMgPSBwYy5fc2VuZGVycyB8fCBbXTtcbiAgICAgICAgICB2YXIgYWxyZWFkeUV4aXN0cyA9IHBjLl9zZW5kZXJzLmZpbmQoZnVuY3Rpb24odCkge1xuICAgICAgICAgICAgcmV0dXJuIHQudHJhY2sgPT09IHRyYWNrO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIGlmIChhbHJlYWR5RXhpc3RzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRE9NRXhjZXB0aW9uKCdUcmFjayBhbHJlYWR5IGV4aXN0cy4nLFxuICAgICAgICAgICAgICAgICdJbnZhbGlkQWNjZXNzRXJyb3InKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBwYy5fc3RyZWFtcyA9IHBjLl9zdHJlYW1zIHx8IHt9O1xuICAgICAgICAgIHZhciBvbGRTdHJlYW0gPSBwYy5fc3RyZWFtc1tzdHJlYW0uaWRdO1xuICAgICAgICAgIGlmIChvbGRTdHJlYW0pIHtcbiAgICAgICAgICAgIG9sZFN0cmVhbS5hZGRUcmFjayh0cmFjayk7XG4gICAgICAgICAgICBwYy5yZW1vdmVTdHJlYW0ob2xkU3RyZWFtKTtcbiAgICAgICAgICAgIHBjLmFkZFN0cmVhbShvbGRTdHJlYW0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgbmV3U3RyZWFtID0gbmV3IHdpbmRvdy5NZWRpYVN0cmVhbShbdHJhY2tdKTtcbiAgICAgICAgICAgIHBjLl9zdHJlYW1zW3N0cmVhbS5pZF0gPSBuZXdTdHJlYW07XG4gICAgICAgICAgICBwYy5hZGRTdHJlYW0obmV3U3RyZWFtKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB2YXIgc2VuZGVyID0ge1xuICAgICAgICAgICAgdHJhY2s6IHRyYWNrLFxuICAgICAgICAgICAgZ2V0IGR0bWYoKSB7XG4gICAgICAgICAgICAgIGlmICh0aGlzLl9kdG1mID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBpZiAodHJhY2sua2luZCA9PT0gJ2F1ZGlvJykge1xuICAgICAgICAgICAgICAgICAgdGhpcy5fZHRtZiA9IHBjLmNyZWF0ZURUTUZTZW5kZXIodHJhY2spO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICB0aGlzLl9kdG1mID0gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2R0bWY7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfTtcbiAgICAgICAgICBwYy5fc2VuZGVycy5wdXNoKHNlbmRlcik7XG4gICAgICAgICAgcmV0dXJuIHNlbmRlcjtcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkU3RyZWFtID0gZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgIHZhciBwYyA9IHRoaXM7XG4gICAgICAgIHBjLl9zZW5kZXJzID0gcGMuX3NlbmRlcnMgfHwgW107XG4gICAgICAgIG9yaWdBZGRTdHJlYW0uYXBwbHkocGMsIFtzdHJlYW1dKTtcbiAgICAgICAgc3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2spIHtcbiAgICAgICAgICBwYy5fc2VuZGVycy5wdXNoKHtcbiAgICAgICAgICAgIHRyYWNrOiB0cmFjayxcbiAgICAgICAgICAgIGdldCBkdG1mKCkge1xuICAgICAgICAgICAgICBpZiAodGhpcy5fZHRtZiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRyYWNrLmtpbmQgPT09ICdhdWRpbycpIHtcbiAgICAgICAgICAgICAgICAgIHRoaXMuX2R0bWYgPSBwYy5jcmVhdGVEVE1GU2VuZGVyKHRyYWNrKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgdGhpcy5fZHRtZiA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJldHVybiB0aGlzLl9kdG1mO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH07XG5cbiAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUucmVtb3ZlU3RyZWFtID0gZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgIHZhciBwYyA9IHRoaXM7XG4gICAgICAgIHBjLl9zZW5kZXJzID0gcGMuX3NlbmRlcnMgfHwgW107XG4gICAgICAgIG9yaWdSZW1vdmVTdHJlYW0uYXBwbHkocGMsIFtzdHJlYW1dKTtcbiAgICAgICAgc3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2spIHtcbiAgICAgICAgICB2YXIgc2VuZGVyID0gcGMuX3NlbmRlcnMuZmluZChmdW5jdGlvbihzKSB7XG4gICAgICAgICAgICByZXR1cm4gcy50cmFjayA9PT0gdHJhY2s7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKHNlbmRlcikge1xuICAgICAgICAgICAgcGMuX3NlbmRlcnMuc3BsaWNlKHBjLl9zZW5kZXJzLmluZGV4T2Yoc2VuZGVyKSwgMSk7IC8vIHJlbW92ZSBzZW5kZXJcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfTtcbiAgICB9XG4gIH0sXG5cbiAgc2hpbVNvdXJjZU9iamVjdDogZnVuY3Rpb24od2luZG93KSB7XG4gICAgdmFyIFVSTCA9IHdpbmRvdyAmJiB3aW5kb3cuVVJMO1xuXG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnKSB7XG4gICAgICBpZiAod2luZG93LkhUTUxNZWRpYUVsZW1lbnQgJiZcbiAgICAgICAgISgnc3JjT2JqZWN0JyBpbiB3aW5kb3cuSFRNTE1lZGlhRWxlbWVudC5wcm90b3R5cGUpKSB7XG4gICAgICAgIC8vIFNoaW0gdGhlIHNyY09iamVjdCBwcm9wZXJ0eSwgb25jZSwgd2hlbiBIVE1MTWVkaWFFbGVtZW50IGlzIGZvdW5kLlxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkod2luZG93LkhUTUxNZWRpYUVsZW1lbnQucHJvdG90eXBlLCAnc3JjT2JqZWN0Jywge1xuICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fc3JjT2JqZWN0O1xuICAgICAgICAgIH0sXG4gICAgICAgICAgc2V0OiBmdW5jdGlvbihzdHJlYW0pIHtcbiAgICAgICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgICAgIC8vIFVzZSBfc3JjT2JqZWN0IGFzIGEgcHJpdmF0ZSBwcm9wZXJ0eSBmb3IgdGhpcyBzaGltXG4gICAgICAgICAgICB0aGlzLl9zcmNPYmplY3QgPSBzdHJlYW07XG4gICAgICAgICAgICBpZiAodGhpcy5zcmMpIHtcbiAgICAgICAgICAgICAgVVJMLnJldm9rZU9iamVjdFVSTCh0aGlzLnNyYyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghc3RyZWFtKSB7XG4gICAgICAgICAgICAgIHRoaXMuc3JjID0gJyc7XG4gICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnNyYyA9IFVSTC5jcmVhdGVPYmplY3RVUkwoc3RyZWFtKTtcbiAgICAgICAgICAgIC8vIFdlIG5lZWQgdG8gcmVjcmVhdGUgdGhlIGJsb2IgdXJsIHdoZW4gYSB0cmFjayBpcyBhZGRlZCBvclxuICAgICAgICAgICAgLy8gcmVtb3ZlZC4gRG9pbmcgaXQgbWFudWFsbHkgc2luY2Ugd2Ugd2FudCB0byBhdm9pZCBhIHJlY3Vyc2lvbi5cbiAgICAgICAgICAgIHN0cmVhbS5hZGRFdmVudExpc3RlbmVyKCdhZGR0cmFjaycsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICBpZiAoc2VsZi5zcmMpIHtcbiAgICAgICAgICAgICAgICBVUkwucmV2b2tlT2JqZWN0VVJMKHNlbGYuc3JjKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBzZWxmLnNyYyA9IFVSTC5jcmVhdGVPYmplY3RVUkwoc3RyZWFtKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgc3RyZWFtLmFkZEV2ZW50TGlzdGVuZXIoJ3JlbW92ZXRyYWNrJywgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgIGlmIChzZWxmLnNyYykge1xuICAgICAgICAgICAgICAgIFVSTC5yZXZva2VPYmplY3RVUkwoc2VsZi5zcmMpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHNlbGYuc3JjID0gVVJMLmNyZWF0ZU9iamVjdFVSTChzdHJlYW0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH0sXG5cbiAgc2hpbVBlZXJDb25uZWN0aW9uOiBmdW5jdGlvbih3aW5kb3cpIHtcbiAgICB2YXIgYnJvd3NlckRldGFpbHMgPSB1dGlscy5kZXRlY3RCcm93c2VyKHdpbmRvdyk7XG5cbiAgICAvLyBUaGUgUlRDUGVlckNvbm5lY3Rpb24gb2JqZWN0LlxuICAgIGlmICghd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uKSB7XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gPSBmdW5jdGlvbihwY0NvbmZpZywgcGNDb25zdHJhaW50cykge1xuICAgICAgICAvLyBUcmFuc2xhdGUgaWNlVHJhbnNwb3J0UG9saWN5IHRvIGljZVRyYW5zcG9ydHMsXG4gICAgICAgIC8vIHNlZSBodHRwczovL2NvZGUuZ29vZ2xlLmNvbS9wL3dlYnJ0Yy9pc3N1ZXMvZGV0YWlsP2lkPTQ4NjlcbiAgICAgICAgLy8gdGhpcyB3YXMgZml4ZWQgaW4gTTU2IGFsb25nIHdpdGggdW5wcmVmaXhpbmcgUlRDUGVlckNvbm5lY3Rpb24uXG4gICAgICAgIGxvZ2dpbmcoJ1BlZXJDb25uZWN0aW9uJyk7XG4gICAgICAgIGlmIChwY0NvbmZpZyAmJiBwY0NvbmZpZy5pY2VUcmFuc3BvcnRQb2xpY3kpIHtcbiAgICAgICAgICBwY0NvbmZpZy5pY2VUcmFuc3BvcnRzID0gcGNDb25maWcuaWNlVHJhbnNwb3J0UG9saWN5O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ldyB3aW5kb3cud2Via2l0UlRDUGVlckNvbm5lY3Rpb24ocGNDb25maWcsIHBjQ29uc3RyYWludHMpO1xuICAgICAgfTtcbiAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUgPVxuICAgICAgICAgIHdpbmRvdy53ZWJraXRSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGU7XG4gICAgICAvLyB3cmFwIHN0YXRpYyBtZXRob2RzLiBDdXJyZW50bHkganVzdCBnZW5lcmF0ZUNlcnRpZmljYXRlLlxuICAgICAgaWYgKHdpbmRvdy53ZWJraXRSVENQZWVyQ29ubmVjdGlvbi5nZW5lcmF0ZUNlcnRpZmljYXRlKSB7XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24sICdnZW5lcmF0ZUNlcnRpZmljYXRlJywge1xuICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gd2luZG93LndlYmtpdFJUQ1BlZXJDb25uZWN0aW9uLmdlbmVyYXRlQ2VydGlmaWNhdGU7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gbWlncmF0ZSBmcm9tIG5vbi1zcGVjIFJUQ0ljZVNlcnZlci51cmwgdG8gUlRDSWNlU2VydmVyLnVybHNcbiAgICAgIHZhciBPcmlnUGVlckNvbm5lY3Rpb24gPSB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb247XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gPSBmdW5jdGlvbihwY0NvbmZpZywgcGNDb25zdHJhaW50cykge1xuICAgICAgICBpZiAocGNDb25maWcgJiYgcGNDb25maWcuaWNlU2VydmVycykge1xuICAgICAgICAgIHZhciBuZXdJY2VTZXJ2ZXJzID0gW107XG4gICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwY0NvbmZpZy5pY2VTZXJ2ZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB2YXIgc2VydmVyID0gcGNDb25maWcuaWNlU2VydmVyc1tpXTtcbiAgICAgICAgICAgIGlmICghc2VydmVyLmhhc093blByb3BlcnR5KCd1cmxzJykgJiZcbiAgICAgICAgICAgICAgICBzZXJ2ZXIuaGFzT3duUHJvcGVydHkoJ3VybCcpKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUud2FybignUlRDSWNlU2VydmVyLnVybCBpcyBkZXByZWNhdGVkISBVc2UgdXJscyBpbnN0ZWFkLicpO1xuICAgICAgICAgICAgICBzZXJ2ZXIgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KHNlcnZlcikpO1xuICAgICAgICAgICAgICBzZXJ2ZXIudXJscyA9IHNlcnZlci51cmw7XG4gICAgICAgICAgICAgIG5ld0ljZVNlcnZlcnMucHVzaChzZXJ2ZXIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgbmV3SWNlU2VydmVycy5wdXNoKHBjQ29uZmlnLmljZVNlcnZlcnNbaV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBwY0NvbmZpZy5pY2VTZXJ2ZXJzID0gbmV3SWNlU2VydmVycztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmV3IE9yaWdQZWVyQ29ubmVjdGlvbihwY0NvbmZpZywgcGNDb25zdHJhaW50cyk7XG4gICAgICB9O1xuICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZSA9IE9yaWdQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGU7XG4gICAgICAvLyB3cmFwIHN0YXRpYyBtZXRob2RzLiBDdXJyZW50bHkganVzdCBnZW5lcmF0ZUNlcnRpZmljYXRlLlxuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbiwgJ2dlbmVyYXRlQ2VydGlmaWNhdGUnLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgcmV0dXJuIE9yaWdQZWVyQ29ubmVjdGlvbi5nZW5lcmF0ZUNlcnRpZmljYXRlO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB2YXIgb3JpZ0dldFN0YXRzID0gd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRTdGF0cztcbiAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFN0YXRzID0gZnVuY3Rpb24oc2VsZWN0b3IsXG4gICAgICAgIHN1Y2Nlc3NDYWxsYmFjaywgZXJyb3JDYWxsYmFjaykge1xuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG5cbiAgICAgIC8vIElmIHNlbGVjdG9yIGlzIGEgZnVuY3Rpb24gdGhlbiB3ZSBhcmUgaW4gdGhlIG9sZCBzdHlsZSBzdGF0cyBzbyBqdXN0XG4gICAgICAvLyBwYXNzIGJhY2sgdGhlIG9yaWdpbmFsIGdldFN0YXRzIGZvcm1hdCB0byBhdm9pZCBicmVha2luZyBvbGQgdXNlcnMuXG4gICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDAgJiYgdHlwZW9mIHNlbGVjdG9yID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHJldHVybiBvcmlnR2V0U3RhdHMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgIH1cblxuICAgICAgLy8gV2hlbiBzcGVjLXN0eWxlIGdldFN0YXRzIGlzIHN1cHBvcnRlZCwgcmV0dXJuIHRob3NlIHdoZW4gY2FsbGVkIHdpdGhcbiAgICAgIC8vIGVpdGhlciBubyBhcmd1bWVudHMgb3IgdGhlIHNlbGVjdG9yIGFyZ3VtZW50IGlzIG51bGwuXG4gICAgICBpZiAob3JpZ0dldFN0YXRzLmxlbmd0aCA9PT0gMCAmJiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCB8fFxuICAgICAgICAgIHR5cGVvZiBhcmd1bWVudHNbMF0gIT09ICdmdW5jdGlvbicpKSB7XG4gICAgICAgIHJldHVybiBvcmlnR2V0U3RhdHMuYXBwbHkodGhpcywgW10pO1xuICAgICAgfVxuXG4gICAgICB2YXIgZml4Q2hyb21lU3RhdHNfID0gZnVuY3Rpb24ocmVzcG9uc2UpIHtcbiAgICAgICAgdmFyIHN0YW5kYXJkUmVwb3J0ID0ge307XG4gICAgICAgIHZhciByZXBvcnRzID0gcmVzcG9uc2UucmVzdWx0KCk7XG4gICAgICAgIHJlcG9ydHMuZm9yRWFjaChmdW5jdGlvbihyZXBvcnQpIHtcbiAgICAgICAgICB2YXIgc3RhbmRhcmRTdGF0cyA9IHtcbiAgICAgICAgICAgIGlkOiByZXBvcnQuaWQsXG4gICAgICAgICAgICB0aW1lc3RhbXA6IHJlcG9ydC50aW1lc3RhbXAsXG4gICAgICAgICAgICB0eXBlOiB7XG4gICAgICAgICAgICAgIGxvY2FsY2FuZGlkYXRlOiAnbG9jYWwtY2FuZGlkYXRlJyxcbiAgICAgICAgICAgICAgcmVtb3RlY2FuZGlkYXRlOiAncmVtb3RlLWNhbmRpZGF0ZSdcbiAgICAgICAgICAgIH1bcmVwb3J0LnR5cGVdIHx8IHJlcG9ydC50eXBlXG4gICAgICAgICAgfTtcbiAgICAgICAgICByZXBvcnQubmFtZXMoKS5mb3JFYWNoKGZ1bmN0aW9uKG5hbWUpIHtcbiAgICAgICAgICAgIHN0YW5kYXJkU3RhdHNbbmFtZV0gPSByZXBvcnQuc3RhdChuYW1lKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBzdGFuZGFyZFJlcG9ydFtzdGFuZGFyZFN0YXRzLmlkXSA9IHN0YW5kYXJkU3RhdHM7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBzdGFuZGFyZFJlcG9ydDtcbiAgICAgIH07XG5cbiAgICAgIC8vIHNoaW0gZ2V0U3RhdHMgd2l0aCBtYXBsaWtlIHN1cHBvcnRcbiAgICAgIHZhciBtYWtlTWFwU3RhdHMgPSBmdW5jdGlvbihzdGF0cykge1xuICAgICAgICByZXR1cm4gbmV3IE1hcChPYmplY3Qua2V5cyhzdGF0cykubWFwKGZ1bmN0aW9uKGtleSkge1xuICAgICAgICAgIHJldHVybiBba2V5LCBzdGF0c1trZXldXTtcbiAgICAgICAgfSkpO1xuICAgICAgfTtcblxuICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPj0gMikge1xuICAgICAgICB2YXIgc3VjY2Vzc0NhbGxiYWNrV3JhcHBlcl8gPSBmdW5jdGlvbihyZXNwb25zZSkge1xuICAgICAgICAgIGFyZ3NbMV0obWFrZU1hcFN0YXRzKGZpeENocm9tZVN0YXRzXyhyZXNwb25zZSkpKTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gb3JpZ0dldFN0YXRzLmFwcGx5KHRoaXMsIFtzdWNjZXNzQ2FsbGJhY2tXcmFwcGVyXyxcbiAgICAgICAgICBhcmd1bWVudHNbMF1dKTtcbiAgICAgIH1cblxuICAgICAgLy8gcHJvbWlzZS1zdXBwb3J0XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICAgIG9yaWdHZXRTdGF0cy5hcHBseShzZWxmLCBbXG4gICAgICAgICAgZnVuY3Rpb24ocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIHJlc29sdmUobWFrZU1hcFN0YXRzKGZpeENocm9tZVN0YXRzXyhyZXNwb25zZSkpKTtcbiAgICAgICAgICB9LCByZWplY3RdKTtcbiAgICAgIH0pLnRoZW4oc3VjY2Vzc0NhbGxiYWNrLCBlcnJvckNhbGxiYWNrKTtcbiAgICB9O1xuXG4gICAgLy8gYWRkIHByb21pc2Ugc3VwcG9ydCAtLSBuYXRpdmVseSBhdmFpbGFibGUgaW4gQ2hyb21lIDUxXG4gICAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCA1MSkge1xuICAgICAgWydzZXRMb2NhbERlc2NyaXB0aW9uJywgJ3NldFJlbW90ZURlc2NyaXB0aW9uJywgJ2FkZEljZUNhbmRpZGF0ZSddXG4gICAgICAgICAgLmZvckVhY2goZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICAgICAgICB2YXIgbmF0aXZlTWV0aG9kID0gd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdO1xuICAgICAgICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgIHZhciBhcmdzID0gYXJndW1lbnRzO1xuICAgICAgICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgICAgICAgIHZhciBwcm9taXNlID0gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICAgICAgICAgICAgbmF0aXZlTWV0aG9kLmFwcGx5KHNlbGYsIFthcmdzWzBdLCByZXNvbHZlLCByZWplY3RdKTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIGlmIChhcmdzLmxlbmd0aCA8IDIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcHJvbWlzZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXR1cm4gcHJvbWlzZS50aGVuKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgIGFyZ3NbMV0uYXBwbHkobnVsbCwgW10pO1xuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBmdW5jdGlvbihlcnIpIHtcbiAgICAgICAgICAgICAgICBpZiAoYXJncy5sZW5ndGggPj0gMykge1xuICAgICAgICAgICAgICAgICAgYXJnc1syXS5hcHBseShudWxsLCBbZXJyXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gcHJvbWlzZSBzdXBwb3J0IGZvciBjcmVhdGVPZmZlciBhbmQgY3JlYXRlQW5zd2VyLiBBdmFpbGFibGUgKHdpdGhvdXRcbiAgICAvLyBidWdzKSBzaW5jZSBNNTI6IGNyYnVnLzYxOTI4OVxuICAgIGlmIChicm93c2VyRGV0YWlscy52ZXJzaW9uIDwgNTIpIHtcbiAgICAgIFsnY3JlYXRlT2ZmZXInLCAnY3JlYXRlQW5zd2VyJ10uZm9yRWFjaChmdW5jdGlvbihtZXRob2QpIHtcbiAgICAgICAgdmFyIG5hdGl2ZU1ldGhvZCA9IHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGVbbWV0aG9kXTtcbiAgICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoIDwgMSB8fCAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSAmJlxuICAgICAgICAgICAgICB0eXBlb2YgYXJndW1lbnRzWzBdID09PSAnb2JqZWN0JykpIHtcbiAgICAgICAgICAgIHZhciBvcHRzID0gYXJndW1lbnRzLmxlbmd0aCA9PT0gMSA/IGFyZ3VtZW50c1swXSA6IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgICAgICAgICAgbmF0aXZlTWV0aG9kLmFwcGx5KHNlbGYsIFtyZXNvbHZlLCByZWplY3QsIG9wdHNdKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gbmF0aXZlTWV0aG9kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBzaGltIGltcGxpY2l0IGNyZWF0aW9uIG9mIFJUQ1Nlc3Npb25EZXNjcmlwdGlvbi9SVENJY2VDYW5kaWRhdGVcbiAgICBbJ3NldExvY2FsRGVzY3JpcHRpb24nLCAnc2V0UmVtb3RlRGVzY3JpcHRpb24nLCAnYWRkSWNlQ2FuZGlkYXRlJ11cbiAgICAgICAgLmZvckVhY2goZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICAgICAgdmFyIG5hdGl2ZU1ldGhvZCA9IHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGVbbWV0aG9kXTtcbiAgICAgICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlW21ldGhvZF0gPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGFyZ3VtZW50c1swXSA9IG5ldyAoKG1ldGhvZCA9PT0gJ2FkZEljZUNhbmRpZGF0ZScpID9cbiAgICAgICAgICAgICAgICB3aW5kb3cuUlRDSWNlQ2FuZGlkYXRlIDpcbiAgICAgICAgICAgICAgICB3aW5kb3cuUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKShhcmd1bWVudHNbMF0pO1xuICAgICAgICAgICAgcmV0dXJuIG5hdGl2ZU1ldGhvZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuXG4gICAgLy8gc3VwcG9ydCBmb3IgYWRkSWNlQ2FuZGlkYXRlKG51bGwgb3IgdW5kZWZpbmVkKVxuICAgIHZhciBuYXRpdmVBZGRJY2VDYW5kaWRhdGUgPVxuICAgICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZEljZUNhbmRpZGF0ZTtcbiAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZEljZUNhbmRpZGF0ZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgaWYgKCFhcmd1bWVudHNbMF0pIHtcbiAgICAgICAgaWYgKGFyZ3VtZW50c1sxXSkge1xuICAgICAgICAgIGFyZ3VtZW50c1sxXS5hcHBseShudWxsKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbmF0aXZlQWRkSWNlQ2FuZGlkYXRlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgfTtcbiAgfVxufTtcblxuXG4vLyBFeHBvc2UgcHVibGljIG1ldGhvZHMuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgc2hpbU1lZGlhU3RyZWFtOiBjaHJvbWVTaGltLnNoaW1NZWRpYVN0cmVhbSxcbiAgc2hpbU9uVHJhY2s6IGNocm9tZVNoaW0uc2hpbU9uVHJhY2ssXG4gIHNoaW1HZXRTZW5kZXJzV2l0aER0bWY6IGNocm9tZVNoaW0uc2hpbUdldFNlbmRlcnNXaXRoRHRtZixcbiAgc2hpbVNvdXJjZU9iamVjdDogY2hyb21lU2hpbS5zaGltU291cmNlT2JqZWN0LFxuICBzaGltUGVlckNvbm5lY3Rpb246IGNocm9tZVNoaW0uc2hpbVBlZXJDb25uZWN0aW9uLFxuICBzaGltR2V0VXNlck1lZGlhOiByZXF1aXJlKCcuL2dldHVzZXJtZWRpYScpXG59O1xuIiwiLypcbiAqICBDb3B5cmlnaHQgKGMpIDIwMTYgVGhlIFdlYlJUQyBwcm9qZWN0IGF1dGhvcnMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlIGxpY2Vuc2VcbiAqICB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGluIHRoZSByb290IG9mIHRoZSBzb3VyY2VcbiAqICB0cmVlLlxuICovXG4gLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy5qcycpO1xudmFyIGxvZ2dpbmcgPSB1dGlscy5sb2c7XG5cbi8vIEV4cG9zZSBwdWJsaWMgbWV0aG9kcy5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24od2luZG93KSB7XG4gIHZhciBicm93c2VyRGV0YWlscyA9IHV0aWxzLmRldGVjdEJyb3dzZXIod2luZG93KTtcbiAgdmFyIG5hdmlnYXRvciA9IHdpbmRvdyAmJiB3aW5kb3cubmF2aWdhdG9yO1xuXG4gIHZhciBjb25zdHJhaW50c1RvQ2hyb21lXyA9IGZ1bmN0aW9uKGMpIHtcbiAgICBpZiAodHlwZW9mIGMgIT09ICdvYmplY3QnIHx8IGMubWFuZGF0b3J5IHx8IGMub3B0aW9uYWwpIHtcbiAgICAgIHJldHVybiBjO1xuICAgIH1cbiAgICB2YXIgY2MgPSB7fTtcbiAgICBPYmplY3Qua2V5cyhjKS5mb3JFYWNoKGZ1bmN0aW9uKGtleSkge1xuICAgICAgaWYgKGtleSA9PT0gJ3JlcXVpcmUnIHx8IGtleSA9PT0gJ2FkdmFuY2VkJyB8fCBrZXkgPT09ICdtZWRpYVNvdXJjZScpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgdmFyIHIgPSAodHlwZW9mIGNba2V5XSA9PT0gJ29iamVjdCcpID8gY1trZXldIDoge2lkZWFsOiBjW2tleV19O1xuICAgICAgaWYgKHIuZXhhY3QgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygci5leGFjdCA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgci5taW4gPSByLm1heCA9IHIuZXhhY3Q7XG4gICAgICB9XG4gICAgICB2YXIgb2xkbmFtZV8gPSBmdW5jdGlvbihwcmVmaXgsIG5hbWUpIHtcbiAgICAgICAgaWYgKHByZWZpeCkge1xuICAgICAgICAgIHJldHVybiBwcmVmaXggKyBuYW1lLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgbmFtZS5zbGljZSgxKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gKG5hbWUgPT09ICdkZXZpY2VJZCcpID8gJ3NvdXJjZUlkJyA6IG5hbWU7XG4gICAgICB9O1xuICAgICAgaWYgKHIuaWRlYWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjYy5vcHRpb25hbCA9IGNjLm9wdGlvbmFsIHx8IFtdO1xuICAgICAgICB2YXIgb2MgPSB7fTtcbiAgICAgICAgaWYgKHR5cGVvZiByLmlkZWFsID09PSAnbnVtYmVyJykge1xuICAgICAgICAgIG9jW29sZG5hbWVfKCdtaW4nLCBrZXkpXSA9IHIuaWRlYWw7XG4gICAgICAgICAgY2Mub3B0aW9uYWwucHVzaChvYyk7XG4gICAgICAgICAgb2MgPSB7fTtcbiAgICAgICAgICBvY1tvbGRuYW1lXygnbWF4Jywga2V5KV0gPSByLmlkZWFsO1xuICAgICAgICAgIGNjLm9wdGlvbmFsLnB1c2gob2MpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG9jW29sZG5hbWVfKCcnLCBrZXkpXSA9IHIuaWRlYWw7XG4gICAgICAgICAgY2Mub3B0aW9uYWwucHVzaChvYyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmIChyLmV4YWN0ICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHIuZXhhY3QgIT09ICdudW1iZXInKSB7XG4gICAgICAgIGNjLm1hbmRhdG9yeSA9IGNjLm1hbmRhdG9yeSB8fCB7fTtcbiAgICAgICAgY2MubWFuZGF0b3J5W29sZG5hbWVfKCcnLCBrZXkpXSA9IHIuZXhhY3Q7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBbJ21pbicsICdtYXgnXS5mb3JFYWNoKGZ1bmN0aW9uKG1peCkge1xuICAgICAgICAgIGlmIChyW21peF0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgY2MubWFuZGF0b3J5ID0gY2MubWFuZGF0b3J5IHx8IHt9O1xuICAgICAgICAgICAgY2MubWFuZGF0b3J5W29sZG5hbWVfKG1peCwga2V5KV0gPSByW21peF07XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBpZiAoYy5hZHZhbmNlZCkge1xuICAgICAgY2Mub3B0aW9uYWwgPSAoY2Mub3B0aW9uYWwgfHwgW10pLmNvbmNhdChjLmFkdmFuY2VkKTtcbiAgICB9XG4gICAgcmV0dXJuIGNjO1xuICB9O1xuXG4gIHZhciBzaGltQ29uc3RyYWludHNfID0gZnVuY3Rpb24oY29uc3RyYWludHMsIGZ1bmMpIHtcbiAgICBjb25zdHJhaW50cyA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoY29uc3RyYWludHMpKTtcbiAgICBpZiAoY29uc3RyYWludHMgJiYgdHlwZW9mIGNvbnN0cmFpbnRzLmF1ZGlvID09PSAnb2JqZWN0Jykge1xuICAgICAgdmFyIHJlbWFwID0gZnVuY3Rpb24ob2JqLCBhLCBiKSB7XG4gICAgICAgIGlmIChhIGluIG9iaiAmJiAhKGIgaW4gb2JqKSkge1xuICAgICAgICAgIG9ialtiXSA9IG9ialthXTtcbiAgICAgICAgICBkZWxldGUgb2JqW2FdO1xuICAgICAgICB9XG4gICAgICB9O1xuICAgICAgY29uc3RyYWludHMgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGNvbnN0cmFpbnRzKSk7XG4gICAgICByZW1hcChjb25zdHJhaW50cy5hdWRpbywgJ2F1dG9HYWluQ29udHJvbCcsICdnb29nQXV0b0dhaW5Db250cm9sJyk7XG4gICAgICByZW1hcChjb25zdHJhaW50cy5hdWRpbywgJ25vaXNlU3VwcHJlc3Npb24nLCAnZ29vZ05vaXNlU3VwcHJlc3Npb24nKTtcbiAgICAgIGNvbnN0cmFpbnRzLmF1ZGlvID0gY29uc3RyYWludHNUb0Nocm9tZV8oY29uc3RyYWludHMuYXVkaW8pO1xuICAgIH1cbiAgICBpZiAoY29uc3RyYWludHMgJiYgdHlwZW9mIGNvbnN0cmFpbnRzLnZpZGVvID09PSAnb2JqZWN0Jykge1xuICAgICAgLy8gU2hpbSBmYWNpbmdNb2RlIGZvciBtb2JpbGUgJiBzdXJmYWNlIHByby5cbiAgICAgIHZhciBmYWNlID0gY29uc3RyYWludHMudmlkZW8uZmFjaW5nTW9kZTtcbiAgICAgIGZhY2UgPSBmYWNlICYmICgodHlwZW9mIGZhY2UgPT09ICdvYmplY3QnKSA/IGZhY2UgOiB7aWRlYWw6IGZhY2V9KTtcbiAgICAgIHZhciBnZXRTdXBwb3J0ZWRGYWNpbmdNb2RlTGllcyA9IGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCA2MTtcblxuICAgICAgaWYgKChmYWNlICYmIChmYWNlLmV4YWN0ID09PSAndXNlcicgfHwgZmFjZS5leGFjdCA9PT0gJ2Vudmlyb25tZW50JyB8fFxuICAgICAgICAgICAgICAgICAgICBmYWNlLmlkZWFsID09PSAndXNlcicgfHwgZmFjZS5pZGVhbCA9PT0gJ2Vudmlyb25tZW50JykpICYmXG4gICAgICAgICAgIShuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFN1cHBvcnRlZENvbnN0cmFpbnRzICYmXG4gICAgICAgICAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFN1cHBvcnRlZENvbnN0cmFpbnRzKCkuZmFjaW5nTW9kZSAmJlxuICAgICAgICAgICAgIWdldFN1cHBvcnRlZEZhY2luZ01vZGVMaWVzKSkge1xuICAgICAgICBkZWxldGUgY29uc3RyYWludHMudmlkZW8uZmFjaW5nTW9kZTtcbiAgICAgICAgdmFyIG1hdGNoZXM7XG4gICAgICAgIGlmIChmYWNlLmV4YWN0ID09PSAnZW52aXJvbm1lbnQnIHx8IGZhY2UuaWRlYWwgPT09ICdlbnZpcm9ubWVudCcpIHtcbiAgICAgICAgICBtYXRjaGVzID0gWydiYWNrJywgJ3JlYXInXTtcbiAgICAgICAgfSBlbHNlIGlmIChmYWNlLmV4YWN0ID09PSAndXNlcicgfHwgZmFjZS5pZGVhbCA9PT0gJ3VzZXInKSB7XG4gICAgICAgICAgbWF0Y2hlcyA9IFsnZnJvbnQnXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobWF0Y2hlcykge1xuICAgICAgICAgIC8vIExvb2sgZm9yIG1hdGNoZXMgaW4gbGFiZWwsIG9yIHVzZSBsYXN0IGNhbSBmb3IgYmFjayAodHlwaWNhbCkuXG4gICAgICAgICAgcmV0dXJuIG5hdmlnYXRvci5tZWRpYURldmljZXMuZW51bWVyYXRlRGV2aWNlcygpXG4gICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZGV2aWNlcykge1xuICAgICAgICAgICAgZGV2aWNlcyA9IGRldmljZXMuZmlsdGVyKGZ1bmN0aW9uKGQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIGQua2luZCA9PT0gJ3ZpZGVvaW5wdXQnO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB2YXIgZGV2ID0gZGV2aWNlcy5maW5kKGZ1bmN0aW9uKGQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIG1hdGNoZXMuc29tZShmdW5jdGlvbihtYXRjaCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBkLmxhYmVsLnRvTG93ZXJDYXNlKCkuaW5kZXhPZihtYXRjaCkgIT09IC0xO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKCFkZXYgJiYgZGV2aWNlcy5sZW5ndGggJiYgbWF0Y2hlcy5pbmRleE9mKCdiYWNrJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgIGRldiA9IGRldmljZXNbZGV2aWNlcy5sZW5ndGggLSAxXTsgLy8gbW9yZSBsaWtlbHkgdGhlIGJhY2sgY2FtXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZGV2KSB7XG4gICAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLmRldmljZUlkID0gZmFjZS5leGFjdCA/IHtleGFjdDogZGV2LmRldmljZUlkfSA6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtpZGVhbDogZGV2LmRldmljZUlkfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvID0gY29uc3RyYWludHNUb0Nocm9tZV8oY29uc3RyYWludHMudmlkZW8pO1xuICAgICAgICAgICAgbG9nZ2luZygnY2hyb21lOiAnICsgSlNPTi5zdHJpbmdpZnkoY29uc3RyYWludHMpKTtcbiAgICAgICAgICAgIHJldHVybiBmdW5jKGNvbnN0cmFpbnRzKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29uc3RyYWludHMudmlkZW8gPSBjb25zdHJhaW50c1RvQ2hyb21lXyhjb25zdHJhaW50cy52aWRlbyk7XG4gICAgfVxuICAgIGxvZ2dpbmcoJ2Nocm9tZTogJyArIEpTT04uc3RyaW5naWZ5KGNvbnN0cmFpbnRzKSk7XG4gICAgcmV0dXJuIGZ1bmMoY29uc3RyYWludHMpO1xuICB9O1xuXG4gIHZhciBzaGltRXJyb3JfID0gZnVuY3Rpb24oZSkge1xuICAgIHJldHVybiB7XG4gICAgICBuYW1lOiB7XG4gICAgICAgIFBlcm1pc3Npb25EZW5pZWRFcnJvcjogJ05vdEFsbG93ZWRFcnJvcicsXG4gICAgICAgIEludmFsaWRTdGF0ZUVycm9yOiAnTm90UmVhZGFibGVFcnJvcicsXG4gICAgICAgIERldmljZXNOb3RGb3VuZEVycm9yOiAnTm90Rm91bmRFcnJvcicsXG4gICAgICAgIENvbnN0cmFpbnROb3RTYXRpc2ZpZWRFcnJvcjogJ092ZXJjb25zdHJhaW5lZEVycm9yJyxcbiAgICAgICAgVHJhY2tTdGFydEVycm9yOiAnTm90UmVhZGFibGVFcnJvcicsXG4gICAgICAgIE1lZGlhRGV2aWNlRmFpbGVkRHVlVG9TaHV0ZG93bjogJ05vdFJlYWRhYmxlRXJyb3InLFxuICAgICAgICBNZWRpYURldmljZUtpbGxTd2l0Y2hPbjogJ05vdFJlYWRhYmxlRXJyb3InXG4gICAgICB9W2UubmFtZV0gfHwgZS5uYW1lLFxuICAgICAgbWVzc2FnZTogZS5tZXNzYWdlLFxuICAgICAgY29uc3RyYWludDogZS5jb25zdHJhaW50TmFtZSxcbiAgICAgIHRvU3RyaW5nOiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubmFtZSArICh0aGlzLm1lc3NhZ2UgJiYgJzogJykgKyB0aGlzLm1lc3NhZ2U7XG4gICAgICB9XG4gICAgfTtcbiAgfTtcblxuICB2YXIgZ2V0VXNlck1lZGlhXyA9IGZ1bmN0aW9uKGNvbnN0cmFpbnRzLCBvblN1Y2Nlc3MsIG9uRXJyb3IpIHtcbiAgICBzaGltQ29uc3RyYWludHNfKGNvbnN0cmFpbnRzLCBmdW5jdGlvbihjKSB7XG4gICAgICBuYXZpZ2F0b3Iud2Via2l0R2V0VXNlck1lZGlhKGMsIG9uU3VjY2VzcywgZnVuY3Rpb24oZSkge1xuICAgICAgICBvbkVycm9yKHNoaW1FcnJvcl8oZSkpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH07XG5cbiAgbmF2aWdhdG9yLmdldFVzZXJNZWRpYSA9IGdldFVzZXJNZWRpYV87XG5cbiAgLy8gUmV0dXJucyB0aGUgcmVzdWx0IG9mIGdldFVzZXJNZWRpYSBhcyBhIFByb21pc2UuXG4gIHZhciBnZXRVc2VyTWVkaWFQcm9taXNlXyA9IGZ1bmN0aW9uKGNvbnN0cmFpbnRzKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgbmF2aWdhdG9yLmdldFVzZXJNZWRpYShjb25zdHJhaW50cywgcmVzb2x2ZSwgcmVqZWN0KTtcbiAgICB9KTtcbiAgfTtcblxuICBpZiAoIW5hdmlnYXRvci5tZWRpYURldmljZXMpIHtcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzID0ge1xuICAgICAgZ2V0VXNlck1lZGlhOiBnZXRVc2VyTWVkaWFQcm9taXNlXyxcbiAgICAgIGVudW1lcmF0ZURldmljZXM6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSkge1xuICAgICAgICAgIHZhciBraW5kcyA9IHthdWRpbzogJ2F1ZGlvaW5wdXQnLCB2aWRlbzogJ3ZpZGVvaW5wdXQnfTtcbiAgICAgICAgICByZXR1cm4gd2luZG93Lk1lZGlhU3RyZWFtVHJhY2suZ2V0U291cmNlcyhmdW5jdGlvbihkZXZpY2VzKSB7XG4gICAgICAgICAgICByZXNvbHZlKGRldmljZXMubWFwKGZ1bmN0aW9uKGRldmljZSkge1xuICAgICAgICAgICAgICByZXR1cm4ge2xhYmVsOiBkZXZpY2UubGFiZWwsXG4gICAgICAgICAgICAgICAga2luZDoga2luZHNbZGV2aWNlLmtpbmRdLFxuICAgICAgICAgICAgICAgIGRldmljZUlkOiBkZXZpY2UuaWQsXG4gICAgICAgICAgICAgICAgZ3JvdXBJZDogJyd9O1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgICBnZXRTdXBwb3J0ZWRDb25zdHJhaW50czogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZGV2aWNlSWQ6IHRydWUsIGVjaG9DYW5jZWxsYXRpb246IHRydWUsIGZhY2luZ01vZGU6IHRydWUsXG4gICAgICAgICAgZnJhbWVSYXRlOiB0cnVlLCBoZWlnaHQ6IHRydWUsIHdpZHRoOiB0cnVlXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIC8vIEEgc2hpbSBmb3IgZ2V0VXNlck1lZGlhIG1ldGhvZCBvbiB0aGUgbWVkaWFEZXZpY2VzIG9iamVjdC5cbiAgLy8gVE9ETyhLYXB0ZW5KYW5zc29uKSByZW1vdmUgb25jZSBpbXBsZW1lbnRlZCBpbiBDaHJvbWUgc3RhYmxlLlxuICBpZiAoIW5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKSB7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEgPSBmdW5jdGlvbihjb25zdHJhaW50cykge1xuICAgICAgcmV0dXJuIGdldFVzZXJNZWRpYVByb21pc2VfKGNvbnN0cmFpbnRzKTtcbiAgICB9O1xuICB9IGVsc2Uge1xuICAgIC8vIEV2ZW4gdGhvdWdoIENocm9tZSA0NSBoYXMgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcyBhbmQgYSBnZXRVc2VyTWVkaWFcbiAgICAvLyBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGEgUHJvbWlzZSwgaXQgZG9lcyBub3QgYWNjZXB0IHNwZWMtc3R5bGVcbiAgICAvLyBjb25zdHJhaW50cy5cbiAgICB2YXIgb3JpZ0dldFVzZXJNZWRpYSA9IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhLlxuICAgICAgICBiaW5kKG5hdmlnYXRvci5tZWRpYURldmljZXMpO1xuICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhID0gZnVuY3Rpb24oY3MpIHtcbiAgICAgIHJldHVybiBzaGltQ29uc3RyYWludHNfKGNzLCBmdW5jdGlvbihjKSB7XG4gICAgICAgIHJldHVybiBvcmlnR2V0VXNlck1lZGlhKGMpLnRoZW4oZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgICAgaWYgKGMuYXVkaW8gJiYgIXN0cmVhbS5nZXRBdWRpb1RyYWNrcygpLmxlbmd0aCB8fFxuICAgICAgICAgICAgICBjLnZpZGVvICYmICFzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGgpIHtcbiAgICAgICAgICAgIHN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgICAgICAgICAgIHRyYWNrLnN0b3AoKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhyb3cgbmV3IERPTUV4Y2VwdGlvbignJywgJ05vdEZvdW5kRXJyb3InKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHN0cmVhbTtcbiAgICAgICAgfSwgZnVuY3Rpb24oZSkge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChzaGltRXJyb3JfKGUpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9O1xuICB9XG5cbiAgLy8gRHVtbXkgZGV2aWNlY2hhbmdlIGV2ZW50IG1ldGhvZHMuXG4gIC8vIFRPRE8oS2FwdGVuSmFuc3NvbikgcmVtb3ZlIG9uY2UgaW1wbGVtZW50ZWQgaW4gQ2hyb21lIHN0YWJsZS5cbiAgaWYgKHR5cGVvZiBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmFkZEV2ZW50TGlzdGVuZXIgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5hZGRFdmVudExpc3RlbmVyID0gZnVuY3Rpb24oKSB7XG4gICAgICBsb2dnaW5nKCdEdW1teSBtZWRpYURldmljZXMuYWRkRXZlbnRMaXN0ZW5lciBjYWxsZWQuJyk7XG4gICAgfTtcbiAgfVxuICBpZiAodHlwZW9mIG5hdmlnYXRvci5tZWRpYURldmljZXMucmVtb3ZlRXZlbnRMaXN0ZW5lciA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLnJlbW92ZUV2ZW50TGlzdGVuZXIgPSBmdW5jdGlvbigpIHtcbiAgICAgIGxvZ2dpbmcoJ0R1bW15IG1lZGlhRGV2aWNlcy5yZW1vdmVFdmVudExpc3RlbmVyIGNhbGxlZC4nKTtcbiAgICB9O1xuICB9XG59O1xuIiwiLypcbiAqICBDb3B5cmlnaHQgKGMpIDIwMTYgVGhlIFdlYlJUQyBwcm9qZWN0IGF1dGhvcnMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlIGxpY2Vuc2VcbiAqICB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGluIHRoZSByb290IG9mIHRoZSBzb3VyY2VcbiAqICB0cmVlLlxuICovXG4gLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG5cbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzJyk7XG52YXIgc2hpbVJUQ1BlZXJDb25uZWN0aW9uID0gcmVxdWlyZSgnLi9ydGNwZWVyY29ubmVjdGlvbl9zaGltJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBzaGltR2V0VXNlck1lZGlhOiByZXF1aXJlKCcuL2dldHVzZXJtZWRpYScpLFxuICBzaGltUGVlckNvbm5lY3Rpb246IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIHZhciBicm93c2VyRGV0YWlscyA9IHV0aWxzLmRldGVjdEJyb3dzZXIod2luZG93KTtcblxuICAgIGlmICh3aW5kb3cuUlRDSWNlR2F0aGVyZXIpIHtcbiAgICAgIC8vIE9SVEMgZGVmaW5lcyBhbiBSVENJY2VDYW5kaWRhdGUgb2JqZWN0IGJ1dCBubyBjb25zdHJ1Y3Rvci5cbiAgICAgIC8vIE5vdCBpbXBsZW1lbnRlZCBpbiBFZGdlLlxuICAgICAgaWYgKCF3aW5kb3cuUlRDSWNlQ2FuZGlkYXRlKSB7XG4gICAgICAgIHdpbmRvdy5SVENJY2VDYW5kaWRhdGUgPSBmdW5jdGlvbihhcmdzKSB7XG4gICAgICAgICAgcmV0dXJuIGFyZ3M7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICAvLyBPUlRDIGRvZXMgbm90IGhhdmUgYSBzZXNzaW9uIGRlc2NyaXB0aW9uIG9iamVjdCBidXRcbiAgICAgIC8vIG90aGVyIGJyb3dzZXJzIChpLmUuIENocm9tZSkgdGhhdCB3aWxsIHN1cHBvcnQgYm90aCBQQyBhbmQgT1JUQ1xuICAgICAgLy8gaW4gdGhlIGZ1dHVyZSBtaWdodCBoYXZlIHRoaXMgZGVmaW5lZCBhbHJlYWR5LlxuICAgICAgaWYgKCF3aW5kb3cuUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKSB7XG4gICAgICAgIHdpbmRvdy5SVENTZXNzaW9uRGVzY3JpcHRpb24gPSBmdW5jdGlvbihhcmdzKSB7XG4gICAgICAgICAgcmV0dXJuIGFyZ3M7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICAvLyB0aGlzIGFkZHMgYW4gYWRkaXRpb25hbCBldmVudCBsaXN0ZW5lciB0byBNZWRpYVN0cmFja1RyYWNrIHRoYXQgc2lnbmFsc1xuICAgICAgLy8gd2hlbiBhIHRyYWNrcyBlbmFibGVkIHByb3BlcnR5IHdhcyBjaGFuZ2VkLiBXb3JrYXJvdW5kIGZvciBhIGJ1ZyBpblxuICAgICAgLy8gYWRkU3RyZWFtLCBzZWUgYmVsb3cuIE5vIGxvbmdlciByZXF1aXJlZCBpbiAxNTAyNStcbiAgICAgIGlmIChicm93c2VyRGV0YWlscy52ZXJzaW9uIDwgMTUwMjUpIHtcbiAgICAgICAgdmFyIG9yaWdNU1RFbmFibGVkID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihcbiAgICAgICAgICAgIHdpbmRvdy5NZWRpYVN0cmVhbVRyYWNrLnByb3RvdHlwZSwgJ2VuYWJsZWQnKTtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdy5NZWRpYVN0cmVhbVRyYWNrLnByb3RvdHlwZSwgJ2VuYWJsZWQnLCB7XG4gICAgICAgICAgc2V0OiBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICAgICAgb3JpZ01TVEVuYWJsZWQuc2V0LmNhbGwodGhpcywgdmFsdWUpO1xuICAgICAgICAgICAgdmFyIGV2ID0gbmV3IEV2ZW50KCdlbmFibGVkJyk7XG4gICAgICAgICAgICBldi5lbmFibGVkID0gdmFsdWU7XG4gICAgICAgICAgICB0aGlzLmRpc3BhdGNoRXZlbnQoZXYpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbiA9XG4gICAgICAgIHNoaW1SVENQZWVyQ29ubmVjdGlvbih3aW5kb3csIGJyb3dzZXJEZXRhaWxzLnZlcnNpb24pO1xuICB9LFxuICBzaGltUmVwbGFjZVRyYWNrOiBmdW5jdGlvbih3aW5kb3cpIHtcbiAgICAvLyBPUlRDIGhhcyByZXBsYWNlVHJhY2sgLS0gaHR0cHM6Ly9naXRodWIuY29tL3czYy9vcnRjL2lzc3Vlcy82MTRcbiAgICBpZiAod2luZG93LlJUQ1J0cFNlbmRlciAmJlxuICAgICAgICAhKCdyZXBsYWNlVHJhY2snIGluIHdpbmRvdy5SVENSdHBTZW5kZXIucHJvdG90eXBlKSkge1xuICAgICAgd2luZG93LlJUQ1J0cFNlbmRlci5wcm90b3R5cGUucmVwbGFjZVRyYWNrID1cbiAgICAgICAgICB3aW5kb3cuUlRDUnRwU2VuZGVyLnByb3RvdHlwZS5zZXRUcmFjaztcbiAgICB9XG4gIH1cbn07XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcblxuLy8gRXhwb3NlIHB1YmxpYyBtZXRob2RzLlxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbih3aW5kb3cpIHtcbiAgdmFyIG5hdmlnYXRvciA9IHdpbmRvdyAmJiB3aW5kb3cubmF2aWdhdG9yO1xuXG4gIHZhciBzaGltRXJyb3JfID0gZnVuY3Rpb24oZSkge1xuICAgIHJldHVybiB7XG4gICAgICBuYW1lOiB7UGVybWlzc2lvbkRlbmllZEVycm9yOiAnTm90QWxsb3dlZEVycm9yJ31bZS5uYW1lXSB8fCBlLm5hbWUsXG4gICAgICBtZXNzYWdlOiBlLm1lc3NhZ2UsXG4gICAgICBjb25zdHJhaW50OiBlLmNvbnN0cmFpbnQsXG4gICAgICB0b1N0cmluZzogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm5hbWU7XG4gICAgICB9XG4gICAgfTtcbiAgfTtcblxuICAvLyBnZXRVc2VyTWVkaWEgZXJyb3Igc2hpbS5cbiAgdmFyIG9yaWdHZXRVc2VyTWVkaWEgPSBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYS5cbiAgICAgIGJpbmQobmF2aWdhdG9yLm1lZGlhRGV2aWNlcyk7XG4gIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhID0gZnVuY3Rpb24oYykge1xuICAgIHJldHVybiBvcmlnR2V0VXNlck1lZGlhKGMpLmNhdGNoKGZ1bmN0aW9uKGUpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChzaGltRXJyb3JfKGUpKTtcbiAgICB9KTtcbiAgfTtcbn07XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNyBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcblxudmFyIFNEUFV0aWxzID0gcmVxdWlyZSgnc2RwJyk7XG5cbi8vIHNvcnQgdHJhY2tzIHN1Y2ggdGhhdCB0aGV5IGZvbGxvdyBhbiBhLXYtYS12Li4uXG4vLyBwYXR0ZXJuLlxuZnVuY3Rpb24gc29ydFRyYWNrcyh0cmFja3MpIHtcbiAgdmFyIGF1ZGlvVHJhY2tzID0gdHJhY2tzLmZpbHRlcihmdW5jdGlvbih0cmFjaykge1xuICAgIHJldHVybiB0cmFjay5raW5kID09PSAnYXVkaW8nO1xuICB9KTtcbiAgdmFyIHZpZGVvVHJhY2tzID0gdHJhY2tzLmZpbHRlcihmdW5jdGlvbih0cmFjaykge1xuICAgIHJldHVybiB0cmFjay5raW5kID09PSAndmlkZW8nO1xuICB9KTtcbiAgdHJhY2tzID0gW107XG4gIHdoaWxlIChhdWRpb1RyYWNrcy5sZW5ndGggfHwgdmlkZW9UcmFja3MubGVuZ3RoKSB7XG4gICAgaWYgKGF1ZGlvVHJhY2tzLmxlbmd0aCkge1xuICAgICAgdHJhY2tzLnB1c2goYXVkaW9UcmFja3Muc2hpZnQoKSk7XG4gICAgfVxuICAgIGlmICh2aWRlb1RyYWNrcy5sZW5ndGgpIHtcbiAgICAgIHRyYWNrcy5wdXNoKHZpZGVvVHJhY2tzLnNoaWZ0KCkpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gdHJhY2tzO1xufVxuXG4vLyBFZGdlIGRvZXMgbm90IGxpa2Vcbi8vIDEpIHN0dW46XG4vLyAyKSB0dXJuOiB0aGF0IGRvZXMgbm90IGhhdmUgYWxsIG9mIHR1cm46aG9zdDpwb3J0P3RyYW5zcG9ydD11ZHBcbi8vIDMpIHR1cm46IHdpdGggaXB2NiBhZGRyZXNzZXNcbi8vIDQpIHR1cm46IG9jY3VycmluZyBtdWxpcGxlIHRpbWVzXG5mdW5jdGlvbiBmaWx0ZXJJY2VTZXJ2ZXJzKGljZVNlcnZlcnMsIGVkZ2VWZXJzaW9uKSB7XG4gIHZhciBoYXNUdXJuID0gZmFsc2U7XG4gIGljZVNlcnZlcnMgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGljZVNlcnZlcnMpKTtcbiAgcmV0dXJuIGljZVNlcnZlcnMuZmlsdGVyKGZ1bmN0aW9uKHNlcnZlcikge1xuICAgIGlmIChzZXJ2ZXIgJiYgKHNlcnZlci51cmxzIHx8IHNlcnZlci51cmwpKSB7XG4gICAgICB2YXIgdXJscyA9IHNlcnZlci51cmxzIHx8IHNlcnZlci51cmw7XG4gICAgICBpZiAoc2VydmVyLnVybCAmJiAhc2VydmVyLnVybHMpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdSVENJY2VTZXJ2ZXIudXJsIGlzIGRlcHJlY2F0ZWQhIFVzZSB1cmxzIGluc3RlYWQuJyk7XG4gICAgICB9XG4gICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgdXJscyA9PT0gJ3N0cmluZyc7XG4gICAgICBpZiAoaXNTdHJpbmcpIHtcbiAgICAgICAgdXJscyA9IFt1cmxzXTtcbiAgICAgIH1cbiAgICAgIHVybHMgPSB1cmxzLmZpbHRlcihmdW5jdGlvbih1cmwpIHtcbiAgICAgICAgdmFyIHZhbGlkVHVybiA9IHVybC5pbmRleE9mKCd0dXJuOicpID09PSAwICYmXG4gICAgICAgICAgICB1cmwuaW5kZXhPZigndHJhbnNwb3J0PXVkcCcpICE9PSAtMSAmJlxuICAgICAgICAgICAgdXJsLmluZGV4T2YoJ3R1cm46WycpID09PSAtMSAmJlxuICAgICAgICAgICAgIWhhc1R1cm47XG5cbiAgICAgICAgaWYgKHZhbGlkVHVybikge1xuICAgICAgICAgIGhhc1R1cm4gPSB0cnVlO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1cmwuaW5kZXhPZignc3R1bjonKSA9PT0gMCAmJiBlZGdlVmVyc2lvbiA+PSAxNDM5MztcbiAgICAgIH0pO1xuXG4gICAgICBkZWxldGUgc2VydmVyLnVybDtcbiAgICAgIHNlcnZlci51cmxzID0gaXNTdHJpbmcgPyB1cmxzWzBdIDogdXJscztcbiAgICAgIHJldHVybiAhIXVybHMubGVuZ3RoO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH0pO1xufVxuXG4vLyBEZXRlcm1pbmVzIHRoZSBpbnRlcnNlY3Rpb24gb2YgbG9jYWwgYW5kIHJlbW90ZSBjYXBhYmlsaXRpZXMuXG5mdW5jdGlvbiBnZXRDb21tb25DYXBhYmlsaXRpZXMobG9jYWxDYXBhYmlsaXRpZXMsIHJlbW90ZUNhcGFiaWxpdGllcykge1xuICB2YXIgY29tbW9uQ2FwYWJpbGl0aWVzID0ge1xuICAgIGNvZGVjczogW10sXG4gICAgaGVhZGVyRXh0ZW5zaW9uczogW10sXG4gICAgZmVjTWVjaGFuaXNtczogW11cbiAgfTtcblxuICB2YXIgZmluZENvZGVjQnlQYXlsb2FkVHlwZSA9IGZ1bmN0aW9uKHB0LCBjb2RlY3MpIHtcbiAgICBwdCA9IHBhcnNlSW50KHB0LCAxMCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb2RlY3MubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChjb2RlY3NbaV0ucGF5bG9hZFR5cGUgPT09IHB0IHx8XG4gICAgICAgICAgY29kZWNzW2ldLnByZWZlcnJlZFBheWxvYWRUeXBlID09PSBwdCkge1xuICAgICAgICByZXR1cm4gY29kZWNzW2ldO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICB2YXIgcnR4Q2FwYWJpbGl0eU1hdGNoZXMgPSBmdW5jdGlvbihsUnR4LCByUnR4LCBsQ29kZWNzLCByQ29kZWNzKSB7XG4gICAgdmFyIGxDb2RlYyA9IGZpbmRDb2RlY0J5UGF5bG9hZFR5cGUobFJ0eC5wYXJhbWV0ZXJzLmFwdCwgbENvZGVjcyk7XG4gICAgdmFyIHJDb2RlYyA9IGZpbmRDb2RlY0J5UGF5bG9hZFR5cGUoclJ0eC5wYXJhbWV0ZXJzLmFwdCwgckNvZGVjcyk7XG4gICAgcmV0dXJuIGxDb2RlYyAmJiByQ29kZWMgJiZcbiAgICAgICAgbENvZGVjLm5hbWUudG9Mb3dlckNhc2UoKSA9PT0gckNvZGVjLm5hbWUudG9Mb3dlckNhc2UoKTtcbiAgfTtcblxuICBsb2NhbENhcGFiaWxpdGllcy5jb2RlY3MuZm9yRWFjaChmdW5jdGlvbihsQ29kZWMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJlbW90ZUNhcGFiaWxpdGllcy5jb2RlY3MubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciByQ29kZWMgPSByZW1vdGVDYXBhYmlsaXRpZXMuY29kZWNzW2ldO1xuICAgICAgaWYgKGxDb2RlYy5uYW1lLnRvTG93ZXJDYXNlKCkgPT09IHJDb2RlYy5uYW1lLnRvTG93ZXJDYXNlKCkgJiZcbiAgICAgICAgICBsQ29kZWMuY2xvY2tSYXRlID09PSByQ29kZWMuY2xvY2tSYXRlKSB7XG4gICAgICAgIGlmIChsQ29kZWMubmFtZS50b0xvd2VyQ2FzZSgpID09PSAncnR4JyAmJlxuICAgICAgICAgICAgbENvZGVjLnBhcmFtZXRlcnMgJiYgckNvZGVjLnBhcmFtZXRlcnMuYXB0KSB7XG4gICAgICAgICAgLy8gZm9yIFJUWCB3ZSBuZWVkIHRvIGZpbmQgdGhlIGxvY2FsIHJ0eCB0aGF0IGhhcyBhIGFwdFxuICAgICAgICAgIC8vIHdoaWNoIHBvaW50cyB0byB0aGUgc2FtZSBsb2NhbCBjb2RlYyBhcyB0aGUgcmVtb3RlIG9uZS5cbiAgICAgICAgICBpZiAoIXJ0eENhcGFiaWxpdHlNYXRjaGVzKGxDb2RlYywgckNvZGVjLFxuICAgICAgICAgICAgICBsb2NhbENhcGFiaWxpdGllcy5jb2RlY3MsIHJlbW90ZUNhcGFiaWxpdGllcy5jb2RlY3MpKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgckNvZGVjID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShyQ29kZWMpKTsgLy8gZGVlcGNvcHlcbiAgICAgICAgLy8gbnVtYmVyIG9mIGNoYW5uZWxzIGlzIHRoZSBoaWdoZXN0IGNvbW1vbiBudW1iZXIgb2YgY2hhbm5lbHNcbiAgICAgICAgckNvZGVjLm51bUNoYW5uZWxzID0gTWF0aC5taW4obENvZGVjLm51bUNoYW5uZWxzLFxuICAgICAgICAgICAgckNvZGVjLm51bUNoYW5uZWxzKTtcbiAgICAgICAgLy8gcHVzaCByQ29kZWMgc28gd2UgcmVwbHkgd2l0aCBvZmZlcmVyIHBheWxvYWQgdHlwZVxuICAgICAgICBjb21tb25DYXBhYmlsaXRpZXMuY29kZWNzLnB1c2gockNvZGVjKTtcblxuICAgICAgICAvLyBkZXRlcm1pbmUgY29tbW9uIGZlZWRiYWNrIG1lY2hhbmlzbXNcbiAgICAgICAgckNvZGVjLnJ0Y3BGZWVkYmFjayA9IHJDb2RlYy5ydGNwRmVlZGJhY2suZmlsdGVyKGZ1bmN0aW9uKGZiKSB7XG4gICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBsQ29kZWMucnRjcEZlZWRiYWNrLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICBpZiAobENvZGVjLnJ0Y3BGZWVkYmFja1tqXS50eXBlID09PSBmYi50eXBlICYmXG4gICAgICAgICAgICAgICAgbENvZGVjLnJ0Y3BGZWVkYmFja1tqXS5wYXJhbWV0ZXIgPT09IGZiLnBhcmFtZXRlcikge1xuICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9KTtcbiAgICAgICAgLy8gRklYTUU6IGFsc28gbmVlZCB0byBkZXRlcm1pbmUgLnBhcmFtZXRlcnNcbiAgICAgICAgLy8gIHNlZSBodHRwczovL2dpdGh1Yi5jb20vb3BlbnBlZXIvb3J0Yy9pc3N1ZXMvNTY5XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgbG9jYWxDYXBhYmlsaXRpZXMuaGVhZGVyRXh0ZW5zaW9ucy5mb3JFYWNoKGZ1bmN0aW9uKGxIZWFkZXJFeHRlbnNpb24pIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJlbW90ZUNhcGFiaWxpdGllcy5oZWFkZXJFeHRlbnNpb25zLmxlbmd0aDtcbiAgICAgICAgIGkrKykge1xuICAgICAgdmFyIHJIZWFkZXJFeHRlbnNpb24gPSByZW1vdGVDYXBhYmlsaXRpZXMuaGVhZGVyRXh0ZW5zaW9uc1tpXTtcbiAgICAgIGlmIChsSGVhZGVyRXh0ZW5zaW9uLnVyaSA9PT0gckhlYWRlckV4dGVuc2lvbi51cmkpIHtcbiAgICAgICAgY29tbW9uQ2FwYWJpbGl0aWVzLmhlYWRlckV4dGVuc2lvbnMucHVzaChySGVhZGVyRXh0ZW5zaW9uKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9KTtcblxuICAvLyBGSVhNRTogZmVjTWVjaGFuaXNtc1xuICByZXR1cm4gY29tbW9uQ2FwYWJpbGl0aWVzO1xufVxuXG4vLyBpcyBhY3Rpb249c2V0TG9jYWxEZXNjcmlwdGlvbiB3aXRoIHR5cGUgYWxsb3dlZCBpbiBzaWduYWxpbmdTdGF0ZVxuZnVuY3Rpb24gaXNBY3Rpb25BbGxvd2VkSW5TaWduYWxpbmdTdGF0ZShhY3Rpb24sIHR5cGUsIHNpZ25hbGluZ1N0YXRlKSB7XG4gIHJldHVybiB7XG4gICAgb2ZmZXI6IHtcbiAgICAgIHNldExvY2FsRGVzY3JpcHRpb246IFsnc3RhYmxlJywgJ2hhdmUtbG9jYWwtb2ZmZXInXSxcbiAgICAgIHNldFJlbW90ZURlc2NyaXB0aW9uOiBbJ3N0YWJsZScsICdoYXZlLXJlbW90ZS1vZmZlciddXG4gICAgfSxcbiAgICBhbnN3ZXI6IHtcbiAgICAgIHNldExvY2FsRGVzY3JpcHRpb246IFsnaGF2ZS1yZW1vdGUtb2ZmZXInLCAnaGF2ZS1sb2NhbC1wcmFuc3dlciddLFxuICAgICAgc2V0UmVtb3RlRGVzY3JpcHRpb246IFsnaGF2ZS1sb2NhbC1vZmZlcicsICdoYXZlLXJlbW90ZS1wcmFuc3dlciddXG4gICAgfVxuICB9W3R5cGVdW2FjdGlvbl0uaW5kZXhPZihzaWduYWxpbmdTdGF0ZSkgIT09IC0xO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKHdpbmRvdywgZWRnZVZlcnNpb24pIHtcbiAgdmFyIFJUQ1BlZXJDb25uZWN0aW9uID0gZnVuY3Rpb24oY29uZmlnKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgdmFyIF9ldmVudFRhcmdldCA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtcbiAgICBbJ2FkZEV2ZW50TGlzdGVuZXInLCAncmVtb3ZlRXZlbnRMaXN0ZW5lcicsICdkaXNwYXRjaEV2ZW50J11cbiAgICAgICAgLmZvckVhY2goZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICAgICAgc2VsZlttZXRob2RdID0gX2V2ZW50VGFyZ2V0W21ldGhvZF0uYmluZChfZXZlbnRUYXJnZXQpO1xuICAgICAgICB9KTtcblxuICAgIHRoaXMubmVlZE5lZ290aWF0aW9uID0gZmFsc2U7XG5cbiAgICB0aGlzLm9uaWNlY2FuZGlkYXRlID0gbnVsbDtcbiAgICB0aGlzLm9uYWRkc3RyZWFtID0gbnVsbDtcbiAgICB0aGlzLm9udHJhY2sgPSBudWxsO1xuICAgIHRoaXMub25yZW1vdmVzdHJlYW0gPSBudWxsO1xuICAgIHRoaXMub25zaWduYWxpbmdzdGF0ZWNoYW5nZSA9IG51bGw7XG4gICAgdGhpcy5vbmljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZSA9IG51bGw7XG4gICAgdGhpcy5vbmljZWdhdGhlcmluZ3N0YXRlY2hhbmdlID0gbnVsbDtcbiAgICB0aGlzLm9ubmVnb3RpYXRpb25uZWVkZWQgPSBudWxsO1xuICAgIHRoaXMub25kYXRhY2hhbm5lbCA9IG51bGw7XG4gICAgdGhpcy5jYW5Ucmlja2xlSWNlQ2FuZGlkYXRlcyA9IG51bGw7XG5cbiAgICB0aGlzLmxvY2FsU3RyZWFtcyA9IFtdO1xuICAgIHRoaXMucmVtb3RlU3RyZWFtcyA9IFtdO1xuICAgIHRoaXMuZ2V0TG9jYWxTdHJlYW1zID0gZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gc2VsZi5sb2NhbFN0cmVhbXM7XG4gICAgfTtcbiAgICB0aGlzLmdldFJlbW90ZVN0cmVhbXMgPSBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiBzZWxmLnJlbW90ZVN0cmVhbXM7XG4gICAgfTtcblxuICAgIHRoaXMubG9jYWxEZXNjcmlwdGlvbiA9IG5ldyB3aW5kb3cuUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgIHR5cGU6ICcnLFxuICAgICAgc2RwOiAnJ1xuICAgIH0pO1xuICAgIHRoaXMucmVtb3RlRGVzY3JpcHRpb24gPSBuZXcgd2luZG93LlJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICB0eXBlOiAnJyxcbiAgICAgIHNkcDogJydcbiAgICB9KTtcbiAgICB0aGlzLnNpZ25hbGluZ1N0YXRlID0gJ3N0YWJsZSc7XG4gICAgdGhpcy5pY2VDb25uZWN0aW9uU3RhdGUgPSAnbmV3JztcbiAgICB0aGlzLmljZUdhdGhlcmluZ1N0YXRlID0gJ25ldyc7XG5cbiAgICB0aGlzLmljZU9wdGlvbnMgPSB7XG4gICAgICBnYXRoZXJQb2xpY3k6ICdhbGwnLFxuICAgICAgaWNlU2VydmVyczogW11cbiAgICB9O1xuICAgIGlmIChjb25maWcgJiYgY29uZmlnLmljZVRyYW5zcG9ydFBvbGljeSkge1xuICAgICAgc3dpdGNoIChjb25maWcuaWNlVHJhbnNwb3J0UG9saWN5KSB7XG4gICAgICAgIGNhc2UgJ2FsbCc6XG4gICAgICAgIGNhc2UgJ3JlbGF5JzpcbiAgICAgICAgICB0aGlzLmljZU9wdGlvbnMuZ2F0aGVyUG9saWN5ID0gY29uZmlnLmljZVRyYW5zcG9ydFBvbGljeTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAvLyBkb24ndCBzZXQgaWNlVHJhbnNwb3J0UG9saWN5LlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLnVzaW5nQnVuZGxlID0gY29uZmlnICYmIGNvbmZpZy5idW5kbGVQb2xpY3kgPT09ICdtYXgtYnVuZGxlJztcblxuICAgIGlmIChjb25maWcgJiYgY29uZmlnLmljZVNlcnZlcnMpIHtcbiAgICAgIHRoaXMuaWNlT3B0aW9ucy5pY2VTZXJ2ZXJzID0gZmlsdGVySWNlU2VydmVycyhjb25maWcuaWNlU2VydmVycyxcbiAgICAgICAgICBlZGdlVmVyc2lvbik7XG4gICAgfVxuICAgIHRoaXMuX2NvbmZpZyA9IGNvbmZpZyB8fCB7fTtcblxuICAgIC8vIHBlci10cmFjayBpY2VHYXRoZXJzLCBpY2VUcmFuc3BvcnRzLCBkdGxzVHJhbnNwb3J0cywgcnRwU2VuZGVycywgLi4uXG4gICAgLy8gZXZlcnl0aGluZyB0aGF0IGlzIG5lZWRlZCB0byBkZXNjcmliZSBhIFNEUCBtLWxpbmUuXG4gICAgdGhpcy50cmFuc2NlaXZlcnMgPSBbXTtcblxuICAgIC8vIHNpbmNlIHRoZSBpY2VHYXRoZXJlciBpcyBjdXJyZW50bHkgY3JlYXRlZCBpbiBjcmVhdGVPZmZlciBidXQgd2VcbiAgICAvLyBtdXN0IG5vdCBlbWl0IGNhbmRpZGF0ZXMgdW50aWwgYWZ0ZXIgc2V0TG9jYWxEZXNjcmlwdGlvbiB3ZSBidWZmZXJcbiAgICAvLyB0aGVtIGluIHRoaXMgYXJyYXkuXG4gICAgdGhpcy5fbG9jYWxJY2VDYW5kaWRhdGVzQnVmZmVyID0gW107XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl9lbWl0R2F0aGVyaW5nU3RhdGVDaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgZXZlbnQgPSBuZXcgRXZlbnQoJ2ljZWdhdGhlcmluZ3N0YXRlY2hhbmdlJyk7XG4gICAgdGhpcy5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICBpZiAodGhpcy5vbmljZWdhdGhlcmluZ3N0YXRlY2hhbmdlICE9PSBudWxsKSB7XG4gICAgICB0aGlzLm9uaWNlZ2F0aGVyaW5nc3RhdGVjaGFuZ2UoZXZlbnQpO1xuICAgIH1cbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX2VtaXRCdWZmZXJlZENhbmRpZGF0ZXMgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHNlY3Rpb25zID0gU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyhzZWxmLmxvY2FsRGVzY3JpcHRpb24uc2RwKTtcbiAgICAvLyBGSVhNRTogbmVlZCB0byBhcHBseSBpY2UgY2FuZGlkYXRlcyBpbiBhIHdheSB3aGljaCBpcyBhc3luYyBidXRcbiAgICAvLyBpbi1vcmRlclxuICAgIHRoaXMuX2xvY2FsSWNlQ2FuZGlkYXRlc0J1ZmZlci5mb3JFYWNoKGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICB2YXIgZW5kID0gIWV2ZW50LmNhbmRpZGF0ZSB8fCBPYmplY3Qua2V5cyhldmVudC5jYW5kaWRhdGUpLmxlbmd0aCA9PT0gMDtcbiAgICAgIGlmIChlbmQpIHtcbiAgICAgICAgZm9yICh2YXIgaiA9IDE7IGogPCBzZWN0aW9ucy5sZW5ndGg7IGorKykge1xuICAgICAgICAgIGlmIChzZWN0aW9uc1tqXS5pbmRleE9mKCdcXHJcXG5hPWVuZC1vZi1jYW5kaWRhdGVzXFxyXFxuJykgPT09IC0xKSB7XG4gICAgICAgICAgICBzZWN0aW9uc1tqXSArPSAnYT1lbmQtb2YtY2FuZGlkYXRlc1xcclxcbic7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzZWN0aW9uc1tldmVudC5jYW5kaWRhdGUuc2RwTUxpbmVJbmRleCArIDFdICs9XG4gICAgICAgICAgICAnYT0nICsgZXZlbnQuY2FuZGlkYXRlLmNhbmRpZGF0ZSArICdcXHJcXG4nO1xuICAgICAgfVxuICAgICAgc2VsZi5sb2NhbERlc2NyaXB0aW9uLnNkcCA9IHNlY3Rpb25zLmpvaW4oJycpO1xuICAgICAgc2VsZi5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICAgIGlmIChzZWxmLm9uaWNlY2FuZGlkYXRlICE9PSBudWxsKSB7XG4gICAgICAgIHNlbGYub25pY2VjYW5kaWRhdGUoZXZlbnQpO1xuICAgICAgfVxuICAgICAgaWYgKCFldmVudC5jYW5kaWRhdGUgJiYgc2VsZi5pY2VHYXRoZXJpbmdTdGF0ZSAhPT0gJ2NvbXBsZXRlJykge1xuICAgICAgICB2YXIgY29tcGxldGUgPSBzZWxmLnRyYW5zY2VpdmVycy5ldmVyeShmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgICAgIHJldHVybiB0cmFuc2NlaXZlci5pY2VHYXRoZXJlciAmJlxuICAgICAgICAgICAgICB0cmFuc2NlaXZlci5pY2VHYXRoZXJlci5zdGF0ZSA9PT0gJ2NvbXBsZXRlZCc7XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoY29tcGxldGUgJiYgc2VsZi5pY2VHYXRoZXJpbmdTdGF0ZUNoYW5nZSAhPT0gJ2NvbXBsZXRlJykge1xuICAgICAgICAgIHNlbGYuaWNlR2F0aGVyaW5nU3RhdGUgPSAnY29tcGxldGUnO1xuICAgICAgICAgIHNlbGYuX2VtaXRHYXRoZXJpbmdTdGF0ZUNoYW5nZSgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgdGhpcy5fbG9jYWxJY2VDYW5kaWRhdGVzQnVmZmVyID0gW107XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldENvbmZpZ3VyYXRpb24gPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5fY29uZmlnO1xuICB9O1xuXG4gIC8vIGludGVybmFsIGhlbHBlciB0byBjcmVhdGUgYSB0cmFuc2NlaXZlciBvYmplY3QuXG4gIC8vICh3aGloIGlzIG5vdCB5ZXQgdGhlIHNhbWUgYXMgdGhlIFdlYlJUQyAxLjAgdHJhbnNjZWl2ZXIpXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5fY3JlYXRlVHJhbnNjZWl2ZXIgPSBmdW5jdGlvbihraW5kKSB7XG4gICAgdmFyIGhhc0J1bmRsZVRyYW5zcG9ydCA9IHRoaXMudHJhbnNjZWl2ZXJzLmxlbmd0aCA+IDA7XG4gICAgdmFyIHRyYW5zY2VpdmVyID0ge1xuICAgICAgdHJhY2s6IG51bGwsXG4gICAgICBpY2VHYXRoZXJlcjogbnVsbCxcbiAgICAgIGljZVRyYW5zcG9ydDogbnVsbCxcbiAgICAgIGR0bHNUcmFuc3BvcnQ6IG51bGwsXG4gICAgICBsb2NhbENhcGFiaWxpdGllczogbnVsbCxcbiAgICAgIHJlbW90ZUNhcGFiaWxpdGllczogbnVsbCxcbiAgICAgIHJ0cFNlbmRlcjogbnVsbCxcbiAgICAgIHJ0cFJlY2VpdmVyOiBudWxsLFxuICAgICAga2luZDoga2luZCxcbiAgICAgIG1pZDogbnVsbCxcbiAgICAgIHNlbmRFbmNvZGluZ1BhcmFtZXRlcnM6IG51bGwsXG4gICAgICByZWN2RW5jb2RpbmdQYXJhbWV0ZXJzOiBudWxsLFxuICAgICAgc3RyZWFtOiBudWxsLFxuICAgICAgd2FudFJlY2VpdmU6IHRydWVcbiAgICB9O1xuICAgIGlmICh0aGlzLnVzaW5nQnVuZGxlICYmIGhhc0J1bmRsZVRyYW5zcG9ydCkge1xuICAgICAgdHJhbnNjZWl2ZXIuaWNlVHJhbnNwb3J0ID0gdGhpcy50cmFuc2NlaXZlcnNbMF0uaWNlVHJhbnNwb3J0O1xuICAgICAgdHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydCA9IHRoaXMudHJhbnNjZWl2ZXJzWzBdLmR0bHNUcmFuc3BvcnQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciB0cmFuc3BvcnRzID0gdGhpcy5fY3JlYXRlSWNlQW5kRHRsc1RyYW5zcG9ydHMoKTtcbiAgICAgIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydCA9IHRyYW5zcG9ydHMuaWNlVHJhbnNwb3J0O1xuICAgICAgdHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydCA9IHRyYW5zcG9ydHMuZHRsc1RyYW5zcG9ydDtcbiAgICB9XG4gICAgdGhpcy50cmFuc2NlaXZlcnMucHVzaCh0cmFuc2NlaXZlcik7XG4gICAgcmV0dXJuIHRyYW5zY2VpdmVyO1xuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRUcmFjayA9IGZ1bmN0aW9uKHRyYWNrLCBzdHJlYW0pIHtcbiAgICB2YXIgdHJhbnNjZWl2ZXI7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnRyYW5zY2VpdmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKCF0aGlzLnRyYW5zY2VpdmVyc1tpXS50cmFjayAmJlxuICAgICAgICAgIHRoaXMudHJhbnNjZWl2ZXJzW2ldLmtpbmQgPT09IHRyYWNrLmtpbmQpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIgPSB0aGlzLnRyYW5zY2VpdmVyc1tpXTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKCF0cmFuc2NlaXZlcikge1xuICAgICAgdHJhbnNjZWl2ZXIgPSB0aGlzLl9jcmVhdGVUcmFuc2NlaXZlcih0cmFjay5raW5kKTtcbiAgICB9XG5cbiAgICB0cmFuc2NlaXZlci50cmFjayA9IHRyYWNrO1xuICAgIHRyYW5zY2VpdmVyLnN0cmVhbSA9IHN0cmVhbTtcbiAgICB0cmFuc2NlaXZlci5ydHBTZW5kZXIgPSBuZXcgd2luZG93LlJUQ1J0cFNlbmRlcih0cmFjayxcbiAgICAgICAgdHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydCk7XG5cbiAgICB0aGlzLl9tYXliZUZpcmVOZWdvdGlhdGlvbk5lZWRlZCgpO1xuICAgIHJldHVybiB0cmFuc2NlaXZlci5ydHBTZW5kZXI7XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZFN0cmVhbSA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZiAoZWRnZVZlcnNpb24gPj0gMTUwMjUpIHtcbiAgICAgIHRoaXMubG9jYWxTdHJlYW1zLnB1c2goc3RyZWFtKTtcbiAgICAgIHN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgICAgIHNlbGYuYWRkVHJhY2sodHJhY2ssIHN0cmVhbSk7XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQ2xvbmUgaXMgbmVjZXNzYXJ5IGZvciBsb2NhbCBkZW1vcyBtb3N0bHksIGF0dGFjaGluZyBkaXJlY3RseVxuICAgICAgLy8gdG8gdHdvIGRpZmZlcmVudCBzZW5kZXJzIGRvZXMgbm90IHdvcmsgKGJ1aWxkIDEwNTQ3KS5cbiAgICAgIC8vIEZpeGVkIGluIDE1MDI1IChvciBlYXJsaWVyKVxuICAgICAgdmFyIGNsb25lZFN0cmVhbSA9IHN0cmVhbS5jbG9uZSgpO1xuICAgICAgc3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2ssIGlkeCkge1xuICAgICAgICB2YXIgY2xvbmVkVHJhY2sgPSBjbG9uZWRTdHJlYW0uZ2V0VHJhY2tzKClbaWR4XTtcbiAgICAgICAgdHJhY2suYWRkRXZlbnRMaXN0ZW5lcignZW5hYmxlZCcsIGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICAgICAgY2xvbmVkVHJhY2suZW5hYmxlZCA9IGV2ZW50LmVuYWJsZWQ7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgICBjbG9uZWRTdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbih0cmFjaykge1xuICAgICAgICBzZWxmLmFkZFRyYWNrKHRyYWNrLCBjbG9uZWRTdHJlYW0pO1xuICAgICAgfSk7XG4gICAgICB0aGlzLmxvY2FsU3RyZWFtcy5wdXNoKGNsb25lZFN0cmVhbSk7XG4gICAgfVxuICAgIHRoaXMuX21heWJlRmlyZU5lZ290aWF0aW9uTmVlZGVkKCk7XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLnJlbW92ZVN0cmVhbSA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgIHZhciBpZHggPSB0aGlzLmxvY2FsU3RyZWFtcy5pbmRleE9mKHN0cmVhbSk7XG4gICAgaWYgKGlkeCA+IC0xKSB7XG4gICAgICB0aGlzLmxvY2FsU3RyZWFtcy5zcGxpY2UoaWR4LCAxKTtcbiAgICAgIHRoaXMuX21heWJlRmlyZU5lZ290aWF0aW9uTmVlZGVkKCk7XG4gICAgfVxuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRTZW5kZXJzID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNjZWl2ZXJzLmZpbHRlcihmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgcmV0dXJuICEhdHJhbnNjZWl2ZXIucnRwU2VuZGVyO1xuICAgIH0pXG4gICAgLm1hcChmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgcmV0dXJuIHRyYW5zY2VpdmVyLnJ0cFNlbmRlcjtcbiAgICB9KTtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuZ2V0UmVjZWl2ZXJzID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNjZWl2ZXJzLmZpbHRlcihmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgcmV0dXJuICEhdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXI7XG4gICAgfSlcbiAgICAubWFwKGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICByZXR1cm4gdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXI7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gQ3JlYXRlIElDRSBnYXRoZXJlciBhbmQgaG9vayBpdCB1cC5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl9jcmVhdGVJY2VHYXRoZXJlciA9IGZ1bmN0aW9uKG1pZCxcbiAgICAgIHNkcE1MaW5lSW5kZXgpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGljZUdhdGhlcmVyID0gbmV3IHdpbmRvdy5SVENJY2VHYXRoZXJlcihzZWxmLmljZU9wdGlvbnMpO1xuICAgIGljZUdhdGhlcmVyLm9ubG9jYWxjYW5kaWRhdGUgPSBmdW5jdGlvbihldnQpIHtcbiAgICAgIHZhciBldmVudCA9IG5ldyBFdmVudCgnaWNlY2FuZGlkYXRlJyk7XG4gICAgICBldmVudC5jYW5kaWRhdGUgPSB7c2RwTWlkOiBtaWQsIHNkcE1MaW5lSW5kZXg6IHNkcE1MaW5lSW5kZXh9O1xuXG4gICAgICB2YXIgY2FuZCA9IGV2dC5jYW5kaWRhdGU7XG4gICAgICB2YXIgZW5kID0gIWNhbmQgfHwgT2JqZWN0LmtleXMoY2FuZCkubGVuZ3RoID09PSAwO1xuICAgICAgLy8gRWRnZSBlbWl0cyBhbiBlbXB0eSBvYmplY3QgZm9yIFJUQ0ljZUNhbmRpZGF0ZUNvbXBsZXRl4oClXG4gICAgICBpZiAoZW5kKSB7XG4gICAgICAgIC8vIHBvbHlmaWxsIHNpbmNlIFJUQ0ljZUdhdGhlcmVyLnN0YXRlIGlzIG5vdCBpbXBsZW1lbnRlZCBpblxuICAgICAgICAvLyBFZGdlIDEwNTQ3IHlldC5cbiAgICAgICAgaWYgKGljZUdhdGhlcmVyLnN0YXRlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBpY2VHYXRoZXJlci5zdGF0ZSA9ICdjb21wbGV0ZWQnO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBSVENJY2VDYW5kaWRhdGUgZG9lc24ndCBoYXZlIGEgY29tcG9uZW50LCBuZWVkcyB0byBiZSBhZGRlZFxuICAgICAgICBjYW5kLmNvbXBvbmVudCA9IDE7XG4gICAgICAgIGV2ZW50LmNhbmRpZGF0ZS5jYW5kaWRhdGUgPSBTRFBVdGlscy53cml0ZUNhbmRpZGF0ZShjYW5kKTtcbiAgICAgIH1cblxuICAgICAgLy8gdXBkYXRlIGxvY2FsIGRlc2NyaXB0aW9uLlxuICAgICAgdmFyIHNlY3Rpb25zID0gU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyhzZWxmLmxvY2FsRGVzY3JpcHRpb24uc2RwKTtcbiAgICAgIGlmICghZW5kKSB7XG4gICAgICAgIHNlY3Rpb25zW2V2ZW50LmNhbmRpZGF0ZS5zZHBNTGluZUluZGV4ICsgMV0gKz1cbiAgICAgICAgICAgICdhPScgKyBldmVudC5jYW5kaWRhdGUuY2FuZGlkYXRlICsgJ1xcclxcbic7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzZWN0aW9uc1tldmVudC5jYW5kaWRhdGUuc2RwTUxpbmVJbmRleCArIDFdICs9XG4gICAgICAgICAgICAnYT1lbmQtb2YtY2FuZGlkYXRlc1xcclxcbic7XG4gICAgICB9XG4gICAgICBzZWxmLmxvY2FsRGVzY3JpcHRpb24uc2RwID0gc2VjdGlvbnMuam9pbignJyk7XG4gICAgICB2YXIgdHJhbnNjZWl2ZXJzID0gc2VsZi5fcGVuZGluZ09mZmVyID8gc2VsZi5fcGVuZGluZ09mZmVyIDpcbiAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVycztcbiAgICAgIHZhciBjb21wbGV0ZSA9IHRyYW5zY2VpdmVycy5ldmVyeShmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgICByZXR1cm4gdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXIgJiZcbiAgICAgICAgICAgIHRyYW5zY2VpdmVyLmljZUdhdGhlcmVyLnN0YXRlID09PSAnY29tcGxldGVkJztcbiAgICAgIH0pO1xuXG4gICAgICAvLyBFbWl0IGNhbmRpZGF0ZSBpZiBsb2NhbERlc2NyaXB0aW9uIGlzIHNldC5cbiAgICAgIC8vIEFsc28gZW1pdHMgbnVsbCBjYW5kaWRhdGUgd2hlbiBhbGwgZ2F0aGVyZXJzIGFyZSBjb21wbGV0ZS5cbiAgICAgIHN3aXRjaCAoc2VsZi5pY2VHYXRoZXJpbmdTdGF0ZSkge1xuICAgICAgICBjYXNlICduZXcnOlxuICAgICAgICAgIGlmICghZW5kKSB7XG4gICAgICAgICAgICBzZWxmLl9sb2NhbEljZUNhbmRpZGF0ZXNCdWZmZXIucHVzaChldmVudCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChlbmQgJiYgY29tcGxldGUpIHtcbiAgICAgICAgICAgIHNlbGYuX2xvY2FsSWNlQ2FuZGlkYXRlc0J1ZmZlci5wdXNoKFxuICAgICAgICAgICAgICAgIG5ldyBFdmVudCgnaWNlY2FuZGlkYXRlJykpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnZ2F0aGVyaW5nJzpcbiAgICAgICAgICBzZWxmLl9lbWl0QnVmZmVyZWRDYW5kaWRhdGVzKCk7XG4gICAgICAgICAgaWYgKCFlbmQpIHtcbiAgICAgICAgICAgIHNlbGYuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgICAgICAgICBpZiAoc2VsZi5vbmljZWNhbmRpZGF0ZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICBzZWxmLm9uaWNlY2FuZGlkYXRlKGV2ZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGNvbXBsZXRlKSB7XG4gICAgICAgICAgICBzZWxmLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KCdpY2VjYW5kaWRhdGUnKSk7XG4gICAgICAgICAgICBpZiAoc2VsZi5vbmljZWNhbmRpZGF0ZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICBzZWxmLm9uaWNlY2FuZGlkYXRlKG5ldyBFdmVudCgnaWNlY2FuZGlkYXRlJykpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2VsZi5pY2VHYXRoZXJpbmdTdGF0ZSA9ICdjb21wbGV0ZSc7XG4gICAgICAgICAgICBzZWxmLl9lbWl0R2F0aGVyaW5nU3RhdGVDaGFuZ2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ2NvbXBsZXRlJzpcbiAgICAgICAgICAvLyBzaG91bGQgbm90IGhhcHBlbi4uLiBjdXJyZW50bHkhXG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6IC8vIG5vLW9wLlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIGljZUdhdGhlcmVyO1xuICB9O1xuXG4gIC8vIENyZWF0ZSBJQ0UgdHJhbnNwb3J0IGFuZCBEVExTIHRyYW5zcG9ydC5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl9jcmVhdGVJY2VBbmREdGxzVHJhbnNwb3J0cyA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgaWNlVHJhbnNwb3J0ID0gbmV3IHdpbmRvdy5SVENJY2VUcmFuc3BvcnQobnVsbCk7XG4gICAgaWNlVHJhbnNwb3J0Lm9uaWNlc3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICAgIHNlbGYuX3VwZGF0ZUNvbm5lY3Rpb25TdGF0ZSgpO1xuICAgIH07XG5cbiAgICB2YXIgZHRsc1RyYW5zcG9ydCA9IG5ldyB3aW5kb3cuUlRDRHRsc1RyYW5zcG9ydChpY2VUcmFuc3BvcnQpO1xuICAgIGR0bHNUcmFuc3BvcnQub25kdGxzc3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICAgIHNlbGYuX3VwZGF0ZUNvbm5lY3Rpb25TdGF0ZSgpO1xuICAgIH07XG4gICAgZHRsc1RyYW5zcG9ydC5vbmVycm9yID0gZnVuY3Rpb24oKSB7XG4gICAgICAvLyBvbmVycm9yIGRvZXMgbm90IHNldCBzdGF0ZSB0byBmYWlsZWQgYnkgaXRzZWxmLlxuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGR0bHNUcmFuc3BvcnQsICdzdGF0ZScsXG4gICAgICAgICAge3ZhbHVlOiAnZmFpbGVkJywgd3JpdGFibGU6IHRydWV9KTtcbiAgICAgIHNlbGYuX3VwZGF0ZUNvbm5lY3Rpb25TdGF0ZSgpO1xuICAgIH07XG5cbiAgICByZXR1cm4ge1xuICAgICAgaWNlVHJhbnNwb3J0OiBpY2VUcmFuc3BvcnQsXG4gICAgICBkdGxzVHJhbnNwb3J0OiBkdGxzVHJhbnNwb3J0XG4gICAgfTtcbiAgfTtcblxuICAvLyBEZXN0cm95IElDRSBnYXRoZXJlciwgSUNFIHRyYW5zcG9ydCBhbmQgRFRMUyB0cmFuc3BvcnQuXG4gIC8vIFdpdGhvdXQgdHJpZ2dlcmluZyB0aGUgY2FsbGJhY2tzLlxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX2Rpc3Bvc2VJY2VBbmREdGxzVHJhbnNwb3J0cyA9IGZ1bmN0aW9uKFxuICAgICAgc2RwTUxpbmVJbmRleCkge1xuICAgIHZhciBpY2VHYXRoZXJlciA9IHRoaXMudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmljZUdhdGhlcmVyO1xuICAgIGlmIChpY2VHYXRoZXJlcikge1xuICAgICAgZGVsZXRlIGljZUdhdGhlcmVyLm9ubG9jYWxjYW5kaWRhdGU7XG4gICAgICBkZWxldGUgdGhpcy50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0uaWNlR2F0aGVyZXI7XG4gICAgfVxuICAgIHZhciBpY2VUcmFuc3BvcnQgPSB0aGlzLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5pY2VUcmFuc3BvcnQ7XG4gICAgaWYgKGljZVRyYW5zcG9ydCkge1xuICAgICAgZGVsZXRlIGljZVRyYW5zcG9ydC5vbmljZXN0YXRlY2hhbmdlO1xuICAgICAgZGVsZXRlIHRoaXMudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmljZVRyYW5zcG9ydDtcbiAgICB9XG4gICAgdmFyIGR0bHNUcmFuc3BvcnQgPSB0aGlzLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5kdGxzVHJhbnNwb3J0O1xuICAgIGlmIChkdGxzVHJhbnNwb3J0KSB7XG4gICAgICBkZWxldGUgZHRsc1RyYW5zcG9ydC5vbmR0bHNzdHRhdGVjaGFuZ2U7XG4gICAgICBkZWxldGUgZHRsc1RyYW5zcG9ydC5vbmVycm9yO1xuICAgICAgZGVsZXRlIHRoaXMudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmR0bHNUcmFuc3BvcnQ7XG4gICAgfVxuICB9O1xuXG4gIC8vIFN0YXJ0IHRoZSBSVFAgU2VuZGVyIGFuZCBSZWNlaXZlciBmb3IgYSB0cmFuc2NlaXZlci5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl90cmFuc2NlaXZlID0gZnVuY3Rpb24odHJhbnNjZWl2ZXIsXG4gICAgICBzZW5kLCByZWN2KSB7XG4gICAgdmFyIHBhcmFtcyA9IGdldENvbW1vbkNhcGFiaWxpdGllcyh0cmFuc2NlaXZlci5sb2NhbENhcGFiaWxpdGllcyxcbiAgICAgICAgdHJhbnNjZWl2ZXIucmVtb3RlQ2FwYWJpbGl0aWVzKTtcbiAgICBpZiAoc2VuZCAmJiB0cmFuc2NlaXZlci5ydHBTZW5kZXIpIHtcbiAgICAgIHBhcmFtcy5lbmNvZGluZ3MgPSB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzO1xuICAgICAgcGFyYW1zLnJ0Y3AgPSB7XG4gICAgICAgIGNuYW1lOiBTRFBVdGlscy5sb2NhbENOYW1lLFxuICAgICAgICBjb21wb3VuZDogdHJhbnNjZWl2ZXIucnRjcFBhcmFtZXRlcnMuY29tcG91bmRcbiAgICAgIH07XG4gICAgICBpZiAodHJhbnNjZWl2ZXIucmVjdkVuY29kaW5nUGFyYW1ldGVycy5sZW5ndGgpIHtcbiAgICAgICAgcGFyYW1zLnJ0Y3Auc3NyYyA9IHRyYW5zY2VpdmVyLnJlY3ZFbmNvZGluZ1BhcmFtZXRlcnNbMF0uc3NyYztcbiAgICAgIH1cbiAgICAgIHRyYW5zY2VpdmVyLnJ0cFNlbmRlci5zZW5kKHBhcmFtcyk7XG4gICAgfVxuICAgIGlmIChyZWN2ICYmIHRyYW5zY2VpdmVyLnJ0cFJlY2VpdmVyKSB7XG4gICAgICAvLyByZW1vdmUgUlRYIGZpZWxkIGluIEVkZ2UgMTQ5NDJcbiAgICAgIGlmICh0cmFuc2NlaXZlci5raW5kID09PSAndmlkZW8nXG4gICAgICAgICAgJiYgdHJhbnNjZWl2ZXIucmVjdkVuY29kaW5nUGFyYW1ldGVyc1xuICAgICAgICAgICYmIGVkZ2VWZXJzaW9uIDwgMTUwMTkpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIucmVjdkVuY29kaW5nUGFyYW1ldGVycy5mb3JFYWNoKGZ1bmN0aW9uKHApIHtcbiAgICAgICAgICBkZWxldGUgcC5ydHg7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcGFyYW1zLmVuY29kaW5ncyA9IHRyYW5zY2VpdmVyLnJlY3ZFbmNvZGluZ1BhcmFtZXRlcnM7XG4gICAgICBwYXJhbXMucnRjcCA9IHtcbiAgICAgICAgY25hbWU6IHRyYW5zY2VpdmVyLnJ0Y3BQYXJhbWV0ZXJzLmNuYW1lLFxuICAgICAgICBjb21wb3VuZDogdHJhbnNjZWl2ZXIucnRjcFBhcmFtZXRlcnMuY29tcG91bmRcbiAgICAgIH07XG4gICAgICBpZiAodHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVycy5sZW5ndGgpIHtcbiAgICAgICAgcGFyYW1zLnJ0Y3Auc3NyYyA9IHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0uc3NyYztcbiAgICAgIH1cbiAgICAgIHRyYW5zY2VpdmVyLnJ0cFJlY2VpdmVyLnJlY2VpdmUocGFyYW1zKTtcbiAgICB9XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLnNldExvY2FsRGVzY3JpcHRpb24gPSBmdW5jdGlvbihkZXNjcmlwdGlvbikge1xuICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgIGlmICghaXNBY3Rpb25BbGxvd2VkSW5TaWduYWxpbmdTdGF0ZSgnc2V0TG9jYWxEZXNjcmlwdGlvbicsXG4gICAgICAgIGRlc2NyaXB0aW9uLnR5cGUsIHRoaXMuc2lnbmFsaW5nU3RhdGUpKSB7XG4gICAgICB2YXIgZSA9IG5ldyBFcnJvcignQ2FuIG5vdCBzZXQgbG9jYWwgJyArIGRlc2NyaXB0aW9uLnR5cGUgK1xuICAgICAgICAgICcgaW4gc3RhdGUgJyArIHRoaXMuc2lnbmFsaW5nU3RhdGUpO1xuICAgICAgZS5uYW1lID0gJ0ludmFsaWRTdGF0ZUVycm9yJztcbiAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMiAmJiB0eXBlb2YgYXJndW1lbnRzWzJdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGFyZ3VtZW50c1syXSwgMCwgZSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZSk7XG4gICAgfVxuXG4gICAgdmFyIHNlY3Rpb25zO1xuICAgIHZhciBzZXNzaW9ucGFydDtcbiAgICBpZiAoZGVzY3JpcHRpb24udHlwZSA9PT0gJ29mZmVyJykge1xuICAgICAgLy8gRklYTUU6IFdoYXQgd2FzIHRoZSBwdXJwb3NlIG9mIHRoaXMgZW1wdHkgaWYgc3RhdGVtZW50P1xuICAgICAgLy8gaWYgKCF0aGlzLl9wZW5kaW5nT2ZmZXIpIHtcbiAgICAgIC8vIH0gZWxzZSB7XG4gICAgICBpZiAodGhpcy5fcGVuZGluZ09mZmVyKSB7XG4gICAgICAgIC8vIFZFUlkgbGltaXRlZCBzdXBwb3J0IGZvciBTRFAgbXVuZ2luZy4gTGltaXRlZCB0bzpcbiAgICAgICAgLy8gKiBjaGFuZ2luZyB0aGUgb3JkZXIgb2YgY29kZWNzXG4gICAgICAgIHNlY3Rpb25zID0gU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyhkZXNjcmlwdGlvbi5zZHApO1xuICAgICAgICBzZXNzaW9ucGFydCA9IHNlY3Rpb25zLnNoaWZ0KCk7XG4gICAgICAgIHNlY3Rpb25zLmZvckVhY2goZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZHBNTGluZUluZGV4KSB7XG4gICAgICAgICAgdmFyIGNhcHMgPSBTRFBVdGlscy5wYXJzZVJ0cFBhcmFtZXRlcnMobWVkaWFTZWN0aW9uKTtcbiAgICAgICAgICBzZWxmLl9wZW5kaW5nT2ZmZXJbc2RwTUxpbmVJbmRleF0ubG9jYWxDYXBhYmlsaXRpZXMgPSBjYXBzO1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy50cmFuc2NlaXZlcnMgPSB0aGlzLl9wZW5kaW5nT2ZmZXI7XG4gICAgICAgIGRlbGV0ZSB0aGlzLl9wZW5kaW5nT2ZmZXI7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChkZXNjcmlwdGlvbi50eXBlID09PSAnYW5zd2VyJykge1xuICAgICAgc2VjdGlvbnMgPSBTRFBVdGlscy5zcGxpdFNlY3Rpb25zKHNlbGYucmVtb3RlRGVzY3JpcHRpb24uc2RwKTtcbiAgICAgIHNlc3Npb25wYXJ0ID0gc2VjdGlvbnMuc2hpZnQoKTtcbiAgICAgIHZhciBpc0ljZUxpdGUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChzZXNzaW9ucGFydCxcbiAgICAgICAgICAnYT1pY2UtbGl0ZScpLmxlbmd0aCA+IDA7XG4gICAgICBzZWN0aW9ucy5mb3JFYWNoKGZ1bmN0aW9uKG1lZGlhU2VjdGlvbiwgc2RwTUxpbmVJbmRleCkge1xuICAgICAgICB2YXIgdHJhbnNjZWl2ZXIgPSBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XTtcbiAgICAgICAgdmFyIGljZUdhdGhlcmVyID0gdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXI7XG4gICAgICAgIHZhciBpY2VUcmFuc3BvcnQgPSB0cmFuc2NlaXZlci5pY2VUcmFuc3BvcnQ7XG4gICAgICAgIHZhciBkdGxzVHJhbnNwb3J0ID0gdHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydDtcbiAgICAgICAgdmFyIGxvY2FsQ2FwYWJpbGl0aWVzID0gdHJhbnNjZWl2ZXIubG9jYWxDYXBhYmlsaXRpZXM7XG4gICAgICAgIHZhciByZW1vdGVDYXBhYmlsaXRpZXMgPSB0cmFuc2NlaXZlci5yZW1vdGVDYXBhYmlsaXRpZXM7XG5cbiAgICAgICAgdmFyIHJlamVjdGVkID0gU0RQVXRpbHMuaXNSZWplY3RlZChtZWRpYVNlY3Rpb24pO1xuXG4gICAgICAgIGlmICghcmVqZWN0ZWQgJiYgIXRyYW5zY2VpdmVyLmlzRGF0YWNoYW5uZWwpIHtcbiAgICAgICAgICB2YXIgcmVtb3RlSWNlUGFyYW1ldGVycyA9IFNEUFV0aWxzLmdldEljZVBhcmFtZXRlcnMoXG4gICAgICAgICAgICAgIG1lZGlhU2VjdGlvbiwgc2Vzc2lvbnBhcnQpO1xuICAgICAgICAgIHZhciByZW1vdGVEdGxzUGFyYW1ldGVycyA9IFNEUFV0aWxzLmdldER0bHNQYXJhbWV0ZXJzKFxuICAgICAgICAgICAgICBtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KTtcbiAgICAgICAgICBpZiAoaXNJY2VMaXRlKSB7XG4gICAgICAgICAgICByZW1vdGVEdGxzUGFyYW1ldGVycy5yb2xlID0gJ3NlcnZlcic7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFzZWxmLnVzaW5nQnVuZGxlIHx8IHNkcE1MaW5lSW5kZXggPT09IDApIHtcbiAgICAgICAgICAgIGljZVRyYW5zcG9ydC5zdGFydChpY2VHYXRoZXJlciwgcmVtb3RlSWNlUGFyYW1ldGVycyxcbiAgICAgICAgICAgICAgICBpc0ljZUxpdGUgPyAnY29udHJvbGxpbmcnIDogJ2NvbnRyb2xsZWQnKTtcbiAgICAgICAgICAgIGR0bHNUcmFuc3BvcnQuc3RhcnQocmVtb3RlRHRsc1BhcmFtZXRlcnMpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIENhbGN1bGF0ZSBpbnRlcnNlY3Rpb24gb2YgY2FwYWJpbGl0aWVzLlxuICAgICAgICAgIHZhciBwYXJhbXMgPSBnZXRDb21tb25DYXBhYmlsaXRpZXMobG9jYWxDYXBhYmlsaXRpZXMsXG4gICAgICAgICAgICAgIHJlbW90ZUNhcGFiaWxpdGllcyk7XG5cbiAgICAgICAgICAvLyBTdGFydCB0aGUgUlRDUnRwU2VuZGVyLiBUaGUgUlRDUnRwUmVjZWl2ZXIgZm9yIHRoaXNcbiAgICAgICAgICAvLyB0cmFuc2NlaXZlciBoYXMgYWxyZWFkeSBiZWVuIHN0YXJ0ZWQgaW4gc2V0UmVtb3RlRGVzY3JpcHRpb24uXG4gICAgICAgICAgc2VsZi5fdHJhbnNjZWl2ZSh0cmFuc2NlaXZlcixcbiAgICAgICAgICAgICAgcGFyYW1zLmNvZGVjcy5sZW5ndGggPiAwLFxuICAgICAgICAgICAgICBmYWxzZSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHRoaXMubG9jYWxEZXNjcmlwdGlvbiA9IHtcbiAgICAgIHR5cGU6IGRlc2NyaXB0aW9uLnR5cGUsXG4gICAgICBzZHA6IGRlc2NyaXB0aW9uLnNkcFxuICAgIH07XG4gICAgc3dpdGNoIChkZXNjcmlwdGlvbi50eXBlKSB7XG4gICAgICBjYXNlICdvZmZlcic6XG4gICAgICAgIHRoaXMuX3VwZGF0ZVNpZ25hbGluZ1N0YXRlKCdoYXZlLWxvY2FsLW9mZmVyJyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnYW5zd2VyJzpcbiAgICAgICAgdGhpcy5fdXBkYXRlU2lnbmFsaW5nU3RhdGUoJ3N0YWJsZScpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3Vuc3VwcG9ydGVkIHR5cGUgXCInICsgZGVzY3JpcHRpb24udHlwZSArXG4gICAgICAgICAgICAnXCInKTtcbiAgICB9XG5cbiAgICAvLyBJZiBhIHN1Y2Nlc3MgY2FsbGJhY2sgd2FzIHByb3ZpZGVkLCBlbWl0IElDRSBjYW5kaWRhdGVzIGFmdGVyIGl0XG4gICAgLy8gaGFzIGJlZW4gZXhlY3V0ZWQuIE90aGVyd2lzZSwgZW1pdCBjYWxsYmFjayBhZnRlciB0aGUgUHJvbWlzZSBpc1xuICAgIC8vIHJlc29sdmVkLlxuICAgIHZhciBoYXNDYWxsYmFjayA9IGFyZ3VtZW50cy5sZW5ndGggPiAxICYmXG4gICAgICB0eXBlb2YgYXJndW1lbnRzWzFdID09PSAnZnVuY3Rpb24nO1xuICAgIGlmIChoYXNDYWxsYmFjaykge1xuICAgICAgdmFyIGNiID0gYXJndW1lbnRzWzFdO1xuICAgICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgIGNiKCk7XG4gICAgICAgIGlmIChzZWxmLmljZUdhdGhlcmluZ1N0YXRlID09PSAnbmV3Jykge1xuICAgICAgICAgIHNlbGYuaWNlR2F0aGVyaW5nU3RhdGUgPSAnZ2F0aGVyaW5nJztcbiAgICAgICAgICBzZWxmLl9lbWl0R2F0aGVyaW5nU3RhdGVDaGFuZ2UoKTtcbiAgICAgICAgfVxuICAgICAgICBzZWxmLl9lbWl0QnVmZmVyZWRDYW5kaWRhdGVzKCk7XG4gICAgICB9LCAwKTtcbiAgICB9XG4gICAgdmFyIHAgPSBQcm9taXNlLnJlc29sdmUoKTtcbiAgICBwLnRoZW4oZnVuY3Rpb24oKSB7XG4gICAgICBpZiAoIWhhc0NhbGxiYWNrKSB7XG4gICAgICAgIGlmIChzZWxmLmljZUdhdGhlcmluZ1N0YXRlID09PSAnbmV3Jykge1xuICAgICAgICAgIHNlbGYuaWNlR2F0aGVyaW5nU3RhdGUgPSAnZ2F0aGVyaW5nJztcbiAgICAgICAgICBzZWxmLl9lbWl0R2F0aGVyaW5nU3RhdGVDaGFuZ2UoKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBVc3VhbGx5IGNhbmRpZGF0ZXMgd2lsbCBiZSBlbWl0dGVkIGVhcmxpZXIuXG4gICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KHNlbGYuX2VtaXRCdWZmZXJlZENhbmRpZGF0ZXMuYmluZChzZWxmKSwgNTAwKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gcDtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuc2V0UmVtb3RlRGVzY3JpcHRpb24gPSBmdW5jdGlvbihkZXNjcmlwdGlvbikge1xuICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgIGlmICghaXNBY3Rpb25BbGxvd2VkSW5TaWduYWxpbmdTdGF0ZSgnc2V0UmVtb3RlRGVzY3JpcHRpb24nLFxuICAgICAgICBkZXNjcmlwdGlvbi50eXBlLCB0aGlzLnNpZ25hbGluZ1N0YXRlKSkge1xuICAgICAgdmFyIGUgPSBuZXcgRXJyb3IoJ0NhbiBub3Qgc2V0IHJlbW90ZSAnICsgZGVzY3JpcHRpb24udHlwZSArXG4gICAgICAgICAgJyBpbiBzdGF0ZSAnICsgdGhpcy5zaWduYWxpbmdTdGF0ZSk7XG4gICAgICBlLm5hbWUgPSAnSW52YWxpZFN0YXRlRXJyb3InO1xuICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAyICYmIHR5cGVvZiBhcmd1bWVudHNbMl0gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgd2luZG93LnNldFRpbWVvdXQoYXJndW1lbnRzWzJdLCAwLCBlKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlKTtcbiAgICB9XG5cbiAgICB2YXIgc3RyZWFtcyA9IHt9O1xuICAgIHZhciByZWNlaXZlckxpc3QgPSBbXTtcbiAgICB2YXIgc2VjdGlvbnMgPSBTRFBVdGlscy5zcGxpdFNlY3Rpb25zKGRlc2NyaXB0aW9uLnNkcCk7XG4gICAgdmFyIHNlc3Npb25wYXJ0ID0gc2VjdGlvbnMuc2hpZnQoKTtcbiAgICB2YXIgaXNJY2VMaXRlID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgoc2Vzc2lvbnBhcnQsXG4gICAgICAgICdhPWljZS1saXRlJykubGVuZ3RoID4gMDtcbiAgICB2YXIgdXNpbmdCdW5kbGUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChzZXNzaW9ucGFydCxcbiAgICAgICAgJ2E9Z3JvdXA6QlVORExFICcpLmxlbmd0aCA+IDA7XG4gICAgdGhpcy51c2luZ0J1bmRsZSA9IHVzaW5nQnVuZGxlO1xuICAgIHZhciBpY2VPcHRpb25zID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgoc2Vzc2lvbnBhcnQsXG4gICAgICAgICdhPWljZS1vcHRpb25zOicpWzBdO1xuICAgIGlmIChpY2VPcHRpb25zKSB7XG4gICAgICB0aGlzLmNhblRyaWNrbGVJY2VDYW5kaWRhdGVzID0gaWNlT3B0aW9ucy5zdWJzdHIoMTQpLnNwbGl0KCcgJylcbiAgICAgICAgICAuaW5kZXhPZigndHJpY2tsZScpID49IDA7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY2FuVHJpY2tsZUljZUNhbmRpZGF0ZXMgPSBmYWxzZTtcbiAgICB9XG5cbiAgICBzZWN0aW9ucy5mb3JFYWNoKGZ1bmN0aW9uKG1lZGlhU2VjdGlvbiwgc2RwTUxpbmVJbmRleCkge1xuICAgICAgdmFyIGxpbmVzID0gU0RQVXRpbHMuc3BsaXRMaW5lcyhtZWRpYVNlY3Rpb24pO1xuICAgICAgdmFyIGtpbmQgPSBTRFBVdGlscy5nZXRLaW5kKG1lZGlhU2VjdGlvbik7XG4gICAgICB2YXIgcmVqZWN0ZWQgPSBTRFBVdGlscy5pc1JlamVjdGVkKG1lZGlhU2VjdGlvbik7XG4gICAgICB2YXIgcHJvdG9jb2wgPSBsaW5lc1swXS5zdWJzdHIoMikuc3BsaXQoJyAnKVsyXTtcblxuICAgICAgdmFyIGRpcmVjdGlvbiA9IFNEUFV0aWxzLmdldERpcmVjdGlvbihtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KTtcbiAgICAgIHZhciByZW1vdGVNc2lkID0gU0RQVXRpbHMucGFyc2VNc2lkKG1lZGlhU2VjdGlvbik7XG5cbiAgICAgIHZhciBtaWQgPSBTRFBVdGlscy5nZXRNaWQobWVkaWFTZWN0aW9uKSB8fCBTRFBVdGlscy5nZW5lcmF0ZUlkZW50aWZpZXIoKTtcblxuICAgICAgLy8gUmVqZWN0IGRhdGFjaGFubmVscyB3aGljaCBhcmUgbm90IGltcGxlbWVudGVkIHlldC5cbiAgICAgIGlmIChraW5kID09PSAnYXBwbGljYXRpb24nICYmIHByb3RvY29sID09PSAnRFRMUy9TQ1RQJykge1xuICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XSA9IHtcbiAgICAgICAgICBtaWQ6IG1pZCxcbiAgICAgICAgICBpc0RhdGFjaGFubmVsOiB0cnVlXG4gICAgICAgIH07XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIHRyYW5zY2VpdmVyO1xuICAgICAgdmFyIGljZUdhdGhlcmVyO1xuICAgICAgdmFyIGljZVRyYW5zcG9ydDtcbiAgICAgIHZhciBkdGxzVHJhbnNwb3J0O1xuICAgICAgdmFyIHJ0cFJlY2VpdmVyO1xuICAgICAgdmFyIHNlbmRFbmNvZGluZ1BhcmFtZXRlcnM7XG4gICAgICB2YXIgcmVjdkVuY29kaW5nUGFyYW1ldGVycztcbiAgICAgIHZhciBsb2NhbENhcGFiaWxpdGllcztcblxuICAgICAgdmFyIHRyYWNrO1xuICAgICAgLy8gRklYTUU6IGVuc3VyZSB0aGUgbWVkaWFTZWN0aW9uIGhhcyBydGNwLW11eCBzZXQuXG4gICAgICB2YXIgcmVtb3RlQ2FwYWJpbGl0aWVzID0gU0RQVXRpbHMucGFyc2VSdHBQYXJhbWV0ZXJzKG1lZGlhU2VjdGlvbik7XG4gICAgICB2YXIgcmVtb3RlSWNlUGFyYW1ldGVycztcbiAgICAgIHZhciByZW1vdGVEdGxzUGFyYW1ldGVycztcbiAgICAgIGlmICghcmVqZWN0ZWQpIHtcbiAgICAgICAgcmVtb3RlSWNlUGFyYW1ldGVycyA9IFNEUFV0aWxzLmdldEljZVBhcmFtZXRlcnMobWVkaWFTZWN0aW9uLFxuICAgICAgICAgICAgc2Vzc2lvbnBhcnQpO1xuICAgICAgICByZW1vdGVEdGxzUGFyYW1ldGVycyA9IFNEUFV0aWxzLmdldER0bHNQYXJhbWV0ZXJzKG1lZGlhU2VjdGlvbixcbiAgICAgICAgICAgIHNlc3Npb25wYXJ0KTtcbiAgICAgICAgcmVtb3RlRHRsc1BhcmFtZXRlcnMucm9sZSA9ICdjbGllbnQnO1xuICAgICAgfVxuICAgICAgcmVjdkVuY29kaW5nUGFyYW1ldGVycyA9XG4gICAgICAgICAgU0RQVXRpbHMucGFyc2VSdHBFbmNvZGluZ1BhcmFtZXRlcnMobWVkaWFTZWN0aW9uKTtcblxuICAgICAgdmFyIHJ0Y3BQYXJhbWV0ZXJzID0gU0RQVXRpbHMucGFyc2VSdGNwUGFyYW1ldGVycyhtZWRpYVNlY3Rpb24pO1xuXG4gICAgICB2YXIgaXNDb21wbGV0ZSA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbixcbiAgICAgICAgICAnYT1lbmQtb2YtY2FuZGlkYXRlcycsIHNlc3Npb25wYXJ0KS5sZW5ndGggPiAwO1xuICAgICAgdmFyIGNhbmRzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1jYW5kaWRhdGU6JylcbiAgICAgICAgICAubWFwKGZ1bmN0aW9uKGNhbmQpIHtcbiAgICAgICAgICAgIHJldHVybiBTRFBVdGlscy5wYXJzZUNhbmRpZGF0ZShjYW5kKTtcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5maWx0ZXIoZnVuY3Rpb24oY2FuZCkge1xuICAgICAgICAgICAgcmV0dXJuIGNhbmQuY29tcG9uZW50ID09PSAnMScgfHwgY2FuZC5jb21wb25lbnQgPT09IDE7XG4gICAgICAgICAgfSk7XG5cbiAgICAgIC8vIENoZWNrIGlmIHdlIGNhbiB1c2UgQlVORExFIGFuZCBkaXNwb3NlIHRyYW5zcG9ydHMuXG4gICAgICBpZiAoKGRlc2NyaXB0aW9uLnR5cGUgPT09ICdvZmZlcicgfHwgZGVzY3JpcHRpb24udHlwZSA9PT0gJ2Fuc3dlcicpICYmXG4gICAgICAgICAgIXJlamVjdGVkICYmIHVzaW5nQnVuZGxlICYmIHNkcE1MaW5lSW5kZXggPiAwICYmXG4gICAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0pIHtcbiAgICAgICAgc2VsZi5fZGlzcG9zZUljZUFuZER0bHNUcmFuc3BvcnRzKHNkcE1MaW5lSW5kZXgpO1xuICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5pY2VHYXRoZXJlciA9XG4gICAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1swXS5pY2VHYXRoZXJlcjtcbiAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0uaWNlVHJhbnNwb3J0ID1cbiAgICAgICAgICAgIHNlbGYudHJhbnNjZWl2ZXJzWzBdLmljZVRyYW5zcG9ydDtcbiAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0uZHRsc1RyYW5zcG9ydCA9XG4gICAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1swXS5kdGxzVHJhbnNwb3J0O1xuICAgICAgICBpZiAoc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0ucnRwU2VuZGVyKSB7XG4gICAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0ucnRwU2VuZGVyLnNldFRyYW5zcG9ydChcbiAgICAgICAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbMF0uZHRsc1RyYW5zcG9ydCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHNlbGYudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLnJ0cFJlY2VpdmVyKSB7XG4gICAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0ucnRwUmVjZWl2ZXIuc2V0VHJhbnNwb3J0KFxuICAgICAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1swXS5kdGxzVHJhbnNwb3J0KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKGRlc2NyaXB0aW9uLnR5cGUgPT09ICdvZmZlcicgJiYgIXJlamVjdGVkKSB7XG4gICAgICAgIHRyYW5zY2VpdmVyID0gc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0gfHxcbiAgICAgICAgICAgIHNlbGYuX2NyZWF0ZVRyYW5zY2VpdmVyKGtpbmQpO1xuICAgICAgICB0cmFuc2NlaXZlci5taWQgPSBtaWQ7XG5cbiAgICAgICAgaWYgKCF0cmFuc2NlaXZlci5pY2VHYXRoZXJlcikge1xuICAgICAgICAgIHRyYW5zY2VpdmVyLmljZUdhdGhlcmVyID0gdXNpbmdCdW5kbGUgJiYgc2RwTUxpbmVJbmRleCA+IDAgP1xuICAgICAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1swXS5pY2VHYXRoZXJlciA6XG4gICAgICAgICAgICAgIHNlbGYuX2NyZWF0ZUljZUdhdGhlcmVyKG1pZCwgc2RwTUxpbmVJbmRleCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaXNDb21wbGV0ZSAmJiAoIXVzaW5nQnVuZGxlIHx8IHNkcE1MaW5lSW5kZXggPT09IDApKSB7XG4gICAgICAgICAgdHJhbnNjZWl2ZXIuaWNlVHJhbnNwb3J0LnNldFJlbW90ZUNhbmRpZGF0ZXMoY2FuZHMpO1xuICAgICAgICB9XG5cbiAgICAgICAgbG9jYWxDYXBhYmlsaXRpZXMgPSB3aW5kb3cuUlRDUnRwUmVjZWl2ZXIuZ2V0Q2FwYWJpbGl0aWVzKGtpbmQpO1xuXG4gICAgICAgIC8vIGZpbHRlciBSVFggdW50aWwgYWRkaXRpb25hbCBzdHVmZiBuZWVkZWQgZm9yIFJUWCBpcyBpbXBsZW1lbnRlZFxuICAgICAgICAvLyBpbiBhZGFwdGVyLmpzXG4gICAgICAgIGlmIChlZGdlVmVyc2lvbiA8IDE1MDE5KSB7XG4gICAgICAgICAgbG9jYWxDYXBhYmlsaXRpZXMuY29kZWNzID0gbG9jYWxDYXBhYmlsaXRpZXMuY29kZWNzLmZpbHRlcihcbiAgICAgICAgICAgICAgZnVuY3Rpb24oY29kZWMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gY29kZWMubmFtZSAhPT0gJ3J0eCc7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgc2VuZEVuY29kaW5nUGFyYW1ldGVycyA9IFt7XG4gICAgICAgICAgc3NyYzogKDIgKiBzZHBNTGluZUluZGV4ICsgMikgKiAxMDAxXG4gICAgICAgIH1dO1xuXG4gICAgICAgIGlmIChkaXJlY3Rpb24gPT09ICdzZW5kcmVjdicgfHwgZGlyZWN0aW9uID09PSAnc2VuZG9ubHknKSB7XG4gICAgICAgICAgcnRwUmVjZWl2ZXIgPSBuZXcgd2luZG93LlJUQ1J0cFJlY2VpdmVyKHRyYW5zY2VpdmVyLmR0bHNUcmFuc3BvcnQsXG4gICAgICAgICAgICAgIGtpbmQpO1xuXG4gICAgICAgICAgdHJhY2sgPSBydHBSZWNlaXZlci50cmFjaztcbiAgICAgICAgICAvLyBGSVhNRTogZG9lcyBub3Qgd29yayB3aXRoIFBsYW4gQi5cbiAgICAgICAgICBpZiAocmVtb3RlTXNpZCkge1xuICAgICAgICAgICAgaWYgKCFzdHJlYW1zW3JlbW90ZU1zaWQuc3RyZWFtXSkge1xuICAgICAgICAgICAgICBzdHJlYW1zW3JlbW90ZU1zaWQuc3RyZWFtXSA9IG5ldyB3aW5kb3cuTWVkaWFTdHJlYW0oKTtcbiAgICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHN0cmVhbXNbcmVtb3RlTXNpZC5zdHJlYW1dLCAnaWQnLCB7XG4gICAgICAgICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiByZW1vdGVNc2lkLnN0cmVhbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRyYWNrLCAnaWQnLCB7XG4gICAgICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlbW90ZU1zaWQudHJhY2s7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgc3RyZWFtc1tyZW1vdGVNc2lkLnN0cmVhbV0uYWRkVHJhY2sodHJhY2spO1xuICAgICAgICAgICAgcmVjZWl2ZXJMaXN0LnB1c2goW3RyYWNrLCBydHBSZWNlaXZlcixcbiAgICAgICAgICAgICAgc3RyZWFtc1tyZW1vdGVNc2lkLnN0cmVhbV1dKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKCFzdHJlYW1zLmRlZmF1bHQpIHtcbiAgICAgICAgICAgICAgc3RyZWFtcy5kZWZhdWx0ID0gbmV3IHdpbmRvdy5NZWRpYVN0cmVhbSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc3RyZWFtcy5kZWZhdWx0LmFkZFRyYWNrKHRyYWNrKTtcbiAgICAgICAgICAgIHJlY2VpdmVyTGlzdC5wdXNoKFt0cmFjaywgcnRwUmVjZWl2ZXIsIHN0cmVhbXMuZGVmYXVsdF0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRyYW5zY2VpdmVyLmxvY2FsQ2FwYWJpbGl0aWVzID0gbG9jYWxDYXBhYmlsaXRpZXM7XG4gICAgICAgIHRyYW5zY2VpdmVyLnJlbW90ZUNhcGFiaWxpdGllcyA9IHJlbW90ZUNhcGFiaWxpdGllcztcbiAgICAgICAgdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXIgPSBydHBSZWNlaXZlcjtcbiAgICAgICAgdHJhbnNjZWl2ZXIucnRjcFBhcmFtZXRlcnMgPSBydGNwUGFyYW1ldGVycztcbiAgICAgICAgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVycyA9IHNlbmRFbmNvZGluZ1BhcmFtZXRlcnM7XG4gICAgICAgIHRyYW5zY2VpdmVyLnJlY3ZFbmNvZGluZ1BhcmFtZXRlcnMgPSByZWN2RW5jb2RpbmdQYXJhbWV0ZXJzO1xuXG4gICAgICAgIC8vIFN0YXJ0IHRoZSBSVENSdHBSZWNlaXZlciBub3cuIFRoZSBSVFBTZW5kZXIgaXMgc3RhcnRlZCBpblxuICAgICAgICAvLyBzZXRMb2NhbERlc2NyaXB0aW9uLlxuICAgICAgICBzZWxmLl90cmFuc2NlaXZlKHNlbGYudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICBkaXJlY3Rpb24gPT09ICdzZW5kcmVjdicgfHwgZGlyZWN0aW9uID09PSAnc2VuZG9ubHknKTtcbiAgICAgIH0gZWxzZSBpZiAoZGVzY3JpcHRpb24udHlwZSA9PT0gJ2Fuc3dlcicgJiYgIXJlamVjdGVkKSB7XG4gICAgICAgIHRyYW5zY2VpdmVyID0gc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF07XG4gICAgICAgIGljZUdhdGhlcmVyID0gdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXI7XG4gICAgICAgIGljZVRyYW5zcG9ydCA9IHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydDtcbiAgICAgICAgZHRsc1RyYW5zcG9ydCA9IHRyYW5zY2VpdmVyLmR0bHNUcmFuc3BvcnQ7XG4gICAgICAgIHJ0cFJlY2VpdmVyID0gdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXI7XG4gICAgICAgIHNlbmRFbmNvZGluZ1BhcmFtZXRlcnMgPSB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzO1xuICAgICAgICBsb2NhbENhcGFiaWxpdGllcyA9IHRyYW5zY2VpdmVyLmxvY2FsQ2FwYWJpbGl0aWVzO1xuXG4gICAgICAgIHNlbGYudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLnJlY3ZFbmNvZGluZ1BhcmFtZXRlcnMgPVxuICAgICAgICAgICAgcmVjdkVuY29kaW5nUGFyYW1ldGVycztcbiAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0ucmVtb3RlQ2FwYWJpbGl0aWVzID1cbiAgICAgICAgICAgIHJlbW90ZUNhcGFiaWxpdGllcztcbiAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0ucnRjcFBhcmFtZXRlcnMgPSBydGNwUGFyYW1ldGVycztcblxuICAgICAgICBpZiAoKGlzSWNlTGl0ZSB8fCBpc0NvbXBsZXRlKSAmJiBjYW5kcy5sZW5ndGgpIHtcbiAgICAgICAgICBpY2VUcmFuc3BvcnQuc2V0UmVtb3RlQ2FuZGlkYXRlcyhjYW5kcyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF1c2luZ0J1bmRsZSB8fCBzZHBNTGluZUluZGV4ID09PSAwKSB7XG4gICAgICAgICAgaWNlVHJhbnNwb3J0LnN0YXJ0KGljZUdhdGhlcmVyLCByZW1vdGVJY2VQYXJhbWV0ZXJzLFxuICAgICAgICAgICAgICAnY29udHJvbGxpbmcnKTtcbiAgICAgICAgICBkdGxzVHJhbnNwb3J0LnN0YXJ0KHJlbW90ZUR0bHNQYXJhbWV0ZXJzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNlbGYuX3RyYW5zY2VpdmUodHJhbnNjZWl2ZXIsXG4gICAgICAgICAgICBkaXJlY3Rpb24gPT09ICdzZW5kcmVjdicgfHwgZGlyZWN0aW9uID09PSAncmVjdm9ubHknLFxuICAgICAgICAgICAgZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnIHx8IGRpcmVjdGlvbiA9PT0gJ3NlbmRvbmx5Jyk7XG5cbiAgICAgICAgaWYgKHJ0cFJlY2VpdmVyICYmXG4gICAgICAgICAgICAoZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnIHx8IGRpcmVjdGlvbiA9PT0gJ3NlbmRvbmx5JykpIHtcbiAgICAgICAgICB0cmFjayA9IHJ0cFJlY2VpdmVyLnRyYWNrO1xuICAgICAgICAgIGlmIChyZW1vdGVNc2lkKSB7XG4gICAgICAgICAgICBpZiAoIXN0cmVhbXNbcmVtb3RlTXNpZC5zdHJlYW1dKSB7XG4gICAgICAgICAgICAgIHN0cmVhbXNbcmVtb3RlTXNpZC5zdHJlYW1dID0gbmV3IHdpbmRvdy5NZWRpYVN0cmVhbSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc3RyZWFtc1tyZW1vdGVNc2lkLnN0cmVhbV0uYWRkVHJhY2sodHJhY2spO1xuICAgICAgICAgICAgcmVjZWl2ZXJMaXN0LnB1c2goW3RyYWNrLCBydHBSZWNlaXZlciwgc3RyZWFtc1tyZW1vdGVNc2lkLnN0cmVhbV1dKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKCFzdHJlYW1zLmRlZmF1bHQpIHtcbiAgICAgICAgICAgICAgc3RyZWFtcy5kZWZhdWx0ID0gbmV3IHdpbmRvdy5NZWRpYVN0cmVhbSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc3RyZWFtcy5kZWZhdWx0LmFkZFRyYWNrKHRyYWNrKTtcbiAgICAgICAgICAgIHJlY2VpdmVyTGlzdC5wdXNoKFt0cmFjaywgcnRwUmVjZWl2ZXIsIHN0cmVhbXMuZGVmYXVsdF0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBGSVhNRTogYWN0dWFsbHkgdGhlIHJlY2VpdmVyIHNob3VsZCBiZSBjcmVhdGVkIGxhdGVyLlxuICAgICAgICAgIGRlbGV0ZSB0cmFuc2NlaXZlci5ydHBSZWNlaXZlcjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5yZW1vdGVEZXNjcmlwdGlvbiA9IHtcbiAgICAgIHR5cGU6IGRlc2NyaXB0aW9uLnR5cGUsXG4gICAgICBzZHA6IGRlc2NyaXB0aW9uLnNkcFxuICAgIH07XG4gICAgc3dpdGNoIChkZXNjcmlwdGlvbi50eXBlKSB7XG4gICAgICBjYXNlICdvZmZlcic6XG4gICAgICAgIHRoaXMuX3VwZGF0ZVNpZ25hbGluZ1N0YXRlKCdoYXZlLXJlbW90ZS1vZmZlcicpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2Fuc3dlcic6XG4gICAgICAgIHRoaXMuX3VwZGF0ZVNpZ25hbGluZ1N0YXRlKCdzdGFibGUnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCd1bnN1cHBvcnRlZCB0eXBlIFwiJyArIGRlc2NyaXB0aW9uLnR5cGUgK1xuICAgICAgICAgICAgJ1wiJyk7XG4gICAgfVxuICAgIE9iamVjdC5rZXlzKHN0cmVhbXMpLmZvckVhY2goZnVuY3Rpb24oc2lkKSB7XG4gICAgICB2YXIgc3RyZWFtID0gc3RyZWFtc1tzaWRdO1xuICAgICAgaWYgKHN0cmVhbS5nZXRUcmFja3MoKS5sZW5ndGgpIHtcbiAgICAgICAgc2VsZi5yZW1vdGVTdHJlYW1zLnB1c2goc3RyZWFtKTtcbiAgICAgICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KCdhZGRzdHJlYW0nKTtcbiAgICAgICAgZXZlbnQuc3RyZWFtID0gc3RyZWFtO1xuICAgICAgICBzZWxmLmRpc3BhdGNoRXZlbnQoZXZlbnQpO1xuICAgICAgICBpZiAoc2VsZi5vbmFkZHN0cmVhbSAhPT0gbnVsbCkge1xuICAgICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgc2VsZi5vbmFkZHN0cmVhbShldmVudCk7XG4gICAgICAgICAgfSwgMCk7XG4gICAgICAgIH1cblxuICAgICAgICByZWNlaXZlckxpc3QuZm9yRWFjaChmdW5jdGlvbihpdGVtKSB7XG4gICAgICAgICAgdmFyIHRyYWNrID0gaXRlbVswXTtcbiAgICAgICAgICB2YXIgcmVjZWl2ZXIgPSBpdGVtWzFdO1xuICAgICAgICAgIGlmIChzdHJlYW0uaWQgIT09IGl0ZW1bMl0uaWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgdmFyIHRyYWNrRXZlbnQgPSBuZXcgRXZlbnQoJ3RyYWNrJyk7XG4gICAgICAgICAgdHJhY2tFdmVudC50cmFjayA9IHRyYWNrO1xuICAgICAgICAgIHRyYWNrRXZlbnQucmVjZWl2ZXIgPSByZWNlaXZlcjtcbiAgICAgICAgICB0cmFja0V2ZW50LnN0cmVhbXMgPSBbc3RyZWFtXTtcbiAgICAgICAgICBzZWxmLmRpc3BhdGNoRXZlbnQodHJhY2tFdmVudCk7XG4gICAgICAgICAgaWYgKHNlbGYub250cmFjayAhPT0gbnVsbCkge1xuICAgICAgICAgICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgIHNlbGYub250cmFjayh0cmFja0V2ZW50KTtcbiAgICAgICAgICAgIH0sIDApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyBjaGVjayB3aGV0aGVyIGFkZEljZUNhbmRpZGF0ZSh7fSkgd2FzIGNhbGxlZCB3aXRoaW4gZm91ciBzZWNvbmRzIGFmdGVyXG4gICAgLy8gc2V0UmVtb3RlRGVzY3JpcHRpb24uXG4gICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICBpZiAoIShzZWxmICYmIHNlbGYudHJhbnNjZWl2ZXJzKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBzZWxmLnRyYW5zY2VpdmVycy5mb3JFYWNoKGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICAgIGlmICh0cmFuc2NlaXZlci5pY2VUcmFuc3BvcnQgJiZcbiAgICAgICAgICAgIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydC5zdGF0ZSA9PT0gJ25ldycgJiZcbiAgICAgICAgICAgIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydC5nZXRSZW1vdGVDYW5kaWRhdGVzKCkubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGNvbnNvbGUud2FybignVGltZW91dCBmb3IgYWRkUmVtb3RlQ2FuZGlkYXRlLiBDb25zaWRlciBzZW5kaW5nICcgK1xuICAgICAgICAgICAgICAnYW4gZW5kLW9mLWNhbmRpZGF0ZXMgbm90aWZpY2F0aW9uJyk7XG4gICAgICAgICAgdHJhbnNjZWl2ZXIuaWNlVHJhbnNwb3J0LmFkZFJlbW90ZUNhbmRpZGF0ZSh7fSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0sIDQwMDApO1xuXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxICYmIHR5cGVvZiBhcmd1bWVudHNbMV0gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGFyZ3VtZW50c1sxXSwgMCk7XG4gICAgfVxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuY2xvc2UgPSBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnRyYW5zY2VpdmVycy5mb3JFYWNoKGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICAvKiBub3QgeWV0XG4gICAgICBpZiAodHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXIpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXIuY2xvc2UoKTtcbiAgICAgIH1cbiAgICAgICovXG4gICAgICBpZiAodHJhbnNjZWl2ZXIuaWNlVHJhbnNwb3J0KSB7XG4gICAgICAgIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydC5zdG9wKCk7XG4gICAgICB9XG4gICAgICBpZiAodHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydCkge1xuICAgICAgICB0cmFuc2NlaXZlci5kdGxzVHJhbnNwb3J0LnN0b3AoKTtcbiAgICAgIH1cbiAgICAgIGlmICh0cmFuc2NlaXZlci5ydHBTZW5kZXIpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIucnRwU2VuZGVyLnN0b3AoKTtcbiAgICAgIH1cbiAgICAgIGlmICh0cmFuc2NlaXZlci5ydHBSZWNlaXZlcikge1xuICAgICAgICB0cmFuc2NlaXZlci5ydHBSZWNlaXZlci5zdG9wKCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgLy8gRklYTUU6IGNsZWFuIHVwIHRyYWNrcywgbG9jYWwgc3RyZWFtcywgcmVtb3RlIHN0cmVhbXMsIGV0Y1xuICAgIHRoaXMuX3VwZGF0ZVNpZ25hbGluZ1N0YXRlKCdjbG9zZWQnKTtcbiAgfTtcblxuICAvLyBVcGRhdGUgdGhlIHNpZ25hbGluZyBzdGF0ZS5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl91cGRhdGVTaWduYWxpbmdTdGF0ZSA9IGZ1bmN0aW9uKG5ld1N0YXRlKSB7XG4gICAgdGhpcy5zaWduYWxpbmdTdGF0ZSA9IG5ld1N0YXRlO1xuICAgIHZhciBldmVudCA9IG5ldyBFdmVudCgnc2lnbmFsaW5nc3RhdGVjaGFuZ2UnKTtcbiAgICB0aGlzLmRpc3BhdGNoRXZlbnQoZXZlbnQpO1xuICAgIGlmICh0aGlzLm9uc2lnbmFsaW5nc3RhdGVjaGFuZ2UgIT09IG51bGwpIHtcbiAgICAgIHRoaXMub25zaWduYWxpbmdzdGF0ZWNoYW5nZShldmVudCk7XG4gICAgfVxuICB9O1xuXG4gIC8vIERldGVybWluZSB3aGV0aGVyIHRvIGZpcmUgdGhlIG5lZ290aWF0aW9ubmVlZGVkIGV2ZW50LlxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX21heWJlRmlyZU5lZ290aWF0aW9uTmVlZGVkID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGlmICh0aGlzLnNpZ25hbGluZ1N0YXRlICE9PSAnc3RhYmxlJyB8fCB0aGlzLm5lZWROZWdvdGlhdGlvbiA9PT0gdHJ1ZSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLm5lZWROZWdvdGlhdGlvbiA9IHRydWU7XG4gICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICBpZiAoc2VsZi5uZWVkTmVnb3RpYXRpb24gPT09IGZhbHNlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHNlbGYubmVlZE5lZ290aWF0aW9uID0gZmFsc2U7XG4gICAgICB2YXIgZXZlbnQgPSBuZXcgRXZlbnQoJ25lZ290aWF0aW9ubmVlZGVkJyk7XG4gICAgICBzZWxmLmRpc3BhdGNoRXZlbnQoZXZlbnQpO1xuICAgICAgaWYgKHNlbGYub25uZWdvdGlhdGlvbm5lZWRlZCAhPT0gbnVsbCkge1xuICAgICAgICBzZWxmLm9ubmVnb3RpYXRpb25uZWVkZWQoZXZlbnQpO1xuICAgICAgfVxuICAgIH0sIDApO1xuICB9O1xuXG4gIC8vIFVwZGF0ZSB0aGUgY29ubmVjdGlvbiBzdGF0ZS5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl91cGRhdGVDb25uZWN0aW9uU3RhdGUgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIG5ld1N0YXRlO1xuICAgIHZhciBzdGF0ZXMgPSB7XG4gICAgICAnbmV3JzogMCxcbiAgICAgIGNsb3NlZDogMCxcbiAgICAgIGNvbm5lY3Rpbmc6IDAsXG4gICAgICBjaGVja2luZzogMCxcbiAgICAgIGNvbm5lY3RlZDogMCxcbiAgICAgIGNvbXBsZXRlZDogMCxcbiAgICAgIGRpc2Nvbm5lY3RlZDogMCxcbiAgICAgIGZhaWxlZDogMFxuICAgIH07XG4gICAgdGhpcy50cmFuc2NlaXZlcnMuZm9yRWFjaChmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgc3RhdGVzW3RyYW5zY2VpdmVyLmljZVRyYW5zcG9ydC5zdGF0ZV0rKztcbiAgICAgIHN0YXRlc1t0cmFuc2NlaXZlci5kdGxzVHJhbnNwb3J0LnN0YXRlXSsrO1xuICAgIH0pO1xuICAgIC8vIElDRVRyYW5zcG9ydC5jb21wbGV0ZWQgYW5kIGNvbm5lY3RlZCBhcmUgdGhlIHNhbWUgZm9yIHRoaXMgcHVycG9zZS5cbiAgICBzdGF0ZXMuY29ubmVjdGVkICs9IHN0YXRlcy5jb21wbGV0ZWQ7XG5cbiAgICBuZXdTdGF0ZSA9ICduZXcnO1xuICAgIGlmIChzdGF0ZXMuZmFpbGVkID4gMCkge1xuICAgICAgbmV3U3RhdGUgPSAnZmFpbGVkJztcbiAgICB9IGVsc2UgaWYgKHN0YXRlcy5jb25uZWN0aW5nID4gMCB8fCBzdGF0ZXMuY2hlY2tpbmcgPiAwKSB7XG4gICAgICBuZXdTdGF0ZSA9ICdjb25uZWN0aW5nJztcbiAgICB9IGVsc2UgaWYgKHN0YXRlcy5kaXNjb25uZWN0ZWQgPiAwKSB7XG4gICAgICBuZXdTdGF0ZSA9ICdkaXNjb25uZWN0ZWQnO1xuICAgIH0gZWxzZSBpZiAoc3RhdGVzLm5ldyA+IDApIHtcbiAgICAgIG5ld1N0YXRlID0gJ25ldyc7XG4gICAgfSBlbHNlIGlmIChzdGF0ZXMuY29ubmVjdGVkID4gMCB8fCBzdGF0ZXMuY29tcGxldGVkID4gMCkge1xuICAgICAgbmV3U3RhdGUgPSAnY29ubmVjdGVkJztcbiAgICB9XG5cbiAgICBpZiAobmV3U3RhdGUgIT09IHNlbGYuaWNlQ29ubmVjdGlvblN0YXRlKSB7XG4gICAgICBzZWxmLmljZUNvbm5lY3Rpb25TdGF0ZSA9IG5ld1N0YXRlO1xuICAgICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KCdpY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2UnKTtcbiAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgICBpZiAodGhpcy5vbmljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZSAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLm9uaWNlY29ubmVjdGlvbnN0YXRlY2hhbmdlKGV2ZW50KTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmNyZWF0ZU9mZmVyID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGlmICh0aGlzLl9wZW5kaW5nT2ZmZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY3JlYXRlT2ZmZXIgY2FsbGVkIHdoaWxlIHRoZXJlIGlzIGEgcGVuZGluZyBvZmZlci4nKTtcbiAgICB9XG4gICAgdmFyIG9mZmVyT3B0aW9ucztcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSAmJiB0eXBlb2YgYXJndW1lbnRzWzBdICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICBvZmZlck9wdGlvbnMgPSBhcmd1bWVudHNbMF07XG4gICAgfSBlbHNlIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAzKSB7XG4gICAgICBvZmZlck9wdGlvbnMgPSBhcmd1bWVudHNbMl07XG4gICAgfVxuXG4gICAgdmFyIG51bUF1ZGlvVHJhY2tzID0gdGhpcy50cmFuc2NlaXZlcnMuZmlsdGVyKGZ1bmN0aW9uKHQpIHtcbiAgICAgIHJldHVybiB0LmtpbmQgPT09ICdhdWRpbyc7XG4gICAgfSkubGVuZ3RoO1xuICAgIHZhciBudW1WaWRlb1RyYWNrcyA9IHRoaXMudHJhbnNjZWl2ZXJzLmZpbHRlcihmdW5jdGlvbih0KSB7XG4gICAgICByZXR1cm4gdC5raW5kID09PSAndmlkZW8nO1xuICAgIH0pLmxlbmd0aDtcblxuICAgIC8vIERldGVybWluZSBudW1iZXIgb2YgYXVkaW8gYW5kIHZpZGVvIHRyYWNrcyB3ZSBuZWVkIHRvIHNlbmQvcmVjdi5cbiAgICBpZiAob2ZmZXJPcHRpb25zKSB7XG4gICAgICAvLyBSZWplY3QgQ2hyb21lIGxlZ2FjeSBjb25zdHJhaW50cy5cbiAgICAgIGlmIChvZmZlck9wdGlvbnMubWFuZGF0b3J5IHx8IG9mZmVyT3B0aW9ucy5vcHRpb25hbCkge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFxuICAgICAgICAgICAgJ0xlZ2FjeSBtYW5kYXRvcnkvb3B0aW9uYWwgY29uc3RyYWludHMgbm90IHN1cHBvcnRlZC4nKTtcbiAgICAgIH1cbiAgICAgIGlmIChvZmZlck9wdGlvbnMub2ZmZXJUb1JlY2VpdmVBdWRpbyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGlmIChvZmZlck9wdGlvbnMub2ZmZXJUb1JlY2VpdmVBdWRpbyA9PT0gdHJ1ZSkge1xuICAgICAgICAgIG51bUF1ZGlvVHJhY2tzID0gMTtcbiAgICAgICAgfSBlbHNlIGlmIChvZmZlck9wdGlvbnMub2ZmZXJUb1JlY2VpdmVBdWRpbyA9PT0gZmFsc2UpIHtcbiAgICAgICAgICBudW1BdWRpb1RyYWNrcyA9IDA7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbnVtQXVkaW9UcmFja3MgPSBvZmZlck9wdGlvbnMub2ZmZXJUb1JlY2VpdmVBdWRpbztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKG9mZmVyT3B0aW9ucy5vZmZlclRvUmVjZWl2ZVZpZGVvICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgaWYgKG9mZmVyT3B0aW9ucy5vZmZlclRvUmVjZWl2ZVZpZGVvID09PSB0cnVlKSB7XG4gICAgICAgICAgbnVtVmlkZW9UcmFja3MgPSAxO1xuICAgICAgICB9IGVsc2UgaWYgKG9mZmVyT3B0aW9ucy5vZmZlclRvUmVjZWl2ZVZpZGVvID09PSBmYWxzZSkge1xuICAgICAgICAgIG51bVZpZGVvVHJhY2tzID0gMDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBudW1WaWRlb1RyYWNrcyA9IG9mZmVyT3B0aW9ucy5vZmZlclRvUmVjZWl2ZVZpZGVvO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy50cmFuc2NlaXZlcnMuZm9yRWFjaChmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgaWYgKHRyYW5zY2VpdmVyLmtpbmQgPT09ICdhdWRpbycpIHtcbiAgICAgICAgbnVtQXVkaW9UcmFja3MtLTtcbiAgICAgICAgaWYgKG51bUF1ZGlvVHJhY2tzIDwgMCkge1xuICAgICAgICAgIHRyYW5zY2VpdmVyLndhbnRSZWNlaXZlID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodHJhbnNjZWl2ZXIua2luZCA9PT0gJ3ZpZGVvJykge1xuICAgICAgICBudW1WaWRlb1RyYWNrcy0tO1xuICAgICAgICBpZiAobnVtVmlkZW9UcmFja3MgPCAwKSB7XG4gICAgICAgICAgdHJhbnNjZWl2ZXIud2FudFJlY2VpdmUgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gQ3JlYXRlIE0tbGluZXMgZm9yIHJlY3Zvbmx5IHN0cmVhbXMuXG4gICAgd2hpbGUgKG51bUF1ZGlvVHJhY2tzID4gMCB8fCBudW1WaWRlb1RyYWNrcyA+IDApIHtcbiAgICAgIGlmIChudW1BdWRpb1RyYWNrcyA+IDApIHtcbiAgICAgICAgdGhpcy5fY3JlYXRlVHJhbnNjZWl2ZXIoJ2F1ZGlvJyk7XG4gICAgICAgIG51bUF1ZGlvVHJhY2tzLS07XG4gICAgICB9XG4gICAgICBpZiAobnVtVmlkZW9UcmFja3MgPiAwKSB7XG4gICAgICAgIHRoaXMuX2NyZWF0ZVRyYW5zY2VpdmVyKCd2aWRlbycpO1xuICAgICAgICBudW1WaWRlb1RyYWNrcy0tO1xuICAgICAgfVxuICAgIH1cbiAgICAvLyByZW9yZGVyIHRyYWNrc1xuICAgIHZhciB0cmFuc2NlaXZlcnMgPSBzb3J0VHJhY2tzKHRoaXMudHJhbnNjZWl2ZXJzKTtcblxuICAgIHZhciBzZHAgPSBTRFBVdGlscy53cml0ZVNlc3Npb25Cb2lsZXJwbGF0ZSgpO1xuICAgIHRyYW5zY2VpdmVycy5mb3JFYWNoKGZ1bmN0aW9uKHRyYW5zY2VpdmVyLCBzZHBNTGluZUluZGV4KSB7XG4gICAgICAvLyBGb3IgZWFjaCB0cmFjaywgY3JlYXRlIGFuIGljZSBnYXRoZXJlciwgaWNlIHRyYW5zcG9ydCxcbiAgICAgIC8vIGR0bHMgdHJhbnNwb3J0LCBwb3RlbnRpYWxseSBydHBzZW5kZXIgYW5kIHJ0cHJlY2VpdmVyLlxuICAgICAgdmFyIHRyYWNrID0gdHJhbnNjZWl2ZXIudHJhY2s7XG4gICAgICB2YXIga2luZCA9IHRyYW5zY2VpdmVyLmtpbmQ7XG4gICAgICB2YXIgbWlkID0gU0RQVXRpbHMuZ2VuZXJhdGVJZGVudGlmaWVyKCk7XG4gICAgICB0cmFuc2NlaXZlci5taWQgPSBtaWQ7XG5cbiAgICAgIGlmICghdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXIpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXIgPSBzZWxmLnVzaW5nQnVuZGxlICYmIHNkcE1MaW5lSW5kZXggPiAwID9cbiAgICAgICAgICAgIHRyYW5zY2VpdmVyc1swXS5pY2VHYXRoZXJlciA6XG4gICAgICAgICAgICBzZWxmLl9jcmVhdGVJY2VHYXRoZXJlcihtaWQsIHNkcE1MaW5lSW5kZXgpO1xuICAgICAgfVxuXG4gICAgICB2YXIgbG9jYWxDYXBhYmlsaXRpZXMgPSB3aW5kb3cuUlRDUnRwU2VuZGVyLmdldENhcGFiaWxpdGllcyhraW5kKTtcbiAgICAgIC8vIGZpbHRlciBSVFggdW50aWwgYWRkaXRpb25hbCBzdHVmZiBuZWVkZWQgZm9yIFJUWCBpcyBpbXBsZW1lbnRlZFxuICAgICAgLy8gaW4gYWRhcHRlci5qc1xuICAgICAgaWYgKGVkZ2VWZXJzaW9uIDwgMTUwMTkpIHtcbiAgICAgICAgbG9jYWxDYXBhYmlsaXRpZXMuY29kZWNzID0gbG9jYWxDYXBhYmlsaXRpZXMuY29kZWNzLmZpbHRlcihcbiAgICAgICAgICAgIGZ1bmN0aW9uKGNvZGVjKSB7XG4gICAgICAgICAgICAgIHJldHVybiBjb2RlYy5uYW1lICE9PSAncnR4JztcbiAgICAgICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgbG9jYWxDYXBhYmlsaXRpZXMuY29kZWNzLmZvckVhY2goZnVuY3Rpb24oY29kZWMpIHtcbiAgICAgICAgLy8gd29yayBhcm91bmQgaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL3dlYnJ0Yy9pc3N1ZXMvZGV0YWlsP2lkPTY1NTJcbiAgICAgICAgLy8gYnkgYWRkaW5nIGxldmVsLWFzeW1tZXRyeS1hbGxvd2VkPTFcbiAgICAgICAgaWYgKGNvZGVjLm5hbWUgPT09ICdIMjY0JyAmJlxuICAgICAgICAgICAgY29kZWMucGFyYW1ldGVyc1snbGV2ZWwtYXN5bW1ldHJ5LWFsbG93ZWQnXSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgY29kZWMucGFyYW1ldGVyc1snbGV2ZWwtYXN5bW1ldHJ5LWFsbG93ZWQnXSA9ICcxJztcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIC8vIGdlbmVyYXRlIGFuIHNzcmMgbm93LCB0byBiZSB1c2VkIGxhdGVyIGluIHJ0cFNlbmRlci5zZW5kXG4gICAgICB2YXIgc2VuZEVuY29kaW5nUGFyYW1ldGVycyA9IFt7XG4gICAgICAgIHNzcmM6ICgyICogc2RwTUxpbmVJbmRleCArIDEpICogMTAwMVxuICAgICAgfV07XG4gICAgICBpZiAodHJhY2spIHtcbiAgICAgICAgLy8gYWRkIFJUWFxuICAgICAgICBpZiAoZWRnZVZlcnNpb24gPj0gMTUwMTkgJiYga2luZCA9PT0gJ3ZpZGVvJykge1xuICAgICAgICAgIHNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0ucnR4ID0ge1xuICAgICAgICAgICAgc3NyYzogKDIgKiBzZHBNTGluZUluZGV4ICsgMSkgKiAxMDAxICsgMVxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRyYW5zY2VpdmVyLndhbnRSZWNlaXZlKSB7XG4gICAgICAgIHRyYW5zY2VpdmVyLnJ0cFJlY2VpdmVyID0gbmV3IHdpbmRvdy5SVENSdHBSZWNlaXZlcihcbiAgICAgICAgICB0cmFuc2NlaXZlci5kdGxzVHJhbnNwb3J0LFxuICAgICAgICAgIGtpbmRcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgdHJhbnNjZWl2ZXIubG9jYWxDYXBhYmlsaXRpZXMgPSBsb2NhbENhcGFiaWxpdGllcztcbiAgICAgIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnMgPSBzZW5kRW5jb2RpbmdQYXJhbWV0ZXJzO1xuICAgIH0pO1xuXG4gICAgLy8gYWx3YXlzIG9mZmVyIEJVTkRMRSBhbmQgZGlzcG9zZSBvbiByZXR1cm4gaWYgbm90IHN1cHBvcnRlZC5cbiAgICBpZiAodGhpcy5fY29uZmlnLmJ1bmRsZVBvbGljeSAhPT0gJ21heC1jb21wYXQnKSB7XG4gICAgICBzZHAgKz0gJ2E9Z3JvdXA6QlVORExFICcgKyB0cmFuc2NlaXZlcnMubWFwKGZ1bmN0aW9uKHQpIHtcbiAgICAgICAgcmV0dXJuIHQubWlkO1xuICAgICAgfSkuam9pbignICcpICsgJ1xcclxcbic7XG4gICAgfVxuICAgIHNkcCArPSAnYT1pY2Utb3B0aW9uczp0cmlja2xlXFxyXFxuJztcblxuICAgIHRyYW5zY2VpdmVycy5mb3JFYWNoKGZ1bmN0aW9uKHRyYW5zY2VpdmVyLCBzZHBNTGluZUluZGV4KSB7XG4gICAgICBzZHAgKz0gU0RQVXRpbHMud3JpdGVNZWRpYVNlY3Rpb24odHJhbnNjZWl2ZXIsXG4gICAgICAgICAgdHJhbnNjZWl2ZXIubG9jYWxDYXBhYmlsaXRpZXMsICdvZmZlcicsIHRyYW5zY2VpdmVyLnN0cmVhbSk7XG4gICAgICBzZHAgKz0gJ2E9cnRjcC1yc2l6ZVxcclxcbic7XG4gICAgfSk7XG5cbiAgICB0aGlzLl9wZW5kaW5nT2ZmZXIgPSB0cmFuc2NlaXZlcnM7XG4gICAgdmFyIGRlc2MgPSBuZXcgd2luZG93LlJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICB0eXBlOiAnb2ZmZXInLFxuICAgICAgc2RwOiBzZHBcbiAgICB9KTtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCAmJiB0eXBlb2YgYXJndW1lbnRzWzBdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB3aW5kb3cuc2V0VGltZW91dChhcmd1bWVudHNbMF0sIDAsIGRlc2MpO1xuICAgIH1cbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGRlc2MpO1xuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5jcmVhdGVBbnN3ZXIgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgc2RwID0gU0RQVXRpbHMud3JpdGVTZXNzaW9uQm9pbGVycGxhdGUoKTtcbiAgICBpZiAodGhpcy51c2luZ0J1bmRsZSkge1xuICAgICAgc2RwICs9ICdhPWdyb3VwOkJVTkRMRSAnICsgdGhpcy50cmFuc2NlaXZlcnMubWFwKGZ1bmN0aW9uKHQpIHtcbiAgICAgICAgcmV0dXJuIHQubWlkO1xuICAgICAgfSkuam9pbignICcpICsgJ1xcclxcbic7XG4gICAgfVxuICAgIHRoaXMudHJhbnNjZWl2ZXJzLmZvckVhY2goZnVuY3Rpb24odHJhbnNjZWl2ZXIsIHNkcE1MaW5lSW5kZXgpIHtcbiAgICAgIGlmICh0cmFuc2NlaXZlci5pc0RhdGFjaGFubmVsKSB7XG4gICAgICAgIHNkcCArPSAnbT1hcHBsaWNhdGlvbiAwIERUTFMvU0NUUCA1MDAwXFxyXFxuJyArXG4gICAgICAgICAgICAnYz1JTiBJUDQgMC4wLjAuMFxcclxcbicgK1xuICAgICAgICAgICAgJ2E9bWlkOicgKyB0cmFuc2NlaXZlci5taWQgKyAnXFxyXFxuJztcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBGSVhNRTogbG9vayBhdCBkaXJlY3Rpb24uXG4gICAgICBpZiAodHJhbnNjZWl2ZXIuc3RyZWFtKSB7XG4gICAgICAgIHZhciBsb2NhbFRyYWNrO1xuICAgICAgICBpZiAodHJhbnNjZWl2ZXIua2luZCA9PT0gJ2F1ZGlvJykge1xuICAgICAgICAgIGxvY2FsVHJhY2sgPSB0cmFuc2NlaXZlci5zdHJlYW0uZ2V0QXVkaW9UcmFja3MoKVswXTtcbiAgICAgICAgfSBlbHNlIGlmICh0cmFuc2NlaXZlci5raW5kID09PSAndmlkZW8nKSB7XG4gICAgICAgICAgbG9jYWxUcmFjayA9IHRyYW5zY2VpdmVyLnN0cmVhbS5nZXRWaWRlb1RyYWNrcygpWzBdO1xuICAgICAgICB9XG4gICAgICAgIGlmIChsb2NhbFRyYWNrKSB7XG4gICAgICAgICAgLy8gYWRkIFJUWFxuICAgICAgICAgIGlmIChlZGdlVmVyc2lvbiA+PSAxNTAxOSAmJiB0cmFuc2NlaXZlci5raW5kID09PSAndmlkZW8nKSB7XG4gICAgICAgICAgICB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eCA9IHtcbiAgICAgICAgICAgICAgc3NyYzogKDIgKiBzZHBNTGluZUluZGV4ICsgMikgKiAxMDAxICsgMVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gQ2FsY3VsYXRlIGludGVyc2VjdGlvbiBvZiBjYXBhYmlsaXRpZXMuXG4gICAgICB2YXIgY29tbW9uQ2FwYWJpbGl0aWVzID0gZ2V0Q29tbW9uQ2FwYWJpbGl0aWVzKFxuICAgICAgICAgIHRyYW5zY2VpdmVyLmxvY2FsQ2FwYWJpbGl0aWVzLFxuICAgICAgICAgIHRyYW5zY2VpdmVyLnJlbW90ZUNhcGFiaWxpdGllcyk7XG5cbiAgICAgIHZhciBoYXNSdHggPSBjb21tb25DYXBhYmlsaXRpZXMuY29kZWNzLmZpbHRlcihmdW5jdGlvbihjKSB7XG4gICAgICAgIHJldHVybiBjLm5hbWUudG9Mb3dlckNhc2UoKSA9PT0gJ3J0eCc7XG4gICAgICB9KS5sZW5ndGg7XG4gICAgICBpZiAoIWhhc1J0eCAmJiB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eCkge1xuICAgICAgICBkZWxldGUgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHg7XG4gICAgICB9XG5cbiAgICAgIHNkcCArPSBTRFBVdGlscy53cml0ZU1lZGlhU2VjdGlvbih0cmFuc2NlaXZlciwgY29tbW9uQ2FwYWJpbGl0aWVzLFxuICAgICAgICAgICdhbnN3ZXInLCB0cmFuc2NlaXZlci5zdHJlYW0pO1xuICAgICAgaWYgKHRyYW5zY2VpdmVyLnJ0Y3BQYXJhbWV0ZXJzICYmXG4gICAgICAgICAgdHJhbnNjZWl2ZXIucnRjcFBhcmFtZXRlcnMucmVkdWNlZFNpemUpIHtcbiAgICAgICAgc2RwICs9ICdhPXJ0Y3AtcnNpemVcXHJcXG4nO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIGRlc2MgPSBuZXcgd2luZG93LlJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICB0eXBlOiAnYW5zd2VyJyxcbiAgICAgIHNkcDogc2RwXG4gICAgfSk7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggJiYgdHlwZW9mIGFyZ3VtZW50c1swXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgd2luZG93LnNldFRpbWVvdXQoYXJndW1lbnRzWzBdLCAwLCBkZXNjKTtcbiAgICB9XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShkZXNjKTtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkSWNlQ2FuZGlkYXRlID0gZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gICAgaWYgKCFjYW5kaWRhdGUpIHtcbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgdGhpcy50cmFuc2NlaXZlcnMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgdGhpcy50cmFuc2NlaXZlcnNbal0uaWNlVHJhbnNwb3J0LmFkZFJlbW90ZUNhbmRpZGF0ZSh7fSk7XG4gICAgICAgIGlmICh0aGlzLnVzaW5nQnVuZGxlKSB7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBtTGluZUluZGV4ID0gY2FuZGlkYXRlLnNkcE1MaW5lSW5kZXg7XG4gICAgICBpZiAoY2FuZGlkYXRlLnNkcE1pZCkge1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMudHJhbnNjZWl2ZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgaWYgKHRoaXMudHJhbnNjZWl2ZXJzW2ldLm1pZCA9PT0gY2FuZGlkYXRlLnNkcE1pZCkge1xuICAgICAgICAgICAgbUxpbmVJbmRleCA9IGk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHZhciB0cmFuc2NlaXZlciA9IHRoaXMudHJhbnNjZWl2ZXJzW21MaW5lSW5kZXhdO1xuICAgICAgaWYgKHRyYW5zY2VpdmVyKSB7XG4gICAgICAgIHZhciBjYW5kID0gT2JqZWN0LmtleXMoY2FuZGlkYXRlLmNhbmRpZGF0ZSkubGVuZ3RoID4gMCA/XG4gICAgICAgICAgICBTRFBVdGlscy5wYXJzZUNhbmRpZGF0ZShjYW5kaWRhdGUuY2FuZGlkYXRlKSA6IHt9O1xuICAgICAgICAvLyBJZ25vcmUgQ2hyb21lJ3MgaW52YWxpZCBjYW5kaWRhdGVzIHNpbmNlIEVkZ2UgZG9lcyBub3QgbGlrZSB0aGVtLlxuICAgICAgICBpZiAoY2FuZC5wcm90b2NvbCA9PT0gJ3RjcCcgJiYgKGNhbmQucG9ydCA9PT0gMCB8fCBjYW5kLnBvcnQgPT09IDkpKSB7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgICB9XG4gICAgICAgIC8vIElnbm9yZSBSVENQIGNhbmRpZGF0ZXMsIHdlIGFzc3VtZSBSVENQLU1VWC5cbiAgICAgICAgaWYgKGNhbmQuY29tcG9uZW50ICYmXG4gICAgICAgICAgICAhKGNhbmQuY29tcG9uZW50ID09PSAnMScgfHwgY2FuZC5jb21wb25lbnQgPT09IDEpKSB7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgICB9XG4gICAgICAgIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydC5hZGRSZW1vdGVDYW5kaWRhdGUoY2FuZCk7XG5cbiAgICAgICAgLy8gdXBkYXRlIHRoZSByZW1vdGVEZXNjcmlwdGlvbi5cbiAgICAgICAgdmFyIHNlY3Rpb25zID0gU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyh0aGlzLnJlbW90ZURlc2NyaXB0aW9uLnNkcCk7XG4gICAgICAgIHNlY3Rpb25zW21MaW5lSW5kZXggKyAxXSArPSAoY2FuZC50eXBlID8gY2FuZGlkYXRlLmNhbmRpZGF0ZS50cmltKClcbiAgICAgICAgICAgIDogJ2E9ZW5kLW9mLWNhbmRpZGF0ZXMnKSArICdcXHJcXG4nO1xuICAgICAgICB0aGlzLnJlbW90ZURlc2NyaXB0aW9uLnNkcCA9IHNlY3Rpb25zLmpvaW4oJycpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgdHlwZW9mIGFyZ3VtZW50c1sxXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgd2luZG93LnNldFRpbWVvdXQoYXJndW1lbnRzWzFdLCAwKTtcbiAgICB9XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRTdGF0cyA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBwcm9taXNlcyA9IFtdO1xuICAgIHRoaXMudHJhbnNjZWl2ZXJzLmZvckVhY2goZnVuY3Rpb24odHJhbnNjZWl2ZXIpIHtcbiAgICAgIFsncnRwU2VuZGVyJywgJ3J0cFJlY2VpdmVyJywgJ2ljZUdhdGhlcmVyJywgJ2ljZVRyYW5zcG9ydCcsXG4gICAgICAgICdkdGxzVHJhbnNwb3J0J10uZm9yRWFjaChmdW5jdGlvbihtZXRob2QpIHtcbiAgICAgICAgICBpZiAodHJhbnNjZWl2ZXJbbWV0aG9kXSkge1xuICAgICAgICAgICAgcHJvbWlzZXMucHVzaCh0cmFuc2NlaXZlclttZXRob2RdLmdldFN0YXRzKCkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfSk7XG4gICAgdmFyIGNiID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgdHlwZW9mIGFyZ3VtZW50c1sxXSA9PT0gJ2Z1bmN0aW9uJyAmJlxuICAgICAgICBhcmd1bWVudHNbMV07XG4gICAgdmFyIGZpeFN0YXRzVHlwZSA9IGZ1bmN0aW9uKHN0YXQpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGluYm91bmRydHA6ICdpbmJvdW5kLXJ0cCcsXG4gICAgICAgIG91dGJvdW5kcnRwOiAnb3V0Ym91bmQtcnRwJyxcbiAgICAgICAgY2FuZGlkYXRlcGFpcjogJ2NhbmRpZGF0ZS1wYWlyJyxcbiAgICAgICAgbG9jYWxjYW5kaWRhdGU6ICdsb2NhbC1jYW5kaWRhdGUnLFxuICAgICAgICByZW1vdGVjYW5kaWRhdGU6ICdyZW1vdGUtY2FuZGlkYXRlJ1xuICAgICAgfVtzdGF0LnR5cGVdIHx8IHN0YXQudHlwZTtcbiAgICB9O1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlKSB7XG4gICAgICAvLyBzaGltIGdldFN0YXRzIHdpdGggbWFwbGlrZSBzdXBwb3J0XG4gICAgICB2YXIgcmVzdWx0cyA9IG5ldyBNYXAoKTtcbiAgICAgIFByb21pc2UuYWxsKHByb21pc2VzKS50aGVuKGZ1bmN0aW9uKHJlcykge1xuICAgICAgICByZXMuZm9yRWFjaChmdW5jdGlvbihyZXN1bHQpIHtcbiAgICAgICAgICBPYmplY3Qua2V5cyhyZXN1bHQpLmZvckVhY2goZnVuY3Rpb24oaWQpIHtcbiAgICAgICAgICAgIHJlc3VsdFtpZF0udHlwZSA9IGZpeFN0YXRzVHlwZShyZXN1bHRbaWRdKTtcbiAgICAgICAgICAgIHJlc3VsdHMuc2V0KGlkLCByZXN1bHRbaWRdKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChjYikge1xuICAgICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGNiLCAwLCByZXN1bHRzKTtcbiAgICAgICAgfVxuICAgICAgICByZXNvbHZlKHJlc3VsdHMpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH07XG4gIHJldHVybiBSVENQZWVyQ29ubmVjdGlvbjtcbn07XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMnKTtcblxudmFyIGZpcmVmb3hTaGltID0ge1xuICBzaGltT25UcmFjazogZnVuY3Rpb24od2luZG93KSB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnICYmIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbiAmJiAhKCdvbnRyYWNrJyBpblxuICAgICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlKSkge1xuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUsICdvbnRyYWNrJywge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHJldHVybiB0aGlzLl9vbnRyYWNrO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uKGYpIHtcbiAgICAgICAgICBpZiAodGhpcy5fb250cmFjaykge1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVyKCd0cmFjaycsIHRoaXMuX29udHJhY2spO1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVyKCdhZGRzdHJlYW0nLCB0aGlzLl9vbnRyYWNrcG9seSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lcigndHJhY2snLCB0aGlzLl9vbnRyYWNrID0gZik7XG4gICAgICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVyKCdhZGRzdHJlYW0nLCB0aGlzLl9vbnRyYWNrcG9seSA9IGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgICAgIGUuc3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2spIHtcbiAgICAgICAgICAgICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KCd0cmFjaycpO1xuICAgICAgICAgICAgICBldmVudC50cmFjayA9IHRyYWNrO1xuICAgICAgICAgICAgICBldmVudC5yZWNlaXZlciA9IHt0cmFjazogdHJhY2t9O1xuICAgICAgICAgICAgICBldmVudC5zdHJlYW1zID0gW2Uuc3RyZWFtXTtcbiAgICAgICAgICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9LFxuXG4gIHNoaW1Tb3VyY2VPYmplY3Q6IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIC8vIEZpcmVmb3ggaGFzIHN1cHBvcnRlZCBtb3pTcmNPYmplY3Qgc2luY2UgRkYyMiwgdW5wcmVmaXhlZCBpbiA0Mi5cbiAgICBpZiAodHlwZW9mIHdpbmRvdyA9PT0gJ29iamVjdCcpIHtcbiAgICAgIGlmICh3aW5kb3cuSFRNTE1lZGlhRWxlbWVudCAmJlxuICAgICAgICAhKCdzcmNPYmplY3QnIGluIHdpbmRvdy5IVE1MTWVkaWFFbGVtZW50LnByb3RvdHlwZSkpIHtcbiAgICAgICAgLy8gU2hpbSB0aGUgc3JjT2JqZWN0IHByb3BlcnR5LCBvbmNlLCB3aGVuIEhUTUxNZWRpYUVsZW1lbnQgaXMgZm91bmQuXG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuSFRNTE1lZGlhRWxlbWVudC5wcm90b3R5cGUsICdzcmNPYmplY3QnLCB7XG4gICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm1velNyY09iamVjdDtcbiAgICAgICAgICB9LFxuICAgICAgICAgIHNldDogZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgICAgICB0aGlzLm1velNyY09iamVjdCA9IHN0cmVhbTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfSxcblxuICBzaGltUGVlckNvbm5lY3Rpb246IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIHZhciBicm93c2VyRGV0YWlscyA9IHV0aWxzLmRldGVjdEJyb3dzZXIod2luZG93KTtcblxuICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSAnb2JqZWN0JyB8fCAhKHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbiB8fFxuICAgICAgICB3aW5kb3cubW96UlRDUGVlckNvbm5lY3Rpb24pKSB7XG4gICAgICByZXR1cm47IC8vIHByb2JhYmx5IG1lZGlhLnBlZXJjb25uZWN0aW9uLmVuYWJsZWQ9ZmFsc2UgaW4gYWJvdXQ6Y29uZmlnXG4gICAgfVxuICAgIC8vIFRoZSBSVENQZWVyQ29ubmVjdGlvbiBvYmplY3QuXG4gICAgaWYgKCF3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24pIHtcbiAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbiA9IGZ1bmN0aW9uKHBjQ29uZmlnLCBwY0NvbnN0cmFpbnRzKSB7XG4gICAgICAgIGlmIChicm93c2VyRGV0YWlscy52ZXJzaW9uIDwgMzgpIHtcbiAgICAgICAgICAvLyAudXJscyBpcyBub3Qgc3VwcG9ydGVkIGluIEZGIDwgMzguXG4gICAgICAgICAgLy8gY3JlYXRlIFJUQ0ljZVNlcnZlcnMgd2l0aCBhIHNpbmdsZSB1cmwuXG4gICAgICAgICAgaWYgKHBjQ29uZmlnICYmIHBjQ29uZmlnLmljZVNlcnZlcnMpIHtcbiAgICAgICAgICAgIHZhciBuZXdJY2VTZXJ2ZXJzID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHBjQ29uZmlnLmljZVNlcnZlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgdmFyIHNlcnZlciA9IHBjQ29uZmlnLmljZVNlcnZlcnNbaV07XG4gICAgICAgICAgICAgIGlmIChzZXJ2ZXIuaGFzT3duUHJvcGVydHkoJ3VybHMnKSkge1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgc2VydmVyLnVybHMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICAgIHZhciBuZXdTZXJ2ZXIgPSB7XG4gICAgICAgICAgICAgICAgICAgIHVybDogc2VydmVyLnVybHNbal1cbiAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICBpZiAoc2VydmVyLnVybHNbal0uaW5kZXhPZigndHVybicpID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIG5ld1NlcnZlci51c2VybmFtZSA9IHNlcnZlci51c2VybmFtZTtcbiAgICAgICAgICAgICAgICAgICAgbmV3U2VydmVyLmNyZWRlbnRpYWwgPSBzZXJ2ZXIuY3JlZGVudGlhbDtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIG5ld0ljZVNlcnZlcnMucHVzaChuZXdTZXJ2ZXIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuZXdJY2VTZXJ2ZXJzLnB1c2gocGNDb25maWcuaWNlU2VydmVyc1tpXSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHBjQ29uZmlnLmljZVNlcnZlcnMgPSBuZXdJY2VTZXJ2ZXJzO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmV3IHdpbmRvdy5tb3pSVENQZWVyQ29ubmVjdGlvbihwY0NvbmZpZywgcGNDb25zdHJhaW50cyk7XG4gICAgICB9O1xuICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZSA9XG4gICAgICAgICAgd2luZG93Lm1velJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZTtcblxuICAgICAgLy8gd3JhcCBzdGF0aWMgbWV0aG9kcy4gQ3VycmVudGx5IGp1c3QgZ2VuZXJhdGVDZXJ0aWZpY2F0ZS5cbiAgICAgIGlmICh3aW5kb3cubW96UlRDUGVlckNvbm5lY3Rpb24uZ2VuZXJhdGVDZXJ0aWZpY2F0ZSkge1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkod2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLCAnZ2VuZXJhdGVDZXJ0aWZpY2F0ZScsIHtcbiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHdpbmRvdy5tb3pSVENQZWVyQ29ubmVjdGlvbi5nZW5lcmF0ZUNlcnRpZmljYXRlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHdpbmRvdy5SVENTZXNzaW9uRGVzY3JpcHRpb24gPSB3aW5kb3cubW96UlRDU2Vzc2lvbkRlc2NyaXB0aW9uO1xuICAgICAgd2luZG93LlJUQ0ljZUNhbmRpZGF0ZSA9IHdpbmRvdy5tb3pSVENJY2VDYW5kaWRhdGU7XG4gICAgfVxuXG4gICAgLy8gc2hpbSBhd2F5IG5lZWQgZm9yIG9ic29sZXRlIFJUQ0ljZUNhbmRpZGF0ZS9SVENTZXNzaW9uRGVzY3JpcHRpb24uXG4gICAgWydzZXRMb2NhbERlc2NyaXB0aW9uJywgJ3NldFJlbW90ZURlc2NyaXB0aW9uJywgJ2FkZEljZUNhbmRpZGF0ZSddXG4gICAgICAgIC5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZCkge1xuICAgICAgICAgIHZhciBuYXRpdmVNZXRob2QgPSB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlW21ldGhvZF07XG4gICAgICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBhcmd1bWVudHNbMF0gPSBuZXcgKChtZXRob2QgPT09ICdhZGRJY2VDYW5kaWRhdGUnKSA/XG4gICAgICAgICAgICAgICAgd2luZG93LlJUQ0ljZUNhbmRpZGF0ZSA6XG4gICAgICAgICAgICAgICAgd2luZG93LlJUQ1Nlc3Npb25EZXNjcmlwdGlvbikoYXJndW1lbnRzWzBdKTtcbiAgICAgICAgICAgIHJldHVybiBuYXRpdmVNZXRob2QuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICB9O1xuICAgICAgICB9KTtcblxuICAgIC8vIHN1cHBvcnQgZm9yIGFkZEljZUNhbmRpZGF0ZShudWxsIG9yIHVuZGVmaW5lZClcbiAgICB2YXIgbmF0aXZlQWRkSWNlQ2FuZGlkYXRlID1cbiAgICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRJY2VDYW5kaWRhdGU7XG4gICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRJY2VDYW5kaWRhdGUgPSBmdW5jdGlvbigpIHtcbiAgICAgIGlmICghYXJndW1lbnRzWzBdKSB7XG4gICAgICAgIGlmIChhcmd1bWVudHNbMV0pIHtcbiAgICAgICAgICBhcmd1bWVudHNbMV0uYXBwbHkobnVsbCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5hdGl2ZUFkZEljZUNhbmRpZGF0ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH07XG5cbiAgICAvLyBzaGltIGdldFN0YXRzIHdpdGggbWFwbGlrZSBzdXBwb3J0XG4gICAgdmFyIG1ha2VNYXBTdGF0cyA9IGZ1bmN0aW9uKHN0YXRzKSB7XG4gICAgICB2YXIgbWFwID0gbmV3IE1hcCgpO1xuICAgICAgT2JqZWN0LmtleXMoc3RhdHMpLmZvckVhY2goZnVuY3Rpb24oa2V5KSB7XG4gICAgICAgIG1hcC5zZXQoa2V5LCBzdGF0c1trZXldKTtcbiAgICAgICAgbWFwW2tleV0gPSBzdGF0c1trZXldO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gbWFwO1xuICAgIH07XG5cbiAgICB2YXIgbW9kZXJuU3RhdHNUeXBlcyA9IHtcbiAgICAgIGluYm91bmRydHA6ICdpbmJvdW5kLXJ0cCcsXG4gICAgICBvdXRib3VuZHJ0cDogJ291dGJvdW5kLXJ0cCcsXG4gICAgICBjYW5kaWRhdGVwYWlyOiAnY2FuZGlkYXRlLXBhaXInLFxuICAgICAgbG9jYWxjYW5kaWRhdGU6ICdsb2NhbC1jYW5kaWRhdGUnLFxuICAgICAgcmVtb3RlY2FuZGlkYXRlOiAncmVtb3RlLWNhbmRpZGF0ZSdcbiAgICB9O1xuXG4gICAgdmFyIG5hdGl2ZUdldFN0YXRzID0gd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRTdGF0cztcbiAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFN0YXRzID0gZnVuY3Rpb24oXG4gICAgICBzZWxlY3RvcixcbiAgICAgIG9uU3VjYyxcbiAgICAgIG9uRXJyXG4gICAgKSB7XG4gICAgICByZXR1cm4gbmF0aXZlR2V0U3RhdHMuYXBwbHkodGhpcywgW3NlbGVjdG9yIHx8IG51bGxdKVxuICAgICAgICAudGhlbihmdW5jdGlvbihzdGF0cykge1xuICAgICAgICAgIGlmIChicm93c2VyRGV0YWlscy52ZXJzaW9uIDwgNDgpIHtcbiAgICAgICAgICAgIHN0YXRzID0gbWFrZU1hcFN0YXRzKHN0YXRzKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCA1MyAmJiAhb25TdWNjKSB7XG4gICAgICAgICAgICAvLyBTaGltIG9ubHkgcHJvbWlzZSBnZXRTdGF0cyB3aXRoIHNwZWMtaHlwaGVucyBpbiB0eXBlIG5hbWVzXG4gICAgICAgICAgICAvLyBMZWF2ZSBjYWxsYmFjayB2ZXJzaW9uIGFsb25lOyBtaXNjIG9sZCB1c2VzIG9mIGZvckVhY2ggYmVmb3JlIE1hcFxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgc3RhdHMuZm9yRWFjaChmdW5jdGlvbihzdGF0KSB7XG4gICAgICAgICAgICAgICAgc3RhdC50eXBlID0gbW9kZXJuU3RhdHNUeXBlc1tzdGF0LnR5cGVdIHx8IHN0YXQudHlwZTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgIGlmIChlLm5hbWUgIT09ICdUeXBlRXJyb3InKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAvLyBBdm9pZCBUeXBlRXJyb3I6IFwidHlwZVwiIGlzIHJlYWQtb25seSwgaW4gb2xkIHZlcnNpb25zLiAzNC00M2lzaFxuICAgICAgICAgICAgICBzdGF0cy5mb3JFYWNoKGZ1bmN0aW9uKHN0YXQsIGkpIHtcbiAgICAgICAgICAgICAgICBzdGF0cy5zZXQoaSwgT2JqZWN0LmFzc2lnbih7fSwgc3RhdCwge1xuICAgICAgICAgICAgICAgICAgdHlwZTogbW9kZXJuU3RhdHNUeXBlc1tzdGF0LnR5cGVdIHx8IHN0YXQudHlwZVxuICAgICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBzdGF0cztcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4ob25TdWNjLCBvbkVycik7XG4gICAgfTtcbiAgfVxufTtcblxuLy8gRXhwb3NlIHB1YmxpYyBtZXRob2RzLlxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHNoaW1PblRyYWNrOiBmaXJlZm94U2hpbS5zaGltT25UcmFjayxcbiAgc2hpbVNvdXJjZU9iamVjdDogZmlyZWZveFNoaW0uc2hpbVNvdXJjZU9iamVjdCxcbiAgc2hpbVBlZXJDb25uZWN0aW9uOiBmaXJlZm94U2hpbS5zaGltUGVlckNvbm5lY3Rpb24sXG4gIHNoaW1HZXRVc2VyTWVkaWE6IHJlcXVpcmUoJy4vZ2V0dXNlcm1lZGlhJylcbn07XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMnKTtcbnZhciBsb2dnaW5nID0gdXRpbHMubG9nO1xuXG4vLyBFeHBvc2UgcHVibGljIG1ldGhvZHMuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKHdpbmRvdykge1xuICB2YXIgYnJvd3NlckRldGFpbHMgPSB1dGlscy5kZXRlY3RCcm93c2VyKHdpbmRvdyk7XG4gIHZhciBuYXZpZ2F0b3IgPSB3aW5kb3cgJiYgd2luZG93Lm5hdmlnYXRvcjtcbiAgdmFyIE1lZGlhU3RyZWFtVHJhY2sgPSB3aW5kb3cgJiYgd2luZG93Lk1lZGlhU3RyZWFtVHJhY2s7XG5cbiAgdmFyIHNoaW1FcnJvcl8gPSBmdW5jdGlvbihlKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6IHtcbiAgICAgICAgSW50ZXJuYWxFcnJvcjogJ05vdFJlYWRhYmxlRXJyb3InLFxuICAgICAgICBOb3RTdXBwb3J0ZWRFcnJvcjogJ1R5cGVFcnJvcicsXG4gICAgICAgIFBlcm1pc3Npb25EZW5pZWRFcnJvcjogJ05vdEFsbG93ZWRFcnJvcicsXG4gICAgICAgIFNlY3VyaXR5RXJyb3I6ICdOb3RBbGxvd2VkRXJyb3InXG4gICAgICB9W2UubmFtZV0gfHwgZS5uYW1lLFxuICAgICAgbWVzc2FnZToge1xuICAgICAgICAnVGhlIG9wZXJhdGlvbiBpcyBpbnNlY3VyZS4nOiAnVGhlIHJlcXVlc3QgaXMgbm90IGFsbG93ZWQgYnkgdGhlICcgK1xuICAgICAgICAndXNlciBhZ2VudCBvciB0aGUgcGxhdGZvcm0gaW4gdGhlIGN1cnJlbnQgY29udGV4dC4nXG4gICAgICB9W2UubWVzc2FnZV0gfHwgZS5tZXNzYWdlLFxuICAgICAgY29uc3RyYWludDogZS5jb25zdHJhaW50LFxuICAgICAgdG9TdHJpbmc6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5uYW1lICsgKHRoaXMubWVzc2FnZSAmJiAnOiAnKSArIHRoaXMubWVzc2FnZTtcbiAgICAgIH1cbiAgICB9O1xuICB9O1xuXG4gIC8vIGdldFVzZXJNZWRpYSBjb25zdHJhaW50cyBzaGltLlxuICB2YXIgZ2V0VXNlck1lZGlhXyA9IGZ1bmN0aW9uKGNvbnN0cmFpbnRzLCBvblN1Y2Nlc3MsIG9uRXJyb3IpIHtcbiAgICB2YXIgY29uc3RyYWludHNUb0ZGMzdfID0gZnVuY3Rpb24oYykge1xuICAgICAgaWYgKHR5cGVvZiBjICE9PSAnb2JqZWN0JyB8fCBjLnJlcXVpcmUpIHtcbiAgICAgICAgcmV0dXJuIGM7XG4gICAgICB9XG4gICAgICB2YXIgcmVxdWlyZSA9IFtdO1xuICAgICAgT2JqZWN0LmtleXMoYykuZm9yRWFjaChmdW5jdGlvbihrZXkpIHtcbiAgICAgICAgaWYgKGtleSA9PT0gJ3JlcXVpcmUnIHx8IGtleSA9PT0gJ2FkdmFuY2VkJyB8fCBrZXkgPT09ICdtZWRpYVNvdXJjZScpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHIgPSBjW2tleV0gPSAodHlwZW9mIGNba2V5XSA9PT0gJ29iamVjdCcpID9cbiAgICAgICAgICAgIGNba2V5XSA6IHtpZGVhbDogY1trZXldfTtcbiAgICAgICAgaWYgKHIubWluICE9PSB1bmRlZmluZWQgfHxcbiAgICAgICAgICAgIHIubWF4ICE9PSB1bmRlZmluZWQgfHwgci5leGFjdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgcmVxdWlyZS5wdXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHIuZXhhY3QgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGlmICh0eXBlb2Ygci5leGFjdCA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICAgIHIuIG1pbiA9IHIubWF4ID0gci5leGFjdDtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY1trZXldID0gci5leGFjdDtcbiAgICAgICAgICB9XG4gICAgICAgICAgZGVsZXRlIHIuZXhhY3Q7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHIuaWRlYWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGMuYWR2YW5jZWQgPSBjLmFkdmFuY2VkIHx8IFtdO1xuICAgICAgICAgIHZhciBvYyA9IHt9O1xuICAgICAgICAgIGlmICh0eXBlb2Ygci5pZGVhbCA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICAgIG9jW2tleV0gPSB7bWluOiByLmlkZWFsLCBtYXg6IHIuaWRlYWx9O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBvY1trZXldID0gci5pZGVhbDtcbiAgICAgICAgICB9XG4gICAgICAgICAgYy5hZHZhbmNlZC5wdXNoKG9jKTtcbiAgICAgICAgICBkZWxldGUgci5pZGVhbDtcbiAgICAgICAgICBpZiAoIU9iamVjdC5rZXlzKHIpLmxlbmd0aCkge1xuICAgICAgICAgICAgZGVsZXRlIGNba2V5XTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgaWYgKHJlcXVpcmUubGVuZ3RoKSB7XG4gICAgICAgIGMucmVxdWlyZSA9IHJlcXVpcmU7XG4gICAgICB9XG4gICAgICByZXR1cm4gYztcbiAgICB9O1xuICAgIGNvbnN0cmFpbnRzID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShjb25zdHJhaW50cykpO1xuICAgIGlmIChicm93c2VyRGV0YWlscy52ZXJzaW9uIDwgMzgpIHtcbiAgICAgIGxvZ2dpbmcoJ3NwZWM6ICcgKyBKU09OLnN0cmluZ2lmeShjb25zdHJhaW50cykpO1xuICAgICAgaWYgKGNvbnN0cmFpbnRzLmF1ZGlvKSB7XG4gICAgICAgIGNvbnN0cmFpbnRzLmF1ZGlvID0gY29uc3RyYWludHNUb0ZGMzdfKGNvbnN0cmFpbnRzLmF1ZGlvKTtcbiAgICAgIH1cbiAgICAgIGlmIChjb25zdHJhaW50cy52aWRlbykge1xuICAgICAgICBjb25zdHJhaW50cy52aWRlbyA9IGNvbnN0cmFpbnRzVG9GRjM3Xyhjb25zdHJhaW50cy52aWRlbyk7XG4gICAgICB9XG4gICAgICBsb2dnaW5nKCdmZjM3OiAnICsgSlNPTi5zdHJpbmdpZnkoY29uc3RyYWludHMpKTtcbiAgICB9XG4gICAgcmV0dXJuIG5hdmlnYXRvci5tb3pHZXRVc2VyTWVkaWEoY29uc3RyYWludHMsIG9uU3VjY2VzcywgZnVuY3Rpb24oZSkge1xuICAgICAgb25FcnJvcihzaGltRXJyb3JfKGUpKTtcbiAgICB9KTtcbiAgfTtcblxuICAvLyBSZXR1cm5zIHRoZSByZXN1bHQgb2YgZ2V0VXNlck1lZGlhIGFzIGEgUHJvbWlzZS5cbiAgdmFyIGdldFVzZXJNZWRpYVByb21pc2VfID0gZnVuY3Rpb24oY29uc3RyYWludHMpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICBnZXRVc2VyTWVkaWFfKGNvbnN0cmFpbnRzLCByZXNvbHZlLCByZWplY3QpO1xuICAgIH0pO1xuICB9O1xuXG4gIC8vIFNoaW0gZm9yIG1lZGlhRGV2aWNlcyBvbiBvbGRlciB2ZXJzaW9ucy5cbiAgaWYgKCFuYXZpZ2F0b3IubWVkaWFEZXZpY2VzKSB7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcyA9IHtnZXRVc2VyTWVkaWE6IGdldFVzZXJNZWRpYVByb21pc2VfLFxuICAgICAgYWRkRXZlbnRMaXN0ZW5lcjogZnVuY3Rpb24oKSB7IH0sXG4gICAgICByZW1vdmVFdmVudExpc3RlbmVyOiBmdW5jdGlvbigpIHsgfVxuICAgIH07XG4gIH1cbiAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzID1cbiAgICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZW51bWVyYXRlRGV2aWNlcyB8fCBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUpIHtcbiAgICAgICAgICB2YXIgaW5mb3MgPSBbXG4gICAgICAgICAgICB7a2luZDogJ2F1ZGlvaW5wdXQnLCBkZXZpY2VJZDogJ2RlZmF1bHQnLCBsYWJlbDogJycsIGdyb3VwSWQ6ICcnfSxcbiAgICAgICAgICAgIHtraW5kOiAndmlkZW9pbnB1dCcsIGRldmljZUlkOiAnZGVmYXVsdCcsIGxhYmVsOiAnJywgZ3JvdXBJZDogJyd9XG4gICAgICAgICAgXTtcbiAgICAgICAgICByZXNvbHZlKGluZm9zKTtcbiAgICAgICAgfSk7XG4gICAgICB9O1xuXG4gIGlmIChicm93c2VyRGV0YWlscy52ZXJzaW9uIDwgNDEpIHtcbiAgICAvLyBXb3JrIGFyb3VuZCBodHRwOi8vYnVnemlsLmxhLzExNjk2NjVcbiAgICB2YXIgb3JnRW51bWVyYXRlRGV2aWNlcyA9XG4gICAgICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZW51bWVyYXRlRGV2aWNlcy5iaW5kKG5hdmlnYXRvci5tZWRpYURldmljZXMpO1xuICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZW51bWVyYXRlRGV2aWNlcyA9IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIG9yZ0VudW1lcmF0ZURldmljZXMoKS50aGVuKHVuZGVmaW5lZCwgZnVuY3Rpb24oZSkge1xuICAgICAgICBpZiAoZS5uYW1lID09PSAnTm90Rm91bmRFcnJvcicpIHtcbiAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH0pO1xuICAgIH07XG4gIH1cbiAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCA0OSkge1xuICAgIHZhciBvcmlnR2V0VXNlck1lZGlhID0gbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEuXG4gICAgICAgIGJpbmQobmF2aWdhdG9yLm1lZGlhRGV2aWNlcyk7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEgPSBmdW5jdGlvbihjKSB7XG4gICAgICByZXR1cm4gb3JpZ0dldFVzZXJNZWRpYShjKS50aGVuKGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICAvLyBXb3JrIGFyb3VuZCBodHRwczovL2J1Z3ppbC5sYS84MDIzMjZcbiAgICAgICAgaWYgKGMuYXVkaW8gJiYgIXN0cmVhbS5nZXRBdWRpb1RyYWNrcygpLmxlbmd0aCB8fFxuICAgICAgICAgICAgYy52aWRlbyAmJiAhc3RyZWFtLmdldFZpZGVvVHJhY2tzKCkubGVuZ3RoKSB7XG4gICAgICAgICAgc3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2spIHtcbiAgICAgICAgICAgIHRyYWNrLnN0b3AoKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aHJvdyBuZXcgRE9NRXhjZXB0aW9uKCdUaGUgb2JqZWN0IGNhbiBub3QgYmUgZm91bmQgaGVyZS4nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ05vdEZvdW5kRXJyb3InKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc3RyZWFtO1xuICAgICAgfSwgZnVuY3Rpb24oZSkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3Qoc2hpbUVycm9yXyhlKSk7XG4gICAgICB9KTtcbiAgICB9O1xuICB9XG4gIGlmICghKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPiA1NSAmJlxuICAgICAgJ2F1dG9HYWluQ29udHJvbCcgaW4gbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRTdXBwb3J0ZWRDb25zdHJhaW50cygpKSkge1xuICAgIHZhciByZW1hcCA9IGZ1bmN0aW9uKG9iaiwgYSwgYikge1xuICAgICAgaWYgKGEgaW4gb2JqICYmICEoYiBpbiBvYmopKSB7XG4gICAgICAgIG9ialtiXSA9IG9ialthXTtcbiAgICAgICAgZGVsZXRlIG9ialthXTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIG5hdGl2ZUdldFVzZXJNZWRpYSA9IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhLlxuICAgICAgICBiaW5kKG5hdmlnYXRvci5tZWRpYURldmljZXMpO1xuICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhID0gZnVuY3Rpb24oYykge1xuICAgICAgaWYgKHR5cGVvZiBjID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgYy5hdWRpbyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgYyA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoYykpO1xuICAgICAgICByZW1hcChjLmF1ZGlvLCAnYXV0b0dhaW5Db250cm9sJywgJ21vekF1dG9HYWluQ29udHJvbCcpO1xuICAgICAgICByZW1hcChjLmF1ZGlvLCAnbm9pc2VTdXBwcmVzc2lvbicsICdtb3pOb2lzZVN1cHByZXNzaW9uJyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbmF0aXZlR2V0VXNlck1lZGlhKGMpO1xuICAgIH07XG5cbiAgICBpZiAoTWVkaWFTdHJlYW1UcmFjayAmJiBNZWRpYVN0cmVhbVRyYWNrLnByb3RvdHlwZS5nZXRTZXR0aW5ncykge1xuICAgICAgdmFyIG5hdGl2ZUdldFNldHRpbmdzID0gTWVkaWFTdHJlYW1UcmFjay5wcm90b3R5cGUuZ2V0U2V0dGluZ3M7XG4gICAgICBNZWRpYVN0cmVhbVRyYWNrLnByb3RvdHlwZS5nZXRTZXR0aW5ncyA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgb2JqID0gbmF0aXZlR2V0U2V0dGluZ3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgcmVtYXAob2JqLCAnbW96QXV0b0dhaW5Db250cm9sJywgJ2F1dG9HYWluQ29udHJvbCcpO1xuICAgICAgICByZW1hcChvYmosICdtb3pOb2lzZVN1cHByZXNzaW9uJywgJ25vaXNlU3VwcHJlc3Npb24nKTtcbiAgICAgICAgcmV0dXJuIG9iajtcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKE1lZGlhU3RyZWFtVHJhY2sgJiYgTWVkaWFTdHJlYW1UcmFjay5wcm90b3R5cGUuYXBwbHlDb25zdHJhaW50cykge1xuICAgICAgdmFyIG5hdGl2ZUFwcGx5Q29uc3RyYWludHMgPSBNZWRpYVN0cmVhbVRyYWNrLnByb3RvdHlwZS5hcHBseUNvbnN0cmFpbnRzO1xuICAgICAgTWVkaWFTdHJlYW1UcmFjay5wcm90b3R5cGUuYXBwbHlDb25zdHJhaW50cyA9IGZ1bmN0aW9uKGMpIHtcbiAgICAgICAgaWYgKHRoaXMua2luZCA9PT0gJ2F1ZGlvJyAmJiB0eXBlb2YgYyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICBjID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShjKSk7XG4gICAgICAgICAgcmVtYXAoYywgJ2F1dG9HYWluQ29udHJvbCcsICdtb3pBdXRvR2FpbkNvbnRyb2wnKTtcbiAgICAgICAgICByZW1hcChjLCAnbm9pc2VTdXBwcmVzc2lvbicsICdtb3pOb2lzZVN1cHByZXNzaW9uJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5hdGl2ZUFwcGx5Q29uc3RyYWludHMuYXBwbHkodGhpcywgW2NdKTtcbiAgICAgIH07XG4gICAgfVxuICB9XG4gIG5hdmlnYXRvci5nZXRVc2VyTWVkaWEgPSBmdW5jdGlvbihjb25zdHJhaW50cywgb25TdWNjZXNzLCBvbkVycm9yKSB7XG4gICAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCA0NCkge1xuICAgICAgcmV0dXJuIGdldFVzZXJNZWRpYV8oY29uc3RyYWludHMsIG9uU3VjY2Vzcywgb25FcnJvcik7XG4gICAgfVxuICAgIC8vIFJlcGxhY2UgRmlyZWZveCA0NCsncyBkZXByZWNhdGlvbiB3YXJuaW5nIHdpdGggdW5wcmVmaXhlZCB2ZXJzaW9uLlxuICAgIGNvbnNvbGUud2FybignbmF2aWdhdG9yLmdldFVzZXJNZWRpYSBoYXMgYmVlbiByZXBsYWNlZCBieSAnICtcbiAgICAgICAgICAgICAgICAgJ25hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhJyk7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEoY29uc3RyYWludHMpLnRoZW4ob25TdWNjZXNzLCBvbkVycm9yKTtcbiAgfTtcbn07XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbid1c2Ugc3RyaWN0JztcbnZhciBzYWZhcmlTaGltID0ge1xuICAvLyBUT0RPOiBEckFsZXgsIHNob3VsZCBiZSBoZXJlLCBkb3VibGUgY2hlY2sgYWdhaW5zdCBMYXlvdXRUZXN0c1xuXG4gIC8vIFRPRE86IG9uY2UgdGhlIGJhY2stZW5kIGZvciB0aGUgbWFjIHBvcnQgaXMgZG9uZSwgYWRkLlxuICAvLyBUT0RPOiBjaGVjayBmb3Igd2Via2l0R1RLK1xuICAvLyBzaGltUGVlckNvbm5lY3Rpb246IGZ1bmN0aW9uKCkgeyB9LFxuXG4gIHNoaW1BZGRTdHJlYW06IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAnb2JqZWN0JyAmJiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gJiZcbiAgICAgICAgISgnYWRkU3RyZWFtJyBpbiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlKSkge1xuICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRTdHJlYW0gPSBmdW5jdGlvbihzdHJlYW0pIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICBzdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbih0cmFjaykge1xuICAgICAgICAgIHNlbGYuYWRkVHJhY2sodHJhY2ssIHN0cmVhbSk7XG4gICAgICAgIH0pO1xuICAgICAgfTtcbiAgICB9XG4gIH0sXG4gIHNoaW1PbkFkZFN0cmVhbTogZnVuY3Rpb24od2luZG93KSB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnICYmIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbiAmJlxuICAgICAgICAhKCdvbmFkZHN0cmVhbScgaW4gd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZSkpIHtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLCAnb25hZGRzdHJlYW0nLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMuX29uYWRkc3RyZWFtO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uKGYpIHtcbiAgICAgICAgICBpZiAodGhpcy5fb25hZGRzdHJlYW0pIHtcbiAgICAgICAgICAgIHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcignYWRkc3RyZWFtJywgdGhpcy5fb25hZGRzdHJlYW0pO1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVyKCd0cmFjaycsIHRoaXMuX29uYWRkc3RyZWFtcG9seSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lcignYWRkc3RyZWFtJywgdGhpcy5fb25hZGRzdHJlYW0gPSBmKTtcbiAgICAgICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXIoJ3RyYWNrJywgdGhpcy5fb25hZGRzdHJlYW1wb2x5ID0gZnVuY3Rpb24oZSkge1xuICAgICAgICAgICAgdmFyIHN0cmVhbSA9IGUuc3RyZWFtc1swXTtcbiAgICAgICAgICAgIGlmICghdGhpcy5fc3RyZWFtcykge1xuICAgICAgICAgICAgICB0aGlzLl9zdHJlYW1zID0gW107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGhpcy5fc3RyZWFtcy5pbmRleE9mKHN0cmVhbSkgPj0gMCkge1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLl9zdHJlYW1zLnB1c2goc3RyZWFtKTtcbiAgICAgICAgICAgIHZhciBldmVudCA9IG5ldyBFdmVudCgnYWRkc3RyZWFtJyk7XG4gICAgICAgICAgICBldmVudC5zdHJlYW0gPSBlLnN0cmVhbXNbMF07XG4gICAgICAgICAgICB0aGlzLmRpc3BhdGNoRXZlbnQoZXZlbnQpO1xuICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfSxcbiAgc2hpbUNhbGxiYWNrc0FQSTogZnVuY3Rpb24od2luZG93KSB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgIT09ICdvYmplY3QnIHx8ICF3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIHByb3RvdHlwZSA9IHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGU7XG4gICAgdmFyIGNyZWF0ZU9mZmVyID0gcHJvdG90eXBlLmNyZWF0ZU9mZmVyO1xuICAgIHZhciBjcmVhdGVBbnN3ZXIgPSBwcm90b3R5cGUuY3JlYXRlQW5zd2VyO1xuICAgIHZhciBzZXRMb2NhbERlc2NyaXB0aW9uID0gcHJvdG90eXBlLnNldExvY2FsRGVzY3JpcHRpb247XG4gICAgdmFyIHNldFJlbW90ZURlc2NyaXB0aW9uID0gcHJvdG90eXBlLnNldFJlbW90ZURlc2NyaXB0aW9uO1xuICAgIHZhciBhZGRJY2VDYW5kaWRhdGUgPSBwcm90b3R5cGUuYWRkSWNlQ2FuZGlkYXRlO1xuXG4gICAgcHJvdG90eXBlLmNyZWF0ZU9mZmVyID0gZnVuY3Rpb24oc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2spIHtcbiAgICAgIHZhciBvcHRpb25zID0gKGFyZ3VtZW50cy5sZW5ndGggPj0gMikgPyBhcmd1bWVudHNbMl0gOiBhcmd1bWVudHNbMF07XG4gICAgICB2YXIgcHJvbWlzZSA9IGNyZWF0ZU9mZmVyLmFwcGx5KHRoaXMsIFtvcHRpb25zXSk7XG4gICAgICBpZiAoIWZhaWx1cmVDYWxsYmFjaykge1xuICAgICAgICByZXR1cm4gcHJvbWlzZTtcbiAgICAgIH1cbiAgICAgIHByb21pc2UudGhlbihzdWNjZXNzQ2FsbGJhY2ssIGZhaWx1cmVDYWxsYmFjayk7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgfTtcblxuICAgIHByb3RvdHlwZS5jcmVhdGVBbnN3ZXIgPSBmdW5jdGlvbihzdWNjZXNzQ2FsbGJhY2ssIGZhaWx1cmVDYWxsYmFjaykge1xuICAgICAgdmFyIG9wdGlvbnMgPSAoYXJndW1lbnRzLmxlbmd0aCA+PSAyKSA/IGFyZ3VtZW50c1syXSA6IGFyZ3VtZW50c1swXTtcbiAgICAgIHZhciBwcm9taXNlID0gY3JlYXRlQW5zd2VyLmFwcGx5KHRoaXMsIFtvcHRpb25zXSk7XG4gICAgICBpZiAoIWZhaWx1cmVDYWxsYmFjaykge1xuICAgICAgICByZXR1cm4gcHJvbWlzZTtcbiAgICAgIH1cbiAgICAgIHByb21pc2UudGhlbihzdWNjZXNzQ2FsbGJhY2ssIGZhaWx1cmVDYWxsYmFjayk7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgfTtcblxuICAgIHZhciB3aXRoQ2FsbGJhY2sgPSBmdW5jdGlvbihkZXNjcmlwdGlvbiwgc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2spIHtcbiAgICAgIHZhciBwcm9taXNlID0gc2V0TG9jYWxEZXNjcmlwdGlvbi5hcHBseSh0aGlzLCBbZGVzY3JpcHRpb25dKTtcbiAgICAgIGlmICghZmFpbHVyZUNhbGxiYWNrKSB7XG4gICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgICAgfVxuICAgICAgcHJvbWlzZS50aGVuKHN1Y2Nlc3NDYWxsYmFjaywgZmFpbHVyZUNhbGxiYWNrKTtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9O1xuICAgIHByb3RvdHlwZS5zZXRMb2NhbERlc2NyaXB0aW9uID0gd2l0aENhbGxiYWNrO1xuXG4gICAgd2l0aENhbGxiYWNrID0gZnVuY3Rpb24oZGVzY3JpcHRpb24sIHN1Y2Nlc3NDYWxsYmFjaywgZmFpbHVyZUNhbGxiYWNrKSB7XG4gICAgICB2YXIgcHJvbWlzZSA9IHNldFJlbW90ZURlc2NyaXB0aW9uLmFwcGx5KHRoaXMsIFtkZXNjcmlwdGlvbl0pO1xuICAgICAgaWYgKCFmYWlsdXJlQ2FsbGJhY2spIHtcbiAgICAgICAgcmV0dXJuIHByb21pc2U7XG4gICAgICB9XG4gICAgICBwcm9taXNlLnRoZW4oc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2spO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH07XG4gICAgcHJvdG90eXBlLnNldFJlbW90ZURlc2NyaXB0aW9uID0gd2l0aENhbGxiYWNrO1xuXG4gICAgd2l0aENhbGxiYWNrID0gZnVuY3Rpb24oY2FuZGlkYXRlLCBzdWNjZXNzQ2FsbGJhY2ssIGZhaWx1cmVDYWxsYmFjaykge1xuICAgICAgdmFyIHByb21pc2UgPSBhZGRJY2VDYW5kaWRhdGUuYXBwbHkodGhpcywgW2NhbmRpZGF0ZV0pO1xuICAgICAgaWYgKCFmYWlsdXJlQ2FsbGJhY2spIHtcbiAgICAgICAgcmV0dXJuIHByb21pc2U7XG4gICAgICB9XG4gICAgICBwcm9taXNlLnRoZW4oc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2spO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH07XG4gICAgcHJvdG90eXBlLmFkZEljZUNhbmRpZGF0ZSA9IHdpdGhDYWxsYmFjaztcbiAgfSxcbiAgc2hpbUdldFVzZXJNZWRpYTogZnVuY3Rpb24od2luZG93KSB7XG4gICAgdmFyIG5hdmlnYXRvciA9IHdpbmRvdyAmJiB3aW5kb3cubmF2aWdhdG9yO1xuXG4gICAgaWYgKCFuYXZpZ2F0b3IuZ2V0VXNlck1lZGlhKSB7XG4gICAgICBpZiAobmF2aWdhdG9yLndlYmtpdEdldFVzZXJNZWRpYSkge1xuICAgICAgICBuYXZpZ2F0b3IuZ2V0VXNlck1lZGlhID0gbmF2aWdhdG9yLndlYmtpdEdldFVzZXJNZWRpYS5iaW5kKG5hdmlnYXRvcik7XG4gICAgICB9IGVsc2UgaWYgKG5hdmlnYXRvci5tZWRpYURldmljZXMgJiZcbiAgICAgICAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYSkge1xuICAgICAgICBuYXZpZ2F0b3IuZ2V0VXNlck1lZGlhID0gZnVuY3Rpb24oY29uc3RyYWludHMsIGNiLCBlcnJjYikge1xuICAgICAgICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKGNvbnN0cmFpbnRzKVxuICAgICAgICAgIC50aGVuKGNiLCBlcnJjYik7XG4gICAgICAgIH0uYmluZChuYXZpZ2F0b3IpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufTtcblxuLy8gRXhwb3NlIHB1YmxpYyBtZXRob2RzLlxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHNoaW1DYWxsYmFja3NBUEk6IHNhZmFyaVNoaW0uc2hpbUNhbGxiYWNrc0FQSSxcbiAgc2hpbUFkZFN0cmVhbTogc2FmYXJpU2hpbS5zaGltQWRkU3RyZWFtLFxuICBzaGltT25BZGRTdHJlYW06IHNhZmFyaVNoaW0uc2hpbU9uQWRkU3RyZWFtLFxuICBzaGltR2V0VXNlck1lZGlhOiBzYWZhcmlTaGltLnNoaW1HZXRVc2VyTWVkaWFcbiAgLy8gVE9ET1xuICAvLyBzaGltUGVlckNvbm5lY3Rpb246IHNhZmFyaVNoaW0uc2hpbVBlZXJDb25uZWN0aW9uXG59O1xuIiwiLypcbiAqICBDb3B5cmlnaHQgKGMpIDIwMTYgVGhlIFdlYlJUQyBwcm9qZWN0IGF1dGhvcnMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlIGxpY2Vuc2VcbiAqICB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGluIHRoZSByb290IG9mIHRoZSBzb3VyY2VcbiAqICB0cmVlLlxuICovXG4gLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG5cbnZhciBsb2dEaXNhYmxlZF8gPSB0cnVlO1xuXG4vLyBVdGlsaXR5IG1ldGhvZHMuXG52YXIgdXRpbHMgPSB7XG4gIGRpc2FibGVMb2c6IGZ1bmN0aW9uKGJvb2wpIHtcbiAgICBpZiAodHlwZW9mIGJvb2wgIT09ICdib29sZWFuJykge1xuICAgICAgcmV0dXJuIG5ldyBFcnJvcignQXJndW1lbnQgdHlwZTogJyArIHR5cGVvZiBib29sICtcbiAgICAgICAgICAnLiBQbGVhc2UgdXNlIGEgYm9vbGVhbi4nKTtcbiAgICB9XG4gICAgbG9nRGlzYWJsZWRfID0gYm9vbDtcbiAgICByZXR1cm4gKGJvb2wpID8gJ2FkYXB0ZXIuanMgbG9nZ2luZyBkaXNhYmxlZCcgOlxuICAgICAgICAnYWRhcHRlci5qcyBsb2dnaW5nIGVuYWJsZWQnO1xuICB9LFxuXG4gIGxvZzogZnVuY3Rpb24oKSB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnKSB7XG4gICAgICBpZiAobG9nRGlzYWJsZWRfKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmICh0eXBlb2YgY29uc29sZSAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIGNvbnNvbGUubG9nID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIGNvbnNvbGUubG9nLmFwcGx5KGNvbnNvbGUsIGFyZ3VtZW50cyk7XG4gICAgICB9XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBFeHRyYWN0IGJyb3dzZXIgdmVyc2lvbiBvdXQgb2YgdGhlIHByb3ZpZGVkIHVzZXIgYWdlbnQgc3RyaW5nLlxuICAgKlxuICAgKiBAcGFyYW0geyFzdHJpbmd9IHVhc3RyaW5nIHVzZXJBZ2VudCBzdHJpbmcuXG4gICAqIEBwYXJhbSB7IXN0cmluZ30gZXhwciBSZWd1bGFyIGV4cHJlc3Npb24gdXNlZCBhcyBtYXRjaCBjcml0ZXJpYS5cbiAgICogQHBhcmFtIHshbnVtYmVyfSBwb3MgcG9zaXRpb24gaW4gdGhlIHZlcnNpb24gc3RyaW5nIHRvIGJlIHJldHVybmVkLlxuICAgKiBAcmV0dXJuIHshbnVtYmVyfSBicm93c2VyIHZlcnNpb24uXG4gICAqL1xuICBleHRyYWN0VmVyc2lvbjogZnVuY3Rpb24odWFzdHJpbmcsIGV4cHIsIHBvcykge1xuICAgIHZhciBtYXRjaCA9IHVhc3RyaW5nLm1hdGNoKGV4cHIpO1xuICAgIHJldHVybiBtYXRjaCAmJiBtYXRjaC5sZW5ndGggPj0gcG9zICYmIHBhcnNlSW50KG1hdGNoW3Bvc10sIDEwKTtcbiAgfSxcblxuICAvKipcbiAgICogQnJvd3NlciBkZXRlY3Rvci5cbiAgICpcbiAgICogQHJldHVybiB7b2JqZWN0fSByZXN1bHQgY29udGFpbmluZyBicm93c2VyIGFuZCB2ZXJzaW9uXG4gICAqICAgICBwcm9wZXJ0aWVzLlxuICAgKi9cbiAgZGV0ZWN0QnJvd3NlcjogZnVuY3Rpb24od2luZG93KSB7XG4gICAgdmFyIG5hdmlnYXRvciA9IHdpbmRvdyAmJiB3aW5kb3cubmF2aWdhdG9yO1xuXG4gICAgLy8gUmV0dXJuZWQgcmVzdWx0IG9iamVjdC5cbiAgICB2YXIgcmVzdWx0ID0ge307XG4gICAgcmVzdWx0LmJyb3dzZXIgPSBudWxsO1xuICAgIHJlc3VsdC52ZXJzaW9uID0gbnVsbDtcblxuICAgIC8vIEZhaWwgZWFybHkgaWYgaXQncyBub3QgYSBicm93c2VyXG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICd1bmRlZmluZWQnIHx8ICF3aW5kb3cubmF2aWdhdG9yKSB7XG4gICAgICByZXN1bHQuYnJvd3NlciA9ICdOb3QgYSBicm93c2VyLic7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8vIEZpcmVmb3guXG4gICAgaWYgKG5hdmlnYXRvci5tb3pHZXRVc2VyTWVkaWEpIHtcbiAgICAgIHJlc3VsdC5icm93c2VyID0gJ2ZpcmVmb3gnO1xuICAgICAgcmVzdWx0LnZlcnNpb24gPSB0aGlzLmV4dHJhY3RWZXJzaW9uKG5hdmlnYXRvci51c2VyQWdlbnQsXG4gICAgICAgICAgL0ZpcmVmb3hcXC8oXFxkKylcXC4vLCAxKTtcbiAgICB9IGVsc2UgaWYgKG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEpIHtcbiAgICAgIC8vIENocm9tZSwgQ2hyb21pdW0sIFdlYnZpZXcsIE9wZXJhLCBhbGwgdXNlIHRoZSBjaHJvbWUgc2hpbSBmb3Igbm93XG4gICAgICBpZiAod2luZG93LndlYmtpdFJUQ1BlZXJDb25uZWN0aW9uKSB7XG4gICAgICAgIHJlc3VsdC5icm93c2VyID0gJ2Nocm9tZSc7XG4gICAgICAgIHJlc3VsdC52ZXJzaW9uID0gdGhpcy5leHRyYWN0VmVyc2lvbihuYXZpZ2F0b3IudXNlckFnZW50LFxuICAgICAgICAgIC9DaHJvbShlfGl1bSlcXC8oXFxkKylcXC4vLCAyKTtcbiAgICAgIH0gZWxzZSB7IC8vIFNhZmFyaSAoaW4gYW4gdW5wdWJsaXNoZWQgdmVyc2lvbikgb3IgdW5rbm93biB3ZWJraXQtYmFzZWQuXG4gICAgICAgIGlmIChuYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKC9WZXJzaW9uXFwvKFxcZCspLihcXGQrKS8pKSB7XG4gICAgICAgICAgcmVzdWx0LmJyb3dzZXIgPSAnc2FmYXJpJztcbiAgICAgICAgICByZXN1bHQudmVyc2lvbiA9IHRoaXMuZXh0cmFjdFZlcnNpb24obmF2aWdhdG9yLnVzZXJBZ2VudCxcbiAgICAgICAgICAgIC9BcHBsZVdlYktpdFxcLyhcXGQrKVxcLi8sIDEpO1xuICAgICAgICB9IGVsc2UgeyAvLyB1bmtub3duIHdlYmtpdC1iYXNlZCBicm93c2VyLlxuICAgICAgICAgIHJlc3VsdC5icm93c2VyID0gJ1Vuc3VwcG9ydGVkIHdlYmtpdC1iYXNlZCBicm93c2VyICcgK1xuICAgICAgICAgICAgICAnd2l0aCBHVU0gc3VwcG9ydCBidXQgbm8gV2ViUlRDIHN1cHBvcnQuJztcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChuYXZpZ2F0b3IubWVkaWFEZXZpY2VzICYmXG4gICAgICAgIG5hdmlnYXRvci51c2VyQWdlbnQubWF0Y2goL0VkZ2VcXC8oXFxkKykuKFxcZCspJC8pKSB7IC8vIEVkZ2UuXG4gICAgICByZXN1bHQuYnJvd3NlciA9ICdlZGdlJztcbiAgICAgIHJlc3VsdC52ZXJzaW9uID0gdGhpcy5leHRyYWN0VmVyc2lvbihuYXZpZ2F0b3IudXNlckFnZW50LFxuICAgICAgICAgIC9FZGdlXFwvKFxcZCspLihcXGQrKSQvLCAyKTtcbiAgICB9IGVsc2UgaWYgKG5hdmlnYXRvci5tZWRpYURldmljZXMgJiZcbiAgICAgICAgbmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgvQXBwbGVXZWJLaXRcXC8oXFxkKylcXC4vKSkge1xuICAgICAgICAvLyBTYWZhcmksIHdpdGggd2Via2l0R2V0VXNlck1lZGlhIHJlbW92ZWQuXG4gICAgICByZXN1bHQuYnJvd3NlciA9ICdzYWZhcmknO1xuICAgICAgcmVzdWx0LnZlcnNpb24gPSB0aGlzLmV4dHJhY3RWZXJzaW9uKG5hdmlnYXRvci51c2VyQWdlbnQsXG4gICAgICAgICAgL0FwcGxlV2ViS2l0XFwvKFxcZCspXFwuLywgMSk7XG4gICAgfSBlbHNlIHsgLy8gRGVmYXVsdCBmYWxsdGhyb3VnaDogbm90IHN1cHBvcnRlZC5cbiAgICAgIHJlc3VsdC5icm93c2VyID0gJ05vdCBhIHN1cHBvcnRlZCBicm93c2VyLic7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH0sXG5cbiAgLy8gc2hpbUNyZWF0ZU9iamVjdFVSTCBtdXN0IGJlIGNhbGxlZCBiZWZvcmUgc2hpbVNvdXJjZU9iamVjdCB0byBhdm9pZCBsb29wLlxuXG4gIHNoaW1DcmVhdGVPYmplY3RVUkw6IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIHZhciBVUkwgPSB3aW5kb3cgJiYgd2luZG93LlVSTDtcblxuICAgIGlmICghKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnICYmIHdpbmRvdy5IVE1MTWVkaWFFbGVtZW50ICYmXG4gICAgICAgICAgJ3NyY09iamVjdCcgaW4gd2luZG93LkhUTUxNZWRpYUVsZW1lbnQucHJvdG90eXBlKSkge1xuICAgICAgLy8gT25seSBzaGltIENyZWF0ZU9iamVjdFVSTCB1c2luZyBzcmNPYmplY3QgaWYgc3JjT2JqZWN0IGV4aXN0cy5cbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgdmFyIG5hdGl2ZUNyZWF0ZU9iamVjdFVSTCA9IFVSTC5jcmVhdGVPYmplY3RVUkwuYmluZChVUkwpO1xuICAgIHZhciBuYXRpdmVSZXZva2VPYmplY3RVUkwgPSBVUkwucmV2b2tlT2JqZWN0VVJMLmJpbmQoVVJMKTtcbiAgICB2YXIgc3RyZWFtcyA9IG5ldyBNYXAoKSwgbmV3SWQgPSAwO1xuXG4gICAgVVJMLmNyZWF0ZU9iamVjdFVSTCA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgaWYgKCdnZXRUcmFja3MnIGluIHN0cmVhbSkge1xuICAgICAgICB2YXIgdXJsID0gJ3BvbHlibG9iOicgKyAoKytuZXdJZCk7XG4gICAgICAgIHN0cmVhbXMuc2V0KHVybCwgc3RyZWFtKTtcbiAgICAgICAgY29uc29sZS5sb2coJ1VSTC5jcmVhdGVPYmplY3RVUkwoc3RyZWFtKSBpcyBkZXByZWNhdGVkISAnICtcbiAgICAgICAgICAgICAgICAgICAgJ1VzZSBlbGVtLnNyY09iamVjdCA9IHN0cmVhbSBpbnN0ZWFkIScpO1xuICAgICAgICByZXR1cm4gdXJsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5hdGl2ZUNyZWF0ZU9iamVjdFVSTChzdHJlYW0pO1xuICAgIH07XG4gICAgVVJMLnJldm9rZU9iamVjdFVSTCA9IGZ1bmN0aW9uKHVybCkge1xuICAgICAgbmF0aXZlUmV2b2tlT2JqZWN0VVJMKHVybCk7XG4gICAgICBzdHJlYW1zLmRlbGV0ZSh1cmwpO1xuICAgIH07XG5cbiAgICB2YXIgZHNjID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih3aW5kb3cuSFRNTE1lZGlhRWxlbWVudC5wcm90b3R5cGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3NyYycpO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuSFRNTE1lZGlhRWxlbWVudC5wcm90b3R5cGUsICdzcmMnLCB7XG4gICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gZHNjLmdldC5hcHBseSh0aGlzKTtcbiAgICAgIH0sXG4gICAgICBzZXQ6IGZ1bmN0aW9uKHVybCkge1xuICAgICAgICB0aGlzLnNyY09iamVjdCA9IHN0cmVhbXMuZ2V0KHVybCkgfHwgbnVsbDtcbiAgICAgICAgcmV0dXJuIGRzYy5zZXQuYXBwbHkodGhpcywgW3VybF0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIG5hdGl2ZVNldEF0dHJpYnV0ZSA9IHdpbmRvdy5IVE1MTWVkaWFFbGVtZW50LnByb3RvdHlwZS5zZXRBdHRyaWJ1dGU7XG4gICAgd2luZG93LkhUTUxNZWRpYUVsZW1lbnQucHJvdG90eXBlLnNldEF0dHJpYnV0ZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDIgJiZcbiAgICAgICAgICAoJycgKyBhcmd1bWVudHNbMF0pLnRvTG93ZXJDYXNlKCkgPT09ICdzcmMnKSB7XG4gICAgICAgIHRoaXMuc3JjT2JqZWN0ID0gc3RyZWFtcy5nZXQoYXJndW1lbnRzWzFdKSB8fCBudWxsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5hdGl2ZVNldEF0dHJpYnV0ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH07XG4gIH1cbn07XG5cbi8vIEV4cG9ydC5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBsb2c6IHV0aWxzLmxvZyxcbiAgZGlzYWJsZUxvZzogdXRpbHMuZGlzYWJsZUxvZyxcbiAgZXh0cmFjdFZlcnNpb246IHV0aWxzLmV4dHJhY3RWZXJzaW9uLFxuICBzaGltQ3JlYXRlT2JqZWN0VVJMOiB1dGlscy5zaGltQ3JlYXRlT2JqZWN0VVJMLFxuICBkZXRlY3RCcm93c2VyOiB1dGlscy5kZXRlY3RCcm93c2VyLmJpbmQodXRpbHMpXG59O1xuIiwiLypcclxuV2lsZEVtaXR0ZXIuanMgaXMgYSBzbGltIGxpdHRsZSBldmVudCBlbWl0dGVyIGJ5IEBoZW5yaWtqb3JldGVnIGxhcmdlbHkgYmFzZWRcclxub24gQHZpc2lvbm1lZGlhJ3MgRW1pdHRlciBmcm9tIFVJIEtpdC5cclxuXHJcbldoeT8gSSB3YW50ZWQgaXQgc3RhbmRhbG9uZS5cclxuXHJcbkkgYWxzbyB3YW50ZWQgc3VwcG9ydCBmb3Igd2lsZGNhcmQgZW1pdHRlcnMgbGlrZSB0aGlzOlxyXG5cclxuZW1pdHRlci5vbignKicsIGZ1bmN0aW9uIChldmVudE5hbWUsIG90aGVyLCBldmVudCwgcGF5bG9hZHMpIHtcclxuXHJcbn0pO1xyXG5cclxuZW1pdHRlci5vbignc29tZW5hbWVzcGFjZSonLCBmdW5jdGlvbiAoZXZlbnROYW1lLCBwYXlsb2Fkcykge1xyXG5cclxufSk7XHJcblxyXG5QbGVhc2Ugbm90ZSB0aGF0IGNhbGxiYWNrcyB0cmlnZ2VyZWQgYnkgd2lsZGNhcmQgcmVnaXN0ZXJlZCBldmVudHMgYWxzbyBnZXRcclxudGhlIGV2ZW50IG5hbWUgYXMgdGhlIGZpcnN0IGFyZ3VtZW50LlxyXG4qL1xyXG5cclxubW9kdWxlLmV4cG9ydHMgPSBXaWxkRW1pdHRlcjtcclxuXHJcbmZ1bmN0aW9uIFdpbGRFbWl0dGVyKCkgeyB9XHJcblxyXG5XaWxkRW1pdHRlci5taXhpbiA9IGZ1bmN0aW9uIChjb25zdHJ1Y3Rvcikge1xyXG4gICAgdmFyIHByb3RvdHlwZSA9IGNvbnN0cnVjdG9yLnByb3RvdHlwZSB8fCBjb25zdHJ1Y3RvcjtcclxuXHJcbiAgICBwcm90b3R5cGUuaXNXaWxkRW1pdHRlcj0gdHJ1ZTtcclxuXHJcbiAgICAvLyBMaXN0ZW4gb24gdGhlIGdpdmVuIGBldmVudGAgd2l0aCBgZm5gLiBTdG9yZSBhIGdyb3VwIG5hbWUgaWYgcHJlc2VudC5cclxuICAgIHByb3RvdHlwZS5vbiA9IGZ1bmN0aW9uIChldmVudCwgZ3JvdXBOYW1lLCBmbikge1xyXG4gICAgICAgIHRoaXMuY2FsbGJhY2tzID0gdGhpcy5jYWxsYmFja3MgfHwge307XHJcbiAgICAgICAgdmFyIGhhc0dyb3VwID0gKGFyZ3VtZW50cy5sZW5ndGggPT09IDMpLFxyXG4gICAgICAgICAgICBncm91cCA9IGhhc0dyb3VwID8gYXJndW1lbnRzWzFdIDogdW5kZWZpbmVkLFxyXG4gICAgICAgICAgICBmdW5jID0gaGFzR3JvdXAgPyBhcmd1bWVudHNbMl0gOiBhcmd1bWVudHNbMV07XHJcbiAgICAgICAgZnVuYy5fZ3JvdXBOYW1lID0gZ3JvdXA7XHJcbiAgICAgICAgKHRoaXMuY2FsbGJhY2tzW2V2ZW50XSA9IHRoaXMuY2FsbGJhY2tzW2V2ZW50XSB8fCBbXSkucHVzaChmdW5jKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH07XHJcblxyXG4gICAgLy8gQWRkcyBhbiBgZXZlbnRgIGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIGEgc2luZ2xlXHJcbiAgICAvLyB0aW1lIHRoZW4gYXV0b21hdGljYWxseSByZW1vdmVkLlxyXG4gICAgcHJvdG90eXBlLm9uY2UgPSBmdW5jdGlvbiAoZXZlbnQsIGdyb3VwTmFtZSwgZm4pIHtcclxuICAgICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgICAgIGhhc0dyb3VwID0gKGFyZ3VtZW50cy5sZW5ndGggPT09IDMpLFxyXG4gICAgICAgICAgICBncm91cCA9IGhhc0dyb3VwID8gYXJndW1lbnRzWzFdIDogdW5kZWZpbmVkLFxyXG4gICAgICAgICAgICBmdW5jID0gaGFzR3JvdXAgPyBhcmd1bWVudHNbMl0gOiBhcmd1bWVudHNbMV07XHJcbiAgICAgICAgZnVuY3Rpb24gb24oKSB7XHJcbiAgICAgICAgICAgIHNlbGYub2ZmKGV2ZW50LCBvbik7XHJcbiAgICAgICAgICAgIGZ1bmMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5vbihldmVudCwgZ3JvdXAsIG9uKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH07XHJcblxyXG4gICAgLy8gVW5iaW5kcyBhbiBlbnRpcmUgZ3JvdXBcclxuICAgIHByb3RvdHlwZS5yZWxlYXNlR3JvdXAgPSBmdW5jdGlvbiAoZ3JvdXBOYW1lKSB7XHJcbiAgICAgICAgdGhpcy5jYWxsYmFja3MgPSB0aGlzLmNhbGxiYWNrcyB8fCB7fTtcclxuICAgICAgICB2YXIgaXRlbSwgaSwgbGVuLCBoYW5kbGVycztcclxuICAgICAgICBmb3IgKGl0ZW0gaW4gdGhpcy5jYWxsYmFja3MpIHtcclxuICAgICAgICAgICAgaGFuZGxlcnMgPSB0aGlzLmNhbGxiYWNrc1tpdGVtXTtcclxuICAgICAgICAgICAgZm9yIChpID0gMCwgbGVuID0gaGFuZGxlcnMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuICAgICAgICAgICAgICAgIGlmIChoYW5kbGVyc1tpXS5fZ3JvdXBOYW1lID09PSBncm91cE5hbWUpIHtcclxuICAgICAgICAgICAgICAgICAgICAvL2NvbnNvbGUubG9nKCdyZW1vdmluZycpO1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSBpdCBhbmQgc2hvcnRlbiB0aGUgYXJyYXkgd2UncmUgbG9vcGluZyB0aHJvdWdoXHJcbiAgICAgICAgICAgICAgICAgICAgaGFuZGxlcnMuc3BsaWNlKGksIDEpO1xyXG4gICAgICAgICAgICAgICAgICAgIGktLTtcclxuICAgICAgICAgICAgICAgICAgICBsZW4tLTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH07XHJcblxyXG4gICAgLy8gUmVtb3ZlIHRoZSBnaXZlbiBjYWxsYmFjayBmb3IgYGV2ZW50YCBvciBhbGxcclxuICAgIC8vIHJlZ2lzdGVyZWQgY2FsbGJhY2tzLlxyXG4gICAgcHJvdG90eXBlLm9mZiA9IGZ1bmN0aW9uIChldmVudCwgZm4pIHtcclxuICAgICAgICB0aGlzLmNhbGxiYWNrcyA9IHRoaXMuY2FsbGJhY2tzIHx8IHt9O1xyXG4gICAgICAgIHZhciBjYWxsYmFja3MgPSB0aGlzLmNhbGxiYWNrc1tldmVudF0sXHJcbiAgICAgICAgICAgIGk7XHJcblxyXG4gICAgICAgIGlmICghY2FsbGJhY2tzKSByZXR1cm4gdGhpcztcclxuXHJcbiAgICAgICAgLy8gcmVtb3ZlIGFsbCBoYW5kbGVyc1xyXG4gICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAxKSB7XHJcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmNhbGxiYWNrc1tldmVudF07XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gcmVtb3ZlIHNwZWNpZmljIGhhbmRsZXJcclxuICAgICAgICBpID0gY2FsbGJhY2tzLmluZGV4T2YoZm4pO1xyXG4gICAgICAgIGNhbGxiYWNrcy5zcGxpY2UoaSwgMSk7XHJcbiAgICAgICAgaWYgKGNhbGxiYWNrcy5sZW5ndGggPT09IDApIHtcclxuICAgICAgICAgICAgZGVsZXRlIHRoaXMuY2FsbGJhY2tzW2V2ZW50XTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9O1xyXG5cclxuICAgIC8vLyBFbWl0IGBldmVudGAgd2l0aCB0aGUgZ2l2ZW4gYXJncy5cclxuICAgIC8vIGFsc28gY2FsbHMgYW55IGAqYCBoYW5kbGVyc1xyXG4gICAgcHJvdG90eXBlLmVtaXQgPSBmdW5jdGlvbiAoZXZlbnQpIHtcclxuICAgICAgICB0aGlzLmNhbGxiYWNrcyA9IHRoaXMuY2FsbGJhY2tzIHx8IHt9O1xyXG4gICAgICAgIHZhciBhcmdzID0gW10uc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpLFxyXG4gICAgICAgICAgICBjYWxsYmFja3MgPSB0aGlzLmNhbGxiYWNrc1tldmVudF0sXHJcbiAgICAgICAgICAgIHNwZWNpYWxDYWxsYmFja3MgPSB0aGlzLmdldFdpbGRjYXJkQ2FsbGJhY2tzKGV2ZW50KSxcclxuICAgICAgICAgICAgaSxcclxuICAgICAgICAgICAgbGVuLFxyXG4gICAgICAgICAgICBpdGVtLFxyXG4gICAgICAgICAgICBsaXN0ZW5lcnM7XHJcblxyXG4gICAgICAgIGlmIChjYWxsYmFja3MpIHtcclxuICAgICAgICAgICAgbGlzdGVuZXJzID0gY2FsbGJhY2tzLnNsaWNlKCk7XHJcbiAgICAgICAgICAgIGZvciAoaSA9IDAsIGxlbiA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBsZW47ICsraSkge1xyXG4gICAgICAgICAgICAgICAgaWYgKCFsaXN0ZW5lcnNbaV0pIHtcclxuICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGxpc3RlbmVyc1tpXS5hcHBseSh0aGlzLCBhcmdzKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHNwZWNpYWxDYWxsYmFja3MpIHtcclxuICAgICAgICAgICAgbGVuID0gc3BlY2lhbENhbGxiYWNrcy5sZW5ndGg7XHJcbiAgICAgICAgICAgIGxpc3RlbmVycyA9IHNwZWNpYWxDYWxsYmFja3Muc2xpY2UoKTtcclxuICAgICAgICAgICAgZm9yIChpID0gMCwgbGVuID0gbGlzdGVuZXJzLmxlbmd0aDsgaSA8IGxlbjsgKytpKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoIWxpc3RlbmVyc1tpXSkge1xyXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgbGlzdGVuZXJzW2ldLmFwcGx5KHRoaXMsIFtldmVudF0uY29uY2F0KGFyZ3MpKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9O1xyXG5cclxuICAgIC8vIEhlbHBlciBmb3IgZm9yIGZpbmRpbmcgc3BlY2lhbCB3aWxkY2FyZCBldmVudCBoYW5kbGVycyB0aGF0IG1hdGNoIHRoZSBldmVudFxyXG4gICAgcHJvdG90eXBlLmdldFdpbGRjYXJkQ2FsbGJhY2tzID0gZnVuY3Rpb24gKGV2ZW50TmFtZSkge1xyXG4gICAgICAgIHRoaXMuY2FsbGJhY2tzID0gdGhpcy5jYWxsYmFja3MgfHwge307XHJcbiAgICAgICAgdmFyIGl0ZW0sXHJcbiAgICAgICAgICAgIHNwbGl0LFxyXG4gICAgICAgICAgICByZXN1bHQgPSBbXTtcclxuXHJcbiAgICAgICAgZm9yIChpdGVtIGluIHRoaXMuY2FsbGJhY2tzKSB7XHJcbiAgICAgICAgICAgIHNwbGl0ID0gaXRlbS5zcGxpdCgnKicpO1xyXG4gICAgICAgICAgICBpZiAoaXRlbSA9PT0gJyonIHx8IChzcGxpdC5sZW5ndGggPT09IDIgJiYgZXZlbnROYW1lLnNsaWNlKDAsIHNwbGl0WzBdLmxlbmd0aCkgPT09IHNwbGl0WzBdKSkge1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0ID0gcmVzdWx0LmNvbmNhdCh0aGlzLmNhbGxiYWNrc1tpdGVtXSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH07XHJcblxyXG59O1xyXG5cclxuV2lsZEVtaXR0ZXIubWl4aW4oV2lsZEVtaXR0ZXIpO1xyXG4iLCIvKiFcbiAqIEV2ZW50RW1pdHRlciB2NC4yLjkgLSBnaXQuaW8vZWVcbiAqIE9saXZlciBDYWxkd2VsbFxuICogTUlUIGxpY2Vuc2VcbiAqIEBwcmVzZXJ2ZVxuICovXG5cbihmdW5jdGlvbiAoKSB7XG4gICAgJ3VzZSBzdHJpY3QnO1xuXG4gICAgLyoqXG4gICAgICogQ2xhc3MgZm9yIG1hbmFnaW5nIGV2ZW50cy5cbiAgICAgKiBDYW4gYmUgZXh0ZW5kZWQgdG8gcHJvdmlkZSBldmVudCBmdW5jdGlvbmFsaXR5IGluIG90aGVyIGNsYXNzZXMuXG4gICAgICpcbiAgICAgKiBAY2xhc3MgRXZlbnRFbWl0dGVyIE1hbmFnZXMgZXZlbnQgcmVnaXN0ZXJpbmcgYW5kIGVtaXR0aW5nLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIEV2ZW50RW1pdHRlcigpIHt9XG5cbiAgICAvLyBTaG9ydGN1dHMgdG8gaW1wcm92ZSBzcGVlZCBhbmQgc2l6ZVxuICAgIHZhciBwcm90byA9IEV2ZW50RW1pdHRlci5wcm90b3R5cGU7XG4gICAgdmFyIGV4cG9ydHMgPSB0aGlzO1xuICAgIHZhciBvcmlnaW5hbEdsb2JhbFZhbHVlID0gZXhwb3J0cy5FdmVudEVtaXR0ZXI7XG5cbiAgICAvKipcbiAgICAgKiBGaW5kcyB0aGUgaW5kZXggb2YgdGhlIGxpc3RlbmVyIGZvciB0aGUgZXZlbnQgaW4gaXRzIHN0b3JhZ2UgYXJyYXkuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9uW119IGxpc3RlbmVycyBBcnJheSBvZiBsaXN0ZW5lcnMgdG8gc2VhcmNoIHRocm91Z2guXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gbGlzdGVuZXIgTWV0aG9kIHRvIGxvb2sgZm9yLlxuICAgICAqIEByZXR1cm4ge051bWJlcn0gSW5kZXggb2YgdGhlIHNwZWNpZmllZCBsaXN0ZW5lciwgLTEgaWYgbm90IGZvdW5kXG4gICAgICogQGFwaSBwcml2YXRlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaW5kZXhPZkxpc3RlbmVyKGxpc3RlbmVycywgbGlzdGVuZXIpIHtcbiAgICAgICAgdmFyIGkgPSBsaXN0ZW5lcnMubGVuZ3RoO1xuICAgICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgICAgICBpZiAobGlzdGVuZXJzW2ldLmxpc3RlbmVyID09PSBsaXN0ZW5lcikge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFsaWFzIGEgbWV0aG9kIHdoaWxlIGtlZXBpbmcgdGhlIGNvbnRleHQgY29ycmVjdCwgdG8gYWxsb3cgZm9yIG92ZXJ3cml0aW5nIG9mIHRhcmdldCBtZXRob2QuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBUaGUgbmFtZSBvZiB0aGUgdGFyZ2V0IG1ldGhvZC5cbiAgICAgKiBAcmV0dXJuIHtGdW5jdGlvbn0gVGhlIGFsaWFzZWQgbWV0aG9kXG4gICAgICogQGFwaSBwcml2YXRlXG4gICAgICovXG4gICAgZnVuY3Rpb24gYWxpYXMobmFtZSkge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gYWxpYXNDbG9zdXJlKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXNbbmFtZV0uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBsaXN0ZW5lciBhcnJheSBmb3IgdGhlIHNwZWNpZmllZCBldmVudC5cbiAgICAgKiBXaWxsIGluaXRpYWxpc2UgdGhlIGV2ZW50IG9iamVjdCBhbmQgbGlzdGVuZXIgYXJyYXlzIGlmIHJlcXVpcmVkLlxuICAgICAqIFdpbGwgcmV0dXJuIGFuIG9iamVjdCBpZiB5b3UgdXNlIGEgcmVnZXggc2VhcmNoLiBUaGUgb2JqZWN0IGNvbnRhaW5zIGtleXMgZm9yIGVhY2ggbWF0Y2hlZCBldmVudC4gU28gL2JhW3J6XS8gbWlnaHQgcmV0dXJuIGFuIG9iamVjdCBjb250YWluaW5nIGJhciBhbmQgYmF6LiBCdXQgb25seSBpZiB5b3UgaGF2ZSBlaXRoZXIgZGVmaW5lZCB0aGVtIHdpdGggZGVmaW5lRXZlbnQgb3IgYWRkZWQgc29tZSBsaXN0ZW5lcnMgdG8gdGhlbS5cbiAgICAgKiBFYWNoIHByb3BlcnR5IGluIHRoZSBvYmplY3QgcmVzcG9uc2UgaXMgYW4gYXJyYXkgb2YgbGlzdGVuZXIgZnVuY3Rpb25zLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBldnQgTmFtZSBvZiB0aGUgZXZlbnQgdG8gcmV0dXJuIHRoZSBsaXN0ZW5lcnMgZnJvbS5cbiAgICAgKiBAcmV0dXJuIHtGdW5jdGlvbltdfE9iamVjdH0gQWxsIGxpc3RlbmVyIGZ1bmN0aW9ucyBmb3IgdGhlIGV2ZW50LlxuICAgICAqL1xuICAgIHByb3RvLmdldExpc3RlbmVycyA9IGZ1bmN0aW9uIGdldExpc3RlbmVycyhldnQpIHtcbiAgICAgICAgdmFyIGV2ZW50cyA9IHRoaXMuX2dldEV2ZW50cygpO1xuICAgICAgICB2YXIgcmVzcG9uc2U7XG4gICAgICAgIHZhciBrZXk7XG5cbiAgICAgICAgLy8gUmV0dXJuIGEgY29uY2F0ZW5hdGVkIGFycmF5IG9mIGFsbCBtYXRjaGluZyBldmVudHMgaWZcbiAgICAgICAgLy8gdGhlIHNlbGVjdG9yIGlzIGEgcmVndWxhciBleHByZXNzaW9uLlxuICAgICAgICBpZiAoZXZ0IGluc3RhbmNlb2YgUmVnRXhwKSB7XG4gICAgICAgICAgICByZXNwb25zZSA9IHt9O1xuICAgICAgICAgICAgZm9yIChrZXkgaW4gZXZlbnRzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGV2ZW50cy5oYXNPd25Qcm9wZXJ0eShrZXkpICYmIGV2dC50ZXN0KGtleSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2Vba2V5XSA9IGV2ZW50c1trZXldO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJlc3BvbnNlID0gZXZlbnRzW2V2dF0gfHwgKGV2ZW50c1tldnRdID0gW10pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBUYWtlcyBhIGxpc3Qgb2YgbGlzdGVuZXIgb2JqZWN0cyBhbmQgZmxhdHRlbnMgaXQgaW50byBhIGxpc3Qgb2YgbGlzdGVuZXIgZnVuY3Rpb25zLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtPYmplY3RbXX0gbGlzdGVuZXJzIFJhdyBsaXN0ZW5lciBvYmplY3RzLlxuICAgICAqIEByZXR1cm4ge0Z1bmN0aW9uW119IEp1c3QgdGhlIGxpc3RlbmVyIGZ1bmN0aW9ucy5cbiAgICAgKi9cbiAgICBwcm90by5mbGF0dGVuTGlzdGVuZXJzID0gZnVuY3Rpb24gZmxhdHRlbkxpc3RlbmVycyhsaXN0ZW5lcnMpIHtcbiAgICAgICAgdmFyIGZsYXRMaXN0ZW5lcnMgPSBbXTtcbiAgICAgICAgdmFyIGk7XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGxpc3RlbmVycy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICAgICAgZmxhdExpc3RlbmVycy5wdXNoKGxpc3RlbmVyc1tpXS5saXN0ZW5lcik7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmxhdExpc3RlbmVycztcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogRmV0Y2hlcyB0aGUgcmVxdWVzdGVkIGxpc3RlbmVycyB2aWEgZ2V0TGlzdGVuZXJzIGJ1dCB3aWxsIGFsd2F5cyByZXR1cm4gdGhlIHJlc3VsdHMgaW5zaWRlIGFuIG9iamVjdC4gVGhpcyBpcyBtYWlubHkgZm9yIGludGVybmFsIHVzZSBidXQgb3RoZXJzIG1heSBmaW5kIGl0IHVzZWZ1bC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gZXZ0IE5hbWUgb2YgdGhlIGV2ZW50IHRvIHJldHVybiB0aGUgbGlzdGVuZXJzIGZyb20uXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBBbGwgbGlzdGVuZXIgZnVuY3Rpb25zIGZvciBhbiBldmVudCBpbiBhbiBvYmplY3QuXG4gICAgICovXG4gICAgcHJvdG8uZ2V0TGlzdGVuZXJzQXNPYmplY3QgPSBmdW5jdGlvbiBnZXRMaXN0ZW5lcnNBc09iamVjdChldnQpIHtcbiAgICAgICAgdmFyIGxpc3RlbmVycyA9IHRoaXMuZ2V0TGlzdGVuZXJzKGV2dCk7XG4gICAgICAgIHZhciByZXNwb25zZTtcblxuICAgICAgICBpZiAobGlzdGVuZXJzIGluc3RhbmNlb2YgQXJyYXkpIHtcbiAgICAgICAgICAgIHJlc3BvbnNlID0ge307XG4gICAgICAgICAgICByZXNwb25zZVtldnRdID0gbGlzdGVuZXJzO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlIHx8IGxpc3RlbmVycztcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBzcGVjaWZpZWQgZXZlbnQuXG4gICAgICogVGhlIGxpc3RlbmVyIHdpbGwgbm90IGJlIGFkZGVkIGlmIGl0IGlzIGEgZHVwbGljYXRlLlxuICAgICAqIElmIHRoZSBsaXN0ZW5lciByZXR1cm5zIHRydWUgdGhlbiBpdCB3aWxsIGJlIHJlbW92ZWQgYWZ0ZXIgaXQgaXMgY2FsbGVkLlxuICAgICAqIElmIHlvdSBwYXNzIGEgcmVndWxhciBleHByZXNzaW9uIGFzIHRoZSBldmVudCBuYW1lIHRoZW4gdGhlIGxpc3RlbmVyIHdpbGwgYmUgYWRkZWQgdG8gYWxsIGV2ZW50cyB0aGF0IG1hdGNoIGl0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBldnQgTmFtZSBvZiB0aGUgZXZlbnQgdG8gYXR0YWNoIHRoZSBsaXN0ZW5lciB0by5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBsaXN0ZW5lciBNZXRob2QgdG8gYmUgY2FsbGVkIHdoZW4gdGhlIGV2ZW50IGlzIGVtaXR0ZWQuIElmIHRoZSBmdW5jdGlvbiByZXR1cm5zIHRydWUgdGhlbiBpdCB3aWxsIGJlIHJlbW92ZWQgYWZ0ZXIgY2FsbGluZy5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5hZGRMaXN0ZW5lciA9IGZ1bmN0aW9uIGFkZExpc3RlbmVyKGV2dCwgbGlzdGVuZXIpIHtcbiAgICAgICAgdmFyIGxpc3RlbmVycyA9IHRoaXMuZ2V0TGlzdGVuZXJzQXNPYmplY3QoZXZ0KTtcbiAgICAgICAgdmFyIGxpc3RlbmVySXNXcmFwcGVkID0gdHlwZW9mIGxpc3RlbmVyID09PSAnb2JqZWN0JztcbiAgICAgICAgdmFyIGtleTtcblxuICAgICAgICBmb3IgKGtleSBpbiBsaXN0ZW5lcnMpIHtcbiAgICAgICAgICAgIGlmIChsaXN0ZW5lcnMuaGFzT3duUHJvcGVydHkoa2V5KSAmJiBpbmRleE9mTGlzdGVuZXIobGlzdGVuZXJzW2tleV0sIGxpc3RlbmVyKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICBsaXN0ZW5lcnNba2V5XS5wdXNoKGxpc3RlbmVySXNXcmFwcGVkID8gbGlzdGVuZXIgOiB7XG4gICAgICAgICAgICAgICAgICAgIGxpc3RlbmVyOiBsaXN0ZW5lcixcbiAgICAgICAgICAgICAgICAgICAgb25jZTogZmFsc2VcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBbGlhcyBvZiBhZGRMaXN0ZW5lclxuICAgICAqL1xuICAgIHByb3RvLm9uID0gYWxpYXMoJ2FkZExpc3RlbmVyJyk7XG5cbiAgICAvKipcbiAgICAgKiBTZW1pLWFsaWFzIG9mIGFkZExpc3RlbmVyLiBJdCB3aWxsIGFkZCBhIGxpc3RlbmVyIHRoYXQgd2lsbCBiZVxuICAgICAqIGF1dG9tYXRpY2FsbHkgcmVtb3ZlZCBhZnRlciBpdHMgZmlyc3QgZXhlY3V0aW9uLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBldnQgTmFtZSBvZiB0aGUgZXZlbnQgdG8gYXR0YWNoIHRoZSBsaXN0ZW5lciB0by5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBsaXN0ZW5lciBNZXRob2QgdG8gYmUgY2FsbGVkIHdoZW4gdGhlIGV2ZW50IGlzIGVtaXR0ZWQuIElmIHRoZSBmdW5jdGlvbiByZXR1cm5zIHRydWUgdGhlbiBpdCB3aWxsIGJlIHJlbW92ZWQgYWZ0ZXIgY2FsbGluZy5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5hZGRPbmNlTGlzdGVuZXIgPSBmdW5jdGlvbiBhZGRPbmNlTGlzdGVuZXIoZXZ0LCBsaXN0ZW5lcikge1xuICAgICAgICByZXR1cm4gdGhpcy5hZGRMaXN0ZW5lcihldnQsIHtcbiAgICAgICAgICAgIGxpc3RlbmVyOiBsaXN0ZW5lcixcbiAgICAgICAgICAgIG9uY2U6IHRydWVcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEFsaWFzIG9mIGFkZE9uY2VMaXN0ZW5lci5cbiAgICAgKi9cbiAgICBwcm90by5vbmNlID0gYWxpYXMoJ2FkZE9uY2VMaXN0ZW5lcicpO1xuXG4gICAgLyoqXG4gICAgICogRGVmaW5lcyBhbiBldmVudCBuYW1lLiBUaGlzIGlzIHJlcXVpcmVkIGlmIHlvdSB3YW50IHRvIHVzZSBhIHJlZ2V4IHRvIGFkZCBhIGxpc3RlbmVyIHRvIG11bHRpcGxlIGV2ZW50cyBhdCBvbmNlLiBJZiB5b3UgZG9uJ3QgZG8gdGhpcyB0aGVuIGhvdyBkbyB5b3UgZXhwZWN0IGl0IHRvIGtub3cgd2hhdCBldmVudCB0byBhZGQgdG8/IFNob3VsZCBpdCBqdXN0IGFkZCB0byBldmVyeSBwb3NzaWJsZSBtYXRjaCBmb3IgYSByZWdleD8gTm8uIFRoYXQgaXMgc2NhcnkgYW5kIGJhZC5cbiAgICAgKiBZb3UgbmVlZCB0byB0ZWxsIGl0IHdoYXQgZXZlbnQgbmFtZXMgc2hvdWxkIGJlIG1hdGNoZWQgYnkgYSByZWdleC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBldnQgTmFtZSBvZiB0aGUgZXZlbnQgdG8gY3JlYXRlLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLmRlZmluZUV2ZW50ID0gZnVuY3Rpb24gZGVmaW5lRXZlbnQoZXZ0KSB7XG4gICAgICAgIHRoaXMuZ2V0TGlzdGVuZXJzKGV2dCk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVc2VzIGRlZmluZUV2ZW50IHRvIGRlZmluZSBtdWx0aXBsZSBldmVudHMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ1tdfSBldnRzIEFuIGFycmF5IG9mIGV2ZW50IG5hbWVzIHRvIGRlZmluZS5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5kZWZpbmVFdmVudHMgPSBmdW5jdGlvbiBkZWZpbmVFdmVudHMoZXZ0cykge1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGV2dHMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgICAgIHRoaXMuZGVmaW5lRXZlbnQoZXZ0c1tpXSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgYSBsaXN0ZW5lciBmdW5jdGlvbiBmcm9tIHRoZSBzcGVjaWZpZWQgZXZlbnQuXG4gICAgICogV2hlbiBwYXNzZWQgYSByZWd1bGFyIGV4cHJlc3Npb24gYXMgdGhlIGV2ZW50IG5hbWUsIGl0IHdpbGwgcmVtb3ZlIHRoZSBsaXN0ZW5lciBmcm9tIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gZXZ0IE5hbWUgb2YgdGhlIGV2ZW50IHRvIHJlbW92ZSB0aGUgbGlzdGVuZXIgZnJvbS5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBsaXN0ZW5lciBNZXRob2QgdG8gcmVtb3ZlIGZyb20gdGhlIGV2ZW50LlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLnJlbW92ZUxpc3RlbmVyID0gZnVuY3Rpb24gcmVtb3ZlTGlzdGVuZXIoZXZ0LCBsaXN0ZW5lcikge1xuICAgICAgICB2YXIgbGlzdGVuZXJzID0gdGhpcy5nZXRMaXN0ZW5lcnNBc09iamVjdChldnQpO1xuICAgICAgICB2YXIgaW5kZXg7XG4gICAgICAgIHZhciBrZXk7XG5cbiAgICAgICAgZm9yIChrZXkgaW4gbGlzdGVuZXJzKSB7XG4gICAgICAgICAgICBpZiAobGlzdGVuZXJzLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICBpbmRleCA9IGluZGV4T2ZMaXN0ZW5lcihsaXN0ZW5lcnNba2V5XSwgbGlzdGVuZXIpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGluZGV4ICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICBsaXN0ZW5lcnNba2V5XS5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBbGlhcyBvZiByZW1vdmVMaXN0ZW5lclxuICAgICAqL1xuICAgIHByb3RvLm9mZiA9IGFsaWFzKCdyZW1vdmVMaXN0ZW5lcicpO1xuXG4gICAgLyoqXG4gICAgICogQWRkcyBsaXN0ZW5lcnMgaW4gYnVsayB1c2luZyB0aGUgbWFuaXB1bGF0ZUxpc3RlbmVycyBtZXRob2QuXG4gICAgICogSWYgeW91IHBhc3MgYW4gb2JqZWN0IGFzIHRoZSBzZWNvbmQgYXJndW1lbnQgeW91IGNhbiBhZGQgdG8gbXVsdGlwbGUgZXZlbnRzIGF0IG9uY2UuIFRoZSBvYmplY3Qgc2hvdWxkIGNvbnRhaW4ga2V5IHZhbHVlIHBhaXJzIG9mIGV2ZW50cyBhbmQgbGlzdGVuZXJzIG9yIGxpc3RlbmVyIGFycmF5cy4gWW91IGNhbiBhbHNvIHBhc3MgaXQgYW4gZXZlbnQgbmFtZSBhbmQgYW4gYXJyYXkgb2YgbGlzdGVuZXJzIHRvIGJlIGFkZGVkLlxuICAgICAqIFlvdSBjYW4gYWxzbyBwYXNzIGl0IGEgcmVndWxhciBleHByZXNzaW9uIHRvIGFkZCB0aGUgYXJyYXkgb2YgbGlzdGVuZXJzIHRvIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKiBZZWFoLCB0aGlzIGZ1bmN0aW9uIGRvZXMgcXVpdGUgYSBiaXQuIFRoYXQncyBwcm9iYWJseSBhIGJhZCB0aGluZy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdHxSZWdFeHB9IGV2dCBBbiBldmVudCBuYW1lIGlmIHlvdSB3aWxsIHBhc3MgYW4gYXJyYXkgb2YgbGlzdGVuZXJzIG5leHQuIEFuIG9iamVjdCBpZiB5b3Ugd2lzaCB0byBhZGQgdG8gbXVsdGlwbGUgZXZlbnRzIGF0IG9uY2UuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbltdfSBbbGlzdGVuZXJzXSBBbiBvcHRpb25hbCBhcnJheSBvZiBsaXN0ZW5lciBmdW5jdGlvbnMgdG8gYWRkLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLmFkZExpc3RlbmVycyA9IGZ1bmN0aW9uIGFkZExpc3RlbmVycyhldnQsIGxpc3RlbmVycykge1xuICAgICAgICAvLyBQYXNzIHRocm91Z2ggdG8gbWFuaXB1bGF0ZUxpc3RlbmVyc1xuICAgICAgICByZXR1cm4gdGhpcy5tYW5pcHVsYXRlTGlzdGVuZXJzKGZhbHNlLCBldnQsIGxpc3RlbmVycyk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgbGlzdGVuZXJzIGluIGJ1bGsgdXNpbmcgdGhlIG1hbmlwdWxhdGVMaXN0ZW5lcnMgbWV0aG9kLlxuICAgICAqIElmIHlvdSBwYXNzIGFuIG9iamVjdCBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IHlvdSBjYW4gcmVtb3ZlIGZyb20gbXVsdGlwbGUgZXZlbnRzIGF0IG9uY2UuIFRoZSBvYmplY3Qgc2hvdWxkIGNvbnRhaW4ga2V5IHZhbHVlIHBhaXJzIG9mIGV2ZW50cyBhbmQgbGlzdGVuZXJzIG9yIGxpc3RlbmVyIGFycmF5cy5cbiAgICAgKiBZb3UgY2FuIGFsc28gcGFzcyBpdCBhbiBldmVudCBuYW1lIGFuZCBhbiBhcnJheSBvZiBsaXN0ZW5lcnMgdG8gYmUgcmVtb3ZlZC5cbiAgICAgKiBZb3UgY2FuIGFsc28gcGFzcyBpdCBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byByZW1vdmUgdGhlIGxpc3RlbmVycyBmcm9tIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdHxSZWdFeHB9IGV2dCBBbiBldmVudCBuYW1lIGlmIHlvdSB3aWxsIHBhc3MgYW4gYXJyYXkgb2YgbGlzdGVuZXJzIG5leHQuIEFuIG9iamVjdCBpZiB5b3Ugd2lzaCB0byByZW1vdmUgZnJvbSBtdWx0aXBsZSBldmVudHMgYXQgb25jZS5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9uW119IFtsaXN0ZW5lcnNdIEFuIG9wdGlvbmFsIGFycmF5IG9mIGxpc3RlbmVyIGZ1bmN0aW9ucyB0byByZW1vdmUuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBDdXJyZW50IGluc3RhbmNlIG9mIEV2ZW50RW1pdHRlciBmb3IgY2hhaW5pbmcuXG4gICAgICovXG4gICAgcHJvdG8ucmVtb3ZlTGlzdGVuZXJzID0gZnVuY3Rpb24gcmVtb3ZlTGlzdGVuZXJzKGV2dCwgbGlzdGVuZXJzKSB7XG4gICAgICAgIC8vIFBhc3MgdGhyb3VnaCB0byBtYW5pcHVsYXRlTGlzdGVuZXJzXG4gICAgICAgIHJldHVybiB0aGlzLm1hbmlwdWxhdGVMaXN0ZW5lcnModHJ1ZSwgZXZ0LCBsaXN0ZW5lcnMpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBFZGl0cyBsaXN0ZW5lcnMgaW4gYnVsay4gVGhlIGFkZExpc3RlbmVycyBhbmQgcmVtb3ZlTGlzdGVuZXJzIG1ldGhvZHMgYm90aCB1c2UgdGhpcyB0byBkbyB0aGVpciBqb2IuIFlvdSBzaG91bGQgcmVhbGx5IHVzZSB0aG9zZSBpbnN0ZWFkLCB0aGlzIGlzIGEgbGl0dGxlIGxvd2VyIGxldmVsLlxuICAgICAqIFRoZSBmaXJzdCBhcmd1bWVudCB3aWxsIGRldGVybWluZSBpZiB0aGUgbGlzdGVuZXJzIGFyZSByZW1vdmVkICh0cnVlKSBvciBhZGRlZCAoZmFsc2UpLlxuICAgICAqIElmIHlvdSBwYXNzIGFuIG9iamVjdCBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IHlvdSBjYW4gYWRkL3JlbW92ZSBmcm9tIG11bHRpcGxlIGV2ZW50cyBhdCBvbmNlLiBUaGUgb2JqZWN0IHNob3VsZCBjb250YWluIGtleSB2YWx1ZSBwYWlycyBvZiBldmVudHMgYW5kIGxpc3RlbmVycyBvciBsaXN0ZW5lciBhcnJheXMuXG4gICAgICogWW91IGNhbiBhbHNvIHBhc3MgaXQgYW4gZXZlbnQgbmFtZSBhbmQgYW4gYXJyYXkgb2YgbGlzdGVuZXJzIHRvIGJlIGFkZGVkL3JlbW92ZWQuXG4gICAgICogWW91IGNhbiBhbHNvIHBhc3MgaXQgYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gbWFuaXB1bGF0ZSB0aGUgbGlzdGVuZXJzIG9mIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7Qm9vbGVhbn0gcmVtb3ZlIFRydWUgaWYgeW91IHdhbnQgdG8gcmVtb3ZlIGxpc3RlbmVycywgZmFsc2UgaWYgeW91IHdhbnQgdG8gYWRkLlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdHxSZWdFeHB9IGV2dCBBbiBldmVudCBuYW1lIGlmIHlvdSB3aWxsIHBhc3MgYW4gYXJyYXkgb2YgbGlzdGVuZXJzIG5leHQuIEFuIG9iamVjdCBpZiB5b3Ugd2lzaCB0byBhZGQvcmVtb3ZlIGZyb20gbXVsdGlwbGUgZXZlbnRzIGF0IG9uY2UuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbltdfSBbbGlzdGVuZXJzXSBBbiBvcHRpb25hbCBhcnJheSBvZiBsaXN0ZW5lciBmdW5jdGlvbnMgdG8gYWRkL3JlbW92ZS5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5tYW5pcHVsYXRlTGlzdGVuZXJzID0gZnVuY3Rpb24gbWFuaXB1bGF0ZUxpc3RlbmVycyhyZW1vdmUsIGV2dCwgbGlzdGVuZXJzKSB7XG4gICAgICAgIHZhciBpO1xuICAgICAgICB2YXIgdmFsdWU7XG4gICAgICAgIHZhciBzaW5nbGUgPSByZW1vdmUgPyB0aGlzLnJlbW92ZUxpc3RlbmVyIDogdGhpcy5hZGRMaXN0ZW5lcjtcbiAgICAgICAgdmFyIG11bHRpcGxlID0gcmVtb3ZlID8gdGhpcy5yZW1vdmVMaXN0ZW5lcnMgOiB0aGlzLmFkZExpc3RlbmVycztcblxuICAgICAgICAvLyBJZiBldnQgaXMgYW4gb2JqZWN0IHRoZW4gcGFzcyBlYWNoIG9mIGl0cyBwcm9wZXJ0aWVzIHRvIHRoaXMgbWV0aG9kXG4gICAgICAgIGlmICh0eXBlb2YgZXZ0ID09PSAnb2JqZWN0JyAmJiAhKGV2dCBpbnN0YW5jZW9mIFJlZ0V4cCkpIHtcbiAgICAgICAgICAgIGZvciAoaSBpbiBldnQpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXZ0Lmhhc093blByb3BlcnR5KGkpICYmICh2YWx1ZSA9IGV2dFtpXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gUGFzcyB0aGUgc2luZ2xlIGxpc3RlbmVyIHN0cmFpZ2h0IHRocm91Z2ggdG8gdGhlIHNpbmd1bGFyIG1ldGhvZFxuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzaW5nbGUuY2FsbCh0aGlzLCBpLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBPdGhlcndpc2UgcGFzcyBiYWNrIHRvIHRoZSBtdWx0aXBsZSBmdW5jdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgbXVsdGlwbGUuY2FsbCh0aGlzLCBpLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBTbyBldnQgbXVzdCBiZSBhIHN0cmluZ1xuICAgICAgICAgICAgLy8gQW5kIGxpc3RlbmVycyBtdXN0IGJlIGFuIGFycmF5IG9mIGxpc3RlbmVyc1xuICAgICAgICAgICAgLy8gTG9vcCBvdmVyIGl0IGFuZCBwYXNzIGVhY2ggb25lIHRvIHRoZSBtdWx0aXBsZSBtZXRob2RcbiAgICAgICAgICAgIGkgPSBsaXN0ZW5lcnMubGVuZ3RoO1xuICAgICAgICAgICAgd2hpbGUgKGktLSkge1xuICAgICAgICAgICAgICAgIHNpbmdsZS5jYWxsKHRoaXMsIGV2dCwgbGlzdGVuZXJzW2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIGFsbCBsaXN0ZW5lcnMgZnJvbSBhIHNwZWNpZmllZCBldmVudC5cbiAgICAgKiBJZiB5b3UgZG8gbm90IHNwZWNpZnkgYW4gZXZlbnQgdGhlbiBhbGwgbGlzdGVuZXJzIHdpbGwgYmUgcmVtb3ZlZC5cbiAgICAgKiBUaGF0IG1lYW5zIGV2ZXJ5IGV2ZW50IHdpbGwgYmUgZW1wdGllZC5cbiAgICAgKiBZb3UgY2FuIGFsc28gcGFzcyBhIHJlZ2V4IHRvIHJlbW92ZSBhbGwgZXZlbnRzIHRoYXQgbWF0Y2ggaXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ3xSZWdFeHB9IFtldnRdIE9wdGlvbmFsIG5hbWUgb2YgdGhlIGV2ZW50IHRvIHJlbW92ZSBhbGwgbGlzdGVuZXJzIGZvci4gV2lsbCByZW1vdmUgZnJvbSBldmVyeSBldmVudCBpZiBub3QgcGFzc2VkLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLnJlbW92ZUV2ZW50ID0gZnVuY3Rpb24gcmVtb3ZlRXZlbnQoZXZ0KSB7XG4gICAgICAgIHZhciB0eXBlID0gdHlwZW9mIGV2dDtcbiAgICAgICAgdmFyIGV2ZW50cyA9IHRoaXMuX2dldEV2ZW50cygpO1xuICAgICAgICB2YXIga2V5O1xuXG4gICAgICAgIC8vIFJlbW92ZSBkaWZmZXJlbnQgdGhpbmdzIGRlcGVuZGluZyBvbiB0aGUgc3RhdGUgb2YgZXZ0XG4gICAgICAgIGlmICh0eXBlID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgLy8gUmVtb3ZlIGFsbCBsaXN0ZW5lcnMgZm9yIHRoZSBzcGVjaWZpZWQgZXZlbnRcbiAgICAgICAgICAgIGRlbGV0ZSBldmVudHNbZXZ0XTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChldnQgaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAgICAgICAgIC8vIFJlbW92ZSBhbGwgZXZlbnRzIG1hdGNoaW5nIHRoZSByZWdleC5cbiAgICAgICAgICAgIGZvciAoa2V5IGluIGV2ZW50cykge1xuICAgICAgICAgICAgICAgIGlmIChldmVudHMuaGFzT3duUHJvcGVydHkoa2V5KSAmJiBldnQudGVzdChrZXkpKSB7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBldmVudHNba2V5XTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBSZW1vdmUgYWxsIGxpc3RlbmVycyBpbiBhbGwgZXZlbnRzXG4gICAgICAgICAgICBkZWxldGUgdGhpcy5fZXZlbnRzO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEFsaWFzIG9mIHJlbW92ZUV2ZW50LlxuICAgICAqXG4gICAgICogQWRkZWQgdG8gbWlycm9yIHRoZSBub2RlIEFQSS5cbiAgICAgKi9cbiAgICBwcm90by5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBhbGlhcygncmVtb3ZlRXZlbnQnKTtcblxuICAgIC8qKlxuICAgICAqIEVtaXRzIGFuIGV2ZW50IG9mIHlvdXIgY2hvaWNlLlxuICAgICAqIFdoZW4gZW1pdHRlZCwgZXZlcnkgbGlzdGVuZXIgYXR0YWNoZWQgdG8gdGhhdCBldmVudCB3aWxsIGJlIGV4ZWN1dGVkLlxuICAgICAqIElmIHlvdSBwYXNzIHRoZSBvcHRpb25hbCBhcmd1bWVudCBhcnJheSB0aGVuIHRob3NlIGFyZ3VtZW50cyB3aWxsIGJlIHBhc3NlZCB0byBldmVyeSBsaXN0ZW5lciB1cG9uIGV4ZWN1dGlvbi5cbiAgICAgKiBCZWNhdXNlIGl0IHVzZXMgYGFwcGx5YCwgeW91ciBhcnJheSBvZiBhcmd1bWVudHMgd2lsbCBiZSBwYXNzZWQgYXMgaWYgeW91IHdyb3RlIHRoZW0gb3V0IHNlcGFyYXRlbHkuXG4gICAgICogU28gdGhleSB3aWxsIG5vdCBhcnJpdmUgd2l0aGluIHRoZSBhcnJheSBvbiB0aGUgb3RoZXIgc2lkZSwgdGhleSB3aWxsIGJlIHNlcGFyYXRlLlxuICAgICAqIFlvdSBjYW4gYWxzbyBwYXNzIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGVtaXQgdG8gYWxsIGV2ZW50cyB0aGF0IG1hdGNoIGl0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBldnQgTmFtZSBvZiB0aGUgZXZlbnQgdG8gZW1pdCBhbmQgZXhlY3V0ZSBsaXN0ZW5lcnMgZm9yLlxuICAgICAqIEBwYXJhbSB7QXJyYXl9IFthcmdzXSBPcHRpb25hbCBhcnJheSBvZiBhcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIGVhY2ggbGlzdGVuZXIuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBDdXJyZW50IGluc3RhbmNlIG9mIEV2ZW50RW1pdHRlciBmb3IgY2hhaW5pbmcuXG4gICAgICovXG4gICAgcHJvdG8uZW1pdEV2ZW50ID0gZnVuY3Rpb24gZW1pdEV2ZW50KGV2dCwgYXJncykge1xuICAgICAgICB2YXIgbGlzdGVuZXJzID0gdGhpcy5nZXRMaXN0ZW5lcnNBc09iamVjdChldnQpO1xuICAgICAgICB2YXIgbGlzdGVuZXI7XG4gICAgICAgIHZhciBpO1xuICAgICAgICB2YXIga2V5O1xuICAgICAgICB2YXIgcmVzcG9uc2U7XG5cbiAgICAgICAgZm9yIChrZXkgaW4gbGlzdGVuZXJzKSB7XG4gICAgICAgICAgICBpZiAobGlzdGVuZXJzLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICBpID0gbGlzdGVuZXJzW2tleV0ubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgd2hpbGUgKGktLSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGUgbGlzdGVuZXIgcmV0dXJucyB0cnVlIHRoZW4gaXQgc2hhbGwgYmUgcmVtb3ZlZCBmcm9tIHRoZSBldmVudFxuICAgICAgICAgICAgICAgICAgICAvLyBUaGUgZnVuY3Rpb24gaXMgZXhlY3V0ZWQgZWl0aGVyIHdpdGggYSBiYXNpYyBjYWxsIG9yIGFuIGFwcGx5IGlmIHRoZXJlIGlzIGFuIGFyZ3MgYXJyYXlcbiAgICAgICAgICAgICAgICAgICAgbGlzdGVuZXIgPSBsaXN0ZW5lcnNba2V5XVtpXTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAobGlzdGVuZXIub25jZSA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVMaXN0ZW5lcihldnQsIGxpc3RlbmVyLmxpc3RlbmVyKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlID0gbGlzdGVuZXIubGlzdGVuZXIuYXBwbHkodGhpcywgYXJncyB8fCBbXSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3BvbnNlID09PSB0aGlzLl9nZXRPbmNlUmV0dXJuVmFsdWUoKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVMaXN0ZW5lcihldnQsIGxpc3RlbmVyLmxpc3RlbmVyKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBbGlhcyBvZiBlbWl0RXZlbnRcbiAgICAgKi9cbiAgICBwcm90by50cmlnZ2VyID0gYWxpYXMoJ2VtaXRFdmVudCcpO1xuXG4gICAgLyoqXG4gICAgICogU3VidGx5IGRpZmZlcmVudCBmcm9tIGVtaXRFdmVudCBpbiB0aGF0IGl0IHdpbGwgcGFzcyBpdHMgYXJndW1lbnRzIG9uIHRvIHRoZSBsaXN0ZW5lcnMsIGFzIG9wcG9zZWQgdG8gdGFraW5nIGEgc2luZ2xlIGFycmF5IG9mIGFyZ3VtZW50cyB0byBwYXNzIG9uLlxuICAgICAqIEFzIHdpdGggZW1pdEV2ZW50LCB5b3UgY2FuIHBhc3MgYSByZWdleCBpbiBwbGFjZSBvZiB0aGUgZXZlbnQgbmFtZSB0byBlbWl0IHRvIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gZXZ0IE5hbWUgb2YgdGhlIGV2ZW50IHRvIGVtaXQgYW5kIGV4ZWN1dGUgbGlzdGVuZXJzIGZvci5cbiAgICAgKiBAcGFyYW0gey4uLip9IE9wdGlvbmFsIGFkZGl0aW9uYWwgYXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byBlYWNoIGxpc3RlbmVyLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLmVtaXQgPSBmdW5jdGlvbiBlbWl0KGV2dCkge1xuICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgICAgIHJldHVybiB0aGlzLmVtaXRFdmVudChldnQsIGFyZ3MpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBjdXJyZW50IHZhbHVlIHRvIGNoZWNrIGFnYWluc3Qgd2hlbiBleGVjdXRpbmcgbGlzdGVuZXJzLiBJZiBhXG4gICAgICogbGlzdGVuZXJzIHJldHVybiB2YWx1ZSBtYXRjaGVzIHRoZSBvbmUgc2V0IGhlcmUgdGhlbiBpdCB3aWxsIGJlIHJlbW92ZWRcbiAgICAgKiBhZnRlciBleGVjdXRpb24uIFRoaXMgdmFsdWUgZGVmYXVsdHMgdG8gdHJ1ZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIG5ldyB2YWx1ZSB0byBjaGVjayBmb3Igd2hlbiBleGVjdXRpbmcgbGlzdGVuZXJzLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLnNldE9uY2VSZXR1cm5WYWx1ZSA9IGZ1bmN0aW9uIHNldE9uY2VSZXR1cm5WYWx1ZSh2YWx1ZSkge1xuICAgICAgICB0aGlzLl9vbmNlUmV0dXJuVmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEZldGNoZXMgdGhlIGN1cnJlbnQgdmFsdWUgdG8gY2hlY2sgYWdhaW5zdCB3aGVuIGV4ZWN1dGluZyBsaXN0ZW5lcnMuIElmXG4gICAgICogdGhlIGxpc3RlbmVycyByZXR1cm4gdmFsdWUgbWF0Y2hlcyB0aGlzIG9uZSB0aGVuIGl0IHNob3VsZCBiZSByZW1vdmVkXG4gICAgICogYXV0b21hdGljYWxseS4gSXQgd2lsbCByZXR1cm4gdHJ1ZSBieSBkZWZhdWx0LlxuICAgICAqXG4gICAgICogQHJldHVybiB7KnxCb29sZWFufSBUaGUgY3VycmVudCB2YWx1ZSB0byBjaGVjayBmb3Igb3IgdGhlIGRlZmF1bHQsIHRydWUuXG4gICAgICogQGFwaSBwcml2YXRlXG4gICAgICovXG4gICAgcHJvdG8uX2dldE9uY2VSZXR1cm5WYWx1ZSA9IGZ1bmN0aW9uIF9nZXRPbmNlUmV0dXJuVmFsdWUoKSB7XG4gICAgICAgIGlmICh0aGlzLmhhc093blByb3BlcnR5KCdfb25jZVJldHVyblZhbHVlJykpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9vbmNlUmV0dXJuVmFsdWU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBGZXRjaGVzIHRoZSBldmVudHMgb2JqZWN0IGFuZCBjcmVhdGVzIG9uZSBpZiByZXF1aXJlZC5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gVGhlIGV2ZW50cyBzdG9yYWdlIG9iamVjdC5cbiAgICAgKiBAYXBpIHByaXZhdGVcbiAgICAgKi9cbiAgICBwcm90by5fZ2V0RXZlbnRzID0gZnVuY3Rpb24gX2dldEV2ZW50cygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2V2ZW50cyB8fCAodGhpcy5fZXZlbnRzID0ge30pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZXZlcnRzIHRoZSBnbG9iYWwge0BsaW5rIEV2ZW50RW1pdHRlcn0gdG8gaXRzIHByZXZpb3VzIHZhbHVlIGFuZCByZXR1cm5zIGEgcmVmZXJlbmNlIHRvIHRoaXMgdmVyc2lvbi5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge0Z1bmN0aW9ufSBOb24gY29uZmxpY3RpbmcgRXZlbnRFbWl0dGVyIGNsYXNzLlxuICAgICAqL1xuICAgIEV2ZW50RW1pdHRlci5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gbm9Db25mbGljdCgpIHtcbiAgICAgICAgZXhwb3J0cy5FdmVudEVtaXR0ZXIgPSBvcmlnaW5hbEdsb2JhbFZhbHVlO1xuICAgICAgICByZXR1cm4gRXZlbnRFbWl0dGVyO1xuICAgIH07XG5cbiAgICAvLyBFeHBvc2UgdGhlIGNsYXNzIGVpdGhlciB2aWEgQU1ELCBDb21tb25KUyBvciB0aGUgZ2xvYmFsIG9iamVjdFxuICAgIGlmICh0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQpIHtcbiAgICAgICAgZGVmaW5lKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBFdmVudEVtaXR0ZXI7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBlbHNlIGlmICh0eXBlb2YgbW9kdWxlID09PSAnb2JqZWN0JyAmJiBtb2R1bGUuZXhwb3J0cyl7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gRXZlbnRFbWl0dGVyO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgZXhwb3J0cy5FdmVudEVtaXR0ZXIgPSBFdmVudEVtaXR0ZXI7XG4gICAgfVxufS5jYWxsKHRoaXMpKTtcbiIsIlxuLyoqXG4gKiBNb2R1bGUgZGVwZW5kZW5jaWVzLlxuICovXG5cbnZhciBnbG9iYWwgPSAoZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzOyB9KSgpO1xuXG4vKipcbiAqIFdlYlNvY2tldCBjb25zdHJ1Y3Rvci5cbiAqL1xuXG52YXIgV2ViU29ja2V0ID0gZ2xvYmFsLldlYlNvY2tldCB8fCBnbG9iYWwuTW96V2ViU29ja2V0O1xuXG4vKipcbiAqIE1vZHVsZSBleHBvcnRzLlxuICovXG5cbm1vZHVsZS5leHBvcnRzID0gV2ViU29ja2V0ID8gd3MgOiBudWxsO1xuXG4vKipcbiAqIFdlYlNvY2tldCBjb25zdHJ1Y3Rvci5cbiAqXG4gKiBUaGUgdGhpcmQgYG9wdHNgIG9wdGlvbnMgb2JqZWN0IGdldHMgaWdub3JlZCBpbiB3ZWIgYnJvd3NlcnMsIHNpbmNlIGl0J3NcbiAqIG5vbi1zdGFuZGFyZCwgYW5kIHRocm93cyBhIFR5cGVFcnJvciBpZiBwYXNzZWQgdG8gdGhlIGNvbnN0cnVjdG9yLlxuICogU2VlOiBodHRwczovL2dpdGh1Yi5jb20vZWluYXJvcy93cy9pc3N1ZXMvMjI3XG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHVyaVxuICogQHBhcmFtIHtBcnJheX0gcHJvdG9jb2xzIChvcHRpb25hbClcbiAqIEBwYXJhbSB7T2JqZWN0KSBvcHRzIChvcHRpb25hbClcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuZnVuY3Rpb24gd3ModXJpLCBwcm90b2NvbHMsIG9wdHMpIHtcbiAgdmFyIGluc3RhbmNlO1xuICBpZiAocHJvdG9jb2xzKSB7XG4gICAgaW5zdGFuY2UgPSBuZXcgV2ViU29ja2V0KHVyaSwgcHJvdG9jb2xzKTtcbiAgfSBlbHNlIHtcbiAgICBpbnN0YW5jZSA9IG5ldyBXZWJTb2NrZXQodXJpKTtcbiAgfVxuICByZXR1cm4gaW5zdGFuY2U7XG59XG5cbmlmIChXZWJTb2NrZXQpIHdzLnByb3RvdHlwZSA9IFdlYlNvY2tldC5wcm90b3R5cGU7XG4iLCJpbXBvcnQgeyBPcGVuVmlkdSB9IGZyb20gJy4vT3BlblZpZHUnO1xuXG4vL1RoaXMgZXhwb3J0IHdpdGggLS1zdGFuZGFsb25lIG9wdGlvbiBhbGxvd3MgdXNpbmcgT3BlblZpZHUgZnJvbSBib3dzZXIgd2l0aCBuYW1lc3BhY2Vcbi8vZXhwb3J0IHsgT3BlblZpZHUgfSBmcm9tICcuL09wZW5WaWR1JztcblxuLy9UaGlzIFwiaGFja1wiIGFsbG93cyB0byB1c2UgT3BlblZpZHUgZnJvbSB0aGUgZ2xvYmFsIHNwYWNlIHdpbmRvd1xuaWYod2luZG93KXtcbiAgICB3aW5kb3dbXCJPcGVuVmlkdVwiXSA9IE9wZW5WaWR1O1xufVxuXG4vL0NvbW1hbmQgdG8gZ2VuZXJhdGUgYnVuZGxlLmpzIHdpdGhvdXQgbmFtZXNwYWNlXG4vL3dhdGNoaWZ5IE1haW4udHMgLXAgWyB0c2lmeSBdIC0tZXhjbHVkZSBrdXJlbnRvLWJyb3dzZXItZXh0ZW5zaW9ucyAtLWRlYnVnIC1vIC4uL3N0YXRpYy9qcy9PcGVuVmlkdS5qcyAtdiIsIi8qXG4gKiAoQykgQ29weXJpZ2h0IDIwMTYgT3BlblZpZHUgKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKi9cbmltcG9ydCB7IE9wZW5WaWR1SW50ZXJuYWwgfSBmcm9tICcuLi9PcGVuVmlkdUludGVybmFsL09wZW5WaWR1SW50ZXJuYWwnO1xuXG5pbXBvcnQgeyBTZXNzaW9uIH0gZnJvbSAnLi9TZXNzaW9uJztcbmltcG9ydCB7IFB1Ymxpc2hlciB9IGZyb20gJy4vUHVibGlzaGVyJztcblxuaW1wb3J0ICogYXMgYWRhcHRlciBmcm9tICd3ZWJydGMtYWRhcHRlcic7XG5cbmlmICh3aW5kb3cpIHtcbiAgICB3aW5kb3dbXCJhZGFwdGVyXCJdID0gYWRhcHRlcjtcbn1cblxuZXhwb3J0IGNsYXNzIE9wZW5WaWR1IHtcblxuICAgIG9wZW5WaWR1OiBPcGVuVmlkdUludGVybmFsO1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSB3c1VyaTogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMub3BlblZpZHUgPSBuZXcgT3BlblZpZHVJbnRlcm5hbCh3c1VyaSk7XG4gICAgfVxuXG4gICAgaW5pdFNlc3Npb24oYXBpS2V5OiBzdHJpbmcsIHNlc3Npb25JZDogc3RyaW5nKTogU2Vzc2lvbjtcbiAgICBpbml0U2Vzc2lvbihzZXNzaW9uSWQ6IHN0cmluZyk6IFNlc3Npb247XG5cbiAgICBpbml0U2Vzc2lvbihwYXJhbTEsIHBhcmFtMj8pOiBhbnkge1xuICAgICAgICBpZiAodGhpcy5jaGVja1N5c3RlbVJlcXVpcmVtZW50cygpKXtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcGFyYW0yID09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IFNlc3Npb24odGhpcy5vcGVuVmlkdS5pbml0U2Vzc2lvbihwYXJhbTIpLCB0aGlzKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBTZXNzaW9uKHRoaXMub3BlblZpZHUuaW5pdFNlc3Npb24ocGFyYW0xKSwgdGhpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhbGVydChcIkJyb3dzZXIgbm90IHN1cHBvcnRlZFwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGluaXRQdWJsaXNoZXIocGFyZW50SWQ6IHN0cmluZyk6IFB1Ymxpc2hlcjtcbiAgICBpbml0UHVibGlzaGVyKHBhcmVudElkOiBzdHJpbmcsIGNhbWVyYU9wdGlvbnM6IGFueSk6IFB1Ymxpc2hlcjtcbiAgICBpbml0UHVibGlzaGVyKHBhcmVudElkOiBzdHJpbmcsIGNhbWVyYU9wdGlvbnM6IGFueSwgY2FsbGJhY2s6IGFueSk6IFB1Ymxpc2hlcjtcblxuICAgIGluaXRQdWJsaXNoZXIocGFyZW50SWQ6IHN0cmluZywgY2FtZXJhT3B0aW9ucz86IGFueSwgY2FsbGJhY2s/OiBGdW5jdGlvbik6IGFueSB7XG4gICAgICAgIGlmICh0aGlzLmNoZWNrU3lzdGVtUmVxdWlyZW1lbnRzKCkpIHtcbiAgICAgICAgICAgIGlmIChjYW1lcmFPcHRpb25zICE9IG51bGwpe1xuICAgICAgICAgICAgICAgIGxldCBjYW1lcmFPcHRpb25zQXV4ID0ge1xuICAgICAgICAgICAgICAgICAgICBhdWRpbzogY2FtZXJhT3B0aW9ucy5hdWRpbyAhPSBudWxsID8gY2FtZXJhT3B0aW9ucy5hdWRpbyA6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIHZpZGVvOiBjYW1lcmFPcHRpb25zLnZpZGVvICE9IG51bGwgPyBjYW1lcmFPcHRpb25zLnZpZGVvIDogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgZGF0YTogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgbWVkaWFDb25zdHJhaW50czogdGhpcy5vcGVuVmlkdS5nZW5lcmF0ZU1lZGlhQ29uc3RyYWludHMoY2FtZXJhT3B0aW9ucy5xdWFsaXR5KVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgY2FtZXJhT3B0aW9ucyA9IGNhbWVyYU9wdGlvbnNBdXg7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNhbWVyYU9wdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgICAgIGF1ZGlvOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICB2aWRlbzogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgZGF0YTogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgbWVkaWFDb25zdHJhaW50czoge1xuICAgICAgICAgICAgICAgICAgICAgICAgYXVkaW86IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICB2aWRlbzogeyB3aWR0aDogeyBpZGVhbDogMTI4MCB9IH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIG5ldyBQdWJsaXNoZXIodGhpcy5vcGVuVmlkdS5pbml0UHVibGlzaGVyVGFnZ2VkKHBhcmVudElkLCBjYW1lcmFPcHRpb25zLCBjYWxsYmFjayksIHBhcmVudElkKTtcblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYWxlcnQoXCJCcm93c2VyIG5vdCBzdXBwb3J0ZWRcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjaGVja1N5c3RlbVJlcXVpcmVtZW50cygpOiBudW1iZXIge1xuICAgICAgICBsZXQgYnJvd3NlciA9IGFkYXB0ZXIuYnJvd3NlckRldGFpbHMuYnJvd3NlcjtcbiAgICAgICAgbGV0IHZlcnNpb24gPSBhZGFwdGVyLmJyb3dzZXJEZXRhaWxzLnZlcnNpb247XG5cbiAgICAgICAgLy9CdWcgZml4OiAnbmF2aWdhdG9yLnVzZXJBZ2VudCcgaW4gRmlyZWZveCBmb3IgVWJ1bnR1IDE0LjA0IGRvZXMgbm90IHJldHVybiBcIkZpcmVmb3gvW3ZlcnNpb25dXCIgaW4gdGhlIHN0cmluZywgc28gdmVyc2lvbiByZXR1cm5lZCBpcyBudWxsXG4gICAgICAgIGlmICgoYnJvd3NlciA9PSAnZmlyZWZveCcpICYmICh2ZXJzaW9uID09IG51bGwpKSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoKChicm93c2VyID09ICdjaHJvbWUnKSAmJiAodmVyc2lvbiA+PSAyOCkpIHx8ICgoYnJvd3NlciA9PSAnZWRnZScpICYmICh2ZXJzaW9uID49IDEyKSkgfHwgKChicm93c2VyID09ICdmaXJlZm94JykgJiYgKHZlcnNpb24gPj0gMjIpKSkge1xuICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldERldmljZXMoY2FsbGJhY2spIHtcbiAgICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzKCkudGhlbigoZGV2aWNlSW5mb3MpID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIGRldmljZUluZm9zKTtcbiAgICAgICAgfSkuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIkVycm9yIGdldHRpbmcgZGV2aWNlczogXCIgKyBlcnJvcik7XG4gICAgICAgICAgICBjYWxsYmFjayhlcnJvciwgbnVsbCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxufVxuIiwiLypcbiAqIG9wdGlvbnM6IG5hbWU6IFhYWCBkYXRhOiB0cnVlIChNYXliZSB0aGlzIGlzIGJhc2VkIG9uIHdlYnJ0YykgYXVkaW86IHRydWUsXG4gKiB2aWRlbzogdHJ1ZSwgdXJsOiBcImZpbGU6Ly8vLi4uXCIgPiBQbGF5ZXIgc2NyZWVuOiB0cnVlID4gRGVza3RvcCAoaW1wbGljaXRcbiAqIHZpZGVvOnRydWUsIGF1ZGlvOmZhbHNlKSBhdWRpbzogdHJ1ZSwgdmlkZW86IHRydWUgPiBXZWJjYW1cbiAqXG4gKiBzdHJlYW0uaGFzQXVkaW8oKTsgc3RyZWFtLmhhc1ZpZGVvKCk7IHN0cmVhbS5oYXNEYXRhKCk7XG4gKi9cbmltcG9ydCB7IFN0cmVhbSwgU3RyZWFtT3B0aW9ucywgVmlkZW9PcHRpb25zIH0gZnJvbSAnLi4vT3BlblZpZHVJbnRlcm5hbC9TdHJlYW0nO1xuaW1wb3J0IHsgU2Vzc2lvbiB9IGZyb20gJy4vU2Vzc2lvbic7XG5cbmltcG9ydCBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCd3b2xmeTg3LWV2ZW50ZW1pdHRlcicpO1xuXG5leHBvcnQgY2xhc3MgUHVibGlzaGVyIHtcblxuICAgIHByaXZhdGUgZWUgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgICBhY2Nlc3NBbGxvd2VkID0gZmFsc2U7XG4gICAgZWxlbWVudDogRWxlbWVudDtcbiAgICBpZDogc3RyaW5nO1xuICAgIHN0cmVhbTogU3RyZWFtO1xuICAgIHNlc3Npb246IFNlc3Npb247IC8vSW5pdGlhbGl6ZWQgYnkgU2Vzc2lvbi5wdWJsaXNoKFB1Ymxpc2hlcilcblxuICAgIGNvbnN0cnVjdG9yKHN0cmVhbTogU3RyZWFtLCBwYXJlbnRJZDogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuc3RyZWFtID0gc3RyZWFtO1xuXG4gICAgICAgIHRoaXMuc3RyZWFtLmFkZEV2ZW50TGlzdGVuZXIoJ2NhbWVyYS1hY2Nlc3MtY2hhbmdlZCcsIChldmVudCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5hY2Nlc3NBbGxvd2VkID0gZXZlbnQuYWNjZXNzQWxsb3dlZDtcbiAgICAgICAgICAgIGlmICh0aGlzLmFjY2Vzc0FsbG93ZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnYWNjZXNzQWxsb3dlZCcpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnYWNjZXNzRGVuaWVkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChkb2N1bWVudC5nZXRFbGVtZW50QnlJZChwYXJlbnRJZCkgIT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5lbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQocGFyZW50SWQpISE7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaXNoQXVkaW8odmFsdWU6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5zdHJlYW0uZ2V0V2ViUnRjUGVlcigpLmF1ZGlvRW5hYmxlZCA9IHZhbHVlO1xuICAgIH1cblxuICAgIHB1Ymxpc2hWaWRlbyh2YWx1ZTogYm9vbGVhbikge1xuICAgICAgICB0aGlzLnN0cmVhbS5nZXRXZWJSdGNQZWVyKCkudmlkZW9FbmFibGVkID0gdmFsdWU7XG4gICAgfVxuXG4gICAgZGVzdHJveSgpIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLnVucHVibGlzaCh0aGlzKTtcbiAgICAgICAgdGhpcy5zdHJlYW0uZGlzcG9zZSgpO1xuICAgICAgICB0aGlzLnN0cmVhbS5yZW1vdmVWaWRlbyh0aGlzLmVsZW1lbnQpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBvbihldmVudE5hbWU6IHN0cmluZywgY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5lZS5hZGRMaXN0ZW5lcihldmVudE5hbWUsIGV2ZW50ID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKGV2ZW50KTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChldmVudE5hbWUgPT0gJ3ZpZGVvRWxlbWVudENyZWF0ZWQnKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5zdHJlYW0uaXNSZWFkeSkge1xuICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCd2aWRlb0VsZW1lbnRDcmVhdGVkJywgW3tcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudDogdGhpcy5zdHJlYW0uZ2V0VmlkZW9FbGVtZW50KClcbiAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RyZWFtLmFkZEV2ZW50TGlzdGVuZXIoJ3ZpZGVvLWVsZW1lbnQtY3JlYXRlZC1ieS1zdHJlYW0nLCAoZWxlbWVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1B1Ymxpc2hlciBlbWl0dGluZyB2aWRlb0VsZW1lbnRDcmVhdGVkJyk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaWQgPSBlbGVtZW50LmlkO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgndmlkZW9FbGVtZW50Q3JlYXRlZCcsIFt7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50OiBlbGVtZW50XG4gICAgICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoZXZlbnROYW1lID09ICdzdHJlYW1DcmVhdGVkJykge1xuICAgICAgICAgICAgaWYgKHRoaXMuc3RyZWFtLmlzUmVhZHkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnc3RyZWFtQ3JlYXRlZCcsIFt7IHN0cmVhbTogdGhpcy5zdHJlYW0gfV0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbS5hZGRFdmVudExpc3RlbmVyKCdzdHJlYW0tY3JlYXRlZC1ieS1wdWJsaXNoZXInLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignUHVibGlzaGVyIGVtaXR0aW5nIHN0cmVhbUNyZWF0ZWQnKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3N0cmVhbUNyZWF0ZWQnLCBbeyBzdHJlYW06IHRoaXMuc3RyZWFtIH1dKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoZXZlbnROYW1lID09ICdhY2Nlc3NBbGxvd2VkJykge1xuICAgICAgICAgICAgaWYgKHRoaXMuc3RyZWFtLmFjY2Vzc0lzQWxsb3dlZCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdhY2Nlc3NBbGxvd2VkJyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RyZWFtLmFkZEV2ZW50TGlzdGVuZXIoJ2FjY2Vzcy1hbGxvd2VkLWJ5LXB1Ymxpc2hlcicsICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2FjY2Vzc0FsbG93ZWQnKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoZXZlbnROYW1lID09ICdhY2Nlc3NEZW5pZWQnKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5zdHJlYW0uYWNjZXNzSXNEZW5pZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnYWNjZXNzRGVuaWVkJyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RyZWFtLmFkZEV2ZW50TGlzdGVuZXIoJ2FjY2Vzcy1kZW5pZWQtYnktcHVibGlzaGVyJywgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnYWNjZXNzRGVuaWVkJyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59IiwiaW1wb3J0IHsgU2Vzc2lvbkludGVybmFsLCBTZXNzaW9uT3B0aW9ucyB9IGZyb20gJy4uL09wZW5WaWR1SW50ZXJuYWwvU2Vzc2lvbkludGVybmFsJztcbmltcG9ydCB7IFN0cmVhbSB9IGZyb20gJy4uL09wZW5WaWR1SW50ZXJuYWwvU3RyZWFtJztcbmltcG9ydCB7IENvbm5lY3Rpb24gfSBmcm9tIFwiLi4vT3BlblZpZHVJbnRlcm5hbC9Db25uZWN0aW9uXCI7XG5cbmltcG9ydCB7IE9wZW5WaWR1IH0gZnJvbSAnLi9PcGVuVmlkdSc7XG5pbXBvcnQgeyBQdWJsaXNoZXIgfSBmcm9tICcuL1B1Ymxpc2hlcic7XG5pbXBvcnQgeyBTdWJzY3JpYmVyIH0gZnJvbSAnLi9TdWJzY3JpYmVyJztcblxuaW1wb3J0IEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ3dvbGZ5ODctZXZlbnRlbWl0dGVyJyk7XG5cbmV4cG9ydCBjbGFzcyBTZXNzaW9uIHtcblxuICAgIHNlc3Npb25JZDogU3RyaW5nO1xuICAgIC8vY2FwYWJpbGl0aWVzOiBDYXBhYmlsaXRpZXNcbiAgICBjb25uZWN0aW9uOiBDb25uZWN0aW9uO1xuXG4gICAgcHJpdmF0ZSBlZSA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgc2Vzc2lvbjogU2Vzc2lvbkludGVybmFsLCBwcml2YXRlIG9wZW5WaWR1OiBPcGVuVmlkdSkge1xuICAgICAgICB0aGlzLnNlc3Npb25JZCA9IHNlc3Npb24uZ2V0U2Vzc2lvbklkKCk7XG5cbiAgICAgICAgLy8gTGlzdGVucyB0byB0aGUgZGVhY3RpdmF0aW9uIG9mIHRoZSBkZWZhdWx0IGJlaGF2aW91ciB1cG9uIHRoZSBkZWxldGlvbiBvZiBhIFN0cmVhbSBvYmplY3RcbiAgICAgICAgdGhpcy5zZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoJ3N0cmVhbS1yZW1vdmVkLWRlZmF1bHQnLCBldmVudCA9PiB7XG4gICAgICAgICAgICBldmVudC5zdHJlYW0ucmVtb3ZlVmlkZW8oKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gTGlzdGVucyB0byB0aGUgZGVhY3RpdmF0aW9uIG9mIHRoZSBkZWZhdWx0IGJlaGF2aW91ciB1cG9uIHRoZSBkaXNjb25uZWN0aW9uIG9mIGEgU2Vzc2lvblxuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcignc2Vzc2lvbi1kaXNjb25uZWN0ZWQtZGVmYXVsdCcsICgpID0+IHtcbiAgICAgICAgICAgIGxldCBzOiBTdHJlYW07XG4gICAgICAgICAgICBmb3IgKHMgb2YgdGhpcy5vcGVuVmlkdS5vcGVuVmlkdS5nZXRSZW1vdGVTdHJlYW1zKCkpIHtcbiAgICAgICAgICAgICAgICBzLnJlbW92ZVZpZGVvKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmb3IgKGxldCBzdHJlYW1JZCBpbiB0aGlzLmNvbm5lY3Rpb24uZ2V0U3RyZWFtcygpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmdldFN0cmVhbXMoKVtzdHJlYW1JZF0ucmVtb3ZlVmlkZW8oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gU2V0cyBvciB1cGRhdGVzIHRoZSB2YWx1ZSBvZiAnY29ubmVjdGlvbicgcHJvcGVydHkuIFRyaWdnZXJlZCBieSBTZXNzaW9uSW50ZXJuYWwgd2hlbiBzdWNjZXNmdWwgY29ubmVjdGlvblxuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcigndXBkYXRlLWNvbm5lY3Rpb24tb2JqZWN0JywgZXZlbnQgPT4ge1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uID0gZXZlbnQuY29ubmVjdGlvbjtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29ubmVjdCh0b2tlbjogc3RyaW5nLCBjYWxsYmFjazogYW55KTtcbiAgICBjb25uZWN0KHRva2VuOiBzdHJpbmcsIG1ldGFkYXRhOiBzdHJpbmcsIGNhbGxiYWNrOiBhbnkpO1xuXG4gICAgY29ubmVjdChwYXJhbTEsIHBhcmFtMiwgcGFyYW0zPykge1xuICAgICAgICAvLyBFYXJseSBjb25maWd1cmF0aW9uIHRvIGRlYWN0aXZhdGUgYXV0b21hdGljIHN1YnNjcmlwdGlvbiB0byBzdHJlYW1zXG4gICAgICAgIGlmICh0eXBlb2YgcGFyYW0yID09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5jb25maWd1cmUoe1xuICAgICAgICAgICAgICAgIHNlc3Npb25JZDogdGhpcy5zZXNzaW9uLmdldFNlc3Npb25JZCgpLFxuICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50SWQ6IHBhcmFtMSxcbiAgICAgICAgICAgICAgICBtZXRhZGF0YTogcGFyYW0yLFxuICAgICAgICAgICAgICAgIHN1YnNjcmliZVRvU3RyZWFtczogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLmNvbm5lY3QocGFyYW0xLCBwYXJhbTMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLmNvbmZpZ3VyZSh7XG4gICAgICAgICAgICAgICAgc2Vzc2lvbklkOiB0aGlzLnNlc3Npb24uZ2V0U2Vzc2lvbklkKCksXG4gICAgICAgICAgICAgICAgcGFydGljaXBhbnRJZDogcGFyYW0xLFxuICAgICAgICAgICAgICAgIG1ldGFkYXRhOiAnJyxcbiAgICAgICAgICAgICAgICBzdWJzY3JpYmVUb1N0cmVhbXM6IGZhbHNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5jb25uZWN0KHBhcmFtMSwgcGFyYW0yKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGRpc2Nvbm5lY3QoKSB7XG4gICAgICAgIHRoaXMub3BlblZpZHUub3BlblZpZHUuY2xvc2UoZmFsc2UpO1xuICAgICAgICB0aGlzLnNlc3Npb24uZW1pdEV2ZW50KCdzZXNzaW9uRGlzY29ubmVjdGVkJywgW3tcbiAgICAgICAgICAgIHByZXZlbnREZWZhdWx0OiAoKSA9PiB7IHRoaXMuc2Vzc2lvbi5yZW1vdmVFdmVudCgnc2Vzc2lvbi1kaXNjb25uZWN0ZWQtZGVmYXVsdCcpOyB9XG4gICAgICAgIH1dKTtcbiAgICAgICAgdGhpcy5zZXNzaW9uLmVtaXRFdmVudCgnc2Vzc2lvbi1kaXNjb25uZWN0ZWQtZGVmYXVsdCcsIFt7fV0pO1xuICAgIH1cblxuICAgIHB1Ymxpc2gocHVibGlzaGVyOiBQdWJsaXNoZXIpIHtcbiAgICAgICAgcHVibGlzaGVyLnNlc3Npb24gPSB0aGlzO1xuICAgICAgICBwdWJsaXNoZXIuc3RyZWFtLnB1Ymxpc2goKTtcbiAgICB9XG5cbiAgICB1bnB1Ymxpc2gocHVibGlzaGVyOiBQdWJsaXNoZXIpIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLnVucHVibGlzaChwdWJsaXNoZXIuc3RyZWFtKTtcbiAgICB9XG5cbiAgICBvbihldmVudE5hbWU6IHN0cmluZywgY2FsbGJhY2spIHtcbiAgICAgICAgbGV0IHJlYWxFdmVudE5hbWUgPSAnJztcbiAgICAgICAgc3dpdGNoIChldmVudE5hbWUpIHtcbiAgICAgICAgICAgIGNhc2UgJ3N0cmVhbUNyZWF0ZWQnOlxuICAgICAgICAgICAgICAgIHJlYWxFdmVudE5hbWUgPSAnc3RyZWFtLWFkZGVkJztcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ3N0cmVhbURlc3Ryb3llZCc6XG4gICAgICAgICAgICAgICAgcmVhbEV2ZW50TmFtZSA9ICdzdHJlYW0tcmVtb3ZlZCc7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlYWxFdmVudE5hbWUgIT0gJycpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKHJlYWxFdmVudE5hbWUsIGV2ZW50ID0+IHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhldmVudCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgZXZlbnQgPT4ge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGV2ZW50KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb25jZShldmVudE5hbWU6IHN0cmluZywgY2FsbGJhY2spIHtcbiAgICAgICAgbGV0IHJlYWxFdmVudE5hbWUgPSAnJztcbiAgICAgICAgc3dpdGNoIChldmVudE5hbWUpIHtcbiAgICAgICAgICAgIGNhc2UgJ3N0cmVhbUNyZWF0ZWQnOlxuICAgICAgICAgICAgICAgIHJlYWxFdmVudE5hbWUgPSAnc3RyZWFtLWFkZGVkJztcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ3N0cmVhbURlc3Ryb3llZCc6XG4gICAgICAgICAgICAgICAgcmVhbEV2ZW50TmFtZSA9ICdzdHJlYW0tcmVtb3ZlZCc7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlYWxFdmVudE5hbWUgIT0gJycpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRPbmNlRXZlbnRMaXN0ZW5lcihyZWFsRXZlbnROYW1lLCBldmVudCA9PiB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soZXZlbnQpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24uYWRkT25jZUV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCBldmVudCA9PiB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soZXZlbnQpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBvZmYoZXZlbnROYW1lOiBzdHJpbmcsIGV2ZW50SGFuZGxlcikge1xuICAgICAgICBsZXQgcmVhbEV2ZW50TmFtZSA9ICcnO1xuICAgICAgICBzd2l0Y2ggKGV2ZW50TmFtZSkge1xuICAgICAgICAgICAgY2FzZSAnc3RyZWFtQ3JlYXRlZCc6XG4gICAgICAgICAgICAgICAgcmVhbEV2ZW50TmFtZSA9ICdzdHJlYW0tYWRkZWQnO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnc3RyZWFtRGVzdHJveWVkJzpcbiAgICAgICAgICAgICAgICByZWFsRXZlbnROYW1lID0gJ3N0cmVhbS1yZW1vdmVkJztcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBpZiAocmVhbEV2ZW50TmFtZSAhPSAnJykge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLnJlbW92ZUxpc3RlbmVyKHJlYWxFdmVudE5hbWUsIGV2ZW50SGFuZGxlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24ucmVtb3ZlTGlzdGVuZXIoZXZlbnROYW1lLCBldmVudEhhbmRsZXIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgc3Vic2NyaWJlKHN0cmVhbTogU3RyZWFtLCBodG1sSWQ6IHN0cmluZywgdmlkZW9PcHRpb25zOiBhbnkpOiBTdWJzY3JpYmVyO1xuICAgIHN1YnNjcmliZShzdHJlYW06IFN0cmVhbSwgaHRtbElkOiBzdHJpbmcpOiBTdWJzY3JpYmVyO1xuXG4gICAgc3Vic2NyaWJlKHBhcmFtMSwgcGFyYW0yLCBwYXJhbTM/KTogU3Vic2NyaWJlciB7XG4gICAgICAgIC8vIFN1YnNjcmlwdGlvblxuICAgICAgICB0aGlzLnNlc3Npb24uc3Vic2NyaWJlKHBhcmFtMSk7XG4gICAgICAgIGxldCBzdWJzY3JpYmVyID0gbmV3IFN1YnNjcmliZXIocGFyYW0xLCBwYXJhbTIpO1xuICAgICAgICBwYXJhbTEucGxheU9ubHlWaWRlbyhwYXJhbTIsIG51bGwpO1xuICAgICAgICByZXR1cm4gc3Vic2NyaWJlcjtcbiAgICB9XG5cbiAgICB1bnN1YnNjcmliZShzdWJzY3JpYmVyOiBTdWJzY3JpYmVyKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi51bnN1c2NyaWJlKHN1YnNjcmliZXIuc3RyZWFtKTtcbiAgICAgICAgc3Vic2NyaWJlci5zdHJlYW0ucmVtb3ZlVmlkZW8oKTtcbiAgICB9XG5cblxuXG5cbiAgICAvKiBTaG9ydGN1dCBldmVudCBBUEkgKi9cblxuICAgIG9uU3RyZWFtQ3JlYXRlZChjYWxsYmFjaykge1xuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcihcInN0cmVhbS1hZGRlZFwiLCBzdHJlYW1FdmVudCA9PiB7XG4gICAgICAgICAgICBjYWxsYmFjayhzdHJlYW1FdmVudC5zdHJlYW0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBvblN0cmVhbURlc3Ryb3llZChjYWxsYmFjaykge1xuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcihcInN0cmVhbS1yZW1vdmVkXCIsIHN0cmVhbUV2ZW50ID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKHN0cmVhbUV2ZW50LnN0cmVhbSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIG9uUGFydGljaXBhbnRKb2luZWQoY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoXCJwYXJ0aWNpcGFudC1qb2luZWRcIiwgcGFydGljaXBhbnRFdmVudCA9PiB7XG4gICAgICAgICAgICBjYWxsYmFjayhwYXJ0aWNpcGFudEV2ZW50LmNvbm5lY3Rpb24pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBvblBhcnRpY2lwYW50TGVmdChjYWxsYmFjaykge1xuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcihcInBhcnRpY2lwYW50LWxlZnRcIiwgcGFydGljaXBhbnRFdmVudCA9PiB7XG4gICAgICAgICAgICBjYWxsYmFjayhwYXJ0aWNpcGFudEV2ZW50LmNvbm5lY3Rpb24pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBvblBhcnRpY2lwYW50UHVibGlzaGVkKGNhbGxiYWNrKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKFwicGFydGljaXBhbnQtcHVibGlzaGVkXCIsIHBhcnRpY2lwYW50RXZlbnQgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2socGFydGljaXBhbnRFdmVudC5jb25uZWN0aW9uKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgb25QYXJ0aWNpcGFudEV2aWN0ZWQoY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoXCJwYXJ0aWNpcGFudC1ldmljdGVkXCIsIHBhcnRpY2lwYW50RXZlbnQgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2socGFydGljaXBhbnRFdmVudC5jb25uZWN0aW9uKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgb25Sb29tQ2xvc2VkKGNhbGxiYWNrKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKFwicm9vbS1jbG9zZWRcIiwgcm9vbUV2ZW50ID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKHJvb21FdmVudC5yb29tKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgb25Mb3N0Q29ubmVjdGlvbihjYWxsYmFjaykge1xuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcihcImxvc3QtY29ubmVjdGlvblwiLCByb29tRXZlbnQgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2socm9vbUV2ZW50LnJvb20pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBvbk1lZGlhRXJyb3IoY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoXCJlcnJvci1tZWRpYVwiLCBlcnJvckV2ZW50ID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKGVycm9yRXZlbnQuZXJyb3IpXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qIFNob3J0Y3V0IGV2ZW50IEFQSSAqL1xufVxuIiwiaW1wb3J0IHsgU3RyZWFtLCBTdHJlYW1PcHRpb25zLCBWaWRlb09wdGlvbnMgfSBmcm9tICcuLi9PcGVuVmlkdUludGVybmFsL1N0cmVhbSc7XG5cbmltcG9ydCBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCd3b2xmeTg3LWV2ZW50ZW1pdHRlcicpO1xuXG5leHBvcnQgY2xhc3MgU3Vic2NyaWJlciB7XG5cbiAgICBwcml2YXRlIGVlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gICAgZWxlbWVudDogRWxlbWVudDtcbiAgICBpZDogc3RyaW5nO1xuICAgIHN0cmVhbTogU3RyZWFtO1xuXG4gICAgY29uc3RydWN0b3Ioc3RyZWFtOiBTdHJlYW0sIHBhcmVudElkOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5zdHJlYW0gPSBzdHJlYW07XG4gICAgICAgIGlmIChkb2N1bWVudC5nZXRFbGVtZW50QnlJZChwYXJlbnRJZCkgIT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5lbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQocGFyZW50SWQpISE7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBvbihldmVudE5hbWU6IHN0cmluZywgY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5lZS5hZGRMaXN0ZW5lcihldmVudE5hbWUsIGV2ZW50ID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKGV2ZW50KTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChldmVudE5hbWUgPT0gJ3ZpZGVvRWxlbWVudENyZWF0ZWQnKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5zdHJlYW0uaXNSZWFkeSkge1xuICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCd2aWRlb0VsZW1lbnRDcmVhdGVkJywgW3tcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudDogdGhpcy5zdHJlYW0uZ2V0VmlkZW9FbGVtZW50KClcbiAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RyZWFtLmFkZEV2ZW50TGlzdGVuZXIoJ3ZpZGVvLWVsZW1lbnQtY3JlYXRlZC1ieS1zdHJlYW0nLCBlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiU3Vic2NyaWJlciBlbWl0dGluZyB2aWRlb0VsZW1lbnRDcmVhdGVkXCIpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmlkID0gZWxlbWVudC5pZDtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3ZpZGVvRWxlbWVudENyZWF0ZWQnLCBbe1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudDogZWxlbWVudFxuICAgICAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59IiwiaW1wb3J0IHsgU3RyZWFtLCBTdHJlYW1PcHRpb25zIH0gZnJvbSAnLi9TdHJlYW0nO1xuaW1wb3J0IHsgT3BlblZpZHVJbnRlcm5hbCB9IGZyb20gJy4vT3BlblZpZHVJbnRlcm5hbCc7XG5pbXBvcnQgeyBTZXNzaW9uSW50ZXJuYWwgfSBmcm9tICcuL1Nlc3Npb25JbnRlcm5hbCc7XG5cbnR5cGUgT2JqTWFwPFQ+ID0geyBbczogc3RyaW5nXTogVDsgfVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbm5lY3Rpb25PcHRpb25zIHtcbiAgICBpZDogc3RyaW5nO1xuICAgIG1ldGFkYXRhOiBzdHJpbmc7XG4gICAgc3RyZWFtcz86IFN0cmVhbU9wdGlvbnNbXTtcbn1cblxuZXhwb3J0IGNsYXNzIENvbm5lY3Rpb24ge1xuXG4gICAgcHVibGljIGNvbm5lY3Rpb25JZDogc3RyaW5nO1xuICAgIHB1YmxpYyBkYXRhOiBzdHJpbmc7XG4gICAgcHVibGljIGNyZWF0aW9uVGltZTogbnVtYmVyO1xuICAgIHByaXZhdGUgc3RyZWFtczogT2JqTWFwPFN0cmVhbT4gPSB7fTtcbiAgICBwcml2YXRlIHN0cmVhbXNPcHRzOiBTdHJlYW1PcHRpb25zW10gPSBbXTtcblxuICAgIGNvbnN0cnVjdG9yKCBwcml2YXRlIG9wZW5WaWR1OiBPcGVuVmlkdUludGVybmFsLCBwcml2YXRlIGxvY2FsOiBib29sZWFuLCBwcml2YXRlIHJvb206IFNlc3Npb25JbnRlcm5hbCwgcHJpdmF0ZSBvcHRpb25zPzogQ29ubmVjdGlvbk9wdGlvbnMgKSB7XG5cbiAgICAgICAgaWYgKCBvcHRpb25zICkge1xuXG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb25JZCA9IG9wdGlvbnMuaWQ7XG4gICAgICAgICAgICB0aGlzLmRhdGEgPSBvcHRpb25zLm1ldGFkYXRhO1xuXG4gICAgICAgICAgICBpZiAoIG9wdGlvbnMuc3RyZWFtcyApIHtcblxuICAgICAgICAgICAgICAgIGZvciAoIGxldCBzdHJlYW1PcHRpb25zIG9mIG9wdGlvbnMuc3RyZWFtcyApIHtcblxuICAgICAgICAgICAgICAgICAgICBsZXQgc3RyZWFtT3B0cyA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlkOiBzdHJlYW1PcHRpb25zLmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGlvbjogdGhpcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlY3ZWaWRlbzogKCBzdHJlYW1PcHRpb25zLnJlY3ZWaWRlbyA9PSB1bmRlZmluZWQgPyB0cnVlIDogc3RyZWFtT3B0aW9ucy5yZWN2VmlkZW8gKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlY3ZBdWRpbzogKCBzdHJlYW1PcHRpb25zLnJlY3ZBdWRpbyA9PSB1bmRlZmluZWQgPyB0cnVlIDogc3RyZWFtT3B0aW9ucy5yZWN2QXVkaW8gKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGF1ZGlvOiBzdHJlYW1PcHRpb25zLmF1ZGlvLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW86IHN0cmVhbU9wdGlvbnMudmlkZW8sXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhOiBzdHJlYW1PcHRpb25zLmRhdGEsXG4gICAgICAgICAgICAgICAgICAgICAgICBtZWRpYUNvbnN0cmFpbnRzOiBzdHJlYW1PcHRpb25zLm1lZGlhQ29uc3RyYWludHNcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBsZXQgc3RyZWFtID0gbmV3IFN0cmVhbSggb3BlblZpZHUsIGZhbHNlLCByb29tLCBzdHJlYW1PcHRzICk7XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5hZGRTdHJlYW0oIHN0cmVhbSApO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbXNPcHRzLnB1c2goIHN0cmVhbU9wdHMgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIGNvbnNvbGUubG9nKCBcIk5ldyBcIiArICggbG9jYWwgPyBcImxvY2FsIFwiIDogXCJyZW1vdGUgXCIgKSArIFwicGFydGljaXBhbnQgXCIgKyB0aGlzLmNvbm5lY3Rpb25JZFxuICAgICAgICAgICAgKyBcIiwgc3RyZWFtcyBvcHRzOiBcIiwgdGhpcy5zdHJlYW1zT3B0cyApO1xuICAgIH1cblxuICAgIGFkZFN0cmVhbSggc3RyZWFtOiBTdHJlYW0gKSB7XG4gICAgICAgIHRoaXMuc3RyZWFtc1tzdHJlYW0uZ2V0SWRJblBhcnRpY2lwYW50KCldID0gc3RyZWFtO1xuICAgICAgICB0aGlzLnJvb20uZ2V0U3RyZWFtcygpW3N0cmVhbS5nZXRJZEluUGFydGljaXBhbnQoKV0gPSBzdHJlYW07XG4gICAgfVxuXG4gICAgZ2V0U3RyZWFtcygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RyZWFtcztcbiAgICB9XG5cbiAgICBkaXNwb3NlKCkge1xuICAgICAgICBmb3IgKCBsZXQga2V5IGluIHRoaXMuc3RyZWFtcyApIHtcbiAgICAgICAgICAgIHRoaXMuc3RyZWFtc1trZXldLmRpc3Bvc2UoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHNlbmRJY2VDYW5kaWRhdGUoIGNhbmRpZGF0ZSApIHtcblxuICAgICAgICBjb25zb2xlLmRlYnVnKCggdGhpcy5sb2NhbCA/IFwiTG9jYWxcIiA6IFwiUmVtb3RlXCIgKSwgXCJjYW5kaWRhdGUgZm9yXCIsXG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb25JZCwgSlNPTi5zdHJpbmdpZnkoIGNhbmRpZGF0ZSApICk7XG5cbiAgICAgICAgdGhpcy5vcGVuVmlkdS5zZW5kUmVxdWVzdCggXCJvbkljZUNhbmRpZGF0ZVwiLCB7XG4gICAgICAgICAgICBlbmRwb2ludE5hbWU6IHRoaXMuY29ubmVjdGlvbklkLFxuICAgICAgICAgICAgY2FuZGlkYXRlOiBjYW5kaWRhdGUuY2FuZGlkYXRlLFxuICAgICAgICAgICAgc2RwTWlkOiBjYW5kaWRhdGUuc2RwTWlkLFxuICAgICAgICAgICAgc2RwTUxpbmVJbmRleDogY2FuZGlkYXRlLnNkcE1MaW5lSW5kZXhcbiAgICAgICAgfSwgZnVuY3Rpb24oIGVycm9yLCByZXNwb25zZSApIHtcbiAgICAgICAgICAgIGlmICggZXJyb3IgKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvciggXCJFcnJvciBzZW5kaW5nIElDRSBjYW5kaWRhdGU6IFwiXG4gICAgICAgICAgICAgICAgICAgICsgSlNPTi5zdHJpbmdpZnkoIGVycm9yICkgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxufSIsIi8qXG4gKiAoQykgQ29weXJpZ2h0IDIwMTYgT3BlblZpZHUgKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKi9cbmltcG9ydCB7IFNlc3Npb25JbnRlcm5hbCwgU2Vzc2lvbk9wdGlvbnMgfSBmcm9tICcuL1Nlc3Npb25JbnRlcm5hbCc7XG5pbXBvcnQgeyBTdHJlYW0gfSBmcm9tICcuL1N0cmVhbSc7XG5pbXBvcnQgKiBhcyBScGNCdWlsZGVyIGZyb20gJ2t1cmVudG8tanNvbnJwYyc7XG5cbmV4cG9ydCB0eXBlIENhbGxiYWNrPFQ+ID0gKGVycm9yPzogYW55LCBvcGVuVmlkdT86IFQpID0+IHZvaWQ7XG5cbmV4cG9ydCBjbGFzcyBPcGVuVmlkdUludGVybmFsIHtcblxuICAgIHByaXZhdGUgc2Vzc2lvbjogU2Vzc2lvbkludGVybmFsO1xuICAgIHByaXZhdGUganNvblJwY0NsaWVudDogYW55O1xuICAgIHByaXZhdGUgcnBjUGFyYW1zOiBhbnk7XG4gICAgcHJpdmF0ZSBjYWxsYmFjazogQ2FsbGJhY2s8T3BlblZpZHVJbnRlcm5hbD47XG4gICAgcHJpdmF0ZSBjYW1lcmE6IFN0cmVhbTtcbiAgICBwcml2YXRlIHJlbW90ZVN0cmVhbXM6IFN0cmVhbVtdID0gW107XG5cbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIHdzVXJpOiBzdHJpbmcpIHtcbiAgICAgICAgaWYgKHRoaXMud3NVcmkuY2hhckF0KHdzVXJpLmxlbmd0aCAtIDEpICE9ICcvJykge1xuICAgICAgICAgICAgdGhpcy53c1VyaSArPSAnLyc7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5jaGVja05ncm9rVXJpKCk7XG4gICAgICAgIHRoaXMud3NVcmkgKz0gJ3Jvb20nO1xuICAgIH1cblxuXG4gICAgY2hlY2tOZ3Jva1VyaSgpIHtcbiAgICAgICAgaWYgKHRoaXMud3NVcmkuaW5kZXhPZihcIi5uZ3Jvay5pb1wiKSAhPT0gLTEpIHtcbiAgICAgICAgICAgIC8vIE9wZW5WaWR1IHNlcnZlciBVUkwgcmVmZXJlcyB0byBhIG5ncm9rIElQOiBzZWN1cmUgd3NzIHByb3RvY29sIGFuZCBkZWxldGUgcG9ydCBvZiBVUkxcbiAgICAgICAgICAgIHRoaXMud3NVcmkgPSB0aGlzLndzVXJpLnJlcGxhY2UoXCJ3czovL1wiLCBcIndzczovL1wiKTtcbiAgICAgICAgICAgIGxldCByZWdleCA9IC9cXC5uZ3Jva1xcLmlvOlxcZCsvO1xuICAgICAgICAgICAgdGhpcy53c1VyaSA9IHRoaXMud3NVcmkucmVwbGFjZShyZWdleCwgXCIubmdyb2suaW9cIik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy53c1VyaS5pbmRleE9mKFwibG9jYWxob3N0XCIpICE9PSAtMSkge1xuICAgICAgICAgICAgLy8gT3BlblZpZHUgc2VydmVyIFVSTCByZWZlcmVzIHRvIGxvY2FsaG9zdCBJUFxuXG4gICAgICAgIH1cbiAgICB9XG5cblxuICAgIC8qIE5FVyBNRVRIT0RTICovXG4gICAgaW5pdFNlc3Npb24oc2Vzc2lvbklkKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiU2Vzc2lvbiBpbml0aWFsaXplZCFcIik7XG4gICAgICAgIHRoaXMuc2Vzc2lvbiA9IG5ldyBTZXNzaW9uSW50ZXJuYWwodGhpcywgc2Vzc2lvbklkKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2Vzc2lvbjtcbiAgICB9XG5cbiAgICBpbml0UHVibGlzaGVyVGFnZ2VkKHBhcmVudElkOiBzdHJpbmcsIGNhbWVyYU9wdGlvbnM6IGFueSwgY2FsbGJhY2s/KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiUHVibGlzaGVyIHRhZ2dlZCBpbml0aWFsaXplZCFcIik7XG5cbiAgICAgICAgdGhpcy5nZXRDYW1lcmEoY2FtZXJhT3B0aW9ucyk7XG5cbiAgICAgICAgaWYgKGNhbGxiYWNrID09IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMuY2FtZXJhLnJlcXVlc3RDYW1lcmFBY2Nlc3MoKGVycm9yLCBjYW1lcmEpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJFcnJvciBhY2Nlc3NpbmcgdGhlIGNhbWVyYVwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY2FtZXJhLnNldFZpZGVvRWxlbWVudCh0aGlzLmNhbWVyYVJlYWR5KGNhbWVyYSEsIHBhcmVudElkKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jYW1lcmE7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmNhbWVyYS5yZXF1ZXN0Q2FtZXJhQWNjZXNzKChlcnJvciwgY2FtZXJhKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKGVycm9yKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY2FtZXJhLnNldFZpZGVvRWxlbWVudCh0aGlzLmNhbWVyYVJlYWR5KGNhbWVyYSEsIHBhcmVudElkKSk7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKHVuZGVmaW5lZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jYW1lcmE7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjYW1lcmFSZWFkeShjYW1lcmE6IFN0cmVhbSwgcGFyZW50SWQ6IHN0cmluZykge1xuICAgICAgICB0aGlzLmNhbWVyYSA9IGNhbWVyYTtcbiAgICAgICAgbGV0IHZpZGVvRWxlbWVudCA9IHRoaXMuY2FtZXJhLnBsYXlPbmx5VmlkZW8ocGFyZW50SWQsIG51bGwpO1xuICAgICAgICB0aGlzLmNhbWVyYS5lbWl0U3RyZWFtUmVhZHlFdmVudCgpO1xuICAgICAgICByZXR1cm4gdmlkZW9FbGVtZW50O1xuICAgIH1cblxuICAgIGluaXRQdWJsaXNoZXIoY2FtZXJhT3B0aW9uczogYW55LCBjYWxsYmFjaykge1xuICAgICAgICBjb25zb2xlLmxvZyhcIlB1Ymxpc2hlciBpbml0aWFsaXplZCFcIik7XG5cbiAgICAgICAgdGhpcy5nZXRDYW1lcmEoY2FtZXJhT3B0aW9ucyk7XG4gICAgICAgIHRoaXMuY2FtZXJhLnJlcXVlc3RDYW1lcmFBY2Nlc3MoKGVycm9yLCBjYW1lcmEpID0+IHtcbiAgICAgICAgICAgIGlmIChlcnJvcikgY2FsbGJhY2soZXJyb3IpO1xuICAgICAgICAgICAgZWxzZSBjYWxsYmFjayh1bmRlZmluZWQpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBnZXRMb2NhbFN0cmVhbSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FtZXJhO1xuICAgIH1cblxuICAgIGdldFJlbW90ZVN0cmVhbXMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJlbW90ZVN0cmVhbXM7XG4gICAgfVxuICAgIC8qIE5FVyBNRVRIT0RTICovXG5cblxuXG4gICAgZ2V0T3BlblZpZHVTZXJ2ZXJVUkwoKSB7XG4gICAgICAgIHJldHVybiAnaHR0cHM6Ly8nICsgdGhpcy53c1VyaS5zcGxpdChcIndzczovL1wiKVsxXS5zcGxpdChcIi9yb29tXCIpWzBdO1xuICAgIH1cblxuICAgIGdldFJvb20oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlc3Npb247XG4gICAgfVxuXG4gICAgY29ubmVjdChjYWxsYmFjazogQ2FsbGJhY2s8T3BlblZpZHVJbnRlcm5hbD4pOiB2b2lkIHtcblxuICAgICAgICB0aGlzLmNhbGxiYWNrID0gY2FsbGJhY2s7XG5cbiAgICAgICAgdGhpcy5pbml0SnNvblJwY0NsaWVudCh0aGlzLndzVXJpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGluaXRKc29uUnBjQ2xpZW50KHdzVXJpOiBzdHJpbmcpOiB2b2lkIHtcblxuICAgICAgICBsZXQgY29uZmlnID0ge1xuICAgICAgICAgICAgaGVhcnRiZWF0OiAzMDAwLFxuICAgICAgICAgICAgc2VuZENsb3NlTWVzc2FnZTogZmFsc2UsXG4gICAgICAgICAgICB3czoge1xuICAgICAgICAgICAgICAgIHVyaTogd3NVcmksXG4gICAgICAgICAgICAgICAgdXNlU29ja0pTOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBvbmNvbm5lY3RlZDogdGhpcy5jb25uZWN0Q2FsbGJhY2suYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBvbmRpc2Nvbm5lY3Q6IHRoaXMuZGlzY29ubmVjdENhbGxiYWNrLmJpbmQodGhpcyksXG4gICAgICAgICAgICAgICAgb25yZWNvbm5lY3Rpbmc6IHRoaXMucmVjb25uZWN0aW5nQ2FsbGJhY2suYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBvbnJlY29ubmVjdGVkOiB0aGlzLnJlY29ubmVjdGVkQ2FsbGJhY2suYmluZCh0aGlzKVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHJwYzoge1xuICAgICAgICAgICAgICAgIHJlcXVlc3RUaW1lb3V0OiAxNTAwMCxcbiAgICAgICAgICAgICAgICAvL25vdGlmaWNhdGlvbnNcbiAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudEpvaW5lZDogdGhpcy5vblBhcnRpY2lwYW50Sm9pbmVkLmJpbmQodGhpcyksXG4gICAgICAgICAgICAgICAgcGFydGljaXBhbnRQdWJsaXNoZWQ6IHRoaXMub25QYXJ0aWNpcGFudFB1Ymxpc2hlZC5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50VW5wdWJsaXNoZWQ6IHRoaXMub25QYXJ0aWNpcGFudExlZnQuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudExlZnQ6IHRoaXMub25QYXJ0aWNpcGFudExlZnQuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudEV2aWN0ZWQ6IHRoaXMub25QYXJ0aWNpcGFudEV2aWN0ZWQuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBzZW5kTWVzc2FnZTogdGhpcy5vbk5ld01lc3NhZ2UuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBpY2VDYW5kaWRhdGU6IHRoaXMuaWNlQ2FuZGlkYXRlRXZlbnQuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBtZWRpYUVycm9yOiB0aGlzLm9uTWVkaWFFcnJvci5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgIGN1c3Rvbk5vdGlmaWNhdGlvbjogdGhpcy5jdXN0b21Ob3RpZmljYXRpb24uYmluZCh0aGlzKVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuanNvblJwY0NsaWVudCA9IG5ldyBScGNCdWlsZGVyLmNsaWVudHMuSnNvblJwY0NsaWVudChjb25maWcpO1xuICAgIH1cblxuXG4gICAgcHJpdmF0ZSBjdXN0b21Ob3RpZmljYXRpb24ocGFyYW1zKSB7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24uZW1pdEV2ZW50KFwiY3VzdG9tLW1lc3NhZ2UtcmVjZWl2ZWRcIiwgW3sgcGFyYW1zOiBwYXJhbXMgfV0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjb25uZWN0Q2FsbGJhY2soZXJyb3IpIHtcbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICB0aGlzLmNhbGxiYWNrKGVycm9yKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuY2FsbGJhY2sobnVsbCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGlzUm9vbUF2YWlsYWJsZSgpIHtcbiAgICAgICAgaWYgKHRoaXMuc2Vzc2lvbiAhPT0gdW5kZWZpbmVkICYmIHRoaXMuc2Vzc2lvbiBpbnN0YW5jZW9mIFNlc3Npb25JbnRlcm5hbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oJ1Jvb20gaW5zdGFuY2Ugbm90IGZvdW5kJyk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGRpc2Nvbm5lY3RDYWxsYmFjaygpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ1dlYnNvY2tldCBjb25uZWN0aW9uIGxvc3QnKTtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5vbkxvc3RDb25uZWN0aW9uKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhbGVydCgnQ29ubmVjdGlvbiBlcnJvci4gUGxlYXNlIHJlbG9hZCBwYWdlLicpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZWNvbm5lY3RpbmdDYWxsYmFjaygpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ1dlYnNvY2tldCBjb25uZWN0aW9uIGxvc3QgKHJlY29ubmVjdGluZyknKTtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5vbkxvc3RDb25uZWN0aW9uKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhbGVydCgnQ29ubmVjdGlvbiBlcnJvci4gUGxlYXNlIHJlbG9hZCBwYWdlLicpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZWNvbm5lY3RlZENhbGxiYWNrKCkge1xuICAgICAgICBjb25zb2xlLmxvZygnV2Vic29ja2V0IHJlY29ubmVjdGVkJyk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblBhcnRpY2lwYW50Sm9pbmVkKHBhcmFtcykge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uUGFydGljaXBhbnRKb2luZWQocGFyYW1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgb25QYXJ0aWNpcGFudFB1Ymxpc2hlZChwYXJhbXMpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5vblBhcnRpY2lwYW50UHVibGlzaGVkKHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIG9uUGFydGljaXBhbnRMZWZ0KHBhcmFtcykge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uUGFydGljaXBhbnRMZWZ0KHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIG9uUGFydGljaXBhbnRFdmljdGVkKHBhcmFtcykge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uUGFydGljaXBhbnRFdmljdGVkKHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIG9uTmV3TWVzc2FnZShwYXJhbXMpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5vbk5ld01lc3NhZ2UocGFyYW1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgaWNlQ2FuZGlkYXRlRXZlbnQocGFyYW1zKSB7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24ucmVjdkljZUNhbmRpZGF0ZShwYXJhbXMpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblJvb21DbG9zZWQocGFyYW1zKSB7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24ub25Sb29tQ2xvc2VkKHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIG9uTWVkaWFFcnJvcihwYXJhbXMpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5vbk1lZGlhRXJyb3IocGFyYW1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgc2V0UnBjUGFyYW1zKHBhcmFtczogYW55KSB7XG4gICAgICAgIHRoaXMucnBjUGFyYW1zID0gcGFyYW1zO1xuICAgIH1cblxuICAgIHNlbmRSZXF1ZXN0KG1ldGhvZCwgcGFyYW1zLCBjYWxsYmFjaz8pIHtcblxuICAgICAgICBpZiAocGFyYW1zICYmIHBhcmFtcyBpbnN0YW5jZW9mIEZ1bmN0aW9uKSB7XG4gICAgICAgICAgICBjYWxsYmFjayA9IHBhcmFtcztcbiAgICAgICAgICAgIHBhcmFtcyA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHBhcmFtcyA9IHBhcmFtcyB8fCB7fTtcblxuICAgICAgICBpZiAodGhpcy5ycGNQYXJhbXMgJiYgdGhpcy5ycGNQYXJhbXMgIT09IG51bGwgJiYgdGhpcy5ycGNQYXJhbXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZm9yIChsZXQgaW5kZXggaW4gdGhpcy5ycGNQYXJhbXMpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5ycGNQYXJhbXMuaGFzT3duUHJvcGVydHkoaW5kZXgpKSB7XG4gICAgICAgICAgICAgICAgICAgIHBhcmFtc1tpbmRleF0gPSB0aGlzLnJwY1BhcmFtc1tpbmRleF07XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdSUEMgcGFyYW0gYWRkZWQgdG8gcmVxdWVzdCB7JyArIGluZGV4ICsgJzogJyArIHRoaXMucnBjUGFyYW1zW2luZGV4XSArICd9Jyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc29sZS5sb2coJ1NlbmRpbmcgcmVxdWVzdDogeyBtZXRob2Q6XCInICsgbWV0aG9kICsgJ1wiLCBwYXJhbXM6ICcgKyBKU09OLnN0cmluZ2lmeShwYXJhbXMpICsgJyB9Jyk7XG5cbiAgICAgICAgdGhpcy5qc29uUnBjQ2xpZW50LnNlbmQobWV0aG9kLCBwYXJhbXMsIGNhbGxiYWNrKTtcbiAgICB9XG5cbiAgICBjbG9zZShmb3JjZWQpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5sZWF2ZShmb3JjZWQsIHRoaXMuanNvblJwY0NsaWVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgZGlzY29ubmVjdFBhcnRpY2lwYW50KHN0cmVhbSkge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLmRpc2Nvbm5lY3Qoc3RyZWFtKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldENhbWVyYShvcHRpb25zPykge1xuXG4gICAgICAgIGlmICh0aGlzLmNhbWVyYSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2FtZXJhO1xuICAgICAgICB9XG5cbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge1xuICAgICAgICAgICAgYXVkaW86IHRydWUsXG4gICAgICAgICAgICB2aWRlbzogdHJ1ZSxcbiAgICAgICAgICAgIGRhdGE6IHRydWUsXG4gICAgICAgICAgICBtZWRpYUNvbnN0cmFpbnRzOiB7XG4gICAgICAgICAgICAgICAgYXVkaW86IHRydWUsXG4gICAgICAgICAgICAgICAgdmlkZW86IHsgd2lkdGg6IHsgaWRlYWw6IDEyODAgfSB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zLmNvbm5lY3Rpb24gPSB0aGlzLnNlc3Npb24uZ2V0TG9jYWxQYXJ0aWNpcGFudCgpO1xuICAgICAgICB0aGlzLmNhbWVyYSA9IG5ldyBTdHJlYW0odGhpcywgdHJ1ZSwgdGhpcy5zZXNzaW9uLCBvcHRpb25zKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FtZXJhO1xuICAgIH07XG5cbiAgICAvKmpvaW5TZXNzaW9uKG9wdGlvbnM6IFNlc3Npb25PcHRpb25zLCBjYWxsYmFjazogQ2FsbGJhY2s8U2Vzc2lvbj4pIHtcbiAgICAgICAgXG4gICAgICAgIHRoaXMuc2Vzc2lvbi5jb25maWd1cmUob3B0aW9ucyk7XG4gICAgICAgIFxuICAgICAgICB0aGlzLnNlc3Npb24uY29ubmVjdDIoKTtcbiAgICAgICAgXG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCdyb29tLWNvbm5lY3RlZCcsIHJvb21FdmVudCA9PiBjYWxsYmFjayh1bmRlZmluZWQsdGhpcy5zZXNzaW9uKSk7XG4gICAgICAgIFxuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcignZXJyb3Itcm9vbScsIGVycm9yID0+IGNhbGxiYWNrKGVycm9yKSk7XG4gICAgICAgIFxuICAgICAgICByZXR1cm4gdGhpcy5zZXNzaW9uO1xuICAgIH07Ki9cblxuICAgIC8vQ0hBVFxuICAgIHNlbmRNZXNzYWdlKHJvb20sIHVzZXIsIG1lc3NhZ2UpIHtcbiAgICAgICAgdGhpcy5zZW5kUmVxdWVzdCgnc2VuZE1lc3NhZ2UnLCB7XG4gICAgICAgICAgICBtZXNzYWdlOiBtZXNzYWdlLFxuICAgICAgICAgICAgdXNlck1lc3NhZ2U6IHVzZXIsXG4gICAgICAgICAgICByb29tTWVzc2FnZTogcm9vbVxuICAgICAgICB9LCBmdW5jdGlvbiAoZXJyb3IsIHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIHNlbmRDdXN0b21SZXF1ZXN0KHBhcmFtcywgY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5zZW5kUmVxdWVzdCgnY3VzdG9tUmVxdWVzdCcsIHBhcmFtcywgY2FsbGJhY2spO1xuICAgIH07XG5cblxuXG5cbiAgICB0b2dnbGVMb2NhbFZpZGVvVHJhY2soYWN0aXZhdGU6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5nZXRDYW1lcmEoKS5nZXRXZWJSdGNQZWVyKCkudmlkZW9FbmFibGVkID0gYWN0aXZhdGU7XG4gICAgfVxuXG4gICAgdG9nZ2xlTG9jYWxBdWRpb1RyYWNrKGFjdGl2YXRlOiBib29sZWFuKSB7XG4gICAgICAgIHRoaXMuZ2V0Q2FtZXJhKCkuZ2V0V2ViUnRjUGVlcigpLmF1ZGlvRW5hYmxlZCA9IGFjdGl2YXRlO1xuICAgIH1cblxuICAgIHB1Ymxpc2hMb2NhbFZpZGVvQXVkaW8oKSB7XG4gICAgICAgIHRoaXMudG9nZ2xlTG9jYWxWaWRlb1RyYWNrKHRydWUpO1xuICAgICAgICB0aGlzLnRvZ2dsZUxvY2FsQXVkaW9UcmFjayh0cnVlKTtcbiAgICB9XG5cbiAgICB1bnB1Ymxpc2hMb2NhbFZpZGVvQXVkaW8oKSB7XG4gICAgICAgIHRoaXMudG9nZ2xlTG9jYWxWaWRlb1RyYWNrKGZhbHNlKTtcbiAgICAgICAgdGhpcy50b2dnbGVMb2NhbEF1ZGlvVHJhY2soZmFsc2UpO1xuICAgIH1cblxuICAgIGdlbmVyYXRlTWVkaWFDb25zdHJhaW50cyhxdWFsaXR5OiBzdHJpbmcpIHtcbiAgICAgICAgbGV0IG1lZGlhQ29uc3RyYWludHMgPSB7XG4gICAgICAgICAgICBhdWRpbzogdHJ1ZSxcbiAgICAgICAgICAgIHZpZGVvOiB7fVxuICAgICAgICB9XG4gICAgICAgIGxldCB3LCBoO1xuICAgICAgICBzd2l0Y2ggKHF1YWxpdHkpIHtcbiAgICAgICAgICAgIGNhc2UgJ0xPVyc6XG4gICAgICAgICAgICAgICAgdyA9IDMyMDtcbiAgICAgICAgICAgICAgICBoID0gMjQwO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnTUVESVVNJzpcbiAgICAgICAgICAgICAgICB3ID0gNjQwO1xuICAgICAgICAgICAgICAgIGggPSA0ODA7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdISUdIJzpcbiAgICAgICAgICAgICAgICB3ID0gMTI4MDtcbiAgICAgICAgICAgICAgICBoID0gNzIwO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICB3ID0gNjQwO1xuICAgICAgICAgICAgICAgIGggPSA0ODA7XG4gICAgICAgIH1cbiAgICAgICAgbWVkaWFDb25zdHJhaW50cy52aWRlb1snd2lkdGgnXSA9IHsgZXhhY3Q6IHcgfTtcbiAgICAgICAgbWVkaWFDb25zdHJhaW50cy52aWRlb1snaGVpZ2h0J10gPSB7IGV4YWN0OiBoIH07XG4gICAgICAgIC8vbWVkaWFDb25zdHJhaW50cy52aWRlb1snZnJhbWVSYXRlJ10gPSB7IGlkZWFsOiBOdW1iZXIoKDxIVE1MSW5wdXRFbGVtZW50PmRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdmcmFtZVJhdGUnKSkudmFsdWUpIH07XG5cbiAgICAgICAgcmV0dXJuIG1lZGlhQ29uc3RyYWludHM7XG4gICAgfVxuXG59XG4iLCJpbXBvcnQgeyBTdHJlYW0gfSBmcm9tICcuL1N0cmVhbSc7XG5pbXBvcnQgeyBPcGVuVmlkdUludGVybmFsIH0gZnJvbSAnLi9PcGVuVmlkdUludGVybmFsJztcbmltcG9ydCB7IENvbm5lY3Rpb24sIENvbm5lY3Rpb25PcHRpb25zIH0gZnJvbSAnLi9Db25uZWN0aW9uJztcbmltcG9ydCBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCd3b2xmeTg3LWV2ZW50ZW1pdHRlcicpO1xuXG5leHBvcnQgaW50ZXJmYWNlIFNlc3Npb25PcHRpb25zIHtcbiAgICBzZXNzaW9uSWQ6IHN0cmluZztcbiAgICBwYXJ0aWNpcGFudElkOiBzdHJpbmc7XG4gICAgbWV0YWRhdGE6IHN0cmluZztcbiAgICBzdWJzY3JpYmVUb1N0cmVhbXM/OiBib29sZWFuO1xuICAgIHVwZGF0ZVNwZWFrZXJJbnRlcnZhbD86IG51bWJlcjtcbiAgICB0aHJlc2hvbGRTcGVha2VyPzogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgU2Vzc2lvbkludGVybmFsIHtcblxuICAgIHByaXZhdGUgaWQ6IHN0cmluZztcbiAgICBwcml2YXRlIGVlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICAgIHByaXZhdGUgc3RyZWFtcyA9IHt9O1xuICAgIHByaXZhdGUgcGFydGljaXBhbnRzID0ge307XG4gICAgcHJpdmF0ZSBwYXJ0aWNpcGFudHNTcGVha2luZzogQ29ubmVjdGlvbltdID0gW107XG4gICAgcHJpdmF0ZSBjb25uZWN0ZWQgPSBmYWxzZTtcbiAgICBwdWJsaWMgbG9jYWxQYXJ0aWNpcGFudDogQ29ubmVjdGlvbjtcbiAgICBwcml2YXRlIHN1YnNjcmliZVRvU3RyZWFtczogYm9vbGVhbjtcbiAgICBwcml2YXRlIHVwZGF0ZVNwZWFrZXJJbnRlcnZhbDogbnVtYmVyO1xuICAgIHB1YmxpYyB0aHJlc2hvbGRTcGVha2VyOiBudW1iZXI7XG4gICAgcHJpdmF0ZSBvcHRpb25zOiBTZXNzaW9uT3B0aW9uc1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBvcGVuVmlkdTogT3BlblZpZHVJbnRlcm5hbCwgcHJpdmF0ZSBzZXNzaW9uSWQ6IHN0cmluZykge1xuICAgICAgICB0aGlzLmxvY2FsUGFydGljaXBhbnQgPSBuZXcgQ29ubmVjdGlvbih0aGlzLm9wZW5WaWR1LCB0cnVlLCB0aGlzKTtcbiAgICB9XG5cblxuXG4gICAgLyogTkVXIE1FVEhPRFMgKi9cbiAgICBjb25uZWN0KHRva2VuLCBjYWxsYmFjaykge1xuXG4gICAgICAgIHRoaXMub3BlblZpZHUuY29ubmVjdCgoZXJyb3IpID0+IHtcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKCdFUlJPUiBDT05ORUNUSU5HIFRPIE9QRU5WSURVJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcblxuICAgICAgICAgICAgICAgIGxldCBqb2luUGFyYW1zID0ge1xuICAgICAgICAgICAgICAgICAgICB0b2tlbjogdG9rZW4sXG4gICAgICAgICAgICAgICAgICAgIHNlc3Npb246IHRoaXMuc2Vzc2lvbklkLFxuICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YTogdGhpcy5vcHRpb25zLm1ldGFkYXRhLFxuICAgICAgICAgICAgICAgICAgICBkYXRhQ2hhbm5lbHM6IGZhbHNlXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMubG9jYWxQYXJ0aWNpcGFudCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoT2JqZWN0LmtleXModGhpcy5sb2NhbFBhcnRpY2lwYW50LmdldFN0cmVhbXMoKSkuc29tZShzdHJlYW1JZCA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zdHJlYW1zW3N0cmVhbUlkXS5pc0RhdGFDaGFubmVsRW5hYmxlZCgpKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgam9pblBhcmFtcy5kYXRhQ2hhbm5lbHMgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5vcGVuVmlkdS5zZW5kUmVxdWVzdCgnam9pblJvb20nLCBqb2luUGFyYW1zLCAoZXJyb3IsIHJlc3BvbnNlKSA9PiB7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjaygnVU5BQkxFIFRPIEpPSU4gUk9PTScpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3RlZCA9IHRydWU7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBleFBhcnRpY2lwYW50cyA9IHJlc3BvbnNlLnZhbHVlO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJTVBPUlRBTlQ6IFVwZGF0ZSBjb25uZWN0aW9uSWQgd2l0aCB2YWx1ZSBzZW5kIGJ5IHNlcnZlclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2NhbFBhcnRpY2lwYW50LmNvbm5lY3Rpb25JZCA9IHJlc3BvbnNlLmlkO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wYXJ0aWNpcGFudHNbcmVzcG9uc2UuaWRdID0gdGhpcy5sb2NhbFBhcnRpY2lwYW50O1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgcm9vbUV2ZW50ID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50czogbmV3IEFycmF5PENvbm5lY3Rpb24+KCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyZWFtczogbmV3IEFycmF5PFN0cmVhbT4oKVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgbGVuZ3RoID0gZXhQYXJ0aWNpcGFudHMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGNvbm5lY3Rpb24gPSBuZXcgQ29ubmVjdGlvbih0aGlzLm9wZW5WaWR1LCBmYWxzZSwgdGhpcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhQYXJ0aWNpcGFudHNbaV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uY3JlYXRpb25UaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBhcnRpY2lwYW50c1tjb25uZWN0aW9uLmNvbm5lY3Rpb25JZF0gPSBjb25uZWN0aW9uO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcm9vbUV2ZW50LnBhcnRpY2lwYW50cy5wdXNoKGNvbm5lY3Rpb24pO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHN0cmVhbXMgPSBjb25uZWN0aW9uLmdldFN0cmVhbXMoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBrZXkgaW4gc3RyZWFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb29tRXZlbnQuc3RyZWFtcy5wdXNoKHN0cmVhbXNba2V5XSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnN1YnNjcmliZVRvU3RyZWFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyZWFtc1trZXldLnN1YnNjcmliZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVcGRhdGUgbG9jYWwgQ29ubmVjdGlvbiBvYmplY3QgcHJvcGVydGllcyB3aXRoIHZhbHVlcyByZXR1cm5lZCBieSBzZXJ2ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubG9jYWxQYXJ0aWNpcGFudC5kYXRhID0gcmVzcG9uc2UubWV0YWRhdGE7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvY2FsUGFydGljaXBhbnQuY3JlYXRpb25UaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVwZGF0ZXMgdGhlIHZhbHVlIG9mIHByb3BlcnR5ICdjb25uZWN0aW9uJyBpbiBTZXNzaW9uIG9iamVjdFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3VwZGF0ZS1jb25uZWN0aW9uLW9iamVjdCcsIFt7IGNvbm5lY3Rpb246IHRoaXMubG9jYWxQYXJ0aWNpcGFudCB9XSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBPd24gY29ubmVjdGlvbiBjcmVhdGVkIGV2ZW50XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnY29ubmVjdGlvbkNyZWF0ZWQnLCBbeyBjb25uZWN0aW9uOiB0aGlzLmxvY2FsUGFydGljaXBhbnQgfV0pO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBPbmUgY29ubmVjdGlvbiBjcmVhdGVkIGV2ZW50IGZvciBlYWNoIGV4aXN0aW5nIGNvbm5lY3Rpb24gaW4gdGhlIHNlc3Npb25cbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAobGV0IHBhcnQgb2Ygcm9vbUV2ZW50LnBhcnRpY2lwYW50cykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdjb25uZWN0aW9uQ3JlYXRlZCcsIFt7IGNvbm5lY3Rpb246IHBhcnQgfV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAvL2lmICh0aGlzLnN1YnNjcmliZVRvU3RyZWFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgc3RyZWFtIG9mIHJvb21FdmVudC5zdHJlYW1zKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3N0cmVhbS1hZGRlZCcsIFt7IHN0cmVhbSB9XSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBZGRpbmcgdGhlIHJlbW90ZSBzdHJlYW0gdG8gdGhlIE9wZW5WaWR1IG9iamVjdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMub3BlblZpZHUuZ2V0UmVtb3RlU3RyZWFtcygpLnB1c2goc3RyZWFtKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjayh1bmRlZmluZWQpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1Ymxpc2goKSB7XG4gICAgICAgIHRoaXMub3BlblZpZHUuZ2V0Q2FtZXJhKCkucHVibGlzaCgpO1xuICAgIH1cbiAgICAvKiBORVcgTUVUSE9EUyAqL1xuXG5cblxuXG5cbiAgICBjb25maWd1cmUob3B0aW9uczogU2Vzc2lvbk9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgICAgICAgdGhpcy5pZCA9IG9wdGlvbnMuc2Vzc2lvbklkO1xuICAgICAgICB0aGlzLnN1YnNjcmliZVRvU3RyZWFtcyA9IG9wdGlvbnMuc3Vic2NyaWJlVG9TdHJlYW1zID09IG51bGwgPyB0cnVlIDogb3B0aW9ucy5zdWJzY3JpYmVUb1N0cmVhbXM7XG4gICAgICAgIHRoaXMudXBkYXRlU3BlYWtlckludGVydmFsID0gb3B0aW9ucy51cGRhdGVTcGVha2VySW50ZXJ2YWwgfHwgMTUwMDtcbiAgICAgICAgdGhpcy50aHJlc2hvbGRTcGVha2VyID0gb3B0aW9ucy50aHJlc2hvbGRTcGVha2VyIHx8IC01MDtcbiAgICAgICAgdGhpcy5hY3RpdmF0ZVVwZGF0ZU1haW5TcGVha2VyKCk7XG4gICAgfVxuXG4gICAgZ2V0SWQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmlkO1xuICAgIH1cblxuICAgIGdldFNlc3Npb25JZCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2Vzc2lvbklkO1xuICAgIH1cblxuICAgIHByaXZhdGUgYWN0aXZhdGVVcGRhdGVNYWluU3BlYWtlcigpIHtcblxuICAgICAgICBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5wYXJ0aWNpcGFudHNTcGVha2luZy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3VwZGF0ZS1tYWluLXNwZWFrZXInLCBbe1xuICAgICAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudElkOiB0aGlzLnBhcnRpY2lwYW50c1NwZWFraW5nW3RoaXMucGFydGljaXBhbnRzU3BlYWtpbmcubGVuZ3RoIC0gMV1cbiAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIHRoaXMudXBkYXRlU3BlYWtlckludGVydmFsKTtcbiAgICB9XG5cbiAgICBnZXRMb2NhbFBhcnRpY2lwYW50KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5sb2NhbFBhcnRpY2lwYW50O1xuICAgIH1cblxuICAgIGFkZEV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCBsaXN0ZW5lcikge1xuICAgICAgICB0aGlzLmVlLm9uKGV2ZW50TmFtZSwgbGlzdGVuZXIpO1xuICAgIH1cblxuICAgIGFkZE9uY2VFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgbGlzdGVuZXIpIHtcbiAgICAgICAgdGhpcy5lZS5vbmNlKGV2ZW50TmFtZSwgbGlzdGVuZXIpO1xuICAgIH1cblxuICAgIHJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSwgbGlzdGVuZXIpIHtcbiAgICAgICAgdGhpcy5lZS5vZmYoZXZlbnROYW1lLCBsaXN0ZW5lcik7XG4gICAgfVxuXG4gICAgcmVtb3ZlRXZlbnQoZXZlbnROYW1lKSB7XG4gICAgICAgIHRoaXMuZWUucmVtb3ZlRXZlbnQoZXZlbnROYW1lKTtcbiAgICB9XG5cbiAgICBlbWl0RXZlbnQoZXZlbnROYW1lLCBldmVudHNBcnJheSkge1xuICAgICAgICB0aGlzLmVlLmVtaXRFdmVudChldmVudE5hbWUsIGV2ZW50c0FycmF5KTtcbiAgICB9XG5cblxuICAgIHN1YnNjcmliZShzdHJlYW06IFN0cmVhbSkge1xuICAgICAgICBzdHJlYW0uc3Vic2NyaWJlKCk7XG4gICAgfVxuXG4gICAgdW5zdXNjcmliZShzdHJlYW0pIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJVbnN1YnNjcmliaW5nIGZyb20gXCIgKyBzdHJlYW0uZ2V0SWQoKSk7XG4gICAgICAgIHRoaXMub3BlblZpZHUuc2VuZFJlcXVlc3QoJ3Vuc3Vic2NyaWJlRnJvbVZpZGVvJywge1xuICAgICAgICAgICAgc2VuZGVyOiBzdHJlYW0uZ2V0SWQoKVxuICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKGVycm9yLCByZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXCJVbnN1YnNjcmliZWQgY29ycmVjdGx5IGZyb20gXCIgKyBzdHJlYW0uZ2V0SWQoKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgb25QYXJ0aWNpcGFudFB1Ymxpc2hlZChvcHRpb25zKSB7XG5cbiAgICAgICAgb3B0aW9ucy5tZXRhZGF0YSA9IHRoaXMucGFydGljaXBhbnRzW29wdGlvbnMuaWRdLmRhdGE7XG5cbiAgICAgICAgbGV0IGNvbm5lY3Rpb24gPSBuZXcgQ29ubmVjdGlvbih0aGlzLm9wZW5WaWR1LCBmYWxzZSwgdGhpcywgb3B0aW9ucyk7XG5cbiAgICAgICAgbGV0IHBpZCA9IGNvbm5lY3Rpb24uY29ubmVjdGlvbklkO1xuICAgICAgICBpZiAoIShwaWQgaW4gdGhpcy5wYXJ0aWNpcGFudHMpKSB7XG4gICAgICAgICAgICBjb25zb2xlLmluZm8oXCJQdWJsaXNoZXIgbm90IGZvdW5kIGluIHBhcnRpY2lwYW50cyBsaXN0IGJ5IGl0cyBpZFwiLCBwaWQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS5sb2coXCJQdWJsaXNoZXIgZm91bmQgaW4gcGFydGljaXBhbnRzIGxpc3QgYnkgaXRzIGlkXCIsIHBpZCk7XG4gICAgICAgIH1cbiAgICAgICAgLy9yZXBsYWNpbmcgb2xkIGNvbm5lY3Rpb24gKHRoaXMgb25lIGhhcyBzdHJlYW1zKVxuICAgICAgICBjb25uZWN0aW9uLmNyZWF0aW9uVGltZSA9IHRoaXMucGFydGljaXBhbnRzW3BpZF0uY3JlYXRpb25UaW1lO1xuICAgICAgICB0aGlzLnBhcnRpY2lwYW50c1twaWRdID0gY29ubmVjdGlvbjtcblxuICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgncGFydGljaXBhbnQtcHVibGlzaGVkJywgW3sgY29ubmVjdGlvbiB9XSk7XG5cbiAgICAgICAgbGV0IHN0cmVhbXMgPSBjb25uZWN0aW9uLmdldFN0cmVhbXMoKTtcbiAgICAgICAgZm9yIChsZXQga2V5IGluIHN0cmVhbXMpIHtcbiAgICAgICAgICAgIGxldCBzdHJlYW0gPSBzdHJlYW1zW2tleV07XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnN1YnNjcmliZVRvU3RyZWFtcykge1xuICAgICAgICAgICAgICAgIHN0cmVhbS5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdzdHJlYW0tYWRkZWQnLCBbeyBzdHJlYW0gfV0pO1xuICAgICAgICAgICAgLy8gQWRkaW5nIHRoZSByZW1vdGUgc3RyZWFtIHRvIHRoZSBPcGVuVmlkdSBvYmplY3RcbiAgICAgICAgICAgIHRoaXMub3BlblZpZHUuZ2V0UmVtb3RlU3RyZWFtcygpLnB1c2goc3RyZWFtKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uUGFydGljaXBhbnRKb2luZWQobXNnKSB7XG5cbiAgICAgICAgbGV0IGNvbm5lY3Rpb24gPSBuZXcgQ29ubmVjdGlvbih0aGlzLm9wZW5WaWR1LCBmYWxzZSwgdGhpcywgbXNnKTtcbiAgICAgICAgY29ubmVjdGlvbi5jcmVhdGlvblRpbWUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcblxuICAgICAgICBsZXQgcGlkID0gY29ubmVjdGlvbi5jb25uZWN0aW9uSWQ7XG4gICAgICAgIGlmICghKHBpZCBpbiB0aGlzLnBhcnRpY2lwYW50cykpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiTmV3IHBhcnRpY2lwYW50IHRvIHBhcnRpY2lwYW50cyBsaXN0IHdpdGggaWRcIiwgcGlkKTtcbiAgICAgICAgICAgIHRoaXMucGFydGljaXBhbnRzW3BpZF0gPSBjb25uZWN0aW9uO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy91c2UgZXhpc3Rpbmcgc28gdGhhdCB3ZSBkb24ndCBsb3NlIHN0cmVhbXMgaW5mb1xuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiUGFydGljaXBhbnQgYWxyZWFkeSBleGlzdHMgaW4gcGFydGljaXBhbnRzIGxpc3Qgd2l0aCBcIiArXG4gICAgICAgICAgICAgICAgXCJ0aGUgc2FtZSBpZCwgb2xkOlwiLCB0aGlzLnBhcnRpY2lwYW50c1twaWRdLCBcIiwgam9pbmVkIG5vdzpcIiwgY29ubmVjdGlvbik7XG4gICAgICAgICAgICBjb25uZWN0aW9uID0gdGhpcy5wYXJ0aWNpcGFudHNbcGlkXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdwYXJ0aWNpcGFudC1qb2luZWQnLCBbe1xuICAgICAgICAgICAgY29ubmVjdGlvbjogY29ubmVjdGlvblxuICAgICAgICB9XSk7XG5cbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2Nvbm5lY3Rpb25DcmVhdGVkJywgW3tcbiAgICAgICAgICAgIGNvbm5lY3Rpb246IGNvbm5lY3Rpb25cbiAgICAgICAgfV0pO1xuXG4gICAgfVxuXG4gICAgb25QYXJ0aWNpcGFudExlZnQobXNnKSB7XG5cbiAgICAgICAgbGV0IGNvbm5lY3Rpb24gPSB0aGlzLnBhcnRpY2lwYW50c1ttc2cubmFtZV07XG5cbiAgICAgICAgaWYgKGNvbm5lY3Rpb24gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMucGFydGljaXBhbnRzW21zZy5uYW1lXTtcblxuICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3BhcnRpY2lwYW50LWxlZnQnLCBbe1xuICAgICAgICAgICAgICAgIGNvbm5lY3Rpb246IGNvbm5lY3Rpb25cbiAgICAgICAgICAgIH1dKTtcblxuICAgICAgICAgICAgbGV0IHN0cmVhbXMgPSBjb25uZWN0aW9uLmdldFN0cmVhbXMoKTtcbiAgICAgICAgICAgIGZvciAobGV0IGtleSBpbiBzdHJlYW1zKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3N0cmVhbS1yZW1vdmVkJywgW3tcbiAgICAgICAgICAgICAgICAgICAgc3RyZWFtOiBzdHJlYW1zW2tleV0sXG4gICAgICAgICAgICAgICAgICAgIHByZXZlbnREZWZhdWx0OiAoKSA9PiB7IHRoaXMuZWUucmVtb3ZlRXZlbnQoJ3N0cmVhbS1yZW1vdmVkLWRlZmF1bHQnKTsgfVxuICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnc3RyZWFtLXJlbW92ZWQtZGVmYXVsdCcsIFt7XG4gICAgICAgICAgICAgICAgICAgIHN0cmVhbTogc3RyZWFtc1trZXldXG4gICAgICAgICAgICAgICAgfV0pO1xuXG4gICAgICAgICAgICAgICAgLy8gRGVsZXRpbmcgdGhlIHJlbW92ZWQgc3RyZWFtIGZyb20gdGhlIE9wZW5WaWR1IG9iamVjdFxuICAgICAgICAgICAgICAgIGxldCBpbmRleCA9IHRoaXMub3BlblZpZHUuZ2V0UmVtb3RlU3RyZWFtcygpLmluZGV4T2Yoc3RyZWFtc1trZXldKTtcbiAgICAgICAgICAgICAgICB0aGlzLm9wZW5WaWR1LmdldFJlbW90ZVN0cmVhbXMoKS5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25uZWN0aW9uLmRpc3Bvc2UoKTtcblxuICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2Nvbm5lY3Rpb25EZXN0cm95ZWQnLCBbe1xuICAgICAgICAgICAgICAgIGNvbm5lY3Rpb246IGNvbm5lY3Rpb25cbiAgICAgICAgICAgIH1dKTtcblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFwiUGFydGljaXBhbnQgXCIgKyBtc2cubmFtZVxuICAgICAgICAgICAgICAgICsgXCIgdW5rbm93bi4gUGFydGljaXBhbnRzOiBcIlxuICAgICAgICAgICAgICAgICsgSlNPTi5zdHJpbmdpZnkodGhpcy5wYXJ0aWNpcGFudHMpKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBvblBhcnRpY2lwYW50RXZpY3RlZChtc2cpIHtcbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3BhcnRpY2lwYW50LWV2aWN0ZWQnLCBbe1xuICAgICAgICAgICAgbG9jYWxQYXJ0aWNpcGFudDogdGhpcy5sb2NhbFBhcnRpY2lwYW50XG4gICAgICAgIH1dKTtcbiAgICB9O1xuXG4gICAgb25OZXdNZXNzYWdlKG1zZykge1xuXG4gICAgICAgIGNvbnNvbGUubG9nKFwiTmV3IG1lc3NhZ2U6IFwiICsgSlNPTi5zdHJpbmdpZnkobXNnKSk7XG4gICAgICAgIGxldCByb29tID0gbXNnLnJvb207XG4gICAgICAgIGxldCB1c2VyID0gbXNnLnVzZXI7XG4gICAgICAgIGxldCBtZXNzYWdlID0gbXNnLm1lc3NhZ2U7XG5cbiAgICAgICAgaWYgKHVzZXIgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ25ld01lc3NhZ2UnLCBbe1xuICAgICAgICAgICAgICAgIHJvb206IHJvb20sXG4gICAgICAgICAgICAgICAgdXNlcjogdXNlcixcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBtZXNzYWdlXG4gICAgICAgICAgICB9XSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJVc2VyIHVuZGVmaW5lZCBpbiBuZXcgbWVzc2FnZTpcIiwgbXNnKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJlY3ZJY2VDYW5kaWRhdGUobXNnKSB7XG5cbiAgICAgICAgbGV0IGNhbmRpZGF0ZSA9IHtcbiAgICAgICAgICAgIGNhbmRpZGF0ZTogbXNnLmNhbmRpZGF0ZSxcbiAgICAgICAgICAgIHNkcE1pZDogbXNnLnNkcE1pZCxcbiAgICAgICAgICAgIHNkcE1MaW5lSW5kZXg6IG1zZy5zZHBNTGluZUluZGV4XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgY29ubmVjdGlvbiA9IHRoaXMucGFydGljaXBhbnRzW21zZy5lbmRwb2ludE5hbWVdO1xuICAgICAgICBpZiAoIWNvbm5lY3Rpb24pIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJQYXJ0aWNpcGFudCBub3QgZm91bmQgZm9yIGVuZHBvaW50IFwiICtcbiAgICAgICAgICAgICAgICBtc2cuZW5kcG9pbnROYW1lICsgXCIuIEljZSBjYW5kaWRhdGUgd2lsbCBiZSBpZ25vcmVkLlwiLFxuICAgICAgICAgICAgICAgIGNhbmRpZGF0ZSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgc3RyZWFtcyA9IGNvbm5lY3Rpb24uZ2V0U3RyZWFtcygpO1xuICAgICAgICBmb3IgKGxldCBrZXkgaW4gc3RyZWFtcykge1xuICAgICAgICAgICAgbGV0IHN0cmVhbSA9IHN0cmVhbXNba2V5XTtcbiAgICAgICAgICAgIHN0cmVhbS5nZXRXZWJSdGNQZWVyKCkuYWRkSWNlQ2FuZGlkYXRlKGNhbmRpZGF0ZSwgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBhZGRpbmcgY2FuZGlkYXRlIGZvciBcIiArIGtleVxuICAgICAgICAgICAgICAgICAgICAgICAgKyBcIiBzdHJlYW0gb2YgZW5kcG9pbnQgXCIgKyBtc2cuZW5kcG9pbnROYW1lXG4gICAgICAgICAgICAgICAgICAgICAgICArIFwiOiBcIiArIGVycm9yKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uUm9vbUNsb3NlZChtc2cpIHtcblxuICAgICAgICBjb25zb2xlLmxvZyhcIlJvb20gY2xvc2VkOiBcIiArIEpTT04uc3RyaW5naWZ5KG1zZykpO1xuICAgICAgICBsZXQgcm9vbSA9IG1zZy5yb29tO1xuICAgICAgICBpZiAocm9vbSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgncm9vbS1jbG9zZWQnLCBbe1xuICAgICAgICAgICAgICAgIHJvb206IHJvb21cbiAgICAgICAgICAgIH1dKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcIlJvb20gdW5kZWZpbmVkIGluIG9uIHJvb20gY2xvc2VkXCIsIG1zZyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBvbkxvc3RDb25uZWN0aW9uKCkge1xuXG4gICAgICAgIGlmICghdGhpcy5jb25uZWN0ZWQpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybignTm90IGNvbm5lY3RlZCB0byByb29tOiBpZiB5b3UgYXJlIG5vdCBkZWJ1Z2dpbmcsIHRoaXMgaXMgcHJvYmFibHkgYSBjZXJ0aWZpY2F0ZSBlcnJvcicpO1xuICAgICAgICAgICAgaWYgKHdpbmRvdy5jb25maXJtKCdJZiB5b3UgYXJlIG5vdCBkZWJ1Z2dpbmcsIHRoaXMgaXMgcHJvYmFibHkgYSBjZXJ0aWZpY2F0ZSBlcnJvciBhdCBcXFwiJyArIHRoaXMub3BlblZpZHUuZ2V0T3BlblZpZHVTZXJ2ZXJVUkwoKSArICdcXFwiXFxuXFxuQ2xpY2sgT0sgdG8gbmF2aWdhdGUgYW5kIGFjY2VwdCBpdCcpKSB7XG4gICAgICAgICAgICAgICAgbG9jYXRpb24uYXNzaWduKHRoaXMub3BlblZpZHUuZ2V0T3BlblZpZHVTZXJ2ZXJVUkwoKSArICcvYWNjZXB0LWNlcnRpZmljYXRlJyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc29sZS5sb2coJ0xvc3QgY29ubmVjdGlvbiBpbiByb29tICcgKyB0aGlzLmlkKTtcbiAgICAgICAgbGV0IHJvb20gPSB0aGlzLmlkO1xuICAgICAgICBpZiAocm9vbSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnbG9zdC1jb25uZWN0aW9uJywgW3sgcm9vbSB9XSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oJ1Jvb20gdW5kZWZpbmVkIHdoZW4gbG9zdCBjb25uZWN0aW9uJyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBvbk1lZGlhRXJyb3IocGFyYW1zKSB7XG5cbiAgICAgICAgY29uc29sZS5lcnJvcihcIk1lZGlhIGVycm9yOiBcIiArIEpTT04uc3RyaW5naWZ5KHBhcmFtcykpO1xuICAgICAgICBsZXQgZXJyb3IgPSBwYXJhbXMuZXJyb3I7XG4gICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2Vycm9yLW1lZGlhJywgW3tcbiAgICAgICAgICAgICAgICBlcnJvcjogZXJyb3JcbiAgICAgICAgICAgIH1dKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcIlJlY2VpdmVkIHVuZGVmaW5lZCBtZWRpYSBlcnJvci4gUGFyYW1zOlwiLCBwYXJhbXMpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLypcbiAgICAgKiBmb3JjZWQgbWVhbnMgdGhlIHVzZXIgd2FzIGV2aWN0ZWQsIG5vIG5lZWQgdG8gc2VuZCB0aGUgJ2xlYXZlUm9vbScgcmVxdWVzdFxuICAgICAqL1xuICAgIGxlYXZlKGZvcmNlZCwganNvblJwY0NsaWVudCkge1xuXG4gICAgICAgIGZvcmNlZCA9ICEhZm9yY2VkO1xuXG4gICAgICAgIGNvbnNvbGUubG9nKFwiTGVhdmluZyByb29tIChmb3JjZWQ9XCIgKyBmb3JjZWQgKyBcIilcIik7XG5cbiAgICAgICAgaWYgKHRoaXMuY29ubmVjdGVkICYmICFmb3JjZWQpIHtcbiAgICAgICAgICAgIHRoaXMub3BlblZpZHUuc2VuZFJlcXVlc3QoJ2xlYXZlUm9vbScsIGZ1bmN0aW9uIChlcnJvciwgcmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGpzb25ScGNDbGllbnQuY2xvc2UoKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAganNvblJwY0NsaWVudC5jbG9zZSgpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY29ubmVjdGVkID0gZmFsc2U7XG4gICAgICAgIGlmICh0aGlzLnBhcnRpY2lwYW50cykge1xuICAgICAgICAgICAgZm9yIChsZXQgcGlkIGluIHRoaXMucGFydGljaXBhbnRzKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5wYXJ0aWNpcGFudHNbcGlkXS5kaXNwb3NlKCk7XG4gICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMucGFydGljaXBhbnRzW3BpZF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBkaXNjb25uZWN0KHN0cmVhbTogU3RyZWFtKSB7XG5cbiAgICAgICAgbGV0IGNvbm5lY3Rpb24gPSBzdHJlYW0uZ2V0UGFydGljaXBhbnQoKTtcbiAgICAgICAgaWYgKCFjb25uZWN0aW9uKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiU3RyZWFtIHRvIGRpc2Nvbm5lY3QgaGFzIG5vIHBhcnRpY2lwYW50XCIsIHN0cmVhbSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBkZWxldGUgdGhpcy5wYXJ0aWNpcGFudHNbY29ubmVjdGlvbi5jb25uZWN0aW9uSWRdO1xuICAgICAgICBjb25uZWN0aW9uLmRpc3Bvc2UoKTtcblxuICAgICAgICBpZiAoY29ubmVjdGlvbiA9PT0gdGhpcy5sb2NhbFBhcnRpY2lwYW50KSB7XG5cbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiVW5wdWJsaXNoaW5nIG15IG1lZGlhIChJJ20gXCIgKyBjb25uZWN0aW9uLmNvbm5lY3Rpb25JZCArIFwiKVwiKTtcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmxvY2FsUGFydGljaXBhbnQ7XG4gICAgICAgICAgICB0aGlzLm9wZW5WaWR1LnNlbmRSZXF1ZXN0KCd1bnB1Ymxpc2hWaWRlbycsIGZ1bmN0aW9uIChlcnJvciwgcmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiTWVkaWEgdW5wdWJsaXNoZWQgY29ycmVjdGx5XCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnVuc3VzY3JpYmUoc3RyZWFtKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHVucHVibGlzaChzdHJlYW06IFN0cmVhbSkge1xuXG4gICAgICAgIGxldCBjb25uZWN0aW9uID0gc3RyZWFtLmdldFBhcnRpY2lwYW50KCk7XG4gICAgICAgIGlmICghY29ubmVjdGlvbikge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIlN0cmVhbSB0byBkaXNjb25uZWN0IGhhcyBubyBwYXJ0aWNpcGFudFwiLCBzdHJlYW0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNvbm5lY3Rpb24gPT09IHRoaXMubG9jYWxQYXJ0aWNpcGFudCkge1xuXG4gICAgICAgICAgICBkZWxldGUgdGhpcy5wYXJ0aWNpcGFudHNbY29ubmVjdGlvbi5jb25uZWN0aW9uSWRdO1xuICAgICAgICAgICAgY29ubmVjdGlvbi5kaXNwb3NlKCk7XG5cbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiVW5wdWJsaXNoaW5nIG15IG1lZGlhIChJJ20gXCIgKyBjb25uZWN0aW9uLmNvbm5lY3Rpb25JZCArIFwiKVwiKTtcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmxvY2FsUGFydGljaXBhbnQ7XG4gICAgICAgICAgICB0aGlzLm9wZW5WaWR1LnNlbmRSZXF1ZXN0KCd1bnB1Ymxpc2hWaWRlbycsIGZ1bmN0aW9uIChlcnJvciwgcmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiTWVkaWEgdW5wdWJsaXNoZWQgY29ycmVjdGx5XCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZ2V0U3RyZWFtcygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RyZWFtcztcbiAgICB9XG5cbiAgICBhZGRQYXJ0aWNpcGFudFNwZWFraW5nKHBhcnRpY2lwYW50SWQpIHtcbiAgICAgICAgdGhpcy5wYXJ0aWNpcGFudHNTcGVha2luZy5wdXNoKHBhcnRpY2lwYW50SWQpO1xuICAgIH1cblxuICAgIHJlbW92ZVBhcnRpY2lwYW50U3BlYWtpbmcocGFydGljaXBhbnRJZCkge1xuICAgICAgICBsZXQgcG9zID0gLTE7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5wYXJ0aWNpcGFudHNTcGVha2luZy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKHRoaXMucGFydGljaXBhbnRzU3BlYWtpbmdbaV0gPT0gcGFydGljaXBhbnRJZCkge1xuICAgICAgICAgICAgICAgIHBvcyA9IGk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHBvcyAhPSAtMSkge1xuICAgICAgICAgICAgdGhpcy5wYXJ0aWNpcGFudHNTcGVha2luZy5zcGxpY2UocG9zLCAxKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsIi8qXG4gKiBvcHRpb25zOiBuYW1lOiBYWFggZGF0YTogdHJ1ZSAoTWF5YmUgdGhpcyBpcyBiYXNlZCBvbiB3ZWJydGMpIGF1ZGlvOiB0cnVlLFxuICogdmlkZW86IHRydWUsIHVybDogXCJmaWxlOi8vLy4uLlwiID4gUGxheWVyIHNjcmVlbjogdHJ1ZSA+IERlc2t0b3AgKGltcGxpY2l0XG4gKiB2aWRlbzp0cnVlLCBhdWRpbzpmYWxzZSkgYXVkaW86IHRydWUsIHZpZGVvOiB0cnVlID4gV2ViY2FtXG4gKlxuICogc3RyZWFtLmhhc0F1ZGlvKCk7IHN0cmVhbS5oYXNWaWRlbygpOyBzdHJlYW0uaGFzRGF0YSgpO1xuICovXG5pbXBvcnQgeyBDb25uZWN0aW9uIH0gZnJvbSAnLi9Db25uZWN0aW9uJztcbmltcG9ydCB7IFNlc3Npb25JbnRlcm5hbCB9IGZyb20gJy4vU2Vzc2lvbkludGVybmFsJztcbmltcG9ydCB7IE9wZW5WaWR1SW50ZXJuYWwsIENhbGxiYWNrIH0gZnJvbSAnLi9PcGVuVmlkdUludGVybmFsJztcbmltcG9ydCBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCd3b2xmeTg3LWV2ZW50ZW1pdHRlcicpO1xuaW1wb3J0ICogYXMga3VyZW50b1V0aWxzIGZyb20gJ2t1cmVudG8tdXRpbHMnO1xuXG5pbXBvcnQgKiBhcyBhZGFwdGVyIGZyb20gJ3dlYnJ0Yy1hZGFwdGVyJztcbmRlY2xhcmUgdmFyIG5hdmlnYXRvcjogYW55O1xuZGVjbGFyZSB2YXIgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uOiBhbnk7XG5cbmlmICh3aW5kb3cpIHtcbiAgICB3aW5kb3dbXCJhZGFwdGVyXCJdID0gYWRhcHRlcjtcbn1cblxuZnVuY3Rpb24ganEoaWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGlkLnJlcGxhY2UoLyhAfDp8XFwufFxcW3xcXF18LCkvZywgXCJcXFxcJDFcIik7XG59XG5cbmZ1bmN0aW9uIHNob3coaWQ6IHN0cmluZykge1xuICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGpxKGlkKSkhLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xufVxuXG5mdW5jdGlvbiBoaWRlKGlkOiBzdHJpbmcpIHtcbiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChqcShpZCkpIS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFN0cmVhbU9wdGlvbnMge1xuICAgIGlkOiBzdHJpbmc7XG4gICAgY29ubmVjdGlvbjogQ29ubmVjdGlvbjtcbiAgICByZWN2VmlkZW86IGFueTtcbiAgICByZWN2QXVkaW86IGFueTtcbiAgICB2aWRlbzogYm9vbGVhbjtcbiAgICBhdWRpbzogYm9vbGVhbjtcbiAgICBkYXRhOiBib29sZWFuO1xuICAgIG1lZGlhQ29uc3RyYWludHM6IGFueTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBWaWRlb09wdGlvbnMge1xuICAgIHRodW1iOiBzdHJpbmc7XG4gICAgdmlkZW86IEhUTUxWaWRlb0VsZW1lbnQ7XG59XG5cbmV4cG9ydCBjbGFzcyBTdHJlYW0ge1xuXG4gICAgcHVibGljIGNvbm5lY3Rpb246IENvbm5lY3Rpb247XG5cbiAgICBwcml2YXRlIGVlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICAgIHByaXZhdGUgd3JTdHJlYW06IGFueTtcbiAgICBwcml2YXRlIHdwOiBhbnk7XG4gICAgcHJpdmF0ZSBpZDogc3RyaW5nO1xuICAgIHByaXZhdGUgdmlkZW86IEhUTUxWaWRlb0VsZW1lbnQ7XG4gICAgcHJpdmF0ZSB2aWRlb0VsZW1lbnRzOiBWaWRlb09wdGlvbnNbXSA9IFtdO1xuICAgIHByaXZhdGUgZWxlbWVudHM6IEhUTUxEaXZFbGVtZW50W10gPSBbXTtcbiAgICBwcml2YXRlIHNwZWVjaEV2ZW50OiBhbnk7XG4gICAgcHJpdmF0ZSByZWN2VmlkZW86IGFueTtcbiAgICBwcml2YXRlIHJlY3ZBdWRpbzogYW55O1xuICAgIHByaXZhdGUgc2VuZFZpZGVvOiBib29sZWFuO1xuICAgIHByaXZhdGUgc2VuZEF1ZGlvOiBib29sZWFuO1xuICAgIHByaXZhdGUgbWVkaWFDb25zdHJhaW50czogYW55O1xuICAgIHByaXZhdGUgc2hvd015UmVtb3RlID0gZmFsc2U7XG4gICAgcHJpdmF0ZSBsb2NhbE1pcnJvcmVkID0gZmFsc2U7XG4gICAgcHJpdmF0ZSBjaGFuSWQgPSAwO1xuICAgIHByaXZhdGUgZGF0YUNoYW5uZWw6IGJvb2xlYW47XG4gICAgcHJpdmF0ZSBkYXRhQ2hhbm5lbE9wZW5lZCA9IGZhbHNlO1xuXG4gICAgcHJpdmF0ZSB2aWRlb1NyYzogc3RyaW5nO1xuICAgIHByaXZhdGUgcGFyZW50SWQ6IHN0cmluZztcbiAgICBwdWJsaWMgaXNSZWFkeTogYm9vbGVhbiA9IGZhbHNlO1xuICAgIHB1YmxpYyBhY2Nlc3NJc0FsbG93ZWQ6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBwdWJsaWMgYWNjZXNzSXNEZW5pZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgb3BlblZpZHU6IE9wZW5WaWR1SW50ZXJuYWwsIHByaXZhdGUgbG9jYWw6IGJvb2xlYW4sIHByaXZhdGUgcm9vbTogU2Vzc2lvbkludGVybmFsLCBvcHRpb25zOiBTdHJlYW1PcHRpb25zKSB7XG5cbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHRoaXMuaWQgPSBvcHRpb25zLmlkO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5pZCA9IFwid2ViY2FtXCI7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmNvbm5lY3Rpb24gPSBvcHRpb25zLmNvbm5lY3Rpb247XG4gICAgICAgIHRoaXMucmVjdlZpZGVvID0gb3B0aW9ucy5yZWN2VmlkZW87XG4gICAgICAgIHRoaXMucmVjdkF1ZGlvID0gb3B0aW9ucy5yZWN2QXVkaW87XG4gICAgICAgIHRoaXMuZGF0YUNoYW5uZWwgPSBvcHRpb25zLmRhdGEgfHwgZmFsc2U7XG4gICAgICAgIHRoaXMuc2VuZFZpZGVvID0gb3B0aW9ucy52aWRlbztcbiAgICAgICAgdGhpcy5zZW5kQXVkaW8gPSBvcHRpb25zLmF1ZGlvO1xuICAgICAgICB0aGlzLm1lZGlhQ29uc3RyYWludHMgPSBvcHRpb25zLm1lZGlhQ29uc3RyYWludHM7XG5cbiAgICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVyKCdzcmMtYWRkZWQnLCAoc3JjRXZlbnQpID0+IHtcbiAgICAgICAgICAgIHRoaXMudmlkZW9TcmMgPSBzcmNFdmVudC5zcmM7XG4gICAgICAgICAgICBpZiAodGhpcy52aWRlbykgdGhpcy52aWRlby5zcmMgPSBzcmNFdmVudC5zcmM7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJWaWRlb3NyYyBbXCIgKyBzcmNFdmVudC5zcmMgKyBcIl0gYWRkZWQgdG8gc3RyZWFtIFtcIiArIHRoaXMuZ2V0SWQoKSArIFwiXVwiKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgZW1pdFNyY0V2ZW50KHdyc3RyZWFtKSB7XG4gICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdzcmMtYWRkZWQnLCBbe1xuICAgICAgICAgICAgc3JjOiBVUkwuY3JlYXRlT2JqZWN0VVJMKHdyc3RyZWFtKVxuICAgICAgICB9XSk7XG4gICAgfVxuXG4gICAgZW1pdFN0cmVhbVJlYWR5RXZlbnQoKSB7XG4gICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdzdHJlYW0tcmVhZHknKSwgW3t9XTtcbiAgICB9XG5cbiAgICBnZXRWaWRlb1NyYygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmlkZW9TcmM7XG4gICAgfVxuXG4gICAgcmVtb3ZlVmlkZW8ocGFyZW50RWxlbWVudDogc3RyaW5nKTtcbiAgICByZW1vdmVWaWRlbyhwYXJlbnRFbGVtZW50OiBFbGVtZW50KTtcbiAgICByZW1vdmVWaWRlbygpO1xuXG4gICAgcmVtb3ZlVmlkZW8ocGFyZW50RWxlbWVudD8pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBwYXJlbnRFbGVtZW50ID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChwYXJlbnRFbGVtZW50KSEucmVtb3ZlQ2hpbGQodGhpcy52aWRlbyk7XG4gICAgICAgIH0gZWxzZSBpZiAocGFyZW50RWxlbWVudCBpbnN0YW5jZW9mIEVsZW1lbnQpIHtcbiAgICAgICAgICAgIHBhcmVudEVsZW1lbnQucmVtb3ZlQ2hpbGQodGhpcy52aWRlbyk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoIXBhcmVudEVsZW1lbnQpIHtcbiAgICAgICAgICAgIGlmIChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnBhcmVudElkKSkge1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMucGFyZW50SWQpIS5yZW1vdmVDaGlsZCh0aGlzLnZpZGVvKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldFZpZGVvRWxlbWVudCgpOiBIVE1MVmlkZW9FbGVtZW50IHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmlkZW87XG4gICAgfVxuXG4gICAgc2V0VmlkZW9FbGVtZW50KHZpZGVvOiBIVE1MVmlkZW9FbGVtZW50KSB7XG4gICAgICAgIHRoaXMudmlkZW8gPSB2aWRlbztcbiAgICB9XG5cblxuXG5cblxuXG4gICAgZ2V0UmVjdlZpZGVvKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5yZWN2VmlkZW87XG4gICAgfVxuXG4gICAgZ2V0UmVjdkF1ZGlvKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5yZWN2QXVkaW87XG4gICAgfVxuXG5cbiAgICBzdWJzY3JpYmVUb015UmVtb3RlKCkge1xuICAgICAgICB0aGlzLnNob3dNeVJlbW90ZSA9IHRydWU7XG4gICAgfVxuXG4gICAgZGlzcGxheU15UmVtb3RlKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zaG93TXlSZW1vdGU7XG4gICAgfVxuXG4gICAgbWlycm9yTG9jYWxTdHJlYW0od3IpIHtcbiAgICAgICAgdGhpcy5zaG93TXlSZW1vdGUgPSB0cnVlO1xuICAgICAgICB0aGlzLmxvY2FsTWlycm9yZWQgPSB0cnVlO1xuICAgICAgICBpZiAod3IpIHtcbiAgICAgICAgICAgIHRoaXMud3JTdHJlYW0gPSB3cjtcbiAgICAgICAgICAgIHRoaXMuZW1pdFNyY0V2ZW50KHRoaXMud3JTdHJlYW0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaXNMb2NhbE1pcnJvcmVkKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5sb2NhbE1pcnJvcmVkO1xuICAgIH1cblxuICAgIGdldENoYW5uZWxOYW1lKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRJZCgpICsgJ18nICsgdGhpcy5jaGFuSWQrKztcbiAgICB9XG5cblxuICAgIGlzRGF0YUNoYW5uZWxFbmFibGVkKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5kYXRhQ2hhbm5lbDtcbiAgICB9XG5cblxuICAgIGlzRGF0YUNoYW5uZWxPcGVuZWQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRhdGFDaGFubmVsT3BlbmVkO1xuICAgIH1cblxuICAgIG9uRGF0YUNoYW5uZWxPcGVuKGV2ZW50KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdEYXRhIGNoYW5uZWwgaXMgb3BlbmVkJyk7XG4gICAgICAgIHRoaXMuZGF0YUNoYW5uZWxPcGVuZWQgPSB0cnVlO1xuICAgIH1cblxuICAgIG9uRGF0YUNoYW5uZWxDbG9zZWQoZXZlbnQpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ0RhdGEgY2hhbm5lbCBpcyBjbG9zZWQnKTtcbiAgICAgICAgdGhpcy5kYXRhQ2hhbm5lbE9wZW5lZCA9IGZhbHNlO1xuICAgIH1cblxuICAgIHNlbmREYXRhKGRhdGEpIHtcbiAgICAgICAgaWYgKHRoaXMud3AgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdXZWJSVEMgcGVlciBoYXMgbm90IGJlZW4gY3JlYXRlZCB5ZXQnKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMuZGF0YUNoYW5uZWxPcGVuZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRGF0YSBjaGFubmVsIGlzIG5vdCBvcGVuZWQnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmxvZyhcIlNlbmRpbmcgdGhyb3VnaCBkYXRhIGNoYW5uZWw6IFwiICsgZGF0YSk7XG4gICAgICAgIHRoaXMud3Auc2VuZChkYXRhKTtcbiAgICB9XG5cbiAgICBnZXRXclN0cmVhbSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMud3JTdHJlYW07XG4gICAgfVxuXG4gICAgZ2V0V2ViUnRjUGVlcigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMud3A7XG4gICAgfVxuXG4gICAgYWRkRXZlbnRMaXN0ZW5lcihldmVudE5hbWU6IHN0cmluZywgbGlzdGVuZXI6IGFueSkge1xuICAgICAgICB0aGlzLmVlLmFkZExpc3RlbmVyKGV2ZW50TmFtZSwgbGlzdGVuZXIpO1xuICAgIH1cblxuICAgIGFkZE9uY2VFdmVudExpc3RlbmVyKGV2ZW50TmFtZTogc3RyaW5nLCBsaXN0ZW5lcjogYW55KSB7XG4gICAgICAgIHRoaXMuZWUuYWRkT25jZUxpc3RlbmVyKGV2ZW50TmFtZSwgbGlzdGVuZXIpO1xuICAgIH1cblxuICAgIHJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSkge1xuICAgICAgICB0aGlzLmVlLnJlbW92ZUFsbExpc3RlbmVycyhldmVudE5hbWUpO1xuICAgIH1cblxuICAgIHNob3dTcGlubmVyKHNwaW5uZXJQYXJlbnRJZDogc3RyaW5nKSB7XG4gICAgICAgIGxldCBwcm9ncmVzcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICBwcm9ncmVzcy5pZCA9ICdwcm9ncmVzcy0nICsgdGhpcy5nZXRJZCgpO1xuICAgICAgICBwcm9ncmVzcy5zdHlsZS5iYWNrZ3JvdW5kID0gXCJjZW50ZXIgdHJhbnNwYXJlbnQgdXJsKCdpbWcvc3Bpbm5lci5naWYnKSBuby1yZXBlYXRcIjtcbiAgICAgICAgbGV0IHNwaW5uZXJQYXJlbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChzcGlubmVyUGFyZW50SWQpO1xuICAgICAgICBpZiAoc3Bpbm5lclBhcmVudCkge1xuICAgICAgICAgICAgc3Bpbm5lclBhcmVudC5hcHBlbmRDaGlsZChwcm9ncmVzcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBoaWRlU3Bpbm5lcihzcGlubmVySWQ/OiBzdHJpbmcpIHtcbiAgICAgICAgc3Bpbm5lcklkID0gKHNwaW5uZXJJZCA9PT0gdW5kZWZpbmVkKSA/IHRoaXMuZ2V0SWQoKSA6IHNwaW5uZXJJZDtcbiAgICAgICAgaGlkZSgncHJvZ3Jlc3MtJyArIHNwaW5uZXJJZCk7XG4gICAgfVxuXG4gICAgcGxheU9ubHlWaWRlbyhwYXJlbnRFbGVtZW50LCB0aHVtYm5haWxJZCkge1xuXG4gICAgICAgIC8vIFRPLURPOiBjaGVjayBzb21laG93IGlmIHRoZSBzdHJlYW0gaXMgYXVkaW8gb25seSwgc28gdGhlIGVsZW1lbnQgY3JlYXRlZCBpcyA8YXVkaW8+IGluc3RlYWQgb2YgPHZpZGVvPlxuICAgIFxuICAgICAgICB0aGlzLnZpZGVvID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndmlkZW8nKTtcblxuICAgICAgICB0aGlzLnZpZGVvLmlkID0gJ25hdGl2ZS12aWRlby0nICsgdGhpcy5nZXRJZCgpO1xuICAgICAgICB0aGlzLnZpZGVvLmF1dG9wbGF5ID0gdHJ1ZTtcbiAgICAgICAgdGhpcy52aWRlby5jb250cm9scyA9IGZhbHNlO1xuICAgICAgICB0aGlzLnZpZGVvLnNyYyA9IHRoaXMudmlkZW9TcmM7XG5cbiAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRzLnB1c2goe1xuICAgICAgICAgICAgdGh1bWI6IHRodW1ibmFpbElkLFxuICAgICAgICAgICAgdmlkZW86IHRoaXMudmlkZW9cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHRoaXMubG9jYWwpIHtcbiAgICAgICAgICAgIHRoaXMudmlkZW8ubXV0ZWQgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy52aWRlby50aXRsZSA9IHRoaXMuZ2V0SWQoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgcGFyZW50RWxlbWVudCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgdGhpcy5wYXJlbnRJZCA9IHBhcmVudEVsZW1lbnQ7XG5cbiAgICAgICAgICAgIGxldCBwYXJlbnRFbGVtZW50RG9tID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQocGFyZW50RWxlbWVudCk7XG4gICAgICAgICAgICBpZiAocGFyZW50RWxlbWVudERvbSkge1xuICAgICAgICAgICAgICAgIHRoaXMudmlkZW8gPSBwYXJlbnRFbGVtZW50RG9tLmFwcGVuZENoaWxkKHRoaXMudmlkZW8pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5wYXJlbnRJZCA9IHBhcmVudEVsZW1lbnQuaWQ7XG4gICAgICAgICAgICB0aGlzLnZpZGVvID0gcGFyZW50RWxlbWVudC5hcHBlbmRDaGlsZCh0aGlzLnZpZGVvKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCd2aWRlby1lbGVtZW50LWNyZWF0ZWQtYnktc3RyZWFtJywgW3tcbiAgICAgICAgICAgIGVsZW1lbnQ6IHRoaXMudmlkZW9cbiAgICAgICAgfV0pO1xuXG4gICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdzdHJlYW0tY3JlYXRlZC1ieS1wdWJsaXNoZXInKTtcblxuICAgICAgICB0aGlzLmlzUmVhZHkgPSB0cnVlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnZpZGVvO1xuICAgIH1cblxuICAgIHBsYXlUaHVtYm5haWwodGh1bWJuYWlsSWQpIHtcblxuICAgICAgICBsZXQgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgICAgIGNvbnRhaW5lci5jbGFzc05hbWUgPSBcInBhcnRpY2lwYW50XCI7XG4gICAgICAgIGNvbnRhaW5lci5pZCA9IHRoaXMuZ2V0SWQoKTtcbiAgICAgICAgbGV0IHRodW1ibmFpbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRodW1ibmFpbElkKTtcbiAgICAgICAgaWYgKHRodW1ibmFpbCkge1xuICAgICAgICAgICAgdGh1bWJuYWlsLmFwcGVuZENoaWxkKGNvbnRhaW5lcik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmVsZW1lbnRzLnB1c2goY29udGFpbmVyKTtcblxuICAgICAgICBsZXQgbmFtZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQobmFtZSk7XG4gICAgICAgIGxldCB1c2VyTmFtZSA9IHRoaXMuZ2V0SWQoKS5yZXBsYWNlKCdfd2ViY2FtJywgJycpO1xuICAgICAgICBpZiAodXNlck5hbWUubGVuZ3RoID49IDE2KSB7XG4gICAgICAgICAgICB1c2VyTmFtZSA9IHVzZXJOYW1lLnN1YnN0cmluZygwLCAxNikgKyBcIi4uLlwiO1xuICAgICAgICB9XG4gICAgICAgIG5hbWUuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUodXNlck5hbWUpKTtcbiAgICAgICAgbmFtZS5pZCA9IFwibmFtZS1cIiArIHRoaXMuZ2V0SWQoKTtcbiAgICAgICAgbmFtZS5jbGFzc05hbWUgPSBcIm5hbWVcIjtcbiAgICAgICAgbmFtZS50aXRsZSA9IHRoaXMuZ2V0SWQoKTtcblxuICAgICAgICB0aGlzLnNob3dTcGlubmVyKHRodW1ibmFpbElkKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5wbGF5T25seVZpZGVvKGNvbnRhaW5lciwgdGh1bWJuYWlsSWQpO1xuICAgIH1cblxuICAgIGdldElkSW5QYXJ0aWNpcGFudCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaWQ7XG4gICAgfVxuXG4gICAgZ2V0UGFydGljaXBhbnQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbm5lY3Rpb247XG4gICAgfVxuXG4gICAgZ2V0SWQoKSB7XG4gICAgICAgIGlmICh0aGlzLmNvbm5lY3Rpb24pIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbm5lY3Rpb24uY29ubmVjdGlvbklkICsgXCJfXCIgKyB0aGlzLmlkO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuaWQgKyBcIl93ZWJjYW1cIjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldFJUQ1BlZXJDb25uZWN0aW9uKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRXZWJSdGNQZWVyKCkucGVlckNvbm5lY3Rpb247XG4gICAgfVxuXG4gICAgcmVxdWVzdENhbWVyYUFjY2VzcyhjYWxsYmFjazogQ2FsbGJhY2s8U3RyZWFtPikge1xuXG4gICAgICAgIHRoaXMuY29ubmVjdGlvbi5hZGRTdHJlYW0odGhpcyk7XG5cbiAgICAgICAgbGV0IGNvbnN0cmFpbnRzID0gdGhpcy5tZWRpYUNvbnN0cmFpbnRzO1xuXG4gICAgICAgIC8qbGV0IGNvbnN0cmFpbnRzMiA9IHtcbiAgICAgICAgICAgIGF1ZGlvOiB0cnVlLFxuICAgICAgICAgICAgdmlkZW86IHtcbiAgICAgICAgICAgICAgICB3aWR0aDoge1xuICAgICAgICAgICAgICAgICAgICBpZGVhbDogMTI4MFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZnJhbWVSYXRlOiB7XG4gICAgICAgICAgICAgICAgICAgIGlkZWFsOiAxNVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTsqL1xuXG4gICAgICAgIHRoaXMudXNlck1lZGlhSGFzVmlkZW8oKGhhc1ZpZGVvKSA9PiB7XG4gICAgICAgICAgICBpZiAoIWhhc1ZpZGVvKSB7XG4gICAgICAgICAgICAgICAgY29uc3RyYWludHMudmlkZW8gPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRWaWRlbyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHRoaXMucmVxdWVzdENhbWVyYUFjY2VzQXV4KGNvbnN0cmFpbnRzLCBjYWxsYmFjayk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMucmVxdWVzdENhbWVyYUFjY2VzQXV4KGNvbnN0cmFpbnRzLCBjYWxsYmFjayk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgcmVxdWVzdENhbWVyYUFjY2VzQXV4KGNvbnN0cmFpbnRzLCBjYWxsYmFjaykge1xuICAgICAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYShjb25zdHJhaW50cylcbiAgICAgICAgICAgIC50aGVuKHVzZXJTdHJlYW0gPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuYWNjZXNzSXNBbGxvd2VkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLmFjY2Vzc0lzRGVuaWVkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2FjY2Vzcy1hbGxvd2VkLWJ5LXB1Ymxpc2hlcicpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHVzZXJTdHJlYW0uZ2V0QXVkaW9UcmFja3MoKVswXSAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIHVzZXJTdHJlYW0uZ2V0QXVkaW9UcmFja3MoKVswXS5lbmFibGVkID0gdGhpcy5zZW5kQXVkaW87XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICh1c2VyU3RyZWFtLmdldFZpZGVvVHJhY2tzKClbMF0gIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICB1c2VyU3RyZWFtLmdldFZpZGVvVHJhY2tzKClbMF0uZW5hYmxlZCA9IHRoaXMuc2VuZFZpZGVvO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMud3JTdHJlYW0gPSB1c2VyU3RyZWFtO1xuICAgICAgICAgICAgICAgIHRoaXMuZW1pdFNyY0V2ZW50KHRoaXMud3JTdHJlYW0pO1xuXG4gICAgICAgICAgICAgICAgY2FsbGJhY2sodW5kZWZpbmVkLCB0aGlzKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuYWNjZXNzSXNEZW5pZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHRoaXMuYWNjZXNzSXNBbGxvd2VkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2FjY2Vzcy1kZW5pZWQtYnktcHVibGlzaGVyJyk7XG5cbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiQWNjZXNzIGRlbmllZFwiLCBlcnJvcik7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soZXJyb3IsIHRoaXMpO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSB1c2VyTWVkaWFIYXNWaWRlbyhjYWxsYmFjaykge1xuICAgICAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmVudW1lcmF0ZURldmljZXMoKS50aGVuKGZ1bmN0aW9uIChtZWRpYURldmljZXMpIHtcbiAgICAgICAgICAgIHZhciB2aWRlb0lucHV0ID0gbWVkaWFEZXZpY2VzLmZpbHRlcihmdW5jdGlvbiAoZGV2aWNlSW5mbykge1xuICAgICAgICAgICAgICAgIHJldHVybiBkZXZpY2VJbmZvLmtpbmQgPT09ICd2aWRlb2lucHV0JztcbiAgICAgICAgICAgIH0pWzBdO1xuICAgICAgICAgICAgY2FsbGJhY2sodmlkZW9JbnB1dCAhPSBudWxsKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGlzaFZpZGVvQ2FsbGJhY2soZXJyb3IsIHNkcE9mZmVyUGFyYW0sIHdwKSB7XG5cbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm4gY29uc29sZS5lcnJvcihcIihwdWJsaXNoKSBTRFAgb2ZmZXIgZXJyb3I6IFwiXG4gICAgICAgICAgICAgICAgKyBKU09OLnN0cmluZ2lmeShlcnJvcikpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc29sZS5sb2coXCJTZW5kaW5nIFNEUCBvZmZlciB0byBwdWJsaXNoIGFzIFwiXG4gICAgICAgICAgICArIHRoaXMuZ2V0SWQoKSwgc2RwT2ZmZXJQYXJhbSk7XG5cbiAgICAgICAgdGhpcy5vcGVuVmlkdS5zZW5kUmVxdWVzdChcInB1Ymxpc2hWaWRlb1wiLCB7XG4gICAgICAgICAgICBzZHBPZmZlcjogc2RwT2ZmZXJQYXJhbSxcbiAgICAgICAgICAgIGRvTG9vcGJhY2s6IHRoaXMuZGlzcGxheU15UmVtb3RlKCkgfHwgZmFsc2VcbiAgICAgICAgfSwgKGVycm9yLCByZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIG9uIHB1Ymxpc2hWaWRlbzogXCIgKyBKU09OLnN0cmluZ2lmeShlcnJvcikpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJvb20uZW1pdEV2ZW50KCdzdHJlYW0tcHVibGlzaGVkJywgW3tcbiAgICAgICAgICAgICAgICAgICAgc3RyZWFtOiB0aGlzXG4gICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgICAgIHRoaXMucHJvY2Vzc1NkcEFuc3dlcihyZXNwb25zZS5zZHBBbnN3ZXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzdGFydFZpZGVvQ2FsbGJhY2soZXJyb3IsIHNkcE9mZmVyUGFyYW0sIHdwKSB7XG4gICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgcmV0dXJuIGNvbnNvbGUuZXJyb3IoXCIoc3Vic2NyaWJlKSBTRFAgb2ZmZXIgZXJyb3I6IFwiXG4gICAgICAgICAgICAgICAgKyBKU09OLnN0cmluZ2lmeShlcnJvcikpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUubG9nKFwiU2VuZGluZyBTRFAgb2ZmZXIgdG8gc3Vic2NyaWJlIHRvIFwiXG4gICAgICAgICAgICArIHRoaXMuZ2V0SWQoKSwgc2RwT2ZmZXJQYXJhbSk7XG4gICAgICAgIHRoaXMub3BlblZpZHUuc2VuZFJlcXVlc3QoXCJyZWNlaXZlVmlkZW9Gcm9tXCIsIHtcbiAgICAgICAgICAgIHNlbmRlcjogdGhpcy5nZXRJZCgpLFxuICAgICAgICAgICAgc2RwT2ZmZXI6IHNkcE9mZmVyUGFyYW1cbiAgICAgICAgfSwgKGVycm9yLCByZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIG9uIHJlY3ZWaWRlb0Zyb206IFwiICsgSlNPTi5zdHJpbmdpZnkoZXJyb3IpKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5wcm9jZXNzU2RwQW5zd2VyKHJlc3BvbnNlLnNkcEFuc3dlcik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgaW5pdFdlYlJ0Y1BlZXIoc2RwT2ZmZXJDYWxsYmFjaykge1xuICAgICAgICBpZiAodGhpcy5sb2NhbCkge1xuXG4gICAgICAgICAgICBsZXQgdXNlck1lZGlhQ29uc3RyYWludHMgPSB7XG4gICAgICAgICAgICAgICAgYXVkaW86IHRoaXMuc2VuZEF1ZGlvLFxuICAgICAgICAgICAgICAgIHZpZGVvOiB0aGlzLnNlbmRWaWRlb1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgb3B0aW9uczogYW55ID0ge1xuICAgICAgICAgICAgICAgIHZpZGVvU3RyZWFtOiB0aGlzLndyU3RyZWFtLFxuICAgICAgICAgICAgICAgIG1lZGlhQ29uc3RyYWludHM6IHVzZXJNZWRpYUNvbnN0cmFpbnRzLFxuICAgICAgICAgICAgICAgIG9uaWNlY2FuZGlkYXRlOiB0aGlzLmNvbm5lY3Rpb24uc2VuZEljZUNhbmRpZGF0ZS5iaW5kKHRoaXMuY29ubmVjdGlvbiksXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLmRhdGFDaGFubmVsKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5kYXRhQ2hhbm5lbENvbmZpZyA9IHtcbiAgICAgICAgICAgICAgICAgICAgaWQ6IHRoaXMuZ2V0Q2hhbm5lbE5hbWUoKSxcbiAgICAgICAgICAgICAgICAgICAgb25vcGVuOiB0aGlzLm9uRGF0YUNoYW5uZWxPcGVuLFxuICAgICAgICAgICAgICAgICAgICBvbmNsb3NlOiB0aGlzLm9uRGF0YUNoYW5uZWxDbG9zZWRcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZGF0YUNoYW5uZWxzID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMuZGlzcGxheU15UmVtb3RlKCkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndwID0gbmV3IGt1cmVudG9VdGlscy5XZWJSdGNQZWVyLldlYlJ0Y1BlZXJTZW5kcmVjdihvcHRpb25zLCBlcnJvciA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRoaXMud3AuZ2VuZXJhdGVPZmZlcihzZHBPZmZlckNhbGxiYWNrLmJpbmQodGhpcykpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLndwID0gbmV3IGt1cmVudG9VdGlscy5XZWJSdGNQZWVyLldlYlJ0Y1BlZXJTZW5kb25seShvcHRpb25zLCBlcnJvciA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRoaXMud3AuZ2VuZXJhdGVPZmZlcihzZHBPZmZlckNhbGxiYWNrLmJpbmQodGhpcykpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbGV0IG9mZmVyQ29uc3RyYWludHMgPSB7XG4gICAgICAgICAgICAgICAgbWFuZGF0b3J5OiB7XG4gICAgICAgICAgICAgICAgICAgIE9mZmVyVG9SZWNlaXZlVmlkZW86IHRoaXMucmVjdlZpZGVvLFxuICAgICAgICAgICAgICAgICAgICBPZmZlclRvUmVjZWl2ZUF1ZGlvOiB0aGlzLnJlY3ZBdWRpb1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIkNvbnN0cmFpbnRzIG9mIGdlbmVyYXRlIFNEUCBvZmZlciAoc3Vic2NyaWJpbmcpXCIsXG4gICAgICAgICAgICAgICAgb2ZmZXJDb25zdHJhaW50cyk7XG4gICAgICAgICAgICBsZXQgb3B0aW9ucyA9IHtcbiAgICAgICAgICAgICAgICBvbmljZWNhbmRpZGF0ZTogdGhpcy5jb25uZWN0aW9uLnNlbmRJY2VDYW5kaWRhdGUuYmluZCh0aGlzLmNvbm5lY3Rpb24pLFxuICAgICAgICAgICAgICAgIGNvbm5lY3Rpb25Db25zdHJhaW50czogb2ZmZXJDb25zdHJhaW50c1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy53cCA9IG5ldyBrdXJlbnRvVXRpbHMuV2ViUnRjUGVlci5XZWJSdGNQZWVyUmVjdm9ubHkob3B0aW9ucywgZXJyb3IgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMud3AuZ2VuZXJhdGVPZmZlcihzZHBPZmZlckNhbGxiYWNrLmJpbmQodGhpcykpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc29sZS5sb2coXCJXYWl0aW5nIGZvciBTRFAgb2ZmZXIgdG8gYmUgZ2VuZXJhdGVkIChcIlxuICAgICAgICAgICAgKyAodGhpcy5sb2NhbCA/IFwibG9jYWxcIiA6IFwicmVtb3RlXCIpICsgXCIgcGVlcjogXCIgKyB0aGlzLmdldElkKCkgKyBcIilcIik7XG4gICAgfVxuXG4gICAgcHVibGlzaCgpIHtcblxuICAgICAgICAvLyBGSVhNRTogVGhyb3cgZXJyb3Igd2hlbiBzdHJlYW0gaXMgbm90IGxvY2FsXG4gICAgICAgIGlmICh0aGlzLmlzUmVhZHkpIHtcbiAgICAgICAgICAgIHRoaXMuaW5pdFdlYlJ0Y1BlZXIodGhpcy5wdWJsaXNoVmlkZW9DYWxsYmFjayk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmVlLm9uY2UoJ3N0cmVhbS1yZWFkeScsIHN0cmVhbUV2ZW50ID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnB1Ymxpc2goKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRklYTUU6IE5vdyB3ZSBoYXZlIGNvdXBsZWQgY29ubmVjdGluZyB0byBhIHJvb20gYW5kIGFkZGluZyBhXG4gICAgICAgIC8vIHN0cmVhbSB0byB0aGlzIHJvb20uIEJ1dCBpbiB0aGUgbmV3IEFQSSwgdGhlcmUgYXJlIHR3byBzdGVwcy5cbiAgICAgICAgLy8gVGhpcyBpcyB0aGUgc2Vjb25kIHN0ZXAuIEZvciBub3csIGl0IGRvIG5vdGhpbmcuXG5cbiAgICB9XG5cbiAgICBzdWJzY3JpYmUoKSB7XG5cbiAgICAgICAgLy8gRklYTUU6IEluIHRoZSBjdXJyZW50IGltcGxlbWVudGF0aW9uIGFsbCBwYXJ0aWNpcGFudHMgYXJlIHN1YnNjcmliZWRcbiAgICAgICAgLy8gYXV0b21hdGljYWxseSB0byBhbGwgb3RoZXIgcGFydGljaXBhbnRzLiBXZSB1c2UgdGhpcyBtZXRob2Qgb25seSB0b1xuICAgICAgICAvLyBuZWdvdGlhdGUgU0RQXG5cbiAgICAgICAgdGhpcy5pbml0V2ViUnRjUGVlcih0aGlzLnN0YXJ0VmlkZW9DYWxsYmFjayk7XG4gICAgfVxuXG4gICAgcHJvY2Vzc1NkcEFuc3dlcihzZHBBbnN3ZXIpIHtcblxuICAgICAgICBsZXQgYW5zd2VyID0gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICAgICAgICB0eXBlOiAnYW5zd2VyJyxcbiAgICAgICAgICAgIHNkcDogc2RwQW5zd2VyLFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc29sZS5sb2codGhpcy5nZXRJZCgpICsgXCI6IHNldCBwZWVyIGNvbm5lY3Rpb24gd2l0aCByZWN2ZCBTRFAgYW5zd2VyXCIsXG4gICAgICAgICAgICBzZHBBbnN3ZXIpO1xuICAgICAgICBsZXQgcGFydGljaXBhbnRJZCA9IHRoaXMuZ2V0SWQoKTtcbiAgICAgICAgbGV0IHBjID0gdGhpcy53cC5wZWVyQ29ubmVjdGlvbjtcbiAgICAgICAgcGMuc2V0UmVtb3RlRGVzY3JpcHRpb24oYW5zd2VyLCAoKSA9PiB7XG4gICAgICAgICAgICAvLyBBdm9pZHMgdG8gc3Vic2NyaWJlIHRvIHlvdXIgb3duIHN0cmVhbSByZW1vdGVseSBcbiAgICAgICAgICAgIC8vIGV4Y2VwdCB3aGVuIHNob3dNeVJlbW90ZSBpcyB0cnVlXG4gICAgICAgICAgICBpZiAoIXRoaXMubG9jYWwgfHwgdGhpcy5kaXNwbGF5TXlSZW1vdGUoKSkge1xuICAgICAgICAgICAgICAgIHRoaXMud3JTdHJlYW0gPSBwYy5nZXRSZW1vdGVTdHJlYW1zKClbMF07XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJQZWVyIHJlbW90ZSBzdHJlYW1cIiwgdGhpcy53clN0cmVhbSk7XG5cbiAgICAgICAgICAgICAgICBpZiAodGhpcy53clN0cmVhbSAhPSB1bmRlZmluZWQpIHtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXRTcmNFdmVudCh0aGlzLndyU3RyZWFtKTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLnNwZWVjaEV2ZW50ID0ga3VyZW50b1V0aWxzLldlYlJ0Y1BlZXIuaGFyayh0aGlzLndyU3RyZWFtLCB7IHRocmVzaG9sZDogdGhpcy5yb29tLnRocmVzaG9sZFNwZWFrZXIgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zcGVlY2hFdmVudC5vbignc3BlYWtpbmcnLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJvb20uYWRkUGFydGljaXBhbnRTcGVha2luZyhwYXJ0aWNpcGFudElkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucm9vbS5lbWl0RXZlbnQoJ3N0cmVhbS1zcGVha2luZycsIFt7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFydGljaXBhbnRJZDogcGFydGljaXBhbnRJZFxuICAgICAgICAgICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLnNwZWVjaEV2ZW50Lm9uKCdzdG9wcGVkX3NwZWFraW5nJywgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yb29tLnJlbW92ZVBhcnRpY2lwYW50U3BlYWtpbmcocGFydGljaXBhbnRJZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJvb20uZW1pdEV2ZW50KCdzdHJlYW0tc3RvcHBlZC1zcGVha2luZycsIFt7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFydGljaXBhbnRJZDogcGFydGljaXBhbnRJZFxuICAgICAgICAgICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgdmlkZW9FbGVtZW50IG9mIHRoaXMudmlkZW9FbGVtZW50cykge1xuICAgICAgICAgICAgICAgICAgICBsZXQgdGh1bWJuYWlsSWQgPSB2aWRlb0VsZW1lbnQudGh1bWI7XG4gICAgICAgICAgICAgICAgICAgIGxldCB2aWRlbyA9IHZpZGVvRWxlbWVudC52aWRlbztcbiAgICAgICAgICAgICAgICAgICAgdmlkZW8uc3JjID0gVVJMLmNyZWF0ZU9iamVjdFVSTCh0aGlzLndyU3RyZWFtKTtcbiAgICAgICAgICAgICAgICAgICAgdmlkZW8ub25wbGF5ID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2codGhpcy5nZXRJZCgpICsgJzogJyArICdWaWRlbyBwbGF5aW5nJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAvL3Nob3codGh1bWJuYWlsSWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy90aGlzLmhpZGVTcGlubmVyKHRoaXMuZ2V0SWQoKSk7XG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMucm9vbS5lbWl0RXZlbnQoJ3N0cmVhbS1zdWJzY3JpYmVkJywgW3tcbiAgICAgICAgICAgICAgICAgICAgc3RyZWFtOiB0aGlzXG4gICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCBlcnJvciA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKHRoaXMuZ2V0SWQoKSArIFwiOiBFcnJvciBzZXR0aW5nIFNEUCB0byB0aGUgcGVlciBjb25uZWN0aW9uOiBcIlxuICAgICAgICAgICAgICAgICsgSlNPTi5zdHJpbmdpZnkoZXJyb3IpKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgdW5wdWJsaXNoKCkge1xuICAgICAgICBpZiAodGhpcy53cCkge1xuICAgICAgICAgICAgdGhpcy53cC5kaXNwb3NlKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAodGhpcy53clN0cmVhbSkge1xuICAgICAgICAgICAgICAgIHRoaXMud3JTdHJlYW0uZ2V0QXVkaW9UcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uICh0cmFjaykge1xuICAgICAgICAgICAgICAgICAgICB0cmFjay5zdG9wICYmIHRyYWNrLnN0b3AoKVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgdGhpcy53clN0cmVhbS5nZXRWaWRlb1RyYWNrcygpLmZvckVhY2goZnVuY3Rpb24gKHRyYWNrKSB7XG4gICAgICAgICAgICAgICAgICAgIHRyYWNrLnN0b3AgJiYgdHJhY2suc3RvcCgpXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLnNwZWVjaEV2ZW50KSB7XG4gICAgICAgICAgICB0aGlzLnNwZWVjaEV2ZW50LnN0b3AoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnNvbGUubG9nKHRoaXMuZ2V0SWQoKSArIFwiOiBTdHJlYW0gJ1wiICsgdGhpcy5pZCArIFwiJyB1bnB1Ymxpc2hlZFwiKTtcbiAgICB9XG5cbiAgICBkaXNwb3NlKCkge1xuXG4gICAgICAgIGZ1bmN0aW9uIGRpc3Bvc2VFbGVtZW50KGVsZW1lbnQpIHtcbiAgICAgICAgICAgIGlmIChlbGVtZW50ICYmIGVsZW1lbnQucGFyZW50Tm9kZSkge1xuICAgICAgICAgICAgICAgIGVsZW1lbnQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChlbGVtZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZWxlbWVudHMuZm9yRWFjaChlID0+IGRpc3Bvc2VFbGVtZW50KGUpKTtcblxuICAgICAgICB0aGlzLnZpZGVvRWxlbWVudHMuZm9yRWFjaCh2ZSA9PiBkaXNwb3NlRWxlbWVudCh2ZSkpO1xuXG4gICAgICAgIGRpc3Bvc2VFbGVtZW50KFwicHJvZ3Jlc3MtXCIgKyB0aGlzLmdldElkKCkpO1xuXG4gICAgICAgIGlmICh0aGlzLndwKSB7XG4gICAgICAgICAgICB0aGlzLndwLmRpc3Bvc2UoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmICh0aGlzLndyU3RyZWFtKSB7XG4gICAgICAgICAgICAgICAgdGhpcy53clN0cmVhbS5nZXRBdWRpb1RyYWNrcygpLmZvckVhY2goZnVuY3Rpb24gKHRyYWNrKSB7XG4gICAgICAgICAgICAgICAgICAgIHRyYWNrLnN0b3AgJiYgdHJhY2suc3RvcCgpXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICB0aGlzLndyU3RyZWFtLmdldFZpZGVvVHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbiAodHJhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgdHJhY2suc3RvcCAmJiB0cmFjay5zdG9wKClcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuc3BlZWNoRXZlbnQpIHtcbiAgICAgICAgICAgIHRoaXMuc3BlZWNoRXZlbnQuc3RvcCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc29sZS5sb2codGhpcy5nZXRJZCgpICsgXCI6IFN0cmVhbSAnXCIgKyB0aGlzLmlkICsgXCInIGRpc3Bvc2VkXCIpO1xuICAgIH1cbn1cbiIsIi8vIENvcHlyaWdodCBKb3llbnQsIEluYy4gYW5kIG90aGVyIE5vZGUgY29udHJpYnV0b3JzLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhXG4vLyBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlXG4vLyBcIlNvZnR3YXJlXCIpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmdcbi8vIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCxcbi8vIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXRcbi8vIHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZVxuLy8gZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWRcbi8vIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuLy9cbi8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1Ncbi8vIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0Zcbi8vIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU5cbi8vIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLFxuLy8gREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SXG4vLyBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFXG4vLyBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLlxuXG5mdW5jdGlvbiBFdmVudEVtaXR0ZXIoKSB7XG4gIHRoaXMuX2V2ZW50cyA9IHRoaXMuX2V2ZW50cyB8fCB7fTtcbiAgdGhpcy5fbWF4TGlzdGVuZXJzID0gdGhpcy5fbWF4TGlzdGVuZXJzIHx8IHVuZGVmaW5lZDtcbn1cbm1vZHVsZS5leHBvcnRzID0gRXZlbnRFbWl0dGVyO1xuXG4vLyBCYWNrd2FyZHMtY29tcGF0IHdpdGggbm9kZSAwLjEwLnhcbkV2ZW50RW1pdHRlci5FdmVudEVtaXR0ZXIgPSBFdmVudEVtaXR0ZXI7XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuX2V2ZW50cyA9IHVuZGVmaW5lZDtcbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuX21heExpc3RlbmVycyA9IHVuZGVmaW5lZDtcblxuLy8gQnkgZGVmYXVsdCBFdmVudEVtaXR0ZXJzIHdpbGwgcHJpbnQgYSB3YXJuaW5nIGlmIG1vcmUgdGhhbiAxMCBsaXN0ZW5lcnMgYXJlXG4vLyBhZGRlZCB0byBpdC4gVGhpcyBpcyBhIHVzZWZ1bCBkZWZhdWx0IHdoaWNoIGhlbHBzIGZpbmRpbmcgbWVtb3J5IGxlYWtzLlxuRXZlbnRFbWl0dGVyLmRlZmF1bHRNYXhMaXN0ZW5lcnMgPSAxMDtcblxuLy8gT2J2aW91c2x5IG5vdCBhbGwgRW1pdHRlcnMgc2hvdWxkIGJlIGxpbWl0ZWQgdG8gMTAuIFRoaXMgZnVuY3Rpb24gYWxsb3dzXG4vLyB0aGF0IHRvIGJlIGluY3JlYXNlZC4gU2V0IHRvIHplcm8gZm9yIHVubGltaXRlZC5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuc2V0TWF4TGlzdGVuZXJzID0gZnVuY3Rpb24obikge1xuICBpZiAoIWlzTnVtYmVyKG4pIHx8IG4gPCAwIHx8IGlzTmFOKG4pKVxuICAgIHRocm93IFR5cGVFcnJvcignbiBtdXN0IGJlIGEgcG9zaXRpdmUgbnVtYmVyJyk7XG4gIHRoaXMuX21heExpc3RlbmVycyA9IG47XG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5lbWl0ID0gZnVuY3Rpb24odHlwZSkge1xuICB2YXIgZXIsIGhhbmRsZXIsIGxlbiwgYXJncywgaSwgbGlzdGVuZXJzO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzKVxuICAgIHRoaXMuX2V2ZW50cyA9IHt9O1xuXG4gIC8vIElmIHRoZXJlIGlzIG5vICdlcnJvcicgZXZlbnQgbGlzdGVuZXIgdGhlbiB0aHJvdy5cbiAgaWYgKHR5cGUgPT09ICdlcnJvcicpIHtcbiAgICBpZiAoIXRoaXMuX2V2ZW50cy5lcnJvciB8fFxuICAgICAgICAoaXNPYmplY3QodGhpcy5fZXZlbnRzLmVycm9yKSAmJiAhdGhpcy5fZXZlbnRzLmVycm9yLmxlbmd0aCkpIHtcbiAgICAgIGVyID0gYXJndW1lbnRzWzFdO1xuICAgICAgaWYgKGVyIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgdGhyb3cgZXI7IC8vIFVuaGFuZGxlZCAnZXJyb3InIGV2ZW50XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBBdCBsZWFzdCBnaXZlIHNvbWUga2luZCBvZiBjb250ZXh0IHRvIHRoZSB1c2VyXG4gICAgICAgIHZhciBlcnIgPSBuZXcgRXJyb3IoJ1VuY2F1Z2h0LCB1bnNwZWNpZmllZCBcImVycm9yXCIgZXZlbnQuICgnICsgZXIgKyAnKScpO1xuICAgICAgICBlcnIuY29udGV4dCA9IGVyO1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgaGFuZGxlciA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICBpZiAoaXNVbmRlZmluZWQoaGFuZGxlcikpXG4gICAgcmV0dXJuIGZhbHNlO1xuXG4gIGlmIChpc0Z1bmN0aW9uKGhhbmRsZXIpKSB7XG4gICAgc3dpdGNoIChhcmd1bWVudHMubGVuZ3RoKSB7XG4gICAgICAvLyBmYXN0IGNhc2VzXG4gICAgICBjYXNlIDE6XG4gICAgICAgIGhhbmRsZXIuY2FsbCh0aGlzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDI6XG4gICAgICAgIGhhbmRsZXIuY2FsbCh0aGlzLCBhcmd1bWVudHNbMV0pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzpcbiAgICAgICAgaGFuZGxlci5jYWxsKHRoaXMsIGFyZ3VtZW50c1sxXSwgYXJndW1lbnRzWzJdKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICAvLyBzbG93ZXJcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgICAgICBoYW5kbGVyLmFwcGx5KHRoaXMsIGFyZ3MpO1xuICAgIH1cbiAgfSBlbHNlIGlmIChpc09iamVjdChoYW5kbGVyKSkge1xuICAgIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIGxpc3RlbmVycyA9IGhhbmRsZXIuc2xpY2UoKTtcbiAgICBsZW4gPSBsaXN0ZW5lcnMubGVuZ3RoO1xuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKylcbiAgICAgIGxpc3RlbmVyc1tpXS5hcHBseSh0aGlzLCBhcmdzKTtcbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5hZGRMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIHZhciBtO1xuXG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICBpZiAoIXRoaXMuX2V2ZW50cylcbiAgICB0aGlzLl9ldmVudHMgPSB7fTtcblxuICAvLyBUbyBhdm9pZCByZWN1cnNpb24gaW4gdGhlIGNhc2UgdGhhdCB0eXBlID09PSBcIm5ld0xpc3RlbmVyXCIhIEJlZm9yZVxuICAvLyBhZGRpbmcgaXQgdG8gdGhlIGxpc3RlbmVycywgZmlyc3QgZW1pdCBcIm5ld0xpc3RlbmVyXCIuXG4gIGlmICh0aGlzLl9ldmVudHMubmV3TGlzdGVuZXIpXG4gICAgdGhpcy5lbWl0KCduZXdMaXN0ZW5lcicsIHR5cGUsXG4gICAgICAgICAgICAgIGlzRnVuY3Rpb24obGlzdGVuZXIubGlzdGVuZXIpID9cbiAgICAgICAgICAgICAgbGlzdGVuZXIubGlzdGVuZXIgOiBsaXN0ZW5lcik7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgLy8gT3B0aW1pemUgdGhlIGNhc2Ugb2Ygb25lIGxpc3RlbmVyLiBEb24ndCBuZWVkIHRoZSBleHRyYSBhcnJheSBvYmplY3QuXG4gICAgdGhpcy5fZXZlbnRzW3R5cGVdID0gbGlzdGVuZXI7XG4gIGVsc2UgaWYgKGlzT2JqZWN0KHRoaXMuX2V2ZW50c1t0eXBlXSkpXG4gICAgLy8gSWYgd2UndmUgYWxyZWFkeSBnb3QgYW4gYXJyYXksIGp1c3QgYXBwZW5kLlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXS5wdXNoKGxpc3RlbmVyKTtcbiAgZWxzZVxuICAgIC8vIEFkZGluZyB0aGUgc2Vjb25kIGVsZW1lbnQsIG5lZWQgdG8gY2hhbmdlIHRvIGFycmF5LlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXSA9IFt0aGlzLl9ldmVudHNbdHlwZV0sIGxpc3RlbmVyXTtcblxuICAvLyBDaGVjayBmb3IgbGlzdGVuZXIgbGVha1xuICBpZiAoaXNPYmplY3QodGhpcy5fZXZlbnRzW3R5cGVdKSAmJiAhdGhpcy5fZXZlbnRzW3R5cGVdLndhcm5lZCkge1xuICAgIGlmICghaXNVbmRlZmluZWQodGhpcy5fbWF4TGlzdGVuZXJzKSkge1xuICAgICAgbSA9IHRoaXMuX21heExpc3RlbmVycztcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IEV2ZW50RW1pdHRlci5kZWZhdWx0TWF4TGlzdGVuZXJzO1xuICAgIH1cblxuICAgIGlmIChtICYmIG0gPiAwICYmIHRoaXMuX2V2ZW50c1t0eXBlXS5sZW5ndGggPiBtKSB7XG4gICAgICB0aGlzLl9ldmVudHNbdHlwZV0ud2FybmVkID0gdHJ1ZTtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJyhub2RlKSB3YXJuaW5nOiBwb3NzaWJsZSBFdmVudEVtaXR0ZXIgbWVtb3J5ICcgK1xuICAgICAgICAgICAgICAgICAgICAnbGVhayBkZXRlY3RlZC4gJWQgbGlzdGVuZXJzIGFkZGVkLiAnICtcbiAgICAgICAgICAgICAgICAgICAgJ1VzZSBlbWl0dGVyLnNldE1heExpc3RlbmVycygpIHRvIGluY3JlYXNlIGxpbWl0LicsXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2V2ZW50c1t0eXBlXS5sZW5ndGgpO1xuICAgICAgaWYgKHR5cGVvZiBjb25zb2xlLnRyYWNlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIC8vIG5vdCBzdXBwb3J0ZWQgaW4gSUUgMTBcbiAgICAgICAgY29uc29sZS50cmFjZSgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbiA9IEV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXI7XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub25jZSA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICB2YXIgZmlyZWQgPSBmYWxzZTtcblxuICBmdW5jdGlvbiBnKCkge1xuICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIodHlwZSwgZyk7XG5cbiAgICBpZiAoIWZpcmVkKSB7XG4gICAgICBmaXJlZCA9IHRydWU7XG4gICAgICBsaXN0ZW5lci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH1cbiAgfVxuXG4gIGcubGlzdGVuZXIgPSBsaXN0ZW5lcjtcbiAgdGhpcy5vbih0eXBlLCBnKTtcblxuICByZXR1cm4gdGhpcztcbn07XG5cbi8vIGVtaXRzIGEgJ3JlbW92ZUxpc3RlbmVyJyBldmVudCBpZmYgdGhlIGxpc3RlbmVyIHdhcyByZW1vdmVkXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnJlbW92ZUxpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHtcbiAgdmFyIGxpc3QsIHBvc2l0aW9uLCBsZW5ndGgsIGk7XG5cbiAgaWYgKCFpc0Z1bmN0aW9uKGxpc3RlbmVyKSlcbiAgICB0aHJvdyBUeXBlRXJyb3IoJ2xpc3RlbmVyIG11c3QgYmUgYSBmdW5jdGlvbicpO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzIHx8ICF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgcmV0dXJuIHRoaXM7XG5cbiAgbGlzdCA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgbGVuZ3RoID0gbGlzdC5sZW5ndGg7XG4gIHBvc2l0aW9uID0gLTE7XG5cbiAgaWYgKGxpc3QgPT09IGxpc3RlbmVyIHx8XG4gICAgICAoaXNGdW5jdGlvbihsaXN0Lmxpc3RlbmVyKSAmJiBsaXN0Lmxpc3RlbmVyID09PSBsaXN0ZW5lcikpIHtcbiAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIGlmICh0aGlzLl9ldmVudHMucmVtb3ZlTGlzdGVuZXIpXG4gICAgICB0aGlzLmVtaXQoJ3JlbW92ZUxpc3RlbmVyJywgdHlwZSwgbGlzdGVuZXIpO1xuXG4gIH0gZWxzZSBpZiAoaXNPYmplY3QobGlzdCkpIHtcbiAgICBmb3IgKGkgPSBsZW5ndGg7IGktLSA+IDA7KSB7XG4gICAgICBpZiAobGlzdFtpXSA9PT0gbGlzdGVuZXIgfHxcbiAgICAgICAgICAobGlzdFtpXS5saXN0ZW5lciAmJiBsaXN0W2ldLmxpc3RlbmVyID09PSBsaXN0ZW5lcikpIHtcbiAgICAgICAgcG9zaXRpb24gPSBpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocG9zaXRpb24gPCAwKVxuICAgICAgcmV0dXJuIHRoaXM7XG5cbiAgICBpZiAobGlzdC5sZW5ndGggPT09IDEpIHtcbiAgICAgIGxpc3QubGVuZ3RoID0gMDtcbiAgICAgIGRlbGV0ZSB0aGlzLl9ldmVudHNbdHlwZV07XG4gICAgfSBlbHNlIHtcbiAgICAgIGxpc3Quc3BsaWNlKHBvc2l0aW9uLCAxKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKVxuICAgICAgdGhpcy5lbWl0KCdyZW1vdmVMaXN0ZW5lcicsIHR5cGUsIGxpc3RlbmVyKTtcbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciBrZXksIGxpc3RlbmVycztcblxuICBpZiAoIXRoaXMuX2V2ZW50cylcbiAgICByZXR1cm4gdGhpcztcblxuICAvLyBub3QgbGlzdGVuaW5nIGZvciByZW1vdmVMaXN0ZW5lciwgbm8gbmVlZCB0byBlbWl0XG4gIGlmICghdGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKSB7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDApXG4gICAgICB0aGlzLl9ldmVudHMgPSB7fTtcbiAgICBlbHNlIGlmICh0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gZW1pdCByZW1vdmVMaXN0ZW5lciBmb3IgYWxsIGxpc3RlbmVycyBvbiBhbGwgZXZlbnRzXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgZm9yIChrZXkgaW4gdGhpcy5fZXZlbnRzKSB7XG4gICAgICBpZiAoa2V5ID09PSAncmVtb3ZlTGlzdGVuZXInKSBjb250aW51ZTtcbiAgICAgIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKGtleSk7XG4gICAgfVxuICAgIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCdyZW1vdmVMaXN0ZW5lcicpO1xuICAgIHRoaXMuX2V2ZW50cyA9IHt9O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgbGlzdGVuZXJzID0gdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gIGlmIChpc0Z1bmN0aW9uKGxpc3RlbmVycykpIHtcbiAgICB0aGlzLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGxpc3RlbmVycyk7XG4gIH0gZWxzZSBpZiAobGlzdGVuZXJzKSB7XG4gICAgLy8gTElGTyBvcmRlclxuICAgIHdoaWxlIChsaXN0ZW5lcnMubGVuZ3RoKVxuICAgICAgdGhpcy5yZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcnNbbGlzdGVuZXJzLmxlbmd0aCAtIDFdKTtcbiAgfVxuICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5saXN0ZW5lcnMgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciByZXQ7XG4gIGlmICghdGhpcy5fZXZlbnRzIHx8ICF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgcmV0ID0gW107XG4gIGVsc2UgaWYgKGlzRnVuY3Rpb24odGhpcy5fZXZlbnRzW3R5cGVdKSlcbiAgICByZXQgPSBbdGhpcy5fZXZlbnRzW3R5cGVdXTtcbiAgZWxzZVxuICAgIHJldCA9IHRoaXMuX2V2ZW50c1t0eXBlXS5zbGljZSgpO1xuICByZXR1cm4gcmV0O1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5saXN0ZW5lckNvdW50ID0gZnVuY3Rpb24odHlwZSkge1xuICBpZiAodGhpcy5fZXZlbnRzKSB7XG4gICAgdmFyIGV2bGlzdGVuZXIgPSB0aGlzLl9ldmVudHNbdHlwZV07XG5cbiAgICBpZiAoaXNGdW5jdGlvbihldmxpc3RlbmVyKSlcbiAgICAgIHJldHVybiAxO1xuICAgIGVsc2UgaWYgKGV2bGlzdGVuZXIpXG4gICAgICByZXR1cm4gZXZsaXN0ZW5lci5sZW5ndGg7XG4gIH1cbiAgcmV0dXJuIDA7XG59O1xuXG5FdmVudEVtaXR0ZXIubGlzdGVuZXJDb3VudCA9IGZ1bmN0aW9uKGVtaXR0ZXIsIHR5cGUpIHtcbiAgcmV0dXJuIGVtaXR0ZXIubGlzdGVuZXJDb3VudCh0eXBlKTtcbn07XG5cbmZ1bmN0aW9uIGlzRnVuY3Rpb24oYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnZnVuY3Rpb24nO1xufVxuXG5mdW5jdGlvbiBpc051bWJlcihhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdudW1iZXInO1xufVxuXG5mdW5jdGlvbiBpc09iamVjdChhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdvYmplY3QnICYmIGFyZyAhPT0gbnVsbDtcbn1cblxuZnVuY3Rpb24gaXNVbmRlZmluZWQoYXJnKSB7XG4gIHJldHVybiBhcmcgPT09IHZvaWQgMDtcbn1cbiIsIi8vIHNoaW0gZm9yIHVzaW5nIHByb2Nlc3MgaW4gYnJvd3NlclxudmFyIHByb2Nlc3MgPSBtb2R1bGUuZXhwb3J0cyA9IHt9O1xuXG4vLyBjYWNoZWQgZnJvbSB3aGF0ZXZlciBnbG9iYWwgaXMgcHJlc2VudCBzbyB0aGF0IHRlc3QgcnVubmVycyB0aGF0IHN0dWIgaXRcbi8vIGRvbid0IGJyZWFrIHRoaW5ncy4gIEJ1dCB3ZSBuZWVkIHRvIHdyYXAgaXQgaW4gYSB0cnkgY2F0Y2ggaW4gY2FzZSBpdCBpc1xuLy8gd3JhcHBlZCBpbiBzdHJpY3QgbW9kZSBjb2RlIHdoaWNoIGRvZXNuJ3QgZGVmaW5lIGFueSBnbG9iYWxzLiAgSXQncyBpbnNpZGUgYVxuLy8gZnVuY3Rpb24gYmVjYXVzZSB0cnkvY2F0Y2hlcyBkZW9wdGltaXplIGluIGNlcnRhaW4gZW5naW5lcy5cblxudmFyIGNhY2hlZFNldFRpbWVvdXQ7XG52YXIgY2FjaGVkQ2xlYXJUaW1lb3V0O1xuXG5mdW5jdGlvbiBkZWZhdWx0U2V0VGltb3V0KCkge1xuICAgIHRocm93IG5ldyBFcnJvcignc2V0VGltZW91dCBoYXMgbm90IGJlZW4gZGVmaW5lZCcpO1xufVxuZnVuY3Rpb24gZGVmYXVsdENsZWFyVGltZW91dCAoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjbGVhclRpbWVvdXQgaGFzIG5vdCBiZWVuIGRlZmluZWQnKTtcbn1cbihmdW5jdGlvbiAoKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgaWYgKHR5cGVvZiBzZXRUaW1lb3V0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gc2V0VGltZW91dDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBkZWZhdWx0U2V0VGltb3V0O1xuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gZGVmYXVsdFNldFRpbW91dDtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgaWYgKHR5cGVvZiBjbGVhclRpbWVvdXQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGNsZWFyVGltZW91dDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGRlZmF1bHRDbGVhclRpbWVvdXQ7XG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGRlZmF1bHRDbGVhclRpbWVvdXQ7XG4gICAgfVxufSAoKSlcbmZ1bmN0aW9uIHJ1blRpbWVvdXQoZnVuKSB7XG4gICAgaWYgKGNhY2hlZFNldFRpbWVvdXQgPT09IHNldFRpbWVvdXQpIHtcbiAgICAgICAgLy9ub3JtYWwgZW52aXJvbWVudHMgaW4gc2FuZSBzaXR1YXRpb25zXG4gICAgICAgIHJldHVybiBzZXRUaW1lb3V0KGZ1biwgMCk7XG4gICAgfVxuICAgIC8vIGlmIHNldFRpbWVvdXQgd2Fzbid0IGF2YWlsYWJsZSBidXQgd2FzIGxhdHRlciBkZWZpbmVkXG4gICAgaWYgKChjYWNoZWRTZXRUaW1lb3V0ID09PSBkZWZhdWx0U2V0VGltb3V0IHx8ICFjYWNoZWRTZXRUaW1lb3V0KSAmJiBzZXRUaW1lb3V0KSB7XG4gICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBzZXRUaW1lb3V0O1xuICAgICAgICByZXR1cm4gc2V0VGltZW91dChmdW4sIDApO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICAvLyB3aGVuIHdoZW4gc29tZWJvZHkgaGFzIHNjcmV3ZWQgd2l0aCBzZXRUaW1lb3V0IGJ1dCBubyBJLkUuIG1hZGRuZXNzXG4gICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0KGZ1biwgMCk7XG4gICAgfSBjYXRjaChlKXtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIFdoZW4gd2UgYXJlIGluIEkuRS4gYnV0IHRoZSBzY3JpcHQgaGFzIGJlZW4gZXZhbGVkIHNvIEkuRS4gZG9lc24ndCB0cnVzdCB0aGUgZ2xvYmFsIG9iamVjdCB3aGVuIGNhbGxlZCBub3JtYWxseVxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZFNldFRpbWVvdXQuY2FsbChudWxsLCBmdW4sIDApO1xuICAgICAgICB9IGNhdGNoKGUpe1xuICAgICAgICAgICAgLy8gc2FtZSBhcyBhYm92ZSBidXQgd2hlbiBpdCdzIGEgdmVyc2lvbiBvZiBJLkUuIHRoYXQgbXVzdCBoYXZlIHRoZSBnbG9iYWwgb2JqZWN0IGZvciAndGhpcycsIGhvcGZ1bGx5IG91ciBjb250ZXh0IGNvcnJlY3Qgb3RoZXJ3aXNlIGl0IHdpbGwgdGhyb3cgYSBnbG9iYWwgZXJyb3JcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0LmNhbGwodGhpcywgZnVuLCAwKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG59XG5mdW5jdGlvbiBydW5DbGVhclRpbWVvdXQobWFya2VyKSB7XG4gICAgaWYgKGNhY2hlZENsZWFyVGltZW91dCA9PT0gY2xlYXJUaW1lb3V0KSB7XG4gICAgICAgIC8vbm9ybWFsIGVudmlyb21lbnRzIGluIHNhbmUgc2l0dWF0aW9uc1xuICAgICAgICByZXR1cm4gY2xlYXJUaW1lb3V0KG1hcmtlcik7XG4gICAgfVxuICAgIC8vIGlmIGNsZWFyVGltZW91dCB3YXNuJ3QgYXZhaWxhYmxlIGJ1dCB3YXMgbGF0dGVyIGRlZmluZWRcbiAgICBpZiAoKGNhY2hlZENsZWFyVGltZW91dCA9PT0gZGVmYXVsdENsZWFyVGltZW91dCB8fCAhY2FjaGVkQ2xlYXJUaW1lb3V0KSAmJiBjbGVhclRpbWVvdXQpIHtcbiAgICAgICAgY2FjaGVkQ2xlYXJUaW1lb3V0ID0gY2xlYXJUaW1lb3V0O1xuICAgICAgICByZXR1cm4gY2xlYXJUaW1lb3V0KG1hcmtlcik7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIC8vIHdoZW4gd2hlbiBzb21lYm9keSBoYXMgc2NyZXdlZCB3aXRoIHNldFRpbWVvdXQgYnV0IG5vIEkuRS4gbWFkZG5lc3NcbiAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH0gY2F0Y2ggKGUpe1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gV2hlbiB3ZSBhcmUgaW4gSS5FLiBidXQgdGhlIHNjcmlwdCBoYXMgYmVlbiBldmFsZWQgc28gSS5FLiBkb2Vzbid0ICB0cnVzdCB0aGUgZ2xvYmFsIG9iamVjdCB3aGVuIGNhbGxlZCBub3JtYWxseVxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dC5jYWxsKG51bGwsIG1hcmtlcik7XG4gICAgICAgIH0gY2F0Y2ggKGUpe1xuICAgICAgICAgICAgLy8gc2FtZSBhcyBhYm92ZSBidXQgd2hlbiBpdCdzIGEgdmVyc2lvbiBvZiBJLkUuIHRoYXQgbXVzdCBoYXZlIHRoZSBnbG9iYWwgb2JqZWN0IGZvciAndGhpcycsIGhvcGZ1bGx5IG91ciBjb250ZXh0IGNvcnJlY3Qgb3RoZXJ3aXNlIGl0IHdpbGwgdGhyb3cgYSBnbG9iYWwgZXJyb3IuXG4gICAgICAgICAgICAvLyBTb21lIHZlcnNpb25zIG9mIEkuRS4gaGF2ZSBkaWZmZXJlbnQgcnVsZXMgZm9yIGNsZWFyVGltZW91dCB2cyBzZXRUaW1lb3V0XG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkQ2xlYXJUaW1lb3V0LmNhbGwodGhpcywgbWFya2VyKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG5cbn1cbnZhciBxdWV1ZSA9IFtdO1xudmFyIGRyYWluaW5nID0gZmFsc2U7XG52YXIgY3VycmVudFF1ZXVlO1xudmFyIHF1ZXVlSW5kZXggPSAtMTtcblxuZnVuY3Rpb24gY2xlYW5VcE5leHRUaWNrKCkge1xuICAgIGlmICghZHJhaW5pbmcgfHwgIWN1cnJlbnRRdWV1ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGRyYWluaW5nID0gZmFsc2U7XG4gICAgaWYgKGN1cnJlbnRRdWV1ZS5sZW5ndGgpIHtcbiAgICAgICAgcXVldWUgPSBjdXJyZW50UXVldWUuY29uY2F0KHF1ZXVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBxdWV1ZUluZGV4ID0gLTE7XG4gICAgfVxuICAgIGlmIChxdWV1ZS5sZW5ndGgpIHtcbiAgICAgICAgZHJhaW5RdWV1ZSgpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gZHJhaW5RdWV1ZSgpIHtcbiAgICBpZiAoZHJhaW5pbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB2YXIgdGltZW91dCA9IHJ1blRpbWVvdXQoY2xlYW5VcE5leHRUaWNrKTtcbiAgICBkcmFpbmluZyA9IHRydWU7XG5cbiAgICB2YXIgbGVuID0gcXVldWUubGVuZ3RoO1xuICAgIHdoaWxlKGxlbikge1xuICAgICAgICBjdXJyZW50UXVldWUgPSBxdWV1ZTtcbiAgICAgICAgcXVldWUgPSBbXTtcbiAgICAgICAgd2hpbGUgKCsrcXVldWVJbmRleCA8IGxlbikge1xuICAgICAgICAgICAgaWYgKGN1cnJlbnRRdWV1ZSkge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRRdWV1ZVtxdWV1ZUluZGV4XS5ydW4oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBxdWV1ZUluZGV4ID0gLTE7XG4gICAgICAgIGxlbiA9IHF1ZXVlLmxlbmd0aDtcbiAgICB9XG4gICAgY3VycmVudFF1ZXVlID0gbnVsbDtcbiAgICBkcmFpbmluZyA9IGZhbHNlO1xuICAgIHJ1bkNsZWFyVGltZW91dCh0aW1lb3V0KTtcbn1cblxucHJvY2Vzcy5uZXh0VGljayA9IGZ1bmN0aW9uIChmdW4pIHtcbiAgICB2YXIgYXJncyA9IG5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoIC0gMSk7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBxdWV1ZS5wdXNoKG5ldyBJdGVtKGZ1biwgYXJncykpO1xuICAgIGlmIChxdWV1ZS5sZW5ndGggPT09IDEgJiYgIWRyYWluaW5nKSB7XG4gICAgICAgIHJ1blRpbWVvdXQoZHJhaW5RdWV1ZSk7XG4gICAgfVxufTtcblxuLy8gdjggbGlrZXMgcHJlZGljdGlibGUgb2JqZWN0c1xuZnVuY3Rpb24gSXRlbShmdW4sIGFycmF5KSB7XG4gICAgdGhpcy5mdW4gPSBmdW47XG4gICAgdGhpcy5hcnJheSA9IGFycmF5O1xufVxuSXRlbS5wcm90b3R5cGUucnVuID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZnVuLmFwcGx5KG51bGwsIHRoaXMuYXJyYXkpO1xufTtcbnByb2Nlc3MudGl0bGUgPSAnYnJvd3Nlcic7XG5wcm9jZXNzLmJyb3dzZXIgPSB0cnVlO1xucHJvY2Vzcy5lbnYgPSB7fTtcbnByb2Nlc3MuYXJndiA9IFtdO1xucHJvY2Vzcy52ZXJzaW9uID0gJyc7IC8vIGVtcHR5IHN0cmluZyB0byBhdm9pZCByZWdleHAgaXNzdWVzXG5wcm9jZXNzLnZlcnNpb25zID0ge307XG5cbmZ1bmN0aW9uIG5vb3AoKSB7fVxuXG5wcm9jZXNzLm9uID0gbm9vcDtcbnByb2Nlc3MuYWRkTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5vbmNlID0gbm9vcDtcbnByb2Nlc3Mub2ZmID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBub29wO1xucHJvY2Vzcy5lbWl0ID0gbm9vcDtcbnByb2Nlc3MucHJlcGVuZExpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3MucHJlcGVuZE9uY2VMaXN0ZW5lciA9IG5vb3A7XG5cbnByb2Nlc3MubGlzdGVuZXJzID0gZnVuY3Rpb24gKG5hbWUpIHsgcmV0dXJuIFtdIH1cblxucHJvY2Vzcy5iaW5kaW5nID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb2Nlc3MuYmluZGluZyBpcyBub3Qgc3VwcG9ydGVkJyk7XG59O1xuXG5wcm9jZXNzLmN3ZCA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuICcvJyB9O1xucHJvY2Vzcy5jaGRpciA9IGZ1bmN0aW9uIChkaXIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb2Nlc3MuY2hkaXIgaXMgbm90IHN1cHBvcnRlZCcpO1xufTtcbnByb2Nlc3MudW1hc2sgPSBmdW5jdGlvbigpIHsgcmV0dXJuIDA7IH07XG4iXX0=