(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 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; } },{}],2:[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":3,"./turn.json":4,"normalice":8}],3:[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" ] },{}],4:[function(require,module,exports){ module.exports=[] },{}],5:[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; if (typeof window !== 'undefined') { 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.frequencyBinCount); 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'); } analyser.disconnect(); sourceNode.disconnect(); }; 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":33}],6:[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 } } },{}],7:[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 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; }; },{}],9:[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'); function writeMediaSection(transceiver, caps, type, stream, dtlsRole) { 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' : dtlsRole || 'active'); sdp += 'a=mid:' + transceiver.mid + '\r\n'; 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; } // Edge does not like // 1) stun: filtered after 14393 unless ?transport=udp is present // 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 && url.indexOf('?transport=udp') === -1; }); delete server.url; server.urls = isString ? urls[0] : urls; return !!urls.length; } }); } // 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; } function maybeAddCandidate(iceTransport, candidate) { // Edge's internal representation adds some fields therefore // not all fieldѕ are taken into account. var alreadyAdded = iceTransport.getRemoteCandidates() .find(function(remoteCandidate) { return candidate.foundation === remoteCandidate.foundation && candidate.ip === remoteCandidate.ip && candidate.port === remoteCandidate.port && candidate.priority === remoteCandidate.priority && candidate.protocol === remoteCandidate.protocol && candidate.type === remoteCandidate.type; }); if (!alreadyAdded) { iceTransport.addRemoteCandidate(candidate); } return !alreadyAdded; } // https://w3c.github.io/mediacapture-main/#mediastream // Helper function to add the track to the stream and // dispatch the event ourselves. function addTrackToStreamAndFireEvent(track, stream) { stream.addTrack(track); var e = new Event('addtrack'); // TODO: MediaStreamTrackEvent e.track = track; stream.dispatchEvent(e); } function removeTrackFromStreamAndFireEvent(track, stream) { stream.removeTrack(track); var e = new Event('removetrack'); // TODO: MediaStreamTrackEvent e.track = track; stream.dispatchEvent(e); } function fireAddTrack(pc, track, receiver, streams) { var trackEvent = new Event('track'); trackEvent.track = track; trackEvent.receiver = receiver; trackEvent.transceiver = {receiver: receiver}; trackEvent.streams = streams; window.setTimeout(function() { pc.dispatchEvent(trackEvent); if (typeof pc.ontrack === 'function') { pc.ontrack(trackEvent); } }); } 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.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.needNegotiation = false; this.localStreams = []; this.remoteStreams = []; this.localDescription = null; this.remoteDescription = null; this.signalingState = 'stable'; this.iceConnectionState = 'new'; this.iceGatheringState = 'new'; config = JSON.parse(JSON.stringify(config || {})); this.usingBundle = config.bundlePolicy === 'max-bundle'; if (config.rtcpMuxPolicy === 'negotiate') { var e = new Error('rtcpMuxPolicy \'negotiate\' is not supported'); e.name = 'NotSupportedError'; throw(e); } else if (!config.rtcpMuxPolicy) { config.rtcpMuxPolicy = 'require'; } switch (config.iceTransportPolicy) { case 'all': case 'relay': break; default: config.iceTransportPolicy = 'all'; break; } switch (config.bundlePolicy) { case 'balanced': case 'max-compat': case 'max-bundle': break; default: config.bundlePolicy = 'balanced'; break; } config.iceServers = filterIceServers(config.iceServers || [], edgeVersion); this._iceGatherers = []; if (config.iceCandidatePoolSize) { for (var i = config.iceCandidatePoolSize; i > 0; i--) { this._iceGatherers = new window.RTCIceGatherer({ iceServers: config.iceServers, gatherPolicy: config.iceTransportPolicy }); } } else { config.iceCandidatePoolSize = 0; } this._config = config; // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... // everything that is needed to describe a SDP m-line. this.transceivers = []; this._sdpSessionId = SDPUtils.generateSessionId(); this._sdpSessionVersion = 0; this._dtlsRole = undefined; // role for a=setup to use in answers. }; RTCPeerConnection.prototype._emitGatheringStateChange = function() { var event = new Event('icegatheringstatechange'); this.dispatchEvent(event); if (typeof this.onicegatheringstatechange === 'function') { this.onicegatheringstatechange(event); } }; RTCPeerConnection.prototype.getConfiguration = function() { return this._config; }; RTCPeerConnection.prototype.getLocalStreams = function() { return this.localStreams; }; RTCPeerConnection.prototype.getRemoteStreams = function() { return this.remoteStreams; }; // 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, associatedRemoteMediaStreams: [], 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); } this._maybeFireNegotiationNeeded(); if (this.localStreams.indexOf(stream) === -1) { this.localStreams.push(stream); } transceiver.track = track; transceiver.stream = stream; transceiver.rtpSender = new window.RTCRtpSender(track, transceiver.dtlsTransport); return transceiver.rtpSender; }; RTCPeerConnection.prototype.addStream = function(stream) { var self = this; if (edgeVersion >= 15025) { 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); }); } }; RTCPeerConnection.prototype.removeTrack = function(sender) { if (!(sender instanceof window.RTCRtpSender)) { throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' + 'does not implement interface RTCRtpSender.'); } var transceiver = this.transceivers.find(function(t) { return t.rtpSender === sender; }); if (!transceiver) { var err = new Error('Sender was not created by this connection.'); err.name = 'InvalidAccessError'; throw err; } var stream = transceiver.stream; transceiver.rtpSender.stop(); transceiver.rtpSender = null; transceiver.track = null; transceiver.stream = null; // remove the stream from the set of local streams var localStreams = this.transceivers.map(function(t) { return t.stream; }); if (localStreams.indexOf(stream) === -1 && this.localStreams.indexOf(stream) > -1) { this.localStreams.splice(this.localStreams.indexOf(stream), 1); } this._maybeFireNegotiationNeeded(); }; RTCPeerConnection.prototype.removeStream = function(stream) { var self = this; stream.getTracks().forEach(function(track) { var sender = self.getSenders().find(function(s) { return s.track === track; }); if (sender) { self.removeTrack(sender); } }); }; 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; }); }; RTCPeerConnection.prototype._createIceGatherer = function(sdpMLineIndex, usingBundle) { var self = this; if (usingBundle && sdpMLineIndex > 0) { return this.transceivers[0].iceGatherer; } else if (this._iceGatherers.length) { return this._iceGatherers.shift(); } var iceGatherer = new window.RTCIceGatherer({ iceServers: this._config.iceServers, gatherPolicy: this._config.iceTransportPolicy }); Object.defineProperty(iceGatherer, 'state', {value: 'new', writable: true} ); this.transceivers[sdpMLineIndex].candidates = []; this.transceivers[sdpMLineIndex].bufferCandidates = function(event) { var end = !event.candidate || Object.keys(event.candidate).length === 0; // polyfill since RTCIceGatherer.state is not implemented in // Edge 10547 yet. iceGatherer.state = end ? 'completed' : 'gathering'; if (self.transceivers[sdpMLineIndex].candidates !== null) { self.transceivers[sdpMLineIndex].candidates.push(event.candidate); } }; iceGatherer.addEventListener('localcandidate', this.transceivers[sdpMLineIndex].bufferCandidates); return iceGatherer; }; // start gathering from an RTCIceGatherer. RTCPeerConnection.prototype._gather = function(mid, sdpMLineIndex) { var self = this; var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; if (iceGatherer.onlocalcandidate) { return; } var candidates = this.transceivers[sdpMLineIndex].candidates; this.transceivers[sdpMLineIndex].candidates = null; iceGatherer.removeEventListener('localcandidate', this.transceivers[sdpMLineIndex].bufferCandidates); iceGatherer.onlocalcandidate = function(evt) { if (self.usingBundle && sdpMLineIndex > 0) { // if we know that we use bundle we can drop candidates with // ѕdpMLineIndex > 0. If we don't do this then our state gets // confused since we dispose the extra ice gatherer. return; } var event = new Event('icecandidate'); event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; var cand = evt.candidate; // Edge emits an empty object for RTCIceCandidateComplete‥ var end = !cand || Object.keys(cand).length === 0; if (end) { // polyfill since RTCIceGatherer.state is not implemented in // Edge 10547 yet. if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') { iceGatherer.state = 'completed'; } } else { if (iceGatherer.state === 'new') { iceGatherer.state = 'gathering'; } // 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 complete = self.transceivers.every(function(transceiver) { return transceiver.iceGatherer && transceiver.iceGatherer.state === 'completed'; }); if (self.iceGatheringState !== 'gathering') { self.iceGatheringState = 'gathering'; self._emitGatheringStateChange(); } // Emit candidate. Also emit null candidate when all gatherers are // complete. if (!end) { self.dispatchEvent(event); if (typeof self.onicecandidate === 'function') { self.onicecandidate(event); } } if (complete) { self.dispatchEvent(new Event('icecandidate')); if (typeof self.onicecandidate === 'function') { self.onicecandidate(new Event('icecandidate')); } self.iceGatheringState = 'complete'; self._emitGatheringStateChange(); } }; // emit already gathered candidates. window.setTimeout(function() { candidates.forEach(function(candidate) { var e = new Event('RTCIceGatherEvent'); e.candidate = candidate; iceGatherer.onlocalcandidate(e); }); }, 0); }; // 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.ondtlsstatechange; 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 && params.codecs.length > 0) { // remove RTX field in Edge 14942 if (transceiver.kind === 'video' && transceiver.recvEncodingParameters && edgeVersion < 15019) { transceiver.recvEncodingParameters.forEach(function(p) { delete p.rtx; }); } if (transceiver.recvEncodingParameters.length) { params.encodings = transceiver.recvEncodingParameters; } params.rtcp = { compound: transceiver.rtcpParameters.compound }; if (transceiver.rtcpParameters.cname) { params.rtcp.cname = transceiver.rtcpParameters.cname; } if (transceiver.sendEncodingParameters.length) { params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; } transceiver.rtpReceiver.receive(params); } }; RTCPeerConnection.prototype.setLocalDescription = function(description) { var self = this; var args = arguments; if (!isActionAllowedInSignalingState('setLocalDescription', description.type, this.signalingState)) { return new Promise(function(resolve, reject) { var e = new Error('Can not set local ' + description.type + ' in state ' + self.signalingState); e.name = 'InvalidStateError'; if (args.length > 2 && typeof args[2] === 'function') { args[2].apply(null, [e]); } reject(e); }); } var sections; var sessionpart; if (description.type === 'offer') { // 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.transceivers[sdpMLineIndex].localCapabilities = caps; }); this.transceivers.forEach(function(transceiver, sdpMLineIndex) { self._gather(transceiver.mid, sdpMLineIndex); }); } 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; // treat bundle-only as not-rejected. var rejected = SDPUtils.isRejected(mediaSection) && !SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 1; 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) { self._gather(transceiver.mid, sdpMLineIndex); if (iceTransport.state === 'new') { iceTransport.start(iceGatherer, remoteIceParameters, isIceLite ? 'controlling' : 'controlled'); } if (dtlsTransport.state === 'new') { 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 cb = arguments.length > 1 && typeof arguments[1] === 'function' && arguments[1]; return new Promise(function(resolve) { if (cb) { cb.apply(null); } resolve(); }); }; RTCPeerConnection.prototype.setRemoteDescription = function(description) { var self = this; var args = arguments; if (!isActionAllowedInSignalingState('setRemoteDescription', description.type, this.signalingState)) { return new Promise(function(resolve, reject) { var e = new Error('Can not set remote ' + description.type + ' in state ' + self.signalingState); e.name = 'InvalidStateError'; if (args.length > 2 && typeof args[2] === 'function') { args[2].apply(null, [e]); } reject(e); }); } var streams = {}; this.remoteStreams.forEach(function(stream) { streams[stream.id] = stream; }); 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); // treat bundle-only as not-rejected. var rejected = SDPUtils.isRejected(mediaSection) && !SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 1; 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; }); // 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 = self._createIceGatherer(sdpMLineIndex, usingBundle); } if (cands.length && transceiver.iceTransport.state === 'new') { if (isComplete && (!usingBundle || sdpMLineIndex === 0)) { transceiver.iceTransport.setRemoteCandidates(cands); } else { cands.forEach(function(candidate) { maybeAddCandidate(transceiver.iceTransport, candidate); }); } } 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 = transceiver.sendEncodingParameters || [{ ssrc: (2 * sdpMLineIndex + 2) * 1001 }]; // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams var isNewTrack = false; if (direction === 'sendrecv' || direction === 'sendonly') { isNewTrack = !transceiver.rtpReceiver; rtpReceiver = transceiver.rtpReceiver || new window.RTCRtpReceiver(transceiver.dtlsTransport, kind); if (isNewTrack) { var stream; track = rtpReceiver.track; // FIXME: does not work with Plan B. if (remoteMsid && remoteMsid.stream === '-') { // no-op. a stream id of '-' means: no associated stream. } else 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; } }); stream = streams[remoteMsid.stream]; } else { if (!streams.default) { streams.default = new window.MediaStream(); } stream = streams.default; } if (stream) { addTrackToStreamAndFireEvent(track, stream); transceiver.associatedRemoteMediaStreams.push(stream); } receiverList.push([track, rtpReceiver, stream]); } } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track) { transceiver.associatedRemoteMediaStreams.forEach(function(s) { var nativeTrack = s.getTracks().find(function(t) { return t.id === transceiver.rtpReceiver.track.id; }); if (nativeTrack) { removeTrackFromStreamAndFireEvent(nativeTrack, s); } }); transceiver.associatedRemoteMediaStreams = []; } 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, isNewTrack); } 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 (cands.length && iceTransport.state === 'new') { if ((isIceLite || isComplete) && (!usingBundle || sdpMLineIndex === 0)) { iceTransport.setRemoteCandidates(cands); } else { cands.forEach(function(candidate) { maybeAddCandidate(transceiver.iceTransport, candidate); }); } } if (!usingBundle || sdpMLineIndex === 0) { if (iceTransport.state === 'new') { iceTransport.start(iceGatherer, remoteIceParameters, 'controlling'); } if (dtlsTransport.state === 'new') { dtlsTransport.start(remoteDtlsParameters); } } self._transceive(transceiver, direction === 'sendrecv' || direction === 'recvonly', direction === 'sendrecv' || direction === 'sendonly'); // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams if (rtpReceiver && (direction === 'sendrecv' || direction === 'sendonly')) { track = rtpReceiver.track; if (remoteMsid) { if (!streams[remoteMsid.stream]) { streams[remoteMsid.stream] = new window.MediaStream(); } addTrackToStreamAndFireEvent(track, streams[remoteMsid.stream]); receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); } else { if (!streams.default) { streams.default = new window.MediaStream(); } addTrackToStreamAndFireEvent(track, streams.default); receiverList.push([track, rtpReceiver, streams.default]); } } else { // FIXME: actually the receiver should be created later. delete transceiver.rtpReceiver; } } }); if (this._dtlsRole === undefined) { this._dtlsRole = description.type === 'offer' ? 'active' : 'passive'; } 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) { if (self.remoteStreams.indexOf(stream) === -1) { self.remoteStreams.push(stream); var event = new Event('addstream'); event.stream = stream; window.setTimeout(function() { self.dispatchEvent(event); if (typeof self.onaddstream === 'function') { self.onaddstream(event); } }); } receiverList.forEach(function(item) { var track = item[0]; var receiver = item[1]; if (stream.id !== item[2].id) { return; } fireAddTrack(self, track, receiver, [stream]); }); } }); receiverList.forEach(function(item) { if (item[2]) { return; } fireAddTrack(self, item[0], item[1], []); }); // 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); return new Promise(function(resolve) { if (args.length > 1 && typeof args[1] === 'function') { args[1].apply(null); } 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 (typeof this.onsignalingstatechange === 'function') { 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 (typeof self.onnegotiationneeded === 'function') { self.onnegotiationneeded(event); } }, 0); }; // Update the connection state. RTCPeerConnection.prototype._updateConnectionState = function() { 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 !== this.iceConnectionState) { this.iceConnectionState = newState; var event = new Event('iceconnectionstatechange'); this.dispatchEvent(event); if (typeof this.oniceconnectionstatechange === 'function') { this.oniceconnectionstatechange(event); } } }; RTCPeerConnection.prototype.createOffer = function() { var self = this; var args = arguments; 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--; } } var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, this._sdpSessionVersion++); this.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._createIceGatherer(sdpMLineIndex, self.usingBundle); } 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 = transceiver.sendEncodingParameters || [{ ssrc: (2 * sdpMLineIndex + 1) * 1001 }]; if (track) { // add RTX if (edgeVersion >= 15019 && kind === 'video' && !sendEncodingParameters[0].rtx) { sendEncodingParameters[0].rtx = { ssrc: sendEncodingParameters[0].ssrc + 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 ' + this.transceivers.map(function(t) { return t.mid; }).join(' ') + '\r\n'; } sdp += 'a=ice-options:trickle\r\n'; this.transceivers.forEach(function(transceiver, sdpMLineIndex) { sdp += writeMediaSection(transceiver, transceiver.localCapabilities, 'offer', transceiver.stream, self._dtlsRole); sdp += 'a=rtcp-rsize\r\n'; if (transceiver.iceGatherer && self.iceGatheringState !== 'new' && (sdpMLineIndex === 0 || !self.usingBundle)) { transceiver.iceGatherer.getLocalCandidates().forEach(function(cand) { cand.component = 1; sdp += 'a=' + SDPUtils.writeCandidate(cand) + '\r\n'; }); if (transceiver.iceGatherer.state === 'completed') { sdp += 'a=end-of-candidates\r\n'; } } }); var desc = new window.RTCSessionDescription({ type: 'offer', sdp: sdp }); return new Promise(function(resolve) { if (args.length > 0 && typeof args[0] === 'function') { args[0].apply(null, [desc]); resolve(); return; } resolve(desc); }); }; RTCPeerConnection.prototype.createAnswer = function() { var self = this; var args = arguments; var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, this._sdpSessionVersion++); if (this.usingBundle) { sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { return t.mid; }).join(' ') + '\r\n'; } var mediaSectionsInOffer = SDPUtils.splitSections( this.remoteDescription.sdp).length - 1; this.transceivers.forEach(function(transceiver, sdpMLineIndex) { if (sdpMLineIndex + 1 > mediaSectionsInOffer) { return; } 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) { transceiver.sendEncodingParameters[0].rtx = { ssrc: transceiver.sendEncodingParameters[0].ssrc + 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 += writeMediaSection(transceiver, commonCapabilities, 'answer', transceiver.stream, self._dtlsRole); if (transceiver.rtcpParameters && transceiver.rtcpParameters.reducedSize) { sdp += 'a=rtcp-rsize\r\n'; } }); var desc = new window.RTCSessionDescription({ type: 'answer', sdp: sdp }); return new Promise(function(resolve) { if (args.length > 0 && typeof args[0] === 'function') { args[0].apply(null, [desc]); resolve(); return; } resolve(desc); }); }; RTCPeerConnection.prototype.addIceCandidate = function(candidate) { var err; var sections; if (!candidate || candidate.candidate === '') { for (var j = 0; j < this.transceivers.length; j++) { if (this.transceivers[j].isDatachannel) { continue; } this.transceivers[j].iceTransport.addRemoteCandidate({}); sections = SDPUtils.splitSections(this.remoteDescription.sdp); sections[j + 1] += 'a=end-of-candidates\r\n'; this.remoteDescription.sdp = sections.join(''); if (this.usingBundle) { break; } } } else if (!(candidate.sdpMLineIndex !== undefined || candidate.sdpMid)) { throw new TypeError('sdpMLineIndex or sdpMid required'); } else if (!this.remoteDescription) { err = new Error('Can not add ICE candidate without ' + 'a remote description'); err.name = 'InvalidStateError'; } else { var sdpMLineIndex = candidate.sdpMLineIndex; if (candidate.sdpMid) { for (var i = 0; i < this.transceivers.length; i++) { if (this.transceivers[i].mid === candidate.sdpMid) { sdpMLineIndex = i; break; } } } var transceiver = this.transceivers[sdpMLineIndex]; if (transceiver) { if (transceiver.isDatachannel) { return Promise.resolve(); } 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) { return Promise.resolve(); } // when using bundle, avoid adding candidates to the wrong // ice transport. And avoid adding candidates added in the SDP. if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 && transceiver.iceTransport !== this.transceivers[0].iceTransport)) { if (!maybeAddCandidate(transceiver.iceTransport, cand)) { err = new Error('Can not add ICE candidate'); err.name = 'OperationError'; } } if (!err) { // update the remoteDescription. var candidateString = candidate.candidate.trim(); if (candidateString.indexOf('a=') === 0) { candidateString = candidateString.substr(2); } sections = SDPUtils.splitSections(this.remoteDescription.sdp); sections[sdpMLineIndex + 1] += 'a=' + (cand.type ? candidateString : 'end-of-candidates') + '\r\n'; this.remoteDescription.sdp = sections.join(''); } } else { err = new Error('Can not add ICE candidate'); err.name = 'OperationError'; } } var args = arguments; return new Promise(function(resolve, reject) { if (err) { if (args.length > 2 && typeof args[2] === 'function') { args[2].apply(null, [err]); } reject(err); } else { if (args.length > 1 && typeof args[1] === 'function') { args[1].apply(null); } 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) { cb.apply(null, results); } resolve(results); }); }); }; return RTCPeerConnection; }; },{"sdp":18}],10:[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"; } }); }); },{}],11:[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":12,"./writer":13}],12:[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":10}],13:[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":10}],14:[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; }; },{}],15:[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":16}],16:[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":14,"./transform":17}],17:[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":11}],18:[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: parseInt(parts[1], 10), 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; case 'ufrag': candidate.ufrag = parts[i + 1]; // for backward compability. candidate.usernameFragment = 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); } if (candidate.ufrag) { sdp.push('ufrag'); sdp.push(candidate.ufrag); } 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: 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) { // use formula from JSEP to convert b=AS to TIAS value. bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 - (50 * 40 * 8); } else { bandwidth = undefined; } 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]}; } }; // Generate a session ID for SDP. // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 // recommends using a cryptographically random +ve 64-bit value // but right now this should be acceptable and within the right range SDPUtils.generateSessionId = function() { return Math.random().toString().substr(2, 21); }; // Write boilder plate for start of SDP // sessId argument is optional - if not supplied it will // be generated randomly // sessVersion is optional and defaults to 2 SDPUtils.writeSessionBoilerplate = function(sessId, sessVer) { var sessionId; var version = sessVer !== undefined ? sessVer : 2; if (sessId) { sessionId = sessId; } else { sessionId = SDPUtils.generateSessionId(); } // FIXME: sess-id should be an NTP timestamp. return 'v=0\r\n' + 'o=thisisadapterortc ' + sessionId + ' ' + version + ' 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'; }; SDPUtils.parseMLine = function(mediaSection) { var lines = SDPUtils.splitLines(mediaSection); var mline = lines[0].split(' '); return { kind: mline[0].substr(2), port: parseInt(mline[1], 10), protocol: mline[2], fmt: mline.slice(3).join(' ') }; }; // Expose public methods. if (typeof module === 'object') { module.exports = SDPUtils; } },{}],19:[function(require,module,exports){ /** * UAParser.js v0.7.17 * Lightweight JavaScript-based User-Agent string parser * https://github.com/faisalman/ua-parser-js * * Copyright © 2012-2016 Faisal Salman * Dual licensed under GPLv2 & MIT */ (function (window, undefined) { 'use strict'; ////////////// // Constants ///////////// var LIBVERSION = '0.7.17', 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 (ua, arrays) { //var result = {}, var i = 0, j, k, p, q, matches, match;//, args = arguments; /*// construct object barebones for (p = 0; p < args[1].length; p++) { q = args[1][p]; result[typeof q === OBJ_TYPE ? q[0] : q] = undefined; }*/ // loop through all regexes maps while (i < arrays.length && !matches) { var regex = arrays[i], // even sequence (0,2,4,..) props = arrays[i + 1]; // odd sequence (1,3,5,..) j = k = 0; // try matching uastring with regexes while (j < regex.length && !matches) { matches = regex[j++].exec(ua); 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 this[q[0]] = q[1].call(this, match); } else { // assign given value, ignore regex match this[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) this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined; } else { // sanitize match using given regex this[q[0]] = match ? match.replace(q[1], q[2]) : undefined; } } else if (q.length == 4) { this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined; } } else { this[q] = match ? match : undefined; } } } } i += 2; } // console.log(this); //return this; }, 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|bowser)\/([\w\.-]+)/i // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser ], [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], [ /(puffin)\/([\w\.]+)/i // Puffin ], [[NAME, 'Puffin'], VERSION], [ /((?:[\s\/])uc?\s?browser|(?:juc.+)ucweb)[\/\s]?([\w\.]+)/i // UCBrowser ], [[NAME, 'UCBrowser'], VERSION], [ /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon ], [[NAME, /_/g, ' '], VERSION], [ /(micromessenger)\/([\w\.]+)/i // WeChat ], [[NAME, 'WeChat'], VERSION], [ /(QQ)\/([\d\.]+)/i // QQ, aka ShouQ ], [NAME, VERSION], [ /m?(qqbrowser)[\/\s]?([\w\.]+)/i // QQBrowser ], [NAME, VERSION], [ /xiaomi\/miuibrowser\/([\w\.]+)/i // MIUI Browser ], [VERSION, [NAME, 'MIUI Browser']], [ /;fbav\/([\w\.]+);/i // Facebook App for iOS & Android ], [VERSION, [NAME, 'Facebook']], [ /headlesschrome(?:\/([\w\.]+)|\s)/i // Chrome Headless ], [VERSION, [NAME, 'Chrome Headless']], [ /\swv\).+(chrome)\/([\w\.]+)/i // Chrome WebView ], [[NAME, /(.+)/, '$1 WebView'], VERSION], [ /((?:oculus|samsung)browser)\/([\w\.]+)/i ], [[NAME, /(.+(?:g|us))(.+)/, '$1 $2'], VERSION], [ // Oculus / Samsung Browser /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 ], [NAME, VERSION], [ /(dolfin)\/([\w\.]+)/i // Dolphin ], [[NAME, 'Dolphin'], VERSION], [ /((?:android.+)crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS ], [[NAME, 'Chrome'], VERSION], [ /(coast)\/([\w\.]+)/i // Opera Coast ], [[NAME, 'Opera Coast'], VERSION], [ /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.+?(gsa)\/([\w\.]+).+?(mobile\s?safari|safari)(\/[\w\.]+)/i // Google Search Appliance on iOS ], [[NAME, 'GSA'], VERSION], [ /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|meizu|motorola|polytron)[\s_-]?([\w-]+)*/i, // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/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]], [ /android.+\s([c-g]\d{4}|so[-l]\w+)\sbuild\//i ], [MODEL, [VENDOR, 'Sony'], [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|lenovo|nexian|panasonic|(?=;\s)sony)[_\s-]?([\w-]+)*/i // Alcatel/GeeksPhone/Lenovo/Nexian/Panasonic/Sony ], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], [ /(nexus\s9)/i // HTC Nexus 9 ], [MODEL, [VENDOR, 'HTC'], [TYPE, TABLET]], [ /d\/huawei([\w\s-]+)[;\)]/i, /(nexus\s6p)/i // Huawei ], [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.+([vl]k\-?\d{3})\s+build/i // LG Tablet ], [MODEL, [VENDOR, 'LG'], [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, /android.+lg(\-?[\d\w]+)\s+build/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(oppo)\s?([\w\s]+)\sbuild/i // OPPO ], [VENDOR, MODEL, [TYPE, MOBILE]], [ /crkey/i // Google Chromecast ], [[MODEL, 'Chromecast'], [VENDOR, 'Google']], [ /android.+;\s(glass)\s\d/i // Google Glass ], [MODEL, [VENDOR, 'Google'], [TYPE, WEARABLE]], [ /android.+;\s(pixel c)\s/i // Google Pixel C ], [MODEL, [VENDOR, 'Google'], [TYPE, TABLET]], [ /android.+;\s(pixel xl|pixel)\s/i // Google Pixel ], [MODEL, [VENDOR, 'Google'], [TYPE, MOBILE]], [ /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 /android.+(redmi[\s\-_]*(?:note)?(?:[\s_]*[\w\s]+)?)\s+build/i // Redmi Phones ], [[MODEL, /_/g, ' '], [VENDOR, 'Xiaomi'], [TYPE, MOBILE]], [ /android.+(mi[\s\-_]*(?:pad)?(?:[\s_]*[\w\s]+)?)\s+build/i // Mi Pad tablets ],[[MODEL, /_/g, ' '], [VENDOR, 'Xiaomi'], [TYPE, TABLET]], [ /android.+;\s(m[1-5]\snote)\sbuild/i // Meizu Tablet ], [MODEL, [VENDOR, 'Meizu'], [TYPE, TABLET]], [ /android.+a000(1)\s+build/i // OnePlus ], [MODEL, [VENDOR, 'OnePlus'], [TYPE, MOBILE]], [ /android.+[;\/]\s*(RCT[\d\w]+)\s+build/i // RCA Tablets ], [MODEL, [VENDOR, 'RCA'], [TYPE, TABLET]], [ /android.+[;\/]\s*(Venue[\d\s]*)\s+build/i // Dell Venue Tablets ], [MODEL, [VENDOR, 'Dell'], [TYPE, TABLET]], [ /android.+[;\/]\s*(Q[T|M][\d\w]+)\s+build/i // Verizon Tablet ], [MODEL, [VENDOR, 'Verizon'], [TYPE, TABLET]], [ /android.+[;\/]\s+(Barnes[&\s]+Noble\s+|BN[RT])(V?.*)\s+build/i // Barnes & Noble Tablet ], [[VENDOR, 'Barnes & Noble'], MODEL, [TYPE, TABLET]], [ /android.+[;\/]\s+(TM\d{3}.*\b)\s+build/i // Barnes & Noble Tablet ], [MODEL, [VENDOR, 'NuVision'], [TYPE, TABLET]], [ /android.+[;\/]\s*(zte)?.+(k\d{2})\s+build/i // ZTE K Series Tablet ], [[VENDOR, 'ZTE'], MODEL, [TYPE, TABLET]], [ /android.+[;\/]\s*(gen\d{3})\s+build.*49h/i // Swiss GEN Mobile ], [MODEL, [VENDOR, 'Swiss'], [TYPE, MOBILE]], [ /android.+[;\/]\s*(zur\d{3})\s+build/i // Swiss ZUR Tablet ], [MODEL, [VENDOR, 'Swiss'], [TYPE, TABLET]], [ /android.+[;\/]\s*((Zeki)?TB.*\b)\s+build/i // Zeki Tablets ], [MODEL, [VENDOR, 'Zeki'], [TYPE, TABLET]], [ /(android).+[;\/]\s+([YR]\d{2}x?.*)\s+build/i, /android.+[;\/]\s+(Dragon[\-\s]+Touch\s+|DT)(.+)\s+build/i // Dragon Touch Tablet ], [[VENDOR, 'Dragon Touch'], MODEL, [TYPE, TABLET]], [ /android.+[;\/]\s*(NS-?.+)\s+build/i // Insignia Tablets ], [MODEL, [VENDOR, 'Insignia'], [TYPE, TABLET]], [ /android.+[;\/]\s*((NX|Next)-?.+)\s+build/i // NextBook Tablets ], [MODEL, [VENDOR, 'NextBook'], [TYPE, TABLET]], [ /android.+[;\/]\s*(Xtreme\_?)?(V(1[045]|2[015]|30|40|60|7[05]|90))\s+build/i ], [[VENDOR, 'Voice'], MODEL, [TYPE, MOBILE]], [ // Voice Xtreme Phones /android.+[;\/]\s*(LVTEL\-?)?(V1[12])\s+build/i // LvTel Phones ], [[VENDOR, 'LvTel'], MODEL, [TYPE, MOBILE]], [ /android.+[;\/]\s*(V(100MD|700NA|7011|917G).*\b)\s+build/i // Envizen Tablets ], [MODEL, [VENDOR, 'Envizen'], [TYPE, TABLET]], [ /android.+[;\/]\s*(Le[\s\-]+Pan)[\s\-]+(.*\b)\s+build/i // Le Pan Tablets ], [VENDOR, MODEL, [TYPE, TABLET]], [ /android.+[;\/]\s*(Trio[\s\-]*.*)\s+build/i // MachSpeed Tablets ], [MODEL, [VENDOR, 'MachSpeed'], [TYPE, TABLET]], [ /android.+[;\/]\s*(Trinity)[\-\s]*(T\d{3})\s+build/i // Trinity Tablets ], [VENDOR, MODEL, [TYPE, TABLET]], [ /android.+[;\/]\s*TU_(1491)\s+build/i // Rotor Tablets ], [MODEL, [VENDOR, 'Rotor'], [TYPE, TABLET]], [ /android.+(KS(.+))\s+build/i // Amazon Kindle Tablets ], [MODEL, [VENDOR, 'Amazon'], [TYPE, TABLET]], [ /android.+(Gigaset)[\s\-]+(Q.+)\s+build/i // Gigaset Tablets ], [VENDOR, MODEL, [TYPE, TABLET]], [ /\s(tablet|tab)[;\/]/i, // Unidentifiable Tablet /\s(mobile)(?:[;\/]|\ssafari)/i // Unidentifiable Mobile ], [[TYPE, util.lowerize], VENDOR, MODEL], [ /(android.+)[;\/].+build/i // Generic Android Device ], [MODEL, [VENDOR, 'Generic']] /*////////////////////////// // 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]], [ /(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],[ /cfnetwork\/.+darwin/i, /ip[honead]+(?:.*os\s([\w]+)\slike\smac|;\sopera)/i // iOS ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [ /(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 Browser = function (name, version) { this[NAME] = name; this[VERSION] = version; }; var CPU = function (arch) { this[ARCHITECTURE] = arch; }; var Device = function (vendor, model, type) { this[VENDOR] = vendor; this[MODEL] = model; this[TYPE] = type; }; var Engine = Browser; var OS = Browser; */ var UAParser = function (uastring, extensions) { if (typeof uastring === 'object') { extensions = uastring; uastring = undefined; } 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; //var browser = new Browser(); //var cpu = new CPU(); //var device = new Device(); //var engine = new Engine(); //var os = new OS(); this.getBrowser = function () { var browser = { name: undefined, version: undefined }; mapper.rgx.call(browser, ua, rgxmap.browser); browser.major = util.major(browser.version); // deprecated return browser; }; this.getCPU = function () { var cpu = { architecture: undefined }; mapper.rgx.call(cpu, ua, rgxmap.cpu); return cpu; }; this.getDevice = function () { var device = { vendor: undefined, model: undefined, type: undefined }; mapper.rgx.call(device, ua, rgxmap.device); return device; }; this.getEngine = function () { var engine = { name: undefined, version: undefined }; mapper.rgx.call(engine, ua, rgxmap.engine); return engine; }; this.getOS = function () { var os = { name: undefined, version: undefined }; mapper.rgx.call(os, ua, rgxmap.os); return 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; //browser = new Browser(); //cpu = new CPU(); //device = new Device(); //engine = new Engine(); //os = new OS(); 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 }; //UAParser.Utils = util; /////////// // Export ////////// // check js environment if (typeof(exports) !== UNDEF_TYPE) { // nodejs env if (typeof module !== UNDEF_TYPE && module.exports) { exports = module.exports = UAParser; } // TODO: test!!!!!!!! /* if (require && require.main === module && process) { // cli var jsonize = function (arr) { var res = []; for (var i in arr) { res.push(new UAParser(arr[i]).getResult()); } process.stdout.write(JSON.stringify(res, null, 2) + '\n'); }; if (process.stdin.isTTY) { // via args jsonize(process.argv.slice(2)); } else { // via pipe var str = ''; process.stdin.on('readable', function() { var read = process.stdin.read(); if (read !== null) { str += read; } }); process.stdin.on('end', function () { jsonize(str.replace(/\n$/, '').split('\n')); }); } } */ exports.UAParser = UAParser; } else { // requirejs env (optional) if (typeof(define) === FUNC_TYPE && define.amd) { define(function () { return UAParser; }); } else if (window) { // 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 && (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); },{}],20:[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 : {}) },{}],21:[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":20}],22:[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":23}],23:[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'); // Shimming starts here. module.exports = function(dependencies, opts) { var window = dependencies && dependencies.window; var options = { shimChrome: true, shimFirefox: true, shimEdge: true, shimSafari: true, }; for (var key in opts) { if (hasOwnProperty.call(opts, key)) { options[key] = opts[key]; } } // 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, disableWarnings: utils.disableWarnings }; // 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; var commonShim = require('./common_shim') || null; // Shim browser if found. switch (browserDetails.browser) { case 'chrome': if (!chromeShim || !chromeShim.shimPeerConnection || !options.shimChrome) { 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; commonShim.shimCreateObjectURL(window); chromeShim.shimGetUserMedia(window); chromeShim.shimMediaStream(window); chromeShim.shimSourceObject(window); chromeShim.shimPeerConnection(window); chromeShim.shimOnTrack(window); chromeShim.shimAddTrackRemoveTrack(window); chromeShim.shimGetSendersWithDtmf(window); commonShim.shimRTCIceCandidate(window); break; case 'firefox': if (!firefoxShim || !firefoxShim.shimPeerConnection || !options.shimFirefox) { 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; commonShim.shimCreateObjectURL(window); firefoxShim.shimGetUserMedia(window); firefoxShim.shimSourceObject(window); firefoxShim.shimPeerConnection(window); firefoxShim.shimOnTrack(window); commonShim.shimRTCIceCandidate(window); break; case 'edge': if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { 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; commonShim.shimCreateObjectURL(window); edgeShim.shimGetUserMedia(window); edgeShim.shimPeerConnection(window); edgeShim.shimReplaceTrack(window); // the edge shim implements the full RTCIceCandidate object. break; case 'safari': if (!safariShim || !options.shimSafari) { 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; commonShim.shimCreateObjectURL(window); safariShim.shimRTCIceServerUrls(window); safariShim.shimCallbacksAPI(window); safariShim.shimLocalStreamsAPI(window); safariShim.shimRemoteStreamsAPI(window); safariShim.shimTrackEventTransceiver(window); safariShim.shimGetUserMedia(window); commonShim.shimRTCIceCandidate(window); break; default: logging('Unsupported browser!'); break; } return adapter; }; },{"./chrome/chrome_shim":24,"./common_shim":26,"./edge/edge_shim":27,"./firefox/firefox_shim":29,"./safari/safari_shim":31,"./utils":32}],24:[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) { if (this._ontrack) { this.removeEventListener('track', this._ontrack); } this.addEventListener('track', this._ontrack = f); } }); var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; window.RTCPeerConnection.prototype.setRemoteDescription = function() { var pc = this; if (!pc._ontrackpoly) { pc._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 = pc.getReceivers().find(function(r) { return r.track && r.track.id === te.track.id; }); } else { receiver = {track: te.track}; } var event = new Event('track'); event.track = te.track; event.receiver = receiver; event.transceiver = {receiver: receiver}; event.streams = [e.stream]; pc.dispatchEvent(event); }); e.stream.getTracks().forEach(function(track) { var receiver; if (window.RTCPeerConnection.prototype.getReceivers) { receiver = pc.getReceivers().find(function(r) { return r.track && r.track.id === track.id; }); } else { receiver = {track: track}; } var event = new Event('track'); event.track = track; event.receiver = receiver; event.transceiver = {receiver: receiver}; event.streams = [e.stream]; pc.dispatchEvent(event); }); }; pc.addEventListener('addstream', pc._ontrackpoly); } return origSetRemoteDescription.apply(pc, arguments); }; } }, shimGetSendersWithDtmf: function(window) { // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. if (typeof window === 'object' && window.RTCPeerConnection && !('getSenders' in window.RTCPeerConnection.prototype) && 'createDTMFSender' in window.RTCPeerConnection.prototype) { var shimSenderWithDtmf = function(pc, track) { return { 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: pc }; }; // augment addTrack when getSenders is not available. if (!window.RTCPeerConnection.prototype.getSenders) { window.RTCPeerConnection.prototype.getSenders = function() { this._senders = this._senders || []; return this._senders.slice(); // return a copy of the internal state. }; var origAddTrack = window.RTCPeerConnection.prototype.addTrack; window.RTCPeerConnection.prototype.addTrack = function(track, stream) { var pc = this; var sender = origAddTrack.apply(pc, arguments); if (!sender) { sender = shimSenderWithDtmf(pc, track); pc._senders.push(sender); } return sender; }; var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; window.RTCPeerConnection.prototype.removeTrack = function(sender) { var pc = this; origRemoveTrack.apply(pc, arguments); var idx = pc._senders.indexOf(sender); if (idx !== -1) { pc._senders.splice(idx, 1); } }; } var origAddStream = window.RTCPeerConnection.prototype.addStream; 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(shimSenderWithDtmf(pc, track)); }); }; var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; window.RTCPeerConnection.prototype.removeStream = function(stream) { var pc = this; pc._senders = pc._senders || []; origRemoveStream.apply(pc, [(pc._streams[stream.id] || 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 } }); }; } else if (typeof window === 'object' && window.RTCPeerConnection && 'getSenders' in window.RTCPeerConnection.prototype && 'createDTMFSender' in window.RTCPeerConnection.prototype && window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { var origGetSenders = window.RTCPeerConnection.prototype.getSenders; window.RTCPeerConnection.prototype.getSenders = function() { var pc = this; var senders = origGetSenders.apply(pc, []); senders.forEach(function(sender) { sender._pc = pc; }); return senders; }; Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { get: function() { if (this._dtmf === undefined) { if (this.track.kind === 'audio') { this._dtmf = this._pc.createDTMFSender(this.track); } else { this._dtmf = null; } } return this._dtmf; } }); } }, 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); }); } }); } } }, shimAddTrackRemoveTrack: function(window) { var browserDetails = utils.detectBrowser(window); // shim addTrack and removeTrack. if (window.RTCPeerConnection.prototype.addTrack && browserDetails.version >= 62) { return; } // also shim pc.getLocalStreams when addTrack is shimmed // to return the original streams. var origGetLocalStreams = window.RTCPeerConnection.prototype .getLocalStreams; window.RTCPeerConnection.prototype.getLocalStreams = function() { var self = this; var nativeStreams = origGetLocalStreams.apply(this); self._reverseStreams = self._reverseStreams || {}; return nativeStreams.map(function(stream) { return self._reverseStreams[stream.id]; }); }; var origAddStream = window.RTCPeerConnection.prototype.addStream; window.RTCPeerConnection.prototype.addStream = function(stream) { var pc = this; pc._streams = pc._streams || {}; pc._reverseStreams = pc._reverseStreams || {}; stream.getTracks().forEach(function(track) { var alreadyExists = pc.getSenders().find(function(s) { return s.track === track; }); if (alreadyExists) { throw new DOMException('Track already exists.', 'InvalidAccessError'); } }); // Add identity mapping for consistency with addTrack. // Unless this is being used with a stream from addTrack. if (!pc._reverseStreams[stream.id]) { var newStream = new window.MediaStream(stream.getTracks()); pc._streams[stream.id] = newStream; pc._reverseStreams[newStream.id] = stream; stream = newStream; } origAddStream.apply(pc, [stream]); }; var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; window.RTCPeerConnection.prototype.removeStream = function(stream) { var pc = this; pc._streams = pc._streams || {}; pc._reverseStreams = pc._reverseStreams || {}; origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]); delete pc._reverseStreams[(pc._streams[stream.id] ? pc._streams[stream.id].id : stream.id)]; delete pc._streams[stream.id]; }; 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'); } var alreadyExists = pc.getSenders().find(function(s) { return s.track === track; }); if (alreadyExists) { throw new DOMException('Track already exists.', 'InvalidAccessError'); } pc._streams = pc._streams || {}; pc._reverseStreams = pc._reverseStreams || {}; var oldStream = pc._streams[stream.id]; if (oldStream) { // this is using odd Chrome behaviour, use with caution: // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 // Note: we rely on the high-level addTrack/dtmf shim to // create the sender with a dtmf sender. oldStream.addTrack(track); // Trigger ONN async. Promise.resolve().then(function() { pc.dispatchEvent(new Event('negotiationneeded')); }); } else { var newStream = new window.MediaStream([track]); pc._streams[stream.id] = newStream; pc._reverseStreams[newStream.id] = stream; pc.addStream(newStream); } return pc.getSenders().find(function(s) { return s.track === track; }); }; // replace the internal stream id with the external one and // vice versa. function replaceInternalStreamId(pc, description) { var sdp = description.sdp; Object.keys(pc._reverseStreams || []).forEach(function(internalId) { var externalStream = pc._reverseStreams[internalId]; var internalStream = pc._streams[externalStream.id]; sdp = sdp.replace(new RegExp(internalStream.id, 'g'), externalStream.id); }); return new RTCSessionDescription({ type: description.type, sdp: sdp }); } function replaceExternalStreamId(pc, description) { var sdp = description.sdp; Object.keys(pc._reverseStreams || []).forEach(function(internalId) { var externalStream = pc._reverseStreams[internalId]; var internalStream = pc._streams[externalStream.id]; sdp = sdp.replace(new RegExp(externalStream.id, 'g'), internalStream.id); }); return new RTCSessionDescription({ type: description.type, sdp: sdp }); } ['createOffer', 'createAnswer'].forEach(function(method) { var nativeMethod = window.RTCPeerConnection.prototype[method]; window.RTCPeerConnection.prototype[method] = function() { var pc = this; var args = arguments; var isLegacyCall = arguments.length && typeof arguments[0] === 'function'; if (isLegacyCall) { return nativeMethod.apply(pc, [ function(description) { var desc = replaceInternalStreamId(pc, description); args[0].apply(null, [desc]); }, function(err) { if (args[1]) { args[1].apply(null, err); } }, arguments[2] ]); } return nativeMethod.apply(pc, arguments) .then(function(description) { return replaceInternalStreamId(pc, description); }); }; }); var origSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; window.RTCPeerConnection.prototype.setLocalDescription = function() { var pc = this; if (!arguments.length || !arguments[0].type) { return origSetLocalDescription.apply(pc, arguments); } arguments[0] = replaceExternalStreamId(pc, arguments[0]); return origSetLocalDescription.apply(pc, arguments); }; // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier var origLocalDescription = Object.getOwnPropertyDescriptor( window.RTCPeerConnection.prototype, 'localDescription'); Object.defineProperty(window.RTCPeerConnection.prototype, 'localDescription', { get: function() { var pc = this; var description = origLocalDescription.get.apply(this); if (description.type === '') { return description; } return replaceInternalStreamId(pc, description); } }); window.RTCPeerConnection.prototype.removeTrack = function(sender) { var pc = this; if (pc.signalingState === 'closed') { throw new DOMException( 'The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); } // We can not yet check for sender instanceof RTCRtpSender // since we shim RTPSender. So we check if sender._pc is set. if (!sender._pc) { throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + 'does not implement interface RTCRtpSender.', 'TypeError'); } var isLocal = sender._pc === pc; if (!isLocal) { throw new DOMException('Sender was not created by this connection.', 'InvalidAccessError'); } // Search for the native stream the senders track belongs to. pc._streams = pc._streams || {}; var stream; Object.keys(pc._streams).forEach(function(streamid) { var hasTrack = pc._streams[streamid].getTracks().find(function(track) { return sender.track === track; }); if (hasTrack) { stream = pc._streams[streamid]; } }); if (stream) { if (stream.getTracks().length === 1) { // if this is the last track of the stream, remove the stream. This // takes care of any shimmed _senders. pc.removeStream(stream); } else { // relying on the same odd chrome behaviour as above. stream.removeTrack(sender.track); } pc.dispatchEvent(new Event('negotiationneeded')); } }; }, 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')) { utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); 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, shimAddTrackRemoveTrack: chromeShim.shimAddTrackRemoveTrack, shimGetSendersWithDtmf: chromeShim.shimGetSendersWithDtmf, shimSourceObject: chromeShim.shimSourceObject, shimPeerConnection: chromeShim.shimPeerConnection, shimGetUserMedia: require('./getusermedia') }; },{"../utils.js":32,"./getusermedia":25}],25:[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) { if (onError) { 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":32}],26:[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'); var utils = require('./utils'); // Wraps the peerconnection event eventNameToWrap in a function // which returns the modified event object. function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { if (!window.RTCPeerConnection) { return; } var proto = window.RTCPeerConnection.prototype; var nativeAddEventListener = proto.addEventListener; proto.addEventListener = function(nativeEventName, cb) { if (nativeEventName !== eventNameToWrap) { return nativeAddEventListener.apply(this, arguments); } var wrappedCallback = function(e) { cb(wrapper(e)); }; this._eventMap = this._eventMap || {}; this._eventMap[cb] = wrappedCallback; return nativeAddEventListener.apply(this, [nativeEventName, wrappedCallback]); }; var nativeRemoveEventListener = proto.removeEventListener; proto.removeEventListener = function(nativeEventName, cb) { if (nativeEventName !== eventNameToWrap || !this._eventMap || !this._eventMap[cb]) { return nativeRemoveEventListener.apply(this, arguments); } var unwrappedCb = this._eventMap[cb]; delete this._eventMap[cb]; return nativeRemoveEventListener.apply(this, [nativeEventName, unwrappedCb]); }; Object.defineProperty(proto, 'on' + eventNameToWrap, { get: function() { return this['_on' + eventNameToWrap]; }, set: function(cb) { if (this['_on' + eventNameToWrap]) { this.removeEventListener(eventNameToWrap, this['_on' + eventNameToWrap]); delete this['_on' + eventNameToWrap]; } if (cb) { this.addEventListener(eventNameToWrap, this['_on' + eventNameToWrap] = cb); } } }); } module.exports = { shimRTCIceCandidate: function(window) { // foundation is arbitrarily chosen as an indicator for full support for // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface if (window.RTCIceCandidate && 'foundation' in window.RTCIceCandidate.prototype) { return; } var NativeRTCIceCandidate = window.RTCIceCandidate; window.RTCIceCandidate = function(args) { // Remove the a= which shouldn't be part of the candidate string. if (typeof args === 'object' && args.candidate && args.candidate.indexOf('a=') === 0) { args = JSON.parse(JSON.stringify(args)); args.candidate = args.candidate.substr(2); } // Augment the native candidate with the parsed fields. var nativeCandidate = new NativeRTCIceCandidate(args); var parsedCandidate = SDPUtils.parseCandidate(args.candidate); var augmentedCandidate = Object.assign(nativeCandidate, parsedCandidate); // Add a serializer that does not serialize the extra attributes. augmentedCandidate.toJSON = function() { return { candidate: augmentedCandidate.candidate, sdpMid: augmentedCandidate.sdpMid, sdpMLineIndex: augmentedCandidate.sdpMLineIndex, usernameFragment: augmentedCandidate.usernameFragment, }; }; return augmentedCandidate; }; // Hook up the augmented candidate in onicecandidate and // addEventListener('icecandidate', ...) wrapPeerConnectionEvent(window, 'icecandidate', function(e) { if (e.candidate) { Object.defineProperty(e, 'candidate', { value: new window.RTCIceCandidate(e.candidate), writable: 'false' }); } return e; }); }, // 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 && URL.createObjectURL && URL.revokeObjectURL)) { // 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); utils.deprecated('URL.createObjectURL(stream)', 'elem.srcObject = stream'); 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); }; } }; },{"./utils":32,"sdp":18}],27:[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); } }); } } // ORTC defines the DTMF sender a bit different. // https://github.com/w3c/ortc/issues/714 if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { get: function() { if (this._dtmf === undefined) { if (this.track.kind === 'audio') { this._dtmf = new window.RTCDtmfSender(this); } else if (this.track.kind === 'video') { this._dtmf = null; } } return this._dtmf; } }); } 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":32,"./getusermedia":28,"rtcpeerconnection-shim":9}],28:[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)); }); }; }; },{}],29:[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.transceiver = {receiver: event.receiver}; event.streams = [e.stream]; this.dispatchEvent(event); }.bind(this)); }.bind(this)); } }); } if (typeof window === 'object' && window.RTCTrackEvent && ('receiver' in window.RTCTrackEvent.prototype) && !('transceiver' in window.RTCTrackEvent.prototype)) { Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { get: function() { return {receiver: this.receiver}; } }); } }, 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":32,"./getusermedia":30}],30:[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. utils.deprecated('navigator.getUserMedia', 'navigator.mediaDevices.getUserMedia'); navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); }; }; },{"../utils":32}],31:[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 utils = require('../utils'); 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() { }, shimLocalStreamsAPI: function(window) { if (typeof window !== 'object' || !window.RTCPeerConnection) { return; } if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { window.RTCPeerConnection.prototype.getLocalStreams = function() { if (!this._localStreams) { this._localStreams = []; } return this._localStreams; }; } if (!('getStreamById' in window.RTCPeerConnection.prototype)) { window.RTCPeerConnection.prototype.getStreamById = function(id) { var result = null; if (this._localStreams) { this._localStreams.forEach(function(stream) { if (stream.id === id) { result = stream; } }); } if (this._remoteStreams) { this._remoteStreams.forEach(function(stream) { if (stream.id === id) { result = stream; } }); } return result; }; } if (!('addStream' in window.RTCPeerConnection.prototype)) { var _addTrack = window.RTCPeerConnection.prototype.addTrack; window.RTCPeerConnection.prototype.addStream = function(stream) { if (!this._localStreams) { this._localStreams = []; } if (this._localStreams.indexOf(stream) === -1) { this._localStreams.push(stream); } var self = this; stream.getTracks().forEach(function(track) { _addTrack.call(self, track, stream); }); }; window.RTCPeerConnection.prototype.addTrack = function(track, stream) { if (stream) { if (!this._localStreams) { this._localStreams = [stream]; } else if (this._localStreams.indexOf(stream) === -1) { this._localStreams.push(stream); } } _addTrack.call(this, track, stream); }; } if (!('removeStream' in window.RTCPeerConnection.prototype)) { window.RTCPeerConnection.prototype.removeStream = function(stream) { if (!this._localStreams) { this._localStreams = []; } var index = this._localStreams.indexOf(stream); if (index === -1) { return; } this._localStreams.splice(index, 1); var self = this; var tracks = stream.getTracks(); this.getSenders().forEach(function(sender) { if (tracks.indexOf(sender.track) !== -1) { self.removeTrack(sender); } }); }; } }, shimRemoteStreamsAPI: function(window) { if (typeof window !== 'object' || !window.RTCPeerConnection) { return; } if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { window.RTCPeerConnection.prototype.getRemoteStreams = function() { return this._remoteStreams ? this._remoteStreams : []; }; } if (!('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._remoteStreams) { this._remoteStreams = []; } if (this._remoteStreams.indexOf(stream) >= 0) { return; } this._remoteStreams.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); } } }, shimRTCIceServerUrls: function(window) { // 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')) { utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); server = JSON.parse(JSON.stringify(server)); server.urls = server.url; delete 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. if ('generateCertificate' in window.RTCPeerConnection) { Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { get: function() { return OrigPeerConnection.generateCertificate; } }); } }, shimTrackEventTransceiver: function(window) { // Add event.transceiver member over deprecated event.receiver if (typeof window === 'object' && window.RTCPeerConnection && ('receiver' in window.RTCTrackEvent.prototype) && // can't check 'transceiver' in window.RTCTrackEvent.prototype, as it is // defined for some reason even when window.RTCTransceiver is not. !window.RTCTransceiver) { Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { get: function() { return {receiver: this.receiver}; } }); } } }; // Expose public methods. module.exports = { shimCallbacksAPI: safariShim.shimCallbacksAPI, shimLocalStreamsAPI: safariShim.shimLocalStreamsAPI, shimRemoteStreamsAPI: safariShim.shimRemoteStreamsAPI, shimGetUserMedia: safariShim.shimGetUserMedia, shimRTCIceServerUrls: safariShim.shimRTCIceServerUrls, shimTrackEventTransceiver: safariShim.shimTrackEventTransceiver // TODO // shimPeerConnection: safariShim.shimPeerConnection }; },{"../utils":32}],32:[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; var deprecationWarnings_ = 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'; }, /** * Disable or enable deprecation warnings * @param {!boolean} bool set to true to disable warnings. */ disableWarnings: function(bool) { if (typeof bool !== 'boolean') { return new Error('Argument type: ' + typeof bool + '. Please use a boolean.'); } deprecationWarnings_ = !bool; return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); }, log: function() { if (typeof window === 'object') { if (logDisabled_) { return; } if (typeof console !== 'undefined' && typeof console.log === 'function') { console.log.apply(console, arguments); } } }, /** * Shows a deprecation warning suggesting the modern and spec-compatible API. */ deprecated: function(oldMethod, newMethod) { if (!deprecationWarnings_) { return; } console.warn(oldMethod + ' is deprecated, please use ' + newMethod + ' instead.'); }, /** * 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; }, }; // Export. module.exports = { log: utils.log, deprecated: utils.deprecated, disableLog: utils.disableLog, disableWarnings: utils.disableWarnings, extractVersion: utils.extractVersion, shimCreateObjectURL: utils.shimCreateObjectURL, detectBrowser: utils.detectBrowser.bind(utils) }; },{}],33:[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); },{}],34:[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)); },{}],35:[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; },{}],36:[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":37}],37:[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 Logger = console; /** * * heartbeat: interval in ms for each heartbeat message, * sendCloseMessage : true / false, before closing the connection, it sends a closeSession message *
 * 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,
 * 	onerror : callback method to invoke when there is an error
 * },
 * rpc : {
 * 	requestTimeout : timeout for a request,
 * 	sessionStatusChanged: callback method for changes in session status,
 * 	mediaRenegotiation: mediaRenegotiation
 * }
 * 
*/ 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; var onerror = wsConfig.onerror; configuration.rpc.pull = function (params, request) { request.reply(null, "push"); }; wsConfig.onreconnecting = function () { Logger.debug("--------- ONRECONNECTING -----------"); if (status === RECONNECTING) { Logger.error("Websocket already in RECONNECTING state when receiving a new ONRECONNECTING message. Ignoring it"); return; } status = RECONNECTING; if (onreconnecting) { onreconnecting(); } }; wsConfig.onreconnected = function () { Logger.debug("--------- ONRECONNECTED -----------"); if (status === CONNECTED) { Logger.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 () { Logger.debug("--------- ONCONNECTED -----------"); if (status === CONNECTED) { Logger.error("Websocket already in CONNECTED state when receiving a new ONCONNECTED message. Ignoring it"); return; } status = CONNECTED; enabledPings = true; usePing(); if (onconnected) { onconnected(); } }; wsConfig.onerror = function (error) { Logger.debug("--------- ONERROR -----------"); status = DISCONNECTED; if (onerror) { onerror(error); } }; var ws = new WebSocketWithReconnection(wsConfig); Logger.debug('Connecting websocket to URI: ' + wsConfig.uri); var rpcBuilderOptions = { request_timeout: configuration.rpc.requestTimeout, ping_request_timeout: configuration.rpc.heartbeatRequestTimeout }; var rpc = new RpcBuilder(RpcBuilder.packers.JsonRPC, rpcBuilderOptions, ws, function (request) { Logger.debug('Received request: ' + JSON.stringify(request)); try { var func = configuration.rpc[request.method]; if (func === undefined) { Logger.error("Method " + request.method + " not registered in client"); } else { func(request.params, request); } } catch (err) { Logger.error('Exception processing request: ' + JSON.stringify(request)); Logger.error(err); } }); this.send = function (method, params, callback) { if (method !== 'ping') { Logger.debug('Request: method:' + method + " params:" + JSON.stringify(params)); } var requestTime = Date.now(); rpc.encode(method, params, function (error, result) { if (error) { try { Logger.error("ERROR:" + error.message + " in Request: method:" + method + " params:" + JSON.stringify(params) + " request:" + error.request); if (error.data) { Logger.error("ERROR DATA:" + JSON.stringify(error.data)); } } catch (e) { } error.requestTime = requestTime; } if (callback) { if (result != undefined && result.value !== 'pong') { Logger.debug('Response: ' + JSON.stringify(result)); } callback(error, result); } }); }; function updateNotReconnectIfLessThan() { Logger.debug("notReconnectIfNumLessThan = " + pingNextNum + ' (old=' + notReconnectIfNumLessThan + ')'); notReconnectIfNumLessThan = pingNextNum; } function sendPing() { if (enabledPings) { var params = null; if (pingNextNum == 0 || pingNextNum == notReconnectIfNumLessThan) { params = { interval: configuration.heartbeat || PING_INTERVAL }; } pingNextNum++; self.send('ping', params, (function (pingNum) { return function (error, result) { if (error) { Logger.debug("Error in ping request #" + pingNum + " (" + error.message + ")"); if (pingNum > notReconnectIfNumLessThan) { enabledPings = false; updateNotReconnectIfLessThan(); Logger.debug("Server did not respond to ping message #" + pingNum + ". Reconnecting... "); ws.reconnectWs(); } } }; })(pingNextNum)); } else { Logger.debug("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) { Logger.debug("Starting ping (if configured)"); pingPongStarted = true; if (configuration.heartbeat != undefined) { pingInterval = setInterval(sendPing, configuration.heartbeat); sendPing(); } } } this.close = function () { Logger.debug("Closing jsonRpcClient explicitly by client"); if (pingInterval != undefined) { Logger.debug("Clearing ping interval"); clearInterval(pingInterval); } pingPongStarted = false; enabledPings = false; if (configuration.sendCloseMessage) { Logger.debug("Sending close message"); this.send('closeSession', null, function (error, result) { if (error) { Logger.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; },{"../":40,"./transports/webSocketWithReconnection":39}],38:[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":39}],39:[function(require,module,exports){ (function (global){ /* * (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 BrowserWebSocket = global.WebSocket || global.MozWebSocket; var Logger = console; /** * Get either the `WebSocket` or `MozWebSocket` globals * in the browser or try to resolve WebSocket-compatible * interface exposed by `ws` for Node-like environment. */ /*var WebSocket = BrowserWebSocket; if (!WebSocket && typeof window === 'undefined') { try { WebSocket = require('ws'); } catch (e) { } }*/ //var SockJS = require('sockjs-client'); var MAX_RETRIES = 2000; // Forever... var RETRY_TIME_MS = 3000; // FIXME: Implement exponential wait times... 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); if (config.onconnected) { config.onconnected(); } }; ws.onerror = function (error) { Logger.error("Could not connect to " + wsUri + " (invoking onerror if defined)", error); if (config.onerror) { config.onerror(error); } }; function logConnected(ws, wsUri) { try { Logger.debug("WebSocket connected to " + wsUri); } catch (e) { Logger.error(e); } } var reconnectionOnClose = function () { if (ws.readyState === CLOSED) { if (closing) { Logger.debug("Connection closed by user"); } else { Logger.debug("Connection closed unexpectecly. Reconnecting..."); reconnectToSameUri(MAX_RETRIES, 1); } } else { Logger.debug("Close callback from previous websocket. Ignoring it"); } }; ws.onclose = reconnectionOnClose; function reconnectToSameUri(maxRetries, numRetries) { Logger.debug("reconnectToSameUri (attempt #" + numRetries + ", max=" + maxRetries + ")"); if (numRetries === 1) { if (reconnecting) { Logger.warn("Trying to reconnectToNewUri when reconnecting... Ignoring this reconnection."); return; } else { reconnecting = true; } if (config.onreconnecting) { config.onreconnecting(); } } if (forcingDisconnection) { reconnectToNewUri(maxRetries, numRetries, wsUri); } else { if (config.newWsUriOnReconnection) { config.newWsUriOnReconnection(function (error, newWsUri) { if (error) { Logger.debug(error); setTimeout(function () { reconnectToSameUri(maxRetries, numRetries + 1); }, RETRY_TIME_MS); } else { reconnectToNewUri(maxRetries, numRetries, newWsUri); } }); } else { reconnectToNewUri(maxRetries, numRetries, wsUri); } } } // TODO Test retries. How to force not connection? function reconnectToNewUri(maxRetries, numRetries, reconnectWsUri) { Logger.debug("Reconnection attempt #" + numRetries); ws.close(); wsUri = reconnectWsUri || wsUri; var newWs; if (useSockJS) { newWs = new SockJS(wsUri); } else { newWs = new WebSocket(wsUri); } newWs.onopen = function () { Logger.debug("Reconnected after " + numRetries + " attempts..."); logConnected(newWs, wsUri); reconnecting = false; registerMessageHandler(); if (config.onreconnected()) { config.onreconnected(); } newWs.onclose = reconnectionOnClose; }; var onErrorOrClose = function (error) { Logger.warn("Reconnection error: ", error); if (numRetries === maxRetries) { if (config.ondisconnect) { config.ondisconnect(); } } else { setTimeout(function () { reconnectToSameUri(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) { Logger.debug("Testing: Force WebSocket close"); if (millis) { Logger.debug("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 () { Logger.debug("Testing: Recover good wsUri " + goodWsUri); wsUri = goodWsUri; forcingDisconnection = false; }, millis); } ws.close(); }; this.reconnectWs = function () { Logger.debug("reconnectWs"); reconnectToSameUri(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; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],40:[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); else if (transport.removeListener) transport.removeListener('data', transportMessage); } ; // Set listener on new transport if (value) { // W3C transports if (value.addEventListener) value.addEventListener('message', transportMessage); 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 ping_request_timeout = options.ping_request_timeout || request_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); } else if (response) message = response.message; 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) { var rt = (method === 'ping' ? ping_request_timeout : request_timeout); request.timeout = setTimeout(timeout, rt * 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.debug(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":35,"./clients":36,"./clients/transports":38,"./packers":43,"events":1,"inherits":6}],41:[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; } 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; },{}],42:[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; },{}],43:[function(require,module,exports){ var JsonRPC = require('./JsonRPC'); var XmlRPC = require('./XmlRPC'); exports.JsonRPC = JsonRPC; exports.XmlRPC = XmlRPC; },{"./JsonRPC":41,"./XmlRPC":42}],44:[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.debug(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.debug('constraints: ' + JSON.stringify(constraints)); pc.createOffer(constraints).then(function (offer) { logger.debug('Created SDP offer'); offer = mangleSdpToAddSimulcast(offer); return pc.setLocalDescription(offer); }).then(function () { var localDescription = pc.localDescription; logger.debug('Local description set', localDescription.sdp); if (multistream && usePlanB) { localDescription = interop.toUnifiedPlan(localDescription); logger.debug('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.debug('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.debug('asnwer::planB', dumpSDP(planBAnswer)); answer = planBAnswer; } logger.debug('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.debug('offer::planB', dumpSDP(planBOffer)); offer = planBOffer; } logger.debug('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.debug('Created SDP answer'); return pc.setLocalDescription(answer); }).then(function () { var localDescription = pc.localDescription; if (multistream && usePlanB) { localDescription = interop.toUnifiedPlan(localDescription); logger.debug('answer::origPlanB->UnifiedPlan', dumpSDP(localDescription)); } logger.debug('Local description set', localDescription.sdp); callback(null, localDescription.sdp); }).catch(callback); }; function mangleSdpToAddSimulcast(answer) { if (simulcast) { if (browser.name === 'Chrome' || browser.name === 'Chromium') { logger.debug('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.debug('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":1,"freeice":2,"hark":5,"inherits":6,"merge":7,"sdp-translator":15,"ua-parser-js":19,"uuid":21}],45:[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":44}],46:[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":47}],47:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* * (C) Copyright 2017 OpenVidu (http://openvidu.io/) * * 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 OpenViduError_1 = require("../OpenViduInternal/OpenViduError"); var adapter = require("webrtc-adapter"); var screenSharingAuto = require("../ScreenSharing/Screen-Capturing-Auto.js"); if (window) { window["adapter"] = adapter; } var OpenVidu = /** @class */ (function () { function OpenVidu() { this.openVidu = new OpenViduInternal_1.OpenViduInternal(); console.info("'OpenVidu' initialized"); } ; 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()) { var publisher_1; if (cameraOptions != null) { cameraOptions.audio = cameraOptions.audio != null ? cameraOptions.audio : true; cameraOptions.video = cameraOptions.video != null ? cameraOptions.video : true; if (!cameraOptions.screen) { // Webcam and/or microphone is being requested var cameraOptionsAux = { sendAudio: cameraOptions.audio != null ? cameraOptions.audio : true, sendVideo: cameraOptions.video != null ? cameraOptions.video : true, activeAudio: cameraOptions.audioActive != null ? cameraOptions.audioActive : true, activeVideo: cameraOptions.videoActive != null ? cameraOptions.videoActive : true, data: true, mediaConstraints: this.openVidu.generateMediaConstraints(cameraOptions) }; cameraOptions = cameraOptionsAux; publisher_1 = new Publisher_1.Publisher(this.openVidu.initPublisherTagged(parentId, cameraOptions, callback), parentId, false); console.info("'Publisher' initialized"); return publisher_1; } else { if (adapter.browserDetails.browser === 'firefox' && adapter.browserDetails.version >= 52) { publisher_1 = new Publisher_1.Publisher(this.openVidu.initPublisherScreen(parentId, callback), parentId, true); screenSharingAuto.getScreenId(function (error, sourceId, screenConstraints) { cameraOptions = { sendAudio: cameraOptions.audio, sendVideo: cameraOptions.video, activeAudio: cameraOptions.audioActive != null ? cameraOptions.audioActive : true, activeVideo: cameraOptions.videoActive != null ? cameraOptions.videoActive : true, data: true, mediaConstraints: { video: screenConstraints.video, audio: false } }; publisher_1.stream.configureScreenOptions(cameraOptions); console.info("'Publisher' initialized"); }); return publisher_1; } else if (adapter.browserDetails.browser === 'chrome') { // Screen is being requested /*screenSharing.isChromeExtensionAvailable((availability) => { switch (availability) { case 'available': console.warn('EXTENSION AVAILABLE!!!'); screenSharing.getScreenConstraints((error, screenConstraints) => { if (!error) { console.warn(screenConstraints); } }); break; case 'unavailable': console.warn('EXTENSION NOT AVAILABLE!!!'); break; case 'isFirefox': console.warn('IT IS FIREFOX!!!'); screenSharing.getScreenConstraints((error, screenConstraints) => { if (!error) { console.warn(screenConstraints); } }); break; } });*/ screenSharingAuto.getScreenId(function (error, sourceId, screenConstraints) { if (error === 'not-installed') { var error_1 = new OpenViduError_1.OpenViduError(OpenViduError_1.OpenViduErrorName.SCREEN_EXTENSION_NOT_INSTALLED, 'https://chrome.google.com/webstore/detail/screen-capturing/ajhifddimkapgcifgcodmmfdlknahffk'); console.error(error_1); if (callback) callback(error_1); return; } else if (error === 'permission-denied') { var error_2 = new OpenViduError_1.OpenViduError(OpenViduError_1.OpenViduErrorName.SCREEN_CAPTURE_DENIED, 'You must allow access to one window of your desktop'); console.error(error_2); if (callback) callback(error_2); return; } cameraOptions = { sendAudio: cameraOptions.audio != null ? cameraOptions.audio : true, sendVideo: cameraOptions.video != null ? cameraOptions.video : true, activeAudio: cameraOptions.audioActive != null ? cameraOptions.audioActive : true, activeVideo: cameraOptions.videoActive != null ? cameraOptions.videoActive : true, data: true, mediaConstraints: { video: screenConstraints.video, audio: false } }; publisher_1.stream.configureScreenOptions(cameraOptions); }, function (error) { console.error('getScreenId error', error); return; }); publisher_1 = new Publisher_1.Publisher(this.openVidu.initPublisherScreen(parentId, callback), parentId, true); console.info("'Publisher' initialized"); return publisher_1; } else { console.error('Screen sharing not supported on ' + adapter.browserDetails.browser); } } } else { cameraOptions = { sendAudio: true, sendVideo: true, activeAudio: true, activeVideo: true, data: true, mediaConstraints: { audio: true, video: { width: { ideal: 1280 } } } }; publisher_1 = new Publisher_1.Publisher(this.openVidu.initPublisherTagged(parentId, cameraOptions, callback), parentId, false); console.info("'Publisher' initialized"); return publisher_1; } } 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.error("Error getting devices", error); callback(error, null); }); }; OpenVidu.prototype.enableProdMode = function () { console.log = function () { }; console.debug = function () { }; console.info = function () { }; console.warn = function () { }; }; return OpenVidu; }()); exports.OpenVidu = OpenVidu; },{"../OpenViduInternal/OpenViduError":52,"../OpenViduInternal/OpenViduInternal":53,"../ScreenSharing/Screen-Capturing-Auto.js":56,"./Publisher":48,"./Session":49,"webrtc-adapter":22}],48:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var EventEmitter = require("wolfy87-eventemitter"); var Publisher = /** @class */ (function () { function Publisher(stream, parentId, isScreenRequested) { var _this = this; this.ee = new EventEmitter(); this.accessAllowed = false; this.isScreenRequested = false; this.stream = stream; this.isScreenRequested = isScreenRequested; 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.subscribeToRemote = function () { this.stream.subscribeToMyRemote(); }; Publisher.prototype.on = function (eventName, callback) { var _this = this; this.ee.addListener(eventName, function (event) { if (event) { console.info("Event '" + eventName + "' triggered by 'Publisher'", event); } else { console.info("Event '" + eventName + "' triggered by 'Publisher'"); } callback(event); }); if (eventName == 'streamCreated') { if (this.stream.isPublisherPublished) { 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 == 'videoElementCreated') { if (this.stream.isVideoELementCreated) { this.ee.emitEvent('videoElementCreated', [{ element: this.stream.getVideoElement() }]); } else { this.stream.addOnceEventListener('video-element-created-by-stream', function (element) { _this.id = element.id; _this.ee.emitEvent('videoElementCreated', [{ element: element.element }]); }); } } if (eventName == 'videoPlaying') { var video = this.stream.getVideoElement(); if (!this.stream.displayMyRemote() && video && video.currentTime > 0 && video.paused == false && video.ended == false && video.readyState == 4) { this.ee.emitEvent('videoPlaying', [{ element: this.stream.getVideoElement() }]); } else { this.stream.addOnceEventListener('video-is-playing', function (element) { _this.ee.emitEvent('videoPlaying', [{ element: element.element }]); }); } } if (eventName == 'remoteVideoPlaying') { var video = this.stream.getVideoElement(); if (this.stream.displayMyRemote() && video && video.currentTime > 0 && video.paused == false && video.ended == false && video.readyState == 4) { this.ee.emitEvent('remoteVideoPlaying', [{ element: this.stream.getVideoElement() }]); } else { this.stream.addOnceEventListener('remote-video-is-playing', function (element) { _this.ee.emitEvent('remoteVideoPlaying', [{ element: element.element }]); }); } } 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":34}],49:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var Subscriber_1 = require("./Subscriber"); var EventEmitter = require("wolfy87-eventemitter"); var Session = /** @class */ (function () { function Session(session, openVidu) { var _this = this; this.session = session; this.openVidu = openVidu; this.ee = new EventEmitter(); this.sessionId = session.getSessionId(); // Listens to the deactivation of the default behaviour upon the deletion of a Stream object this.session.addEventListener('stream-destroyed-default', function (event) { event.stream.removeVideo(); }); // Listens to the deactivation of the default behaviour upon the disconnection of a Session this.session.addEventListener('session-disconnected-default', function () { var s; for (var _i = 0, _a = _this.openVidu.openVidu.getRemoteStreams(); _i < _a.length; _i++) { s = _a[_i]; s.removeVideo(); } if (_this.connection) { for (var streamId in _this.connection.getStreams()) { _this.connection.getStreams()[streamId].removeVideo(); } } }); // Sets or updates the value of 'connection' property. Triggered by SessionInternal when succesful connection this.session.addEventListener('update-connection-object', function (event) { _this.connection = event.connection; }); } Session.prototype.connect = function (param1, param2, param3) { // Early configuration to deactivate automatic subscription to streams if (param3) { this.session.configure({ sessionId: this.session.getSessionId(), participantId: param1, metadata: this.session.stringClientMetadata(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) { var _this = this; if (publisher.isScreenRequested && !publisher.stream.isScreenRequestedReady) { publisher.stream.addOnceEventListener('screen-ready', function () { publisher.session = _this; publisher.stream.publish(); }); } else { publisher.session = this; publisher.stream.publish(); } }; Session.prototype.unpublish = function (publisher) { this.session.unpublish(publisher.stream); }; Session.prototype.on = function (eventName, callback) { this.session.addEventListener(eventName, function (event) { if (event) { console.info("Event '" + eventName + "' triggered by 'Session'", event); } else { console.info("Event '" + eventName + "' triggered by 'Session'"); } callback(event); }); }; Session.prototype.once = function (eventName, callback) { this.session.addOnceEventListener(eventName, function (event) { callback(event); }); }; Session.prototype.off = function (eventName, eventHandler) { this.session.removeListener(eventName, eventHandler); }; Session.prototype.subscribe = function (param1, param2, param3) { // Subscription this.session.subscribe(param1); var subscriber = new Subscriber_1.Subscriber(param1, param2); param1.playOnlyVideo(param2, null); return subscriber; }; Session.prototype.unsubscribe = function (subscriber) { this.session.unsubscribe(subscriber.stream); subscriber.stream.removeVideo(); }; Session.prototype.signal = function (signal, completionHandler) { var signalMessage = {}; if (signal.to && signal.to.length > 0) { var connectionIds = []; for (var i = 0; i < signal.to.length; i++) { connectionIds.push(signal.to[i].connectionId); } signalMessage['to'] = connectionIds; } else { signalMessage['to'] = []; } signalMessage['data'] = signal.data ? signal.data : ''; signalMessage['type'] = signal.type ? signal.type : ''; this.openVidu.openVidu.sendMessage(this.sessionId, this.connection.connectionId, JSON.stringify(signalMessage)); }; return Session; }()); exports.Session = Session; },{"./Subscriber":50,"wolfy87-eventemitter":34}],50:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var EventEmitter = require("wolfy87-eventemitter"); var Subscriber = /** @class */ (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) { if (event) { console.info("Event '" + eventName + "' triggered by 'Subscriber'", event); } else { console.info("Event '" + eventName + "' triggered by 'Subscriber'"); } callback(event); }); if (eventName == 'videoElementCreated') { if (this.stream.isVideoELementCreated) { this.ee.emitEvent('videoElementCreated', [{ element: this.stream.getVideoElement() }]); } else { this.stream.addOnceEventListener('video-element-created-by-stream', function (element) { console.warn("Subscriber emitting videoElementCreated"); _this.id = element.id; _this.ee.emitEvent('videoElementCreated', [{ element: element }]); }); } } if (eventName == 'videoPlaying') { var video = this.stream.getVideoElement(); if (!this.stream.displayMyRemote() && video && video.currentTime > 0 && video.paused == false && video.ended == false && video.readyState == 4) { this.ee.emitEvent('videoPlaying', [{ element: this.stream.getVideoElement() }]); } else { this.stream.addOnceEventListener('video-is-playing', function (element) { _this.ee.emitEvent('videoPlaying', [{ element: element.element }]); }); } } }; return Subscriber; }()); exports.Subscriber = Subscriber; },{"wolfy87-eventemitter":34}],51:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var Stream_1 = require("./Stream"); var Connection = /** @class */ (function () { function Connection(openVidu, local, room, options) { this.openVidu = openVidu; this.local = local; this.room = room; this.options = options; this.streams = {}; this.streamsOpts = []; console.info("'Connection' created (" + (local ? "local" : "remote") + ")" + (local ? "" : ", with 'connectionId' [" + (options ? options.id : '') + "] ")); if (options) { this.connectionId = options.id; this.data = options.metadata; if (options.streams) { this.initStreams(options); } } } Connection.prototype.addStream = function (stream) { this.streams[stream.streamId] = stream; this.room.getStreams()[stream.streamId] = 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)); } }); }; Connection.prototype.initStreams = function (options) { for (var _i = 0, _a = options.streams; _i < _a.length; _i++) { var streamOptions = _a[_i]; var streamOpts = { id: streamOptions.id, connection: this, sendAudio: streamOptions.sendAudio, sendVideo: streamOptions.sendVideo, recvAudio: (streamOptions.audioActive == undefined ? true : streamOptions.audioActive), recvVideo: (streamOptions.videoActive == undefined ? true : streamOptions.videoActive), typeOfVideo: streamOptions.typeOfVideo, activeAudio: streamOptions.activeAudio, activeVideo: streamOptions.activeVideo, data: streamOptions.data, mediaConstraints: streamOptions.mediaConstraints }; var stream = new Stream_1.Stream(this.openVidu, false, this.room, streamOpts); this.addStream(stream); this.streamsOpts.push(streamOpts); } console.info("Remote 'Connection' with 'connectionId' [" + this.connectionId + "] is now configured for receiving Streams with options: ", this.streamsOpts); }; return Connection; }()); exports.Connection = Connection; },{"./Stream":55}],52:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var OpenViduErrorName; (function (OpenViduErrorName) { OpenViduErrorName["CAMERA_ACCESS_DENIED"] = "CAMERA_ACCESS_DENIED"; OpenViduErrorName["MICROPHONE_ACCESS_DENIED"] = "MICROPHONE_ACCESS_DENIED"; OpenViduErrorName["SCREEN_CAPTURE_DENIED"] = "SCREEN_CAPTURE_DENIED"; OpenViduErrorName["NO_VIDEO_DEVICE"] = "NO_VIDEO_DEVICE"; OpenViduErrorName["NO_INPUT_DEVICE"] = "NO_INPUT_DEVICE"; OpenViduErrorName["SCREEN_EXTENSION_NOT_INSTALLED"] = "SCREEN_EXTENSION_NOT_INSTALLED"; OpenViduErrorName["GENERIC_ERROR"] = "GENERIC_ERROR"; })(OpenViduErrorName = exports.OpenViduErrorName || (exports.OpenViduErrorName = {})); var OpenViduError = /** @class */ (function () { function OpenViduError(name, message) { this.name = name; this.message = message; } return OpenViduError; }()); exports.OpenViduError = OpenViduError; },{}],53:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* * (C) Copyright 2017 OpenVidu (http://openvidu.io/) * * 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 OpenViduError_1 = require("./OpenViduError"); var Stream_1 = require("./Stream"); var RpcBuilder = require("../KurentoUtils/kurento-jsonrpc"); var OpenViduInternal = /** @class */ (function () { function OpenViduInternal() { this.remoteStreams = []; } ; /* NEW METHODS */ OpenViduInternal.prototype.initSession = function (sessionId) { console.info("'Session' initialized with 'sessionId' [" + sessionId + "]"); this.session = new SessionInternal_1.SessionInternal(this, sessionId); return this.session; }; OpenViduInternal.prototype.initPublisherTagged = function (parentId, cameraOptions, callback) { var _this = this; this.getCamera(cameraOptions); this.camera.requestCameraAccess(function (error, camera) { if (error) { // Neither camera or microphone device is allowed/able to capture media console.error(error); if (callback) { callback(error); } _this.camera.ee.emitEvent('access-denied-by-publisher'); } else { _this.camera.setVideoElement(_this.cameraReady(camera, parentId)); if (callback) { callback(undefined); } } }); return this.camera; }; OpenViduInternal.prototype.initPublisherScreen = function (parentId, callback) { var _this = this; this.camera = new Stream_1.Stream(this, true, this.session, 'screen-options'); this.camera.addOnceEventListener('can-request-screen', function () { _this.camera.requestCameraAccess(function (error, camera) { if (error) { _this.camera.ee.emitEvent('access-denied-by-publisher'); var errorName = OpenViduError_1.OpenViduErrorName.SCREEN_CAPTURE_DENIED; var errorMessage = 'You must allow access to one window of your desktop'; var e = new OpenViduError_1.OpenViduError(errorName, errorMessage); console.error(e); if (callback) { callback(e); } } else { _this.camera.setVideoElement(_this.cameraReady(camera, parentId)); if (_this.camera.getSendAudio()) { // If the user wants to send audio with the screen capturing navigator.mediaDevices.getUserMedia({ audio: true, video: false }) .then(function (userStream) { _this.camera.getWrStream().addTrack(userStream.getAudioTracks()[0]); _this.camera.isScreenRequestedReady = true; _this.camera.ee.emitEvent('screen-ready'); if (callback) { callback(undefined); } }) .catch(function (error) { _this.camera.ee.emitEvent('access-denied-by-publisher'); console.error("Error accessing the microphone", error); if (callback) { var errorName = OpenViduError_1.OpenViduErrorName.MICROPHONE_ACCESS_DENIED; var errorMessage = error.toString(); callback(new OpenViduError_1.OpenViduError(errorName, errorMessage)); } }); } else { _this.camera.isScreenRequestedReady = true; _this.camera.ee.emitEvent('screen-ready'); if (callback) { 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) { this.getCamera(cameraOptions); this.camera.requestCameraAccess(function (error, camera) { if (error) callback(error); else callback(undefined); }); }; OpenViduInternal.prototype.getLocalStream = function () { return this.camera; }; OpenViduInternal.prototype.getRemoteStreams = function () { return this.remoteStreams; }; /* NEW METHODS */ OpenViduInternal.prototype.getWsUri = function () { return this.wsUri; }; OpenViduInternal.prototype.setWsUri = function (wsUri) { this.wsUri = wsUri; }; OpenViduInternal.prototype.getSecret = function () { return this.secret; }; OpenViduInternal.prototype.setSecret = function (secret) { this.secret = secret; }; 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.warn('Websocket connection lost'); if (this.isRoomAvailable()) { this.session.onLostConnection(); } else { alert('Connection error. Please reload page.'); } }; OpenViduInternal.prototype.reconnectingCallback = function () { console.warn('Websocket connection lost (reconnecting)'); if (this.isRoomAvailable()) { this.session.onLostConnection(); } else { alert('Connection error. Please reload page.'); } }; OpenViduInternal.prototype.reconnectedCallback = function () { console.warn('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.debug('RPC param added to request {' + index + ': ' + this.rpcParams[index] + '}'); } } } console.debug('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 || { sendAudio: true, sendVideo: true, activeAudio: true, activeVideo: 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; }; ; //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 (cameraOptions) { var mediaConstraints = { audio: cameraOptions.audio, video: {} }; if (!cameraOptions.video) { mediaConstraints.video = false; } else { var w = void 0, h = void 0; switch (cameraOptions.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((document.getElementById('frameRate')).value) }; } return mediaConstraints; }; return OpenViduInternal; }()); exports.OpenViduInternal = OpenViduInternal; },{"../KurentoUtils/kurento-jsonrpc":40,"./OpenViduError":52,"./SessionInternal":54,"./Stream":55}],54:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var Connection_1 = require("./Connection"); var EventEmitter = require("wolfy87-eventemitter"); var SECRET_PARAM = '?secret='; var SessionInternal = /** @class */ (function () { function SessionInternal(openVidu, sessionId) { this.openVidu = openVidu; this.ee = new EventEmitter(); this.streams = {}; this.participants = {}; this.publishersSpeaking = []; this.connected = false; this.sessionId = this.getUrlWithoutSecret(sessionId); this.localParticipant = new Connection_1.Connection(this.openVidu, true, this); if (!this.openVidu.getWsUri()) { this.processOpenViduUrl(sessionId); } } SessionInternal.prototype.processOpenViduUrl = function (url) { this.openVidu.setSecret(this.getSecretFromUrl(url)); this.openVidu.setWsUri(this.getFinalUrl(url)); }; SessionInternal.prototype.getSecretFromUrl = function (url) { var secret = ''; if (url.indexOf(SECRET_PARAM) !== -1) { secret = url.substring(url.lastIndexOf(SECRET_PARAM) + SECRET_PARAM.length, url.length); } return secret; }; SessionInternal.prototype.getUrlWithoutSecret = function (url) { if (!url) { console.error('sessionId is not defined'); } if (url.indexOf(SECRET_PARAM) !== -1) { url = url.substring(0, url.lastIndexOf(SECRET_PARAM)); } return url; }; SessionInternal.prototype.getFinalUrl = function (url) { url = this.getUrlWithoutSecret(url).substring(0, url.lastIndexOf('/')) + '/room'; if (url.indexOf(".ngrok.io") !== -1) { // OpenVidu server URL referes to a ngrok IP: secure wss protocol and delete port of URL url = url.replace("ws://", "wss://"); var regex = /\.ngrok\.io:\d+/; url = url.replace(regex, ".ngrok.io"); } else if ((url.indexOf("localhost") !== -1) || (url.indexOf("127.0.0.1") != -1)) { // OpenVidu server URL referes to localhost IP } return url; }; /* NEW METHODS */ SessionInternal.prototype.connect = function (token, callback) { var _this = this; this.openVidu.connect(function (error) { if (error) { callback('ERROR CONNECTING TO OPENVIDU'); } else { if (!token) { token = _this.randomToken(); } var joinParams = { token: token, session: _this.sessionId, metadata: _this.options.metadata, secret: _this.openVidu.getSecret(), 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(error); } else { _this.connected = true; var exParticipants = response.value; // IMPORTANT: Update connectionId with value send by server _this.localParticipant.connectionId = response.id; _this.participants[response.id] = _this.localParticipant; var roomEvent = { participants: new Array(), streams: new Array() }; var length_1 = exParticipants.length; for (var i = 0; i < length_1; i++) { var connection = new Connection_1.Connection(_this.openVidu, false, _this, exParticipants[i]); connection.creationTime = new Date().getTime(); _this.participants[connection.connectionId] = connection; roomEvent.participants.push(connection); var streams = connection.getStreams(); for (var key in streams) { roomEvent.streams.push(streams[key]); if (_this.subscribeToStreams) { streams[key].subscribe(); } } } // Update local Connection object properties with values returned by server _this.localParticipant.data = response.metadata; _this.localParticipant.creationTime = new Date().getTime(); // Updates the value of property 'connection' in Session object _this.ee.emitEvent('update-connection-object', [{ connection: _this.localParticipant }]); // Own connection created event _this.ee.emitEvent('connectionCreated', [{ connection: _this.localParticipant }]); // One connection created event for each existing connection in the session for (var _i = 0, _a = roomEvent.participants; _i < _a.length; _i++) { var part = _a[_i]; _this.ee.emitEvent('connectionCreated', [{ connection: part }]); } //if (this.subscribeToStreams) { for (var _b = 0, _c = roomEvent.streams; _b < _c.length; _b++) { var stream = _c[_b]; _this.ee.emitEvent('streamCreated', [{ stream: stream }]); // Adding the remote stream to the OpenVidu object _this.openVidu.getRemoteStreams().push(stream); } callback(undefined); } }); } }); }; SessionInternal.prototype.publish = function () { this.openVidu.getCamera().publish(); }; /* NEW METHODS */ SessionInternal.prototype.configure = function (options) { this.options = options; this.id = options.sessionId; this.subscribeToStreams = options.subscribeToStreams == null ? true : options.subscribeToStreams; this.updateSpeakerInterval = options.updateSpeakerInterval || 1500; this.thresholdSpeaker = options.thresholdSpeaker || -50; this.activateUpdateMainSpeaker(); }; SessionInternal.prototype.getId = function () { return this.id; }; SessionInternal.prototype.getSessionId = function () { return this.sessionId; }; SessionInternal.prototype.activateUpdateMainSpeaker = function () { /*setInterval(() => { if (this.publishersSpeaking.length > 0) { this.ee.emitEvent('publisherStartSpeaking', [{ participantId: this.publishersSpeaking[this.publishersSpeaking.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.unsubscribe = function (stream) { console.info("Unsubscribing from " + stream.streamId); this.openVidu.sendRequest('unsubscribeFromVideo', { sender: stream.streamId }, function (error, response) { if (error) { console.error("Error unsubscribing from Subscriber", error); } else { console.info("Unsubscribed correctly from " + stream.streamId); } }); }; SessionInternal.prototype.onParticipantPublished = function (options) { // Get the existing Connection created on 'onParticipantJoined' for // existing participants or create a new one for new participants var connection = this.participants[options.id]; if (connection) { // Update existing Connection options.metadata = connection.data; connection.options = options; connection.initStreams(options); } else { // Create new Connection connection = new Connection_1.Connection(this.openVidu, false, this, options); } var pid = connection.connectionId; if (!(pid in this.participants)) { console.debug("Remote Connection not found in connections list by its id [" + pid + "]"); } else { console.debug("Remote Connection found in connections list by its id [" + pid + "]"); } this.participants[pid] = connection; this.ee.emitEvent('participant-published', [{ connection: connection }]); var streams = connection.getStreams(); for (var key in streams) { var stream = streams[key]; if (this.subscribeToStreams) { stream.subscribe(); } this.ee.emitEvent('streamCreated', [{ stream: stream }]); // Adding the remote stream to the OpenVidu object this.openVidu.getRemoteStreams().push(stream); } }; SessionInternal.prototype.onParticipantJoined = function (msg) { var connection = new Connection_1.Connection(this.openVidu, false, this, msg); connection.creationTime = new Date().getTime(); var pid = connection.connectionId; if (!(pid in this.participants)) { this.participants[pid] = connection; } else { //use existing so that we don't lose streams info console.warn("Connection already exists in connections list with " + "the same connectionId, old:", this.participants[pid], ", joined now:", connection); connection = this.participants[pid]; } this.ee.emitEvent('participant-joined', [{ connection: connection }]); this.ee.emitEvent('connectionCreated', [{ connection: connection }]); }; SessionInternal.prototype.onParticipantLeft = function (msg) { var _this = this; var connection = this.participants[msg.name]; if (connection !== undefined) { delete this.participants[msg.name]; this.ee.emitEvent('participant-left', [{ connection: connection }]); var streams = connection.getStreams(); for (var key in streams) { this.ee.emitEvent('streamDestroyed', [{ stream: streams[key], preventDefault: function () { _this.ee.removeEvent('stream-destroyed-default'); } }]); this.ee.emitEvent('stream-destroyed-default', [{ stream: streams[key] }]); // Deleting the removed stream from the OpenVidu object var index = this.openVidu.getRemoteStreams().indexOf(streams[key]); this.openVidu.getRemoteStreams().splice(index, 1); } connection.dispose(); this.ee.emitEvent('connectionDestroyed', [{ connection: connection }]); } else { console.warn("Participant " + msg.name + " unknown. Participants: " + JSON.stringify(this.participants)); } }; ; SessionInternal.prototype.onParticipantEvicted = function (msg) { this.ee.emitEvent('participant-evicted', [{ localParticipant: this.localParticipant }]); }; ; SessionInternal.prototype.onNewMessage = function (msg) { console.info("New signal: " + JSON.stringify(msg)); this.ee.emitEvent('signal', [{ data: msg.data, from: this.participants[msg.from], type: msg.type }]); this.ee.emitEvent('signal:' + msg.type, [{ data: msg.data, from: this.participants[msg.from], type: msg.type }]); }; 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.info("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.warn('Lost connection in Session ' + 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.info("Leaving Session (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.info("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.unsubscribe(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.info("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.publishersSpeaking.push(participantId); this.ee.emitEvent('publisherStartSpeaking', [{ participantId: participantId }]); }; SessionInternal.prototype.removeParticipantSpeaking = function (participantId) { var pos = -1; for (var i = 0; i < this.publishersSpeaking.length; i++) { if (this.publishersSpeaking[i] == participantId) { pos = i; break; } } if (pos != -1) { this.publishersSpeaking.splice(pos, 1); this.ee.emitEvent('publisherStopSpeaking', [{ participantId: participantId }]); } }; SessionInternal.prototype.stringClientMetadata = function (metadata) { if (!(typeof metadata === 'string')) { return JSON.stringify(metadata); } else { return metadata; } }; SessionInternal.prototype.randomToken = function () { return Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2); }; return SessionInternal; }()); exports.SessionInternal = SessionInternal; },{"./Connection":51,"wolfy87-eventemitter":34}],55:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var OpenViduError_1 = require("./OpenViduError"); var EventEmitter = require("wolfy87-eventemitter"); var kurentoUtils = require("../KurentoUtils/kurento-utils-js"); 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 = /** @class */ (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.activeAudio = true; this.activeVideo = true; this.isReadyToPublish = false; this.isPublisherPublished = false; this.isVideoELementCreated = false; this.accessIsAllowed = false; this.accessIsDenied = false; this.isScreenRequestedReady = false; this.isScreenRequested = false; if (options !== 'screen-options') { this.configureOptions(options); } else { this.isScreenRequested = true; this.connection = this.room.getLocalParticipant(); } this.addEventListener('src-added', function (srcEvent) { _this.videoSrcObject = srcEvent.srcObject; if (_this.video) _this.video.srcObject = srcEvent.srcObject; console.debug("Video srcObject [" + srcEvent.srcObject + "] added to stream [" + _this.streamId + "]"); }); } Stream.prototype.emitSrcEvent = function (wrstream) { this.ee.emitEvent('src-added', [{ srcObject: wrstream }]); }; Stream.prototype.emitStreamReadyEvent = function () { this.ee.emitEvent('stream-ready'), [{}]; }; Stream.prototype.getVideoSrcObject = function () { return this.videoSrcObject; }; 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.getSendVideo = function () { return this.sendVideo; }; Stream.prototype.getSendAudio = function () { return this.sendAudio; }; 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.streamId + '_' + this.chanId++; }; Stream.prototype.isDataChannelEnabled = function () { return this.dataChannel; }; Stream.prototype.isDataChannelOpened = function () { return this.dataChannelOpened; }; Stream.prototype.onDataChannelOpen = function (event) { console.debug('Data channel is opened'); this.dataChannelOpened = true; }; Stream.prototype.onDataChannelClosed = function (event) { console.debug('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.info("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.streamId; 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.streamId : spinnerId; hide('progress-' + spinnerId); }; Stream.prototype.playOnlyVideo = function (parentElement, thumbnailId) { var _this = this; this.video = document.createElement('video'); this.video.id = (this.local ? 'local-' : 'remote-') + 'video-' + this.streamId; this.video.autoplay = true; this.video.controls = false; this.video.srcObject = this.videoSrcObject; this.videoElements.push({ thumb: thumbnailId, video: this.video }); if (this.local && !this.displayMyRemote()) { this.video.muted = true; this.video.oncanplay = function () { console.info("Local 'Stream' with id [" + _this.streamId + "] video is now playing"); _this.ee.emitEvent('video-is-playing', [{ element: _this.video }]); }; } else { this.video.title = this.streamId; } if (typeof parentElement === "string") { this.parentId = parentElement; var parentElementDom = document.getElementById(parentElement); if (parentElementDom) { this.video = parentElementDom.appendChild(this.video); this.ee.emitEvent('video-element-created-by-stream', [{ element: this.video }]); this.isVideoELementCreated = true; } } else { this.parentId = parentElement.id; this.video = parentElement.appendChild(this.video); } this.isReadyToPublish = true; return this.video; }; Stream.prototype.playThumbnail = function (thumbnailId) { var container = document.createElement('div'); container.className = "participant"; container.id = this.streamId; 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.streamId.replace('_webcam', ''); if (userName.length >= 16) { userName = userName.substring(0, 16) + "..."; } name.appendChild(document.createTextNode(userName)); name.id = "name-" + this.streamId; name.className = "name"; name.title = this.streamId; this.showSpinner(thumbnailId); return this.playOnlyVideo(container, thumbnailId); }; Stream.prototype.getParticipant = function () { return this.connection; }; 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) { if (_this.sendVideo) { callback(new OpenViduError_1.OpenViduError(OpenViduError_1.OpenViduErrorName.NO_VIDEO_DEVICE, 'You have requested camera access but there is no video input device available. Trying to connect with an audio input device only'), _this); } if (!_this.sendAudio) { callback(new OpenViduError_1.OpenViduError(OpenViduError_1.OpenViduErrorName.NO_INPUT_DEVICE, 'You must init Publisher object with audio or video streams enabled'), undefined); } else { 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.cameraAccessSuccess(userStream, callback); }) .catch(function (error) { _this.accessIsDenied = true; _this.accessIsAllowed = false; var errorName; var errorMessage = error.toString(); ; if (!_this.isScreenRequested) { errorName = _this.sendVideo ? OpenViduError_1.OpenViduErrorName.CAMERA_ACCESS_DENIED : OpenViduError_1.OpenViduErrorName.MICROPHONE_ACCESS_DENIED; } else { errorName = OpenViduError_1.OpenViduErrorName.SCREEN_CAPTURE_DENIED; // This code is only reachable for Firefox } callback(new OpenViduError_1.OpenViduError(errorName, errorMessage), undefined); }); }; Stream.prototype.cameraAccessSuccess = function (userStream, callback) { this.accessIsAllowed = true; this.accessIsDenied = false; this.ee.emitEvent('access-allowed-by-publisher'); if (userStream.getAudioTracks()[0] != null) { userStream.getAudioTracks()[0].enabled = this.activeAudio; } if (userStream.getVideoTracks()[0] != null) { userStream.getVideoTracks()[0].enabled = this.activeVideo; } this.wrStream = userStream; this.emitSrcEvent(this.wrStream); callback(undefined, this); }; Stream.prototype.userMediaHasVideo = function (callback) { // If the user is going to publish its screen there's a video source if (this.isScreenRequested) { callback(true); return; } else { // List all input devices and serach for a video kind 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.debug("Sending SDP offer to publish as " + this.streamId, sdpOfferParam); this.openVidu.sendRequest("publishVideo", { sdpOffer: sdpOfferParam, doLoopback: this.displayMyRemote() || false, audioActive: this.sendAudio, videoActive: this.sendVideo, typeOfVideo: ((this.sendVideo) ? ((this.isScreenRequested) ? 'SCREEN' : 'CAMERA') : '') }, function (error, response) { if (error) { console.error("Error on publishVideo: " + JSON.stringify(error)); } else { _this.processSdpAnswer(response.sdpAnswer); console.info("'Publisher' succesfully published to session"); } }); }; Stream.prototype.startVideoCallback = function (error, sdpOfferParam, wp) { var _this = this; if (error) { return console.error("(subscribe) SDP offer error: " + JSON.stringify(error)); } console.debug("Sending SDP offer to subscribe to " + this.streamId, sdpOfferParam); this.openVidu.sendRequest("receiveVideoFrom", { sender: this.streamId, 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 = kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv(options, function (error) { if (error) { return console.error(error); } _this.wp.generateOffer(sdpOfferCallback.bind(_this)); }); } else { this.wp = kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(options, function (error) { if (error) { return console.error(error); } _this.wp.generateOffer(sdpOfferCallback.bind(_this)); }); } this.isPublisherPublished = true; this.ee.emitEvent('stream-created-by-publisher'); } else { var offerConstraints = { audio: this.recvAudio, video: this.recvVideo }; console.debug("'Session.subscribe(Stream)' called. Constraints of generate SDP offer", offerConstraints); var options = { onicecandidate: this.connection.sendIceCandidate.bind(this.connection), mediaConstraints: offerConstraints }; this.wp = kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options, function (error) { if (error) { return console.error(error); } _this.wp.generateOffer(sdpOfferCallback.bind(_this)); }); } console.debug("Waiting for SDP offer to be generated (" + (this.local ? "local" : "remote") + " 'Stream': " + this.streamId + ")"); }; Stream.prototype.publish = function () { var _this = this; // FIXME: Throw error when stream is not local if (this.isReadyToPublish) { 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.debug(this.streamId + ": set peer connection with recvd SDP answer", sdpAnswer); var participantId = this.streamId; 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.debug("Peer remote stream", _this.wrStream); if (_this.wrStream != undefined) { _this.emitSrcEvent(_this.wrStream); if (_this.wrStream.getAudioTracks()[0] != null) { _this.speechEvent = kurentoUtils.WebRtcPeer.hark(_this.wrStream, { threshold: _this.room.thresholdSpeaker }); _this.speechEvent.on('speaking', function () { //this.room.addParticipantSpeaking(participantId); _this.room.emitEvent('publisherStartSpeaking', [{ connection: _this.connection, streamId: _this.streamId }]); }); _this.speechEvent.on('stopped_speaking', function () { //this.room.removeParticipantSpeaking(participantId); _this.room.emitEvent('publisherStopSpeaking', [{ connection: _this.connection, streamId: _this.streamId }]); }); } } var _loop_1 = function (videoElement) { var thumbnailId = videoElement.thumb; var video = videoElement.video; video.srcObject = _this.wrStream; video.oncanplay = function () { if (_this.local && _this.displayMyRemote()) { console.info("Your own remote 'Stream' with id [" + _this.streamId + "] video is now playing"); _this.ee.emitEvent('remote-video-is-playing', [{ element: video }]); } else if (!_this.local && !_this.displayMyRemote()) { console.info("Remote 'Stream' with id [" + _this.streamId + "] video is now playing"); _this.ee.emitEvent('video-is-playing', [{ element: video }]); } //show(thumbnailId); //this.hideSpinner(this.streamId); }; }; for (var _i = 0, _a = _this.videoElements; _i < _a.length; _i++) { var videoElement = _a[_i]; _loop_1(videoElement); } _this.room.emitEvent('stream-subscribed', [{ stream: _this }]); } }, function (error) { console.error(_this.streamId + ": 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.info(this.streamId + ": Stream '" + this.streamId + "' 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(ve => disposeElement(ve.video)); disposeElement("progress-" + this.streamId); 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.info((this.local ? "Local " : "Remote ") + "'Stream' with id [" + this.streamId + "]' has been succesfully disposed"); }; Stream.prototype.configureOptions = function (options) { if (options.id) { this.streamId = options.id; } else { this.streamId = "WEBCAM"; } this.connection = options.connection; this.recvVideo = options.recvVideo || false; this.recvAudio = options.recvAudio || false; this.sendVideo = options.sendVideo; this.sendAudio = options.sendAudio; this.activeAudio = options.activeAudio; this.activeVideo = options.activeVideo; this.dataChannel = options.data || false; this.mediaConstraints = options.mediaConstraints; this.hasAudio = ((this.recvAudio || this.sendAudio) != undefined) ? (this.recvAudio || this.sendAudio) : false; this.hasVideo = ((this.recvVideo || this.sendVideo) != undefined) ? (this.recvVideo || this.sendVideo) : false; this.typeOfVideo = options.typeOfVideo; }; Stream.prototype.configureScreenOptions = function (options) { if (options.id) { this.streamId = options.id; } else { this.streamId = "SCREEN"; } this.recvVideo = options.recvVideo || false; this.recvAudio = options.recvAudio || false; this.sendVideo = options.sendVideo; this.sendAudio = options.sendAudio; this.activeAudio = options.activeAudio; this.activeVideo = options.activeVideo; this.dataChannel = options.data || false; this.mediaConstraints = options.mediaConstraints; this.ee.emitEvent('can-request-screen'); }; return Stream; }()); exports.Stream = Stream; },{"../KurentoUtils/kurento-utils-js":45,"./OpenViduError":52,"webrtc-adapter":22,"wolfy87-eventemitter":34}],56:[function(require,module,exports){ // Last time updated at Feb 16, 2017, 08:32:23 // Latest file can be found here: https://cdn.webrtc-experiment.com/getScreenId.js // Muaz Khan - www.MuazKhan.com // MIT License - www.WebRTC-Experiment.com/licence // Documentation - https://github.com/muaz-khan/getScreenId. // ______________ // getScreenId.js /* getScreenId(function (error, sourceId, screen_constraints) { // error == null || 'permission-denied' || 'not-installed' || 'installed-disabled' || 'not-chrome' // sourceId == null || 'string' || 'firefox' if(sourceId == 'firefox') { navigator.mozGetUserMedia(screen_constraints, onSuccess, onFailure); } else navigator.webkitGetUserMedia(screen_constraints, onSuccess, onFailure); }); */ window.getScreenId = function (callback) { // for Firefox: // sourceId == 'firefox' // screen_constraints = {...} if (!!navigator.mozGetUserMedia) { callback(null, 'firefox', { video: { mozMediaSource: 'window', mediaSource: 'window' } }); return; } window.addEventListener('message', onIFrameCallback); function onIFrameCallback(event) { if (!event.data) return; if (event.data.chromeMediaSourceId) { if (event.data.chromeMediaSourceId === 'PermissionDeniedError') { callback('permission-denied'); } else callback(null, event.data.chromeMediaSourceId, getScreenConstraints(null, event.data.chromeMediaSourceId)); } if (event.data.chromeExtensionStatus) { callback(event.data.chromeExtensionStatus, null, getScreenConstraints(event.data.chromeExtensionStatus)); } // this event listener is no more needed window.removeEventListener('message', onIFrameCallback); } setTimeout(postGetSourceIdMessage, 100); }; function getScreenConstraints(error, sourceId) { var screen_constraints = { audio: false, video: { mandatory: { chromeMediaSource: error ? 'screen' : 'desktop', maxWidth: window.screen.width > 1920 ? window.screen.width : 1920, maxHeight: window.screen.height > 1080 ? window.screen.height : 1080 }, optional: [] } }; if (sourceId) { screen_constraints.video.mandatory.chromeMediaSourceId = sourceId; } return screen_constraints; } function postGetSourceIdMessage() { if (!iframe) { loadIFrame(postGetSourceIdMessage); return; } if (!iframe.isLoaded) { setTimeout(postGetSourceIdMessage, 100); return; } iframe.contentWindow.postMessage({ captureSourceId: true }, '*'); } var iframe; // this function is used in RTCMultiConnection v3 window.getScreenConstraints = function (callback) { loadIFrame(function () { getScreenId(function (error, sourceId, screen_constraints) { callback(error, screen_constraints.video); }); }); }; function loadIFrame(loadCallback) { if (iframe) { loadCallback(); return; } iframe = document.createElement('iframe'); iframe.onload = function () { iframe.isLoaded = true; loadCallback(); }; iframe.src = 'https://www.webrtc-experiment.com/getSourceId/'; // https://wwww.yourdomain.com/getScreenId.html iframe.style.display = 'none'; (document.body || document.documentElement).appendChild(iframe); } window.getChromeExtensionStatus = function (callback) { // for Firefox: if (!!navigator.mozGetUserMedia) { callback('installed-enabled'); return; } window.addEventListener('message', onIFrameCallback); function onIFrameCallback(event) { if (!event.data) return; if (event.data.chromeExtensionStatus) { callback(event.data.chromeExtensionStatus); } // this event listener is no more needed window.removeEventListener('message', onIFrameCallback); } setTimeout(postGetChromeExtensionStatusMessage, 100); }; function postGetChromeExtensionStatusMessage() { if (!iframe) { loadIFrame(postGetChromeExtensionStatusMessage); return; } if (!iframe.isLoaded) { setTimeout(postGetChromeExtensionStatusMessage, 100); return; } iframe.contentWindow.postMessage({ getChromeExtensionStatus: true }, '*'); } exports.getScreenId = getScreenId; exports.getChromeExtensionStatus = getChromeExtensionStatus; },{}]},{},[46]) //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvZXZlbnRzL2V2ZW50cy5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9mcmVlaWNlL2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2ZyZWVpY2Uvc3R1bi5qc29uIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2ZyZWVpY2UvdHVybi5qc29uIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2hhcmsvaGFyay5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9pbmhlcml0cy9pbmhlcml0c19icm93c2VyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL21lcmdlL21lcmdlLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL25vcm1hbGljZS9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9ydGNwZWVyY29ubmVjdGlvbi1zaGltL3J0Y3BlZXJjb25uZWN0aW9uLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC10cmFuc2Zvcm0vbGliL2dyYW1tYXIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc2RwLXRyYW5zZm9ybS9saWIvaW5kZXguanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc2RwLXRyYW5zZm9ybS9saWIvcGFyc2VyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC10cmFuc2Zvcm0vbGliL3dyaXRlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNsYXRvci9saWIvYXJyYXktZXF1YWxzLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC10cmFuc2xhdG9yL2xpYi9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNsYXRvci9saWIvaW50ZXJvcC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNsYXRvci9saWIvdHJhbnNmb3JtLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC9zZHAuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvdWEtcGFyc2VyLWpzL3NyYy91YS1wYXJzZXIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvdXVpZC9ybmctYnJvd3Nlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy91dWlkL3V1aWQuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL2FkYXB0ZXJfY29yZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93ZWJydGMtYWRhcHRlci9zcmMvanMvYWRhcHRlcl9mYWN0b3J5LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dlYnJ0Yy1hZGFwdGVyL3NyYy9qcy9jaHJvbWUvY2hyb21lX3NoaW0uanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL2Nocm9tZS9nZXR1c2VybWVkaWEuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL2NvbW1vbl9zaGltLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dlYnJ0Yy1hZGFwdGVyL3NyYy9qcy9lZGdlL2VkZ2Vfc2hpbS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93ZWJydGMtYWRhcHRlci9zcmMvanMvZWRnZS9nZXR1c2VybWVkaWEuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL2ZpcmVmb3gvZmlyZWZveF9zaGltLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dlYnJ0Yy1hZGFwdGVyL3NyYy9qcy9maXJlZm94L2dldHVzZXJtZWRpYS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93ZWJydGMtYWRhcHRlci9zcmMvanMvc2FmYXJpL3NhZmFyaV9zaGltLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dlYnJ0Yy1hZGFwdGVyL3NyYy9qcy91dGlscy5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93aWxkZW1pdHRlci93aWxkZW1pdHRlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93b2xmeTg3LWV2ZW50ZW1pdHRlci9FdmVudEVtaXR0ZXIuanMiLCIuLi9LdXJlbnRvVXRpbHMva3VyZW50by1qc29ucnBjL01hcHBlci5qcyIsIi4uL0t1cmVudG9VdGlscy9rdXJlbnRvLWpzb25ycGMvY2xpZW50cy9pbmRleC5qcyIsIi4uL0t1cmVudG9VdGlscy9rdXJlbnRvLWpzb25ycGMvY2xpZW50cy9qc29ucnBjY2xpZW50LmpzIiwiLi4vS3VyZW50b1V0aWxzL2t1cmVudG8tanNvbnJwYy9jbGllbnRzL3RyYW5zcG9ydHMvaW5kZXguanMiLCIuLi9LdXJlbnRvVXRpbHMva3VyZW50by1qc29ucnBjL2NsaWVudHMvdHJhbnNwb3J0cy93ZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uLmpzIiwiLi4vS3VyZW50b1V0aWxzL2t1cmVudG8tanNvbnJwYy9pbmRleC5qcyIsIi4uL0t1cmVudG9VdGlscy9rdXJlbnRvLWpzb25ycGMvcGFja2Vycy9Kc29uUlBDLmpzIiwiLi4vS3VyZW50b1V0aWxzL2t1cmVudG8tanNvbnJwYy9wYWNrZXJzL1htbFJQQy5qcyIsIi4uL0t1cmVudG9VdGlscy9rdXJlbnRvLWpzb25ycGMvcGFja2Vycy9pbmRleC5qcyIsIi4uL0t1cmVudG9VdGlscy9rdXJlbnRvLXV0aWxzLWpzL1dlYlJ0Y1BlZXIuanMiLCIuLi9LdXJlbnRvVXRpbHMva3VyZW50by11dGlscy1qcy9pbmRleC5qcyIsIk1haW4udHMiLCJPcGVuVmlkdS50cyIsIlB1Ymxpc2hlci50cyIsIlNlc3Npb24udHMiLCJTdWJzY3JpYmVyLnRzIiwiLi4vT3BlblZpZHVJbnRlcm5hbC9Db25uZWN0aW9uLnRzIiwiLi4vT3BlblZpZHVJbnRlcm5hbC9PcGVuVmlkdUVycm9yLnRzIiwiLi4vT3BlblZpZHVJbnRlcm5hbC9PcGVuVmlkdUludGVybmFsLnRzIiwiLi4vT3BlblZpZHVJbnRlcm5hbC9TZXNzaW9uSW50ZXJuYWwudHMiLCIuLi9PcGVuVmlkdUludGVybmFsL1N0cmVhbS50cyIsIi4uL1NjcmVlblNoYXJpbmcvU2NyZWVuLUNhcHR1cmluZy1BdXRvLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlTQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTs7QUNEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNtREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxb0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ2hqQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDaENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUN2TEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ2JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6SUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqcUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaE5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1UUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6SkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4ZEE7SUFFRSxJQUFJLE9BQU8sR0FBRyxFQUFFLENBQUM7SUFHakIsSUFBSSxDQUFDLE9BQU8sR0FBRyxVQUFTLFFBQVE7UUFFOUIsR0FBRyxDQUFBLENBQUMsSUFBSSxHQUFHLElBQUksT0FBTyxDQUFDLENBQ3ZCLENBQUM7WUFDQyxJQUFJLE1BQU0sR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7WUFFMUIsR0FBRyxDQUFBLENBQUMsSUFBSSxJQUFJLElBQUksTUFBTSxDQUFDO2dCQUNyQixRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFD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QUF3QztRQUN4QyxNQUFNLENBQUMsbUJBQW1CLENBQUMsU0FBUyxFQUFFLGdCQUFnQixDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVELFVBQVUsQ0FBQyxtQ0FBbUMsRUFBRSxHQUFHLENBQUMsQ0FBQztBQUN6RCxDQUFDLENBQUM7QUFFRjtJQUNJLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUNWLFVBQVUsQ0FBQyxtQ0FBbUMsQ0FBQyxDQUFDO1FBQ2hELE1BQU0sQ0FBQztJQUNYLENBQUM7SUFFRCxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO1FBQ25CLFVBQVUsQ0FBQyxtQ0FBbUMsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNyRCxNQUFNLENBQUM7SUFDWCxDQUFDO0lBRUQsTUFBTSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUM7UUFDN0Isd0JBQXdCLEVBQUUsSUFBSTtLQUNqQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBQ1osQ0FBQztBQUVELE9BQU8sQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO0FBQ2xDLE9BQU8sQ0FBQyx3QkFBd0IsR0FBRyx3QkFBd0IsQ0FBQyIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIvLyBDb3B5cmlnaHQgSm95ZW50LCBJbmMuIGFuZCBvdGhlciBOb2RlIGNvbnRyaWJ1dG9ycy5cbi8vXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYVxuLy8gY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZVxuLy8gXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nXG4vLyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsXG4vLyBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0XG4vLyBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGVcbi8vIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkXG4vLyBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTXG4vLyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GXG4vLyBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOXG4vLyBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSxcbi8vIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUlxuLy8gT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRVxuLy8gVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS5cblxuZnVuY3Rpb24gRXZlbnRFbWl0dGVyKCkge1xuICB0aGlzLl9ldmVudHMgPSB0aGlzLl9ldmVudHMgfHwge307XG4gIHRoaXMuX21heExpc3RlbmVycyA9IHRoaXMuX21heExpc3RlbmVycyB8fCB1bmRlZmluZWQ7XG59XG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50RW1pdHRlcjtcblxuLy8gQmFja3dhcmRzLWNvbXBhdCB3aXRoIG5vZGUgMC4xMC54XG5FdmVudEVtaXR0ZXIuRXZlbnRFbWl0dGVyID0gRXZlbnRFbWl0dGVyO1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLl9ldmVudHMgPSB1bmRlZmluZWQ7XG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLl9tYXhMaXN0ZW5lcnMgPSB1bmRlZmluZWQ7XG5cbi8vIEJ5IGRlZmF1bHQgRXZlbnRFbWl0dGVycyB3aWxsIHByaW50IGEgd2FybmluZyBpZiBtb3JlIHRoYW4gMTAgbGlzdGVuZXJzIGFyZVxuLy8gYWRkZWQgdG8gaXQuIFRoaXMgaXMgYSB1c2VmdWwgZGVmYXVsdCB3aGljaCBoZWxwcyBmaW5kaW5nIG1lbW9yeSBsZWFrcy5cbkV2ZW50RW1pdHRlci5kZWZhdWx0TWF4TGlzdGVuZXJzID0gMTA7XG5cbi8vIE9idmlvdXNseSBub3QgYWxsIEVtaXR0ZXJzIHNob3VsZCBiZSBsaW1pdGVkIHRvIDEwLiBUaGlzIGZ1bmN0aW9uIGFsbG93c1xuLy8gdGhhdCB0byBiZSBpbmNyZWFzZWQuIFNldCB0byB6ZXJvIGZvciB1bmxpbWl0ZWQuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnNldE1heExpc3RlbmVycyA9IGZ1bmN0aW9uKG4pIHtcbiAgaWYgKCFpc051bWJlcihuKSB8fCBuIDwgMCB8fCBpc05hTihuKSlcbiAgICB0aHJvdyBUeXBlRXJyb3IoJ24gbXVzdCBiZSBhIHBvc2l0aXZlIG51bWJlcicpO1xuICB0aGlzLl9tYXhMaXN0ZW5lcnMgPSBuO1xuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuZW1pdCA9IGZ1bmN0aW9uKHR5cGUpIHtcbiAgdmFyIGVyLCBoYW5kbGVyLCBsZW4sIGFyZ3MsIGksIGxpc3RlbmVycztcblxuICBpZiAoIXRoaXMuX2V2ZW50cylcbiAgICB0aGlzLl9ldmVudHMgPSB7fTtcblxuICAvLyBJZiB0aGVyZSBpcyBubyAnZXJyb3InIGV2ZW50IGxpc3RlbmVyIHRoZW4gdGhyb3cuXG4gIGlmICh0eXBlID09PSAnZXJyb3InKSB7XG4gICAgaWYgKCF0aGlzLl9ldmVudHMuZXJyb3IgfHxcbiAgICAgICAgKGlzT2JqZWN0KHRoaXMuX2V2ZW50cy5lcnJvcikgJiYgIXRoaXMuX2V2ZW50cy5lcnJvci5sZW5ndGgpKSB7XG4gICAgICBlciA9IGFyZ3VtZW50c1sxXTtcbiAgICAgIGlmIChlciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAgIHRocm93IGVyOyAvLyBVbmhhbmRsZWQgJ2Vycm9yJyBldmVudFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gQXQgbGVhc3QgZ2l2ZSBzb21lIGtpbmQgb2YgY29udGV4dCB0byB0aGUgdXNlclxuICAgICAgICB2YXIgZXJyID0gbmV3IEVycm9yKCdVbmNhdWdodCwgdW5zcGVjaWZpZWQgXCJlcnJvclwiIGV2ZW50LiAoJyArIGVyICsgJyknKTtcbiAgICAgICAgZXJyLmNvbnRleHQgPSBlcjtcbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGhhbmRsZXIgPSB0aGlzLl9ldmVudHNbdHlwZV07XG5cbiAgaWYgKGlzVW5kZWZpbmVkKGhhbmRsZXIpKVxuICAgIHJldHVybiBmYWxzZTtcblxuICBpZiAoaXNGdW5jdGlvbihoYW5kbGVyKSkge1xuICAgIHN3aXRjaCAoYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgLy8gZmFzdCBjYXNlc1xuICAgICAgY2FzZSAxOlxuICAgICAgICBoYW5kbGVyLmNhbGwodGhpcyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAyOlxuICAgICAgICBoYW5kbGVyLmNhbGwodGhpcywgYXJndW1lbnRzWzFdKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDM6XG4gICAgICAgIGhhbmRsZXIuY2FsbCh0aGlzLCBhcmd1bWVudHNbMV0sIGFyZ3VtZW50c1syXSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgLy8gc2xvd2VyXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgaGFuZGxlci5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICB9XG4gIH0gZWxzZSBpZiAoaXNPYmplY3QoaGFuZGxlcikpIHtcbiAgICBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICBsaXN0ZW5lcnMgPSBoYW5kbGVyLnNsaWNlKCk7XG4gICAgbGVuID0gbGlzdGVuZXJzLmxlbmd0aDtcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspXG4gICAgICBsaXN0ZW5lcnNbaV0uYXBwbHkodGhpcywgYXJncyk7XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXIgPSBmdW5jdGlvbih0eXBlLCBsaXN0ZW5lcikge1xuICB2YXIgbTtcblxuICBpZiAoIWlzRnVuY3Rpb24obGlzdGVuZXIpKVxuICAgIHRocm93IFR5cGVFcnJvcignbGlzdGVuZXIgbXVzdCBiZSBhIGZ1bmN0aW9uJyk7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpXG4gICAgdGhpcy5fZXZlbnRzID0ge307XG5cbiAgLy8gVG8gYXZvaWQgcmVjdXJzaW9uIGluIHRoZSBjYXNlIHRoYXQgdHlwZSA9PT0gXCJuZXdMaXN0ZW5lclwiISBCZWZvcmVcbiAgLy8gYWRkaW5nIGl0IHRvIHRoZSBsaXN0ZW5lcnMsIGZpcnN0IGVtaXQgXCJuZXdMaXN0ZW5lclwiLlxuICBpZiAodGhpcy5fZXZlbnRzLm5ld0xpc3RlbmVyKVxuICAgIHRoaXMuZW1pdCgnbmV3TGlzdGVuZXInLCB0eXBlLFxuICAgICAgICAgICAgICBpc0Z1bmN0aW9uKGxpc3RlbmVyLmxpc3RlbmVyKSA/XG4gICAgICAgICAgICAgIGxpc3RlbmVyLmxpc3RlbmVyIDogbGlzdGVuZXIpO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIC8vIE9wdGltaXplIHRoZSBjYXNlIG9mIG9uZSBsaXN0ZW5lci4gRG9uJ3QgbmVlZCB0aGUgZXh0cmEgYXJyYXkgb2JqZWN0LlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXSA9IGxpc3RlbmVyO1xuICBlbHNlIGlmIChpc09iamVjdCh0aGlzLl9ldmVudHNbdHlwZV0pKVxuICAgIC8vIElmIHdlJ3ZlIGFscmVhZHkgZ290IGFuIGFycmF5LCBqdXN0IGFwcGVuZC5cbiAgICB0aGlzLl9ldmVudHNbdHlwZV0ucHVzaChsaXN0ZW5lcik7XG4gIGVsc2VcbiAgICAvLyBBZGRpbmcgdGhlIHNlY29uZCBlbGVtZW50LCBuZWVkIHRvIGNoYW5nZSB0byBhcnJheS5cbiAgICB0aGlzLl9ldmVudHNbdHlwZV0gPSBbdGhpcy5fZXZlbnRzW3R5cGVdLCBsaXN0ZW5lcl07XG5cbiAgLy8gQ2hlY2sgZm9yIGxpc3RlbmVyIGxlYWtcbiAgaWYgKGlzT2JqZWN0KHRoaXMuX2V2ZW50c1t0eXBlXSkgJiYgIXRoaXMuX2V2ZW50c1t0eXBlXS53YXJuZWQpIHtcbiAgICBpZiAoIWlzVW5kZWZpbmVkKHRoaXMuX21heExpc3RlbmVycykpIHtcbiAgICAgIG0gPSB0aGlzLl9tYXhMaXN0ZW5lcnM7XG4gICAgfSBlbHNlIHtcbiAgICAgIG0gPSBFdmVudEVtaXR0ZXIuZGVmYXVsdE1heExpc3RlbmVycztcbiAgICB9XG5cbiAgICBpZiAobSAmJiBtID4gMCAmJiB0aGlzLl9ldmVudHNbdHlwZV0ubGVuZ3RoID4gbSkge1xuICAgICAgdGhpcy5fZXZlbnRzW3R5cGVdLndhcm5lZCA9IHRydWU7XG4gICAgICBjb25zb2xlLmVycm9yKCcobm9kZSkgd2FybmluZzogcG9zc2libGUgRXZlbnRFbWl0dGVyIG1lbW9yeSAnICtcbiAgICAgICAgICAgICAgICAgICAgJ2xlYWsgZGV0ZWN0ZWQuICVkIGxpc3RlbmVycyBhZGRlZC4gJyArXG4gICAgICAgICAgICAgICAgICAgICdVc2UgZW1pdHRlci5zZXRNYXhMaXN0ZW5lcnMoKSB0byBpbmNyZWFzZSBsaW1pdC4nLFxuICAgICAgICAgICAgICAgICAgICB0aGlzLl9ldmVudHNbdHlwZV0ubGVuZ3RoKTtcbiAgICAgIGlmICh0eXBlb2YgY29uc29sZS50cmFjZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAvLyBub3Qgc3VwcG9ydGVkIGluIElFIDEwXG4gICAgICAgIGNvbnNvbGUudHJhY2UoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub24gPSBFdmVudEVtaXR0ZXIucHJvdG90eXBlLmFkZExpc3RlbmVyO1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLm9uY2UgPSBmdW5jdGlvbih0eXBlLCBsaXN0ZW5lcikge1xuICBpZiAoIWlzRnVuY3Rpb24obGlzdGVuZXIpKVxuICAgIHRocm93IFR5cGVFcnJvcignbGlzdGVuZXIgbXVzdCBiZSBhIGZ1bmN0aW9uJyk7XG5cbiAgdmFyIGZpcmVkID0gZmFsc2U7XG5cbiAgZnVuY3Rpb24gZygpIHtcbiAgICB0aGlzLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGcpO1xuXG4gICAgaWYgKCFmaXJlZCkge1xuICAgICAgZmlyZWQgPSB0cnVlO1xuICAgICAgbGlzdGVuZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9XG4gIH1cblxuICBnLmxpc3RlbmVyID0gbGlzdGVuZXI7XG4gIHRoaXMub24odHlwZSwgZyk7XG5cbiAgcmV0dXJuIHRoaXM7XG59O1xuXG4vLyBlbWl0cyBhICdyZW1vdmVMaXN0ZW5lcicgZXZlbnQgaWZmIHRoZSBsaXN0ZW5lciB3YXMgcmVtb3ZlZFxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIHZhciBsaXN0LCBwb3NpdGlvbiwgbGVuZ3RoLCBpO1xuXG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICBpZiAoIXRoaXMuX2V2ZW50cyB8fCAhdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIHJldHVybiB0aGlzO1xuXG4gIGxpc3QgPSB0aGlzLl9ldmVudHNbdHlwZV07XG4gIGxlbmd0aCA9IGxpc3QubGVuZ3RoO1xuICBwb3NpdGlvbiA9IC0xO1xuXG4gIGlmIChsaXN0ID09PSBsaXN0ZW5lciB8fFxuICAgICAgKGlzRnVuY3Rpb24obGlzdC5saXN0ZW5lcikgJiYgbGlzdC5saXN0ZW5lciA9PT0gbGlzdGVuZXIpKSB7XG4gICAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgICBpZiAodGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKVxuICAgICAgdGhpcy5lbWl0KCdyZW1vdmVMaXN0ZW5lcicsIHR5cGUsIGxpc3RlbmVyKTtcblxuICB9IGVsc2UgaWYgKGlzT2JqZWN0KGxpc3QpKSB7XG4gICAgZm9yIChpID0gbGVuZ3RoOyBpLS0gPiAwOykge1xuICAgICAgaWYgKGxpc3RbaV0gPT09IGxpc3RlbmVyIHx8XG4gICAgICAgICAgKGxpc3RbaV0ubGlzdGVuZXIgJiYgbGlzdFtpXS5saXN0ZW5lciA9PT0gbGlzdGVuZXIpKSB7XG4gICAgICAgIHBvc2l0aW9uID0gaTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHBvc2l0aW9uIDwgMClcbiAgICAgIHJldHVybiB0aGlzO1xuXG4gICAgaWYgKGxpc3QubGVuZ3RoID09PSAxKSB7XG4gICAgICBsaXN0Lmxlbmd0aCA9IDA7XG4gICAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIH0gZWxzZSB7XG4gICAgICBsaXN0LnNwbGljZShwb3NpdGlvbiwgMSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2V2ZW50cy5yZW1vdmVMaXN0ZW5lcilcbiAgICAgIHRoaXMuZW1pdCgncmVtb3ZlTGlzdGVuZXInLCB0eXBlLCBsaXN0ZW5lcik7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlQWxsTGlzdGVuZXJzID0gZnVuY3Rpb24odHlwZSkge1xuICB2YXIga2V5LCBsaXN0ZW5lcnM7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpXG4gICAgcmV0dXJuIHRoaXM7XG5cbiAgLy8gbm90IGxpc3RlbmluZyBmb3IgcmVtb3ZlTGlzdGVuZXIsIG5vIG5lZWQgdG8gZW1pdFxuICBpZiAoIXRoaXMuX2V2ZW50cy5yZW1vdmVMaXN0ZW5lcikge1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKVxuICAgICAgdGhpcy5fZXZlbnRzID0ge307XG4gICAgZWxzZSBpZiAodGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgICAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIGVtaXQgcmVtb3ZlTGlzdGVuZXIgZm9yIGFsbCBsaXN0ZW5lcnMgb24gYWxsIGV2ZW50c1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIGZvciAoa2V5IGluIHRoaXMuX2V2ZW50cykge1xuICAgICAgaWYgKGtleSA9PT0gJ3JlbW92ZUxpc3RlbmVyJykgY29udGludWU7XG4gICAgICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycyhrZXkpO1xuICAgIH1cbiAgICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygncmVtb3ZlTGlzdGVuZXInKTtcbiAgICB0aGlzLl9ldmVudHMgPSB7fTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICBpZiAoaXNGdW5jdGlvbihsaXN0ZW5lcnMpKSB7XG4gICAgdGhpcy5yZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcnMpO1xuICB9IGVsc2UgaWYgKGxpc3RlbmVycykge1xuICAgIC8vIExJRk8gb3JkZXJcbiAgICB3aGlsZSAobGlzdGVuZXJzLmxlbmd0aClcbiAgICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIodHlwZSwgbGlzdGVuZXJzW2xpc3RlbmVycy5sZW5ndGggLSAxXSk7XG4gIH1cbiAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUubGlzdGVuZXJzID0gZnVuY3Rpb24odHlwZSkge1xuICB2YXIgcmV0O1xuICBpZiAoIXRoaXMuX2V2ZW50cyB8fCAhdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIHJldCA9IFtdO1xuICBlbHNlIGlmIChpc0Z1bmN0aW9uKHRoaXMuX2V2ZW50c1t0eXBlXSkpXG4gICAgcmV0ID0gW3RoaXMuX2V2ZW50c1t0eXBlXV07XG4gIGVsc2VcbiAgICByZXQgPSB0aGlzLl9ldmVudHNbdHlwZV0uc2xpY2UoKTtcbiAgcmV0dXJuIHJldDtcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUubGlzdGVuZXJDb3VudCA9IGZ1bmN0aW9uKHR5cGUpIHtcbiAgaWYgKHRoaXMuX2V2ZW50cykge1xuICAgIHZhciBldmxpc3RlbmVyID0gdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gICAgaWYgKGlzRnVuY3Rpb24oZXZsaXN0ZW5lcikpXG4gICAgICByZXR1cm4gMTtcbiAgICBlbHNlIGlmIChldmxpc3RlbmVyKVxuICAgICAgcmV0dXJuIGV2bGlzdGVuZXIubGVuZ3RoO1xuICB9XG4gIHJldHVybiAwO1xufTtcblxuRXZlbnRFbWl0dGVyLmxpc3RlbmVyQ291bnQgPSBmdW5jdGlvbihlbWl0dGVyLCB0eXBlKSB7XG4gIHJldHVybiBlbWl0dGVyLmxpc3RlbmVyQ291bnQodHlwZSk7XG59O1xuXG5mdW5jdGlvbiBpc0Z1bmN0aW9uKGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ2Z1bmN0aW9uJztcbn1cblxuZnVuY3Rpb24gaXNOdW1iZXIoYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnbnVtYmVyJztcbn1cblxuZnVuY3Rpb24gaXNPYmplY3QoYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnb2JqZWN0JyAmJiBhcmcgIT09IG51bGw7XG59XG5cbmZ1bmN0aW9uIGlzVW5kZWZpbmVkKGFyZykge1xuICByZXR1cm4gYXJnID09PSB2b2lkIDA7XG59XG4iLCIvKiBqc2hpbnQgbm9kZTogdHJ1ZSAqL1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgbm9ybWFsaWNlID0gcmVxdWlyZSgnbm9ybWFsaWNlJyk7XG5cbi8qKlxuICAjIGZyZWVpY2VcblxuICBUaGUgYGZyZWVpY2VgIG1vZHVsZSBpcyBhIHNpbXBsZSB3YXkgb2YgZ2V0dGluZyByYW5kb20gU1RVTiBvciBUVVJOIHNlcnZlclxuICBmb3IgeW91ciBXZWJSVEMgYXBwbGljYXRpb24uICBUaGUgbGlzdCBvZiBzZXJ2ZXJzIChqdXN0IFNUVU4gYXQgdGhpcyBzdGFnZSlcbiAgd2VyZSBzb3VyY2VkIGZyb20gdGhpcyBbZ2lzdF0oaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20venppdW5pLzM3NDE5MzMpLlxuXG4gICMjIEV4YW1wbGUgVXNlXG5cbiAgVGhlIGZvbGxvd2luZyBkZW1vbnN0cmF0ZXMgaG93IHlvdSBjYW4gdXNlIGBmcmVlaWNlYCB3aXRoXG4gIFtydGMtcXVpY2tjb25uZWN0XShodHRwczovL2dpdGh1Yi5jb20vcnRjLWlvL3J0Yy1xdWlja2Nvbm5lY3QpOlxuXG4gIDw8PCBleGFtcGxlcy9xdWlja2Nvbm5lY3QuanNcblxuICBBcyB0aGUgYGZyZWVpY2VgIG1vZHVsZSBnZW5lcmF0ZXMgaWNlIHNlcnZlcnMgaW4gYSBsaXN0IGNvbXBsaWFudCB3aXRoIHRoZVxuICBXZWJSVEMgc3BlYyB5b3Ugd2lsbCBiZSBhYmxlIHRvIHVzZSBpdCB3aXRoIHJhdyBgUlRDUGVlckNvbm5lY3Rpb25gXG4gIGNvbnN0cnVjdG9ycyBhbmQgb3RoZXIgV2ViUlRDIGxpYnJhcmllcy5cblxuICAjIyBIZXksIGRvbid0IHVzZSBteSBTVFVOL1RVUk4gc2VydmVyIVxuXG4gIElmIGZvciBzb21lIHJlYXNvbiB5b3VyIGZyZWUgU1RVTiBvciBUVVJOIHNlcnZlciBlbmRzIHVwIGluIHRoZVxuICBsaXN0IG9mIHNlcnZlcnMgKFtzdHVuXShodHRwczovL2dpdGh1Yi5jb20vRGFtb25PZWhsbWFuL2ZyZWVpY2UvYmxvYi9tYXN0ZXIvc3R1bi5qc29uKSBvclxuICBbdHVybl0oaHR0cHM6Ly9naXRodWIuY29tL0RhbW9uT2VobG1hbi9mcmVlaWNlL2Jsb2IvbWFzdGVyL3R1cm4uanNvbikpXG4gIHRoYXQgaXMgdXNlZCBpbiB0aGlzIG1vZHVsZSwgeW91IGNhbiBmZWVsXG4gIGZyZWUgdG8gb3BlbiBhbiBpc3N1ZSBvbiB0aGlzIHJlcG9zaXRvcnkgYW5kIHRob3NlIHNlcnZlcnMgd2lsbCBiZSByZW1vdmVkXG4gIHdpdGhpbiAyNCBob3VycyAob3Igc29vbmVyKS4gIFRoaXMgaXMgdGhlIHF1aWNrZXN0IGFuZCBwcm9iYWJseSB0aGUgbW9zdFxuICBwb2xpdGUgd2F5IHRvIGhhdmUgc29tZXRoaW5nIHJlbW92ZWQgKGFuZCBwcm92aWRlcyB1cyBzb21lIHZpc2liaWxpdHlcbiAgaWYgc29tZW9uZSBvcGVucyBhIHB1bGwgcmVxdWVzdCByZXF1ZXN0aW5nIHRoYXQgYSBzZXJ2ZXIgaXMgYWRkZWQpLlxuXG4gICMjIFBsZWFzZSBhZGQgbXkgc2VydmVyIVxuXG4gIElmIHlvdSBoYXZlIGEgc2VydmVyIHRoYXQgeW91IHdpc2ggdG8gYWRkIHRvIHRoZSBsaXN0LCB0aGF0J3MgYXdlc29tZSEgSSdtXG4gIHN1cmUgSSBzcGVhayBvbiBiZWhhbGYgb2YgYSB3aG9sZSBwaWxlIG9mIFdlYlJUQyBkZXZlbG9wZXJzIHdobyBzYXkgdGhhbmtzLlxuICBUbyBnZXQgaXQgaW50byB0aGUgbGlzdCwgZmVlbCBmcmVlIHRvIGVpdGhlciBvcGVuIGEgcHVsbCByZXF1ZXN0IG9yIGlmIHlvdVxuICBmaW5kIHRoYXQgcHJvY2VzcyBhIGJpdCBkYXVudGluZyB0aGVuIGp1c3QgY3JlYXRlIGFuIGlzc3VlIHJlcXVlc3RpbmdcbiAgdGhlIGFkZGl0aW9uIG9mIHRoZSBzZXJ2ZXIgKG1ha2Ugc3VyZSB5b3UgcHJvdmlkZSBhbGwgdGhlIGRldGFpbHMsIGFuZCBpZlxuICB5b3UgaGF2ZSBhIFRlcm1zIG9mIFNlcnZpY2UgdGhlbiBpbmNsdWRpbmcgdGhhdCBpbiB0aGUgUFIvaXNzdWUgd291bGQgYmVcbiAgYXdlc29tZSkuXG5cbiAgIyMgSSBrbm93IG9mIGEgZnJlZSBzZXJ2ZXIsIGNhbiBJIGFkZCBpdD9cblxuICBTdXJlLCBpZiB5b3UgZG8geW91ciBob21ld29yayBhbmQgbWFrZSBzdXJlIGl0IGlzIG9rIHRvIHVzZSAoSSdtIGN1cnJlbnRseVxuICBpbiB0aGUgcHJvY2VzcyBvZiByZXZpZXdpbmcgdGhlIHRlcm1zIG9mIHRob3NlIFNUVU4gc2VydmVycyBpbmNsdWRlZCBmcm9tXG4gIHRoZSBvcmlnaW5hbCBsaXN0KS4gIElmIGl0J3Mgb2sgdG8gZ28sIHRoZW4gcGxlYXNlIHNlZSB0aGUgcHJldmlvdXMgZW50cnlcbiAgZm9yIGhvdyB0byBhZGQgaXQuXG5cbiAgIyMgQ3VycmVudCBMaXN0IG9mIFNlcnZlcnNcblxuICAqIGN1cnJlbnQgYXMgYXQgdGhlIHRpbWUgb2YgbGFzdCBgUkVBRE1FLm1kYCBmaWxlIGdlbmVyYXRpb25cblxuICAjIyMgU1RVTlxuXG4gIDw8PCBzdHVuLmpzb25cblxuICAjIyMgVFVSTlxuXG4gIDw8PCB0dXJuLmpzb25cblxuKiovXG5cbnZhciBmcmVlaWNlID0gbW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihvcHRzKSB7XG4gIC8vIGlmIGEgbGlzdCBvZiBzZXJ2ZXJzIGhhcyBiZWVuIHByb3ZpZGVkLCB0aGVuIHVzZSBpdCBpbnN0ZWFkIG9mIGRlZmF1bHRzXG4gIHZhciBzZXJ2ZXJzID0ge1xuICAgIHN0dW46IChvcHRzIHx8IHt9KS5zdHVuIHx8IHJlcXVpcmUoJy4vc3R1bi5qc29uJyksXG4gICAgdHVybjogKG9wdHMgfHwge30pLnR1cm4gfHwgcmVxdWlyZSgnLi90dXJuLmpzb24nKVxuICB9O1xuXG4gIHZhciBzdHVuQ291bnQgPSAob3B0cyB8fCB7fSkuc3R1bkNvdW50IHx8IDI7XG4gIHZhciB0dXJuQ291bnQgPSAob3B0cyB8fCB7fSkudHVybkNvdW50IHx8IDA7XG4gIHZhciBzZWxlY3RlZDtcblxuICBmdW5jdGlvbiBnZXRTZXJ2ZXJzKHR5cGUsIGNvdW50KSB7XG4gICAgdmFyIG91dCA9IFtdO1xuICAgIHZhciBpbnB1dCA9IFtdLmNvbmNhdChzZXJ2ZXJzW3R5cGVdKTtcbiAgICB2YXIgaWR4O1xuXG4gICAgd2hpbGUgKGlucHV0Lmxlbmd0aCAmJiBvdXQubGVuZ3RoIDwgY291bnQpIHtcbiAgICAgIGlkeCA9IChNYXRoLnJhbmRvbSgpICogaW5wdXQubGVuZ3RoKSB8IDA7XG4gICAgICBvdXQgPSBvdXQuY29uY2F0KGlucHV0LnNwbGljZShpZHgsIDEpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gb3V0Lm1hcChmdW5jdGlvbih1cmwpIHtcbiAgICAgICAgLy9JZiBpdCdzIGEgbm90IGEgc3RyaW5nLCBkb24ndCB0cnkgdG8gXCJub3JtYWxpY2VcIiBpdCBvdGhlcndpc2UgdXNpbmcgdHlwZTp1cmwgd2lsbCBzY3JldyBpdCB1cFxuICAgICAgICBpZiAoKHR5cGVvZiB1cmwgIT09ICdzdHJpbmcnKSAmJiAoISAodXJsIGluc3RhbmNlb2YgU3RyaW5nKSkpIHtcbiAgICAgICAgICAgIHJldHVybiB1cmw7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbm9ybWFsaWNlKHR5cGUgKyAnOicgKyB1cmwpO1xuICAgICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvLyBhZGQgc3R1biBzZXJ2ZXJzXG4gIHNlbGVjdGVkID0gW10uY29uY2F0KGdldFNlcnZlcnMoJ3N0dW4nLCBzdHVuQ291bnQpKTtcblxuICBpZiAodHVybkNvdW50KSB7XG4gICAgc2VsZWN0ZWQgPSBzZWxlY3RlZC5jb25jYXQoZ2V0U2VydmVycygndHVybicsIHR1cm5Db3VudCkpO1xuICB9XG5cbiAgcmV0dXJuIHNlbGVjdGVkO1xufTtcbiIsIm1vZHVsZS5leHBvcnRzPVtcbiAgXCJzdHVuLmwuZ29vZ2xlLmNvbToxOTMwMlwiLFxuICBcInN0dW4xLmwuZ29vZ2xlLmNvbToxOTMwMlwiLFxuICBcInN0dW4yLmwuZ29vZ2xlLmNvbToxOTMwMlwiLFxuICBcInN0dW4zLmwuZ29vZ2xlLmNvbToxOTMwMlwiLFxuICBcInN0dW40LmwuZ29vZ2xlLmNvbToxOTMwMlwiLFxuICBcInN0dW4uZWtpZ2EubmV0XCIsXG4gIFwic3R1bi5pZGVhc2lwLmNvbVwiLFxuICBcInN0dW4uc2NobHVuZC5kZVwiLFxuICBcInN0dW4uc3R1bnByb3RvY29sLm9yZzozNDc4XCIsXG4gIFwic3R1bi52b2lwYXJvdW5kLmNvbVwiLFxuICBcInN0dW4udm9pcGJ1c3Rlci5jb21cIixcbiAgXCJzdHVuLnZvaXBzdHVudC5jb21cIixcbiAgXCJzdHVuLnZveGdyYXRpYS5vcmdcIixcbiAgXCJzdHVuLnNlcnZpY2VzLm1vemlsbGEuY29tXCJcbl1cbiIsIm1vZHVsZS5leHBvcnRzPVtdXG4iLCJ2YXIgV2lsZEVtaXR0ZXIgPSByZXF1aXJlKCd3aWxkZW1pdHRlcicpO1xuXG5mdW5jdGlvbiBnZXRNYXhWb2x1bWUgKGFuYWx5c2VyLCBmZnRCaW5zKSB7XG4gIHZhciBtYXhWb2x1bWUgPSAtSW5maW5pdHk7XG4gIGFuYWx5c2VyLmdldEZsb2F0RnJlcXVlbmN5RGF0YShmZnRCaW5zKTtcblxuICBmb3IodmFyIGk9NCwgaWk9ZmZ0Qmlucy5sZW5ndGg7IGkgPCBpaTsgaSsrKSB7XG4gICAgaWYgKGZmdEJpbnNbaV0gPiBtYXhWb2x1bWUgJiYgZmZ0Qmluc1tpXSA8IDApIHtcbiAgICAgIG1heFZvbHVtZSA9IGZmdEJpbnNbaV07XG4gICAgfVxuICB9O1xuXG4gIHJldHVybiBtYXhWb2x1bWU7XG59XG5cblxudmFyIGF1ZGlvQ29udGV4dFR5cGU7XG5pZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgYXVkaW9Db250ZXh0VHlwZSA9IHdpbmRvdy5BdWRpb0NvbnRleHQgfHwgd2luZG93LndlYmtpdEF1ZGlvQ29udGV4dDtcbn1cbi8vIHVzZSBhIHNpbmdsZSBhdWRpbyBjb250ZXh0IGR1ZSB0byBoYXJkd2FyZSBsaW1pdHNcbnZhciBhdWRpb0NvbnRleHQgPSBudWxsO1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihzdHJlYW0sIG9wdGlvbnMpIHtcbiAgdmFyIGhhcmtlciA9IG5ldyBXaWxkRW1pdHRlcigpO1xuXG5cbiAgLy8gbWFrZSBpdCBub3QgYnJlYWsgaW4gbm9uLXN1cHBvcnRlZCBicm93c2Vyc1xuICBpZiAoIWF1ZGlvQ29udGV4dFR5cGUpIHJldHVybiBoYXJrZXI7XG5cbiAgLy9Db25maWdcbiAgdmFyIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9LFxuICAgICAgc21vb3RoaW5nID0gKG9wdGlvbnMuc21vb3RoaW5nIHx8IDAuMSksXG4gICAgICBpbnRlcnZhbCA9IChvcHRpb25zLmludGVydmFsIHx8IDUwKSxcbiAgICAgIHRocmVzaG9sZCA9IG9wdGlvbnMudGhyZXNob2xkLFxuICAgICAgcGxheSA9IG9wdGlvbnMucGxheSxcbiAgICAgIGhpc3RvcnkgPSBvcHRpb25zLmhpc3RvcnkgfHwgMTAsXG4gICAgICBydW5uaW5nID0gdHJ1ZTtcblxuICAvL1NldHVwIEF1ZGlvIENvbnRleHRcbiAgaWYgKCFhdWRpb0NvbnRleHQpIHtcbiAgICBhdWRpb0NvbnRleHQgPSBuZXcgYXVkaW9Db250ZXh0VHlwZSgpO1xuICB9XG4gIHZhciBzb3VyY2VOb2RlLCBmZnRCaW5zLCBhbmFseXNlcjtcblxuICBhbmFseXNlciA9IGF1ZGlvQ29udGV4dC5jcmVhdGVBbmFseXNlcigpO1xuICBhbmFseXNlci5mZnRTaXplID0gNTEyO1xuICBhbmFseXNlci5zbW9vdGhpbmdUaW1lQ29uc3RhbnQgPSBzbW9vdGhpbmc7XG4gIGZmdEJpbnMgPSBuZXcgRmxvYXQzMkFycmF5KGFuYWx5c2VyLmZyZXF1ZW5jeUJpbkNvdW50KTtcblxuICBpZiAoc3RyZWFtLmpxdWVyeSkgc3RyZWFtID0gc3RyZWFtWzBdO1xuICBpZiAoc3RyZWFtIGluc3RhbmNlb2YgSFRNTEF1ZGlvRWxlbWVudCB8fCBzdHJlYW0gaW5zdGFuY2VvZiBIVE1MVmlkZW9FbGVtZW50KSB7XG4gICAgLy9BdWRpbyBUYWdcbiAgICBzb3VyY2VOb2RlID0gYXVkaW9Db250ZXh0LmNyZWF0ZU1lZGlhRWxlbWVudFNvdXJjZShzdHJlYW0pO1xuICAgIGlmICh0eXBlb2YgcGxheSA9PT0gJ3VuZGVmaW5lZCcpIHBsYXkgPSB0cnVlO1xuICAgIHRocmVzaG9sZCA9IHRocmVzaG9sZCB8fCAtNTA7XG4gIH0gZWxzZSB7XG4gICAgLy9XZWJSVEMgU3RyZWFtXG4gICAgc291cmNlTm9kZSA9IGF1ZGlvQ29udGV4dC5jcmVhdGVNZWRpYVN0cmVhbVNvdXJjZShzdHJlYW0pO1xuICAgIHRocmVzaG9sZCA9IHRocmVzaG9sZCB8fCAtNTA7XG4gIH1cblxuICBzb3VyY2VOb2RlLmNvbm5lY3QoYW5hbHlzZXIpO1xuICBpZiAocGxheSkgYW5hbHlzZXIuY29ubmVjdChhdWRpb0NvbnRleHQuZGVzdGluYXRpb24pO1xuXG4gIGhhcmtlci5zcGVha2luZyA9IGZhbHNlO1xuXG4gIGhhcmtlci5zZXRUaHJlc2hvbGQgPSBmdW5jdGlvbih0KSB7XG4gICAgdGhyZXNob2xkID0gdDtcbiAgfTtcblxuICBoYXJrZXIuc2V0SW50ZXJ2YWwgPSBmdW5jdGlvbihpKSB7XG4gICAgaW50ZXJ2YWwgPSBpO1xuICB9O1xuXG4gIGhhcmtlci5zdG9wID0gZnVuY3Rpb24oKSB7XG4gICAgcnVubmluZyA9IGZhbHNlO1xuICAgIGhhcmtlci5lbWl0KCd2b2x1bWVfY2hhbmdlJywgLTEwMCwgdGhyZXNob2xkKTtcbiAgICBpZiAoaGFya2VyLnNwZWFraW5nKSB7XG4gICAgICBoYXJrZXIuc3BlYWtpbmcgPSBmYWxzZTtcbiAgICAgIGhhcmtlci5lbWl0KCdzdG9wcGVkX3NwZWFraW5nJyk7XG4gICAgfVxuICAgIGFuYWx5c2VyLmRpc2Nvbm5lY3QoKTtcbiAgICBzb3VyY2VOb2RlLmRpc2Nvbm5lY3QoKTtcbiAgfTtcbiAgaGFya2VyLnNwZWFraW5nSGlzdG9yeSA9IFtdO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGhpc3Rvcnk7IGkrKykge1xuICAgICAgaGFya2VyLnNwZWFraW5nSGlzdG9yeS5wdXNoKDApO1xuICB9XG5cbiAgLy8gUG9sbCB0aGUgYW5hbHlzZXIgbm9kZSB0byBkZXRlcm1pbmUgaWYgc3BlYWtpbmdcbiAgLy8gYW5kIGVtaXQgZXZlbnRzIGlmIGNoYW5nZWRcbiAgdmFyIGxvb3BlciA9IGZ1bmN0aW9uKCkge1xuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG5cbiAgICAgIC8vY2hlY2sgaWYgc3RvcCBoYXMgYmVlbiBjYWxsZWRcbiAgICAgIGlmKCFydW5uaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIGN1cnJlbnRWb2x1bWUgPSBnZXRNYXhWb2x1bWUoYW5hbHlzZXIsIGZmdEJpbnMpO1xuXG4gICAgICBoYXJrZXIuZW1pdCgndm9sdW1lX2NoYW5nZScsIGN1cnJlbnRWb2x1bWUsIHRocmVzaG9sZCk7XG5cbiAgICAgIHZhciBoaXN0b3J5ID0gMDtcbiAgICAgIGlmIChjdXJyZW50Vm9sdW1lID4gdGhyZXNob2xkICYmICFoYXJrZXIuc3BlYWtpbmcpIHtcbiAgICAgICAgLy8gdHJpZ2dlciBxdWlja2x5LCBzaG9ydCBoaXN0b3J5XG4gICAgICAgIGZvciAodmFyIGkgPSBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5Lmxlbmd0aCAtIDM7IGkgPCBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgaGlzdG9yeSArPSBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5W2ldO1xuICAgICAgICB9XG4gICAgICAgIGlmIChoaXN0b3J5ID49IDIpIHtcbiAgICAgICAgICBoYXJrZXIuc3BlYWtpbmcgPSB0cnVlO1xuICAgICAgICAgIGhhcmtlci5lbWl0KCdzcGVha2luZycpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGN1cnJlbnRWb2x1bWUgPCB0aHJlc2hvbGQgJiYgaGFya2VyLnNwZWFraW5nKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaGFya2VyLnNwZWFraW5nSGlzdG9yeS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIGhpc3RvcnkgKz0gaGFya2VyLnNwZWFraW5nSGlzdG9yeVtpXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaGlzdG9yeSA9PSAwKSB7XG4gICAgICAgICAgaGFya2VyLnNwZWFraW5nID0gZmFsc2U7XG4gICAgICAgICAgaGFya2VyLmVtaXQoJ3N0b3BwZWRfc3BlYWtpbmcnKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaGFya2VyLnNwZWFraW5nSGlzdG9yeS5zaGlmdCgpO1xuICAgICAgaGFya2VyLnNwZWFraW5nSGlzdG9yeS5wdXNoKDAgKyAoY3VycmVudFZvbHVtZSA+IHRocmVzaG9sZCkpO1xuXG4gICAgICBsb29wZXIoKTtcbiAgICB9LCBpbnRlcnZhbCk7XG4gIH07XG4gIGxvb3BlcigpO1xuXG5cbiAgcmV0dXJuIGhhcmtlcjtcbn1cbiIsImlmICh0eXBlb2YgT2JqZWN0LmNyZWF0ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAvLyBpbXBsZW1lbnRhdGlvbiBmcm9tIHN0YW5kYXJkIG5vZGUuanMgJ3V0aWwnIG1vZHVsZVxuICBtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGluaGVyaXRzKGN0b3IsIHN1cGVyQ3Rvcikge1xuICAgIGN0b3Iuc3VwZXJfID0gc3VwZXJDdG9yXG4gICAgY3Rvci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHN1cGVyQ3Rvci5wcm90b3R5cGUsIHtcbiAgICAgIGNvbnN0cnVjdG9yOiB7XG4gICAgICAgIHZhbHVlOiBjdG9yLFxuICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgICAgfVxuICAgIH0pO1xuICB9O1xufSBlbHNlIHtcbiAgLy8gb2xkIHNjaG9vbCBzaGltIGZvciBvbGQgYnJvd3NlcnNcbiAgbW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBpbmhlcml0cyhjdG9yLCBzdXBlckN0b3IpIHtcbiAgICBjdG9yLnN1cGVyXyA9IHN1cGVyQ3RvclxuICAgIHZhciBUZW1wQ3RvciA9IGZ1bmN0aW9uICgpIHt9XG4gICAgVGVtcEN0b3IucHJvdG90eXBlID0gc3VwZXJDdG9yLnByb3RvdHlwZVxuICAgIGN0b3IucHJvdG90eXBlID0gbmV3IFRlbXBDdG9yKClcbiAgICBjdG9yLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IGN0b3JcbiAgfVxufVxuIiwiLyohXHJcbiAqIEBuYW1lIEphdmFTY3JpcHQvTm9kZUpTIE1lcmdlIHYxLjIuMFxyXG4gKiBAYXV0aG9yIHllaWtvc1xyXG4gKiBAcmVwb3NpdG9yeSBodHRwczovL2dpdGh1Yi5jb20veWVpa29zL2pzLm1lcmdlXHJcblxyXG4gKiBDb3B5cmlnaHQgMjAxNCB5ZWlrb3MgLSBNSVQgbGljZW5zZVxyXG4gKiBodHRwczovL3Jhdy5naXRodWIuY29tL3llaWtvcy9qcy5tZXJnZS9tYXN0ZXIvTElDRU5TRVxyXG4gKi9cclxuXHJcbjsoZnVuY3Rpb24oaXNOb2RlKSB7XHJcblxyXG5cdC8qKlxyXG5cdCAqIE1lcmdlIG9uZSBvciBtb3JlIG9iamVjdHMgXHJcblx0ICogQHBhcmFtIGJvb2w/IGNsb25lXHJcblx0ICogQHBhcmFtIG1peGVkLC4uLiBhcmd1bWVudHNcclxuXHQgKiBAcmV0dXJuIG9iamVjdFxyXG5cdCAqL1xyXG5cclxuXHR2YXIgUHVibGljID0gZnVuY3Rpb24oY2xvbmUpIHtcclxuXHJcblx0XHRyZXR1cm4gbWVyZ2UoY2xvbmUgPT09IHRydWUsIGZhbHNlLCBhcmd1bWVudHMpO1xyXG5cclxuXHR9LCBwdWJsaWNOYW1lID0gJ21lcmdlJztcclxuXHJcblx0LyoqXHJcblx0ICogTWVyZ2UgdHdvIG9yIG1vcmUgb2JqZWN0cyByZWN1cnNpdmVseSBcclxuXHQgKiBAcGFyYW0gYm9vbD8gY2xvbmVcclxuXHQgKiBAcGFyYW0gbWl4ZWQsLi4uIGFyZ3VtZW50c1xyXG5cdCAqIEByZXR1cm4gb2JqZWN0XHJcblx0ICovXHJcblxyXG5cdFB1YmxpYy5yZWN1cnNpdmUgPSBmdW5jdGlvbihjbG9uZSkge1xyXG5cclxuXHRcdHJldHVybiBtZXJnZShjbG9uZSA9PT0gdHJ1ZSwgdHJ1ZSwgYXJndW1lbnRzKTtcclxuXHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogQ2xvbmUgdGhlIGlucHV0IHJlbW92aW5nIGFueSByZWZlcmVuY2VcclxuXHQgKiBAcGFyYW0gbWl4ZWQgaW5wdXRcclxuXHQgKiBAcmV0dXJuIG1peGVkXHJcblx0ICovXHJcblxyXG5cdFB1YmxpYy5jbG9uZSA9IGZ1bmN0aW9uKGlucHV0KSB7XHJcblxyXG5cdFx0dmFyIG91dHB1dCA9IGlucHV0LFxyXG5cdFx0XHR0eXBlID0gdHlwZU9mKGlucHV0KSxcclxuXHRcdFx0aW5kZXgsIHNpemU7XHJcblxyXG5cdFx0aWYgKHR5cGUgPT09ICdhcnJheScpIHtcclxuXHJcblx0XHRcdG91dHB1dCA9IFtdO1xyXG5cdFx0XHRzaXplID0gaW5wdXQubGVuZ3RoO1xyXG5cclxuXHRcdFx0Zm9yIChpbmRleD0wO2luZGV4PHNpemU7KytpbmRleClcclxuXHJcblx0XHRcdFx0b3V0cHV0W2luZGV4XSA9IFB1YmxpYy5jbG9uZShpbnB1dFtpbmRleF0pO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAodHlwZSA9PT0gJ29iamVjdCcpIHtcclxuXHJcblx0XHRcdG91dHB1dCA9IHt9O1xyXG5cclxuXHRcdFx0Zm9yIChpbmRleCBpbiBpbnB1dClcclxuXHJcblx0XHRcdFx0b3V0cHV0W2luZGV4XSA9IFB1YmxpYy5jbG9uZShpbnB1dFtpbmRleF0pO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gb3V0cHV0O1xyXG5cclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBNZXJnZSB0d28gb2JqZWN0cyByZWN1cnNpdmVseVxyXG5cdCAqIEBwYXJhbSBtaXhlZCBpbnB1dFxyXG5cdCAqIEBwYXJhbSBtaXhlZCBleHRlbmRcclxuXHQgKiBAcmV0dXJuIG1peGVkXHJcblx0ICovXHJcblxyXG5cdGZ1bmN0aW9uIG1lcmdlX3JlY3Vyc2l2ZShiYXNlLCBleHRlbmQpIHtcclxuXHJcblx0XHRpZiAodHlwZU9mKGJhc2UpICE9PSAnb2JqZWN0JylcclxuXHJcblx0XHRcdHJldHVybiBleHRlbmQ7XHJcblxyXG5cdFx0Zm9yICh2YXIga2V5IGluIGV4dGVuZCkge1xyXG5cclxuXHRcdFx0aWYgKHR5cGVPZihiYXNlW2tleV0pID09PSAnb2JqZWN0JyAmJiB0eXBlT2YoZXh0ZW5kW2tleV0pID09PSAnb2JqZWN0Jykge1xyXG5cclxuXHRcdFx0XHRiYXNlW2tleV0gPSBtZXJnZV9yZWN1cnNpdmUoYmFzZVtrZXldLCBleHRlbmRba2V5XSk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRiYXNlW2tleV0gPSBleHRlbmRba2V5XTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGJhc2U7XHJcblxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogTWVyZ2UgdHdvIG9yIG1vcmUgb2JqZWN0c1xyXG5cdCAqIEBwYXJhbSBib29sIGNsb25lXHJcblx0ICogQHBhcmFtIGJvb2wgcmVjdXJzaXZlXHJcblx0ICogQHBhcmFtIGFycmF5IGFyZ3ZcclxuXHQgKiBAcmV0dXJuIG9iamVjdFxyXG5cdCAqL1xyXG5cclxuXHRmdW5jdGlvbiBtZXJnZShjbG9uZSwgcmVjdXJzaXZlLCBhcmd2KSB7XHJcblxyXG5cdFx0dmFyIHJlc3VsdCA9IGFyZ3ZbMF0sXHJcblx0XHRcdHNpemUgPSBhcmd2Lmxlbmd0aDtcclxuXHJcblx0XHRpZiAoY2xvbmUgfHwgdHlwZU9mKHJlc3VsdCkgIT09ICdvYmplY3QnKVxyXG5cclxuXHRcdFx0cmVzdWx0ID0ge307XHJcblxyXG5cdFx0Zm9yICh2YXIgaW5kZXg9MDtpbmRleDxzaXplOysraW5kZXgpIHtcclxuXHJcblx0XHRcdHZhciBpdGVtID0gYXJndltpbmRleF0sXHJcblxyXG5cdFx0XHRcdHR5cGUgPSB0eXBlT2YoaXRlbSk7XHJcblxyXG5cdFx0XHRpZiAodHlwZSAhPT0gJ29iamVjdCcpIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0Zm9yICh2YXIga2V5IGluIGl0ZW0pIHtcclxuXHJcblx0XHRcdFx0dmFyIHNpdGVtID0gY2xvbmUgPyBQdWJsaWMuY2xvbmUoaXRlbVtrZXldKSA6IGl0ZW1ba2V5XTtcclxuXHJcblx0XHRcdFx0aWYgKHJlY3Vyc2l2ZSkge1xyXG5cclxuXHRcdFx0XHRcdHJlc3VsdFtrZXldID0gbWVyZ2VfcmVjdXJzaXZlKHJlc3VsdFtrZXldLCBzaXRlbSk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0cmVzdWx0W2tleV0gPSBzaXRlbTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcmVzdWx0O1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCB0eXBlIG9mIHZhcmlhYmxlXHJcblx0ICogQHBhcmFtIG1peGVkIGlucHV0XHJcblx0ICogQHJldHVybiBzdHJpbmdcclxuXHQgKlxyXG5cdCAqIEBzZWUgaHR0cDovL2pzcGVyZi5jb20vdHlwZW9mdmFyXHJcblx0ICovXHJcblxyXG5cdGZ1bmN0aW9uIHR5cGVPZihpbnB1dCkge1xyXG5cclxuXHRcdHJldHVybiAoe30pLnRvU3RyaW5nLmNhbGwoaW5wdXQpLnNsaWNlKDgsIC0xKS50b0xvd2VyQ2FzZSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdGlmIChpc05vZGUpIHtcclxuXHJcblx0XHRtb2R1bGUuZXhwb3J0cyA9IFB1YmxpYztcclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHR3aW5kb3dbcHVibGljTmFtZV0gPSBQdWJsaWM7XHJcblxyXG5cdH1cclxuXHJcbn0pKHR5cGVvZiBtb2R1bGUgPT09ICdvYmplY3QnICYmIG1vZHVsZSAmJiB0eXBlb2YgbW9kdWxlLmV4cG9ydHMgPT09ICdvYmplY3QnICYmIG1vZHVsZS5leHBvcnRzKTsiLCIvKipcbiAgIyBub3JtYWxpY2VcblxuICBOb3JtYWxpemUgYW4gaWNlIHNlcnZlciBjb25maWd1cmF0aW9uIG9iamVjdCAob3IgcGxhaW4gb2xkIHN0cmluZykgaW50byBhIGZvcm1hdFxuICB0aGF0IGlzIHVzYWJsZSBpbiBhbGwgYnJvd3NlcnMgc3VwcG9ydGluZyBXZWJSVEMuICBQcmltYXJpbHkgdGhpcyBtb2R1bGUgaXMgZGVzaWduZWRcbiAgdG8gaGVscCB3aXRoIHRoZSB0cmFuc2l0aW9uIG9mIHRoZSBgdXJsYCBhdHRyaWJ1dGUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvXG4gIHRoZSBgdXJsc2AgYXR0cmlidXRlLlxuXG4gICMjIEV4YW1wbGUgVXNhZ2VcblxuICA8PDwgZXhhbXBsZXMvc2ltcGxlLmpzXG5cbioqL1xuXG52YXIgcHJvdG9jb2xzID0gW1xuICAnc3R1bjonLFxuICAndHVybjonXG5dO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKGlucHV0KSB7XG4gIHZhciB1cmwgPSAoaW5wdXQgfHwge30pLnVybCB8fCBpbnB1dDtcbiAgdmFyIHByb3RvY29sO1xuICB2YXIgcGFydHM7XG4gIHZhciBvdXRwdXQgPSB7fTtcblxuICAvLyBpZiB3ZSBkb24ndCBoYXZlIGEgc3RyaW5nIHVybCwgdGhlbiBhbGxvdyB0aGUgaW5wdXQgdG8gcGFzc3Rocm91Z2hcbiAgaWYgKHR5cGVvZiB1cmwgIT0gJ3N0cmluZycgJiYgKCEgKHVybCBpbnN0YW5jZW9mIFN0cmluZykpKSB7XG4gICAgcmV0dXJuIGlucHV0O1xuICB9XG5cbiAgLy8gdHJpbSB0aGUgdXJsIHN0cmluZywgYW5kIGNvbnZlcnQgdG8gYW4gYXJyYXlcbiAgdXJsID0gdXJsLnRyaW0oKTtcblxuICAvLyBpZiB0aGUgcHJvdG9jb2wgaXMgbm90IGtub3duLCB0aGVuIHBhc3N0aHJvdWdoXG4gIHByb3RvY29sID0gcHJvdG9jb2xzW3Byb3RvY29scy5pbmRleE9mKHVybC5zbGljZSgwLCA1KSldO1xuICBpZiAoISBwcm90b2NvbCkge1xuICAgIHJldHVybiBpbnB1dDtcbiAgfVxuXG4gIC8vIG5vdyBsZXQncyBhdHRhY2sgdGhlIHJlbWFpbmluZyB1cmwgcGFydHNcbiAgdXJsID0gdXJsLnNsaWNlKDUpO1xuICBwYXJ0cyA9IHVybC5zcGxpdCgnQCcpO1xuXG4gIG91dHB1dC51c2VybmFtZSA9IGlucHV0LnVzZXJuYW1lO1xuICBvdXRwdXQuY3JlZGVudGlhbCA9IGlucHV0LmNyZWRlbnRpYWw7XG4gIC8vIGlmIHdlIGhhdmUgYW4gYXV0aGVudGljYXRpb24gcGFydCwgdGhlbiBzZXQgdGhlIGNyZWRlbnRpYWxzXG4gIGlmIChwYXJ0cy5sZW5ndGggPiAxKSB7XG4gICAgdXJsID0gcGFydHNbMV07XG4gICAgcGFydHMgPSBwYXJ0c1swXS5zcGxpdCgnOicpO1xuXG4gICAgLy8gYWRkIHRoZSBvdXRwdXQgY3JlZGVudGlhbCBhbmQgdXNlcm5hbWVcbiAgICBvdXRwdXQudXNlcm5hbWUgPSBwYXJ0c1swXTtcbiAgICBvdXRwdXQuY3JlZGVudGlhbCA9IChpbnB1dCB8fCB7fSkuY3JlZGVudGlhbCB8fCBwYXJ0c1sxXSB8fCAnJztcbiAgfVxuXG4gIG91dHB1dC51cmwgPSBwcm90b2NvbCArIHVybDtcbiAgb3V0cHV0LnVybHMgPSBbIG91dHB1dC51cmwgXTtcblxuICByZXR1cm4gb3V0cHV0O1xufTtcbiIsIi8qXG4gKiAgQ29weXJpZ2h0IChjKSAyMDE3IFRoZSBXZWJSVEMgcHJvamVjdCBhdXRob3JzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqICBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhIEJTRC1zdHlsZSBsaWNlbnNlXG4gKiAgdGhhdCBjYW4gYmUgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBvZiB0aGUgc291cmNlXG4gKiAgdHJlZS5cbiAqL1xuIC8qIGVzbGludC1lbnYgbm9kZSAqL1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgU0RQVXRpbHMgPSByZXF1aXJlKCdzZHAnKTtcblxuZnVuY3Rpb24gd3JpdGVNZWRpYVNlY3Rpb24odHJhbnNjZWl2ZXIsIGNhcHMsIHR5cGUsIHN0cmVhbSwgZHRsc1JvbGUpIHtcbiAgdmFyIHNkcCA9IFNEUFV0aWxzLndyaXRlUnRwRGVzY3JpcHRpb24odHJhbnNjZWl2ZXIua2luZCwgY2Fwcyk7XG5cbiAgLy8gTWFwIElDRSBwYXJhbWV0ZXJzICh1ZnJhZywgcHdkKSB0byBTRFAuXG4gIHNkcCArPSBTRFBVdGlscy53cml0ZUljZVBhcmFtZXRlcnMoXG4gICAgICB0cmFuc2NlaXZlci5pY2VHYXRoZXJlci5nZXRMb2NhbFBhcmFtZXRlcnMoKSk7XG5cbiAgLy8gTWFwIERUTFMgcGFyYW1ldGVycyB0byBTRFAuXG4gIHNkcCArPSBTRFBVdGlscy53cml0ZUR0bHNQYXJhbWV0ZXJzKFxuICAgICAgdHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydC5nZXRMb2NhbFBhcmFtZXRlcnMoKSxcbiAgICAgIHR5cGUgPT09ICdvZmZlcicgPyAnYWN0cGFzcycgOiBkdGxzUm9sZSB8fCAnYWN0aXZlJyk7XG5cbiAgc2RwICs9ICdhPW1pZDonICsgdHJhbnNjZWl2ZXIubWlkICsgJ1xcclxcbic7XG5cbiAgaWYgKHRyYW5zY2VpdmVyLnJ0cFNlbmRlciAmJiB0cmFuc2NlaXZlci5ydHBSZWNlaXZlcikge1xuICAgIHNkcCArPSAnYT1zZW5kcmVjdlxcclxcbic7XG4gIH0gZWxzZSBpZiAodHJhbnNjZWl2ZXIucnRwU2VuZGVyKSB7XG4gICAgc2RwICs9ICdhPXNlbmRvbmx5XFxyXFxuJztcbiAgfSBlbHNlIGlmICh0cmFuc2NlaXZlci5ydHBSZWNlaXZlcikge1xuICAgIHNkcCArPSAnYT1yZWN2b25seVxcclxcbic7XG4gIH0gZWxzZSB7XG4gICAgc2RwICs9ICdhPWluYWN0aXZlXFxyXFxuJztcbiAgfVxuXG4gIGlmICh0cmFuc2NlaXZlci5ydHBTZW5kZXIpIHtcbiAgICAvLyBzcGVjLlxuICAgIHZhciBtc2lkID0gJ21zaWQ6JyArIHN0cmVhbS5pZCArICcgJyArXG4gICAgICAgIHRyYW5zY2VpdmVyLnJ0cFNlbmRlci50cmFjay5pZCArICdcXHJcXG4nO1xuICAgIHNkcCArPSAnYT0nICsgbXNpZDtcblxuICAgIC8vIGZvciBDaHJvbWUuXG4gICAgc2RwICs9ICdhPXNzcmM6JyArIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0uc3NyYyArXG4gICAgICAgICcgJyArIG1zaWQ7XG4gICAgaWYgKHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0ucnR4KSB7XG4gICAgICBzZHAgKz0gJ2E9c3NyYzonICsgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHguc3NyYyArXG4gICAgICAgICAgJyAnICsgbXNpZDtcbiAgICAgIHNkcCArPSAnYT1zc3JjLWdyb3VwOkZJRCAnICtcbiAgICAgICAgICB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnNzcmMgKyAnICcgK1xuICAgICAgICAgIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0ucnR4LnNzcmMgK1xuICAgICAgICAgICdcXHJcXG4nO1xuICAgIH1cbiAgfVxuICAvLyBGSVhNRTogdGhpcyBzaG91bGQgYmUgd3JpdHRlbiBieSB3cml0ZVJ0cERlc2NyaXB0aW9uLlxuICBzZHAgKz0gJ2E9c3NyYzonICsgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5zc3JjICtcbiAgICAgICcgY25hbWU6JyArIFNEUFV0aWxzLmxvY2FsQ05hbWUgKyAnXFxyXFxuJztcbiAgaWYgKHRyYW5zY2VpdmVyLnJ0cFNlbmRlciAmJiB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eCkge1xuICAgIHNkcCArPSAnYT1zc3JjOicgKyB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eC5zc3JjICtcbiAgICAgICAgJyBjbmFtZTonICsgU0RQVXRpbHMubG9jYWxDTmFtZSArICdcXHJcXG4nO1xuICB9XG4gIHJldHVybiBzZHA7XG59XG5cbi8vIEVkZ2UgZG9lcyBub3QgbGlrZVxuLy8gMSkgc3R1bjogZmlsdGVyZWQgYWZ0ZXIgMTQzOTMgdW5sZXNzID90cmFuc3BvcnQ9dWRwIGlzIHByZXNlbnRcbi8vIDIpIHR1cm46IHRoYXQgZG9lcyBub3QgaGF2ZSBhbGwgb2YgdHVybjpob3N0OnBvcnQ/dHJhbnNwb3J0PXVkcFxuLy8gMykgdHVybjogd2l0aCBpcHY2IGFkZHJlc3Nlc1xuLy8gNCkgdHVybjogb2NjdXJyaW5nIG11bGlwbGUgdGltZXNcbmZ1bmN0aW9uIGZpbHRlckljZVNlcnZlcnMoaWNlU2VydmVycywgZWRnZVZlcnNpb24pIHtcbiAgdmFyIGhhc1R1cm4gPSBmYWxzZTtcbiAgaWNlU2VydmVycyA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoaWNlU2VydmVycykpO1xuICByZXR1cm4gaWNlU2VydmVycy5maWx0ZXIoZnVuY3Rpb24oc2VydmVyKSB7XG4gICAgaWYgKHNlcnZlciAmJiAoc2VydmVyLnVybHMgfHwgc2VydmVyLnVybCkpIHtcbiAgICAgIHZhciB1cmxzID0gc2VydmVyLnVybHMgfHwgc2VydmVyLnVybDtcbiAgICAgIGlmIChzZXJ2ZXIudXJsICYmICFzZXJ2ZXIudXJscykge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1JUQ0ljZVNlcnZlci51cmwgaXMgZGVwcmVjYXRlZCEgVXNlIHVybHMgaW5zdGVhZC4nKTtcbiAgICAgIH1cbiAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiB1cmxzID09PSAnc3RyaW5nJztcbiAgICAgIGlmIChpc1N0cmluZykge1xuICAgICAgICB1cmxzID0gW3VybHNdO1xuICAgICAgfVxuICAgICAgdXJscyA9IHVybHMuZmlsdGVyKGZ1bmN0aW9uKHVybCkge1xuICAgICAgICB2YXIgdmFsaWRUdXJuID0gdXJsLmluZGV4T2YoJ3R1cm46JykgPT09IDAgJiZcbiAgICAgICAgICAgIHVybC5pbmRleE9mKCd0cmFuc3BvcnQ9dWRwJykgIT09IC0xICYmXG4gICAgICAgICAgICB1cmwuaW5kZXhPZigndHVybjpbJykgPT09IC0xICYmXG4gICAgICAgICAgICAhaGFzVHVybjtcblxuICAgICAgICBpZiAodmFsaWRUdXJuKSB7XG4gICAgICAgICAgaGFzVHVybiA9IHRydWU7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybC5pbmRleE9mKCdzdHVuOicpID09PSAwICYmIGVkZ2VWZXJzaW9uID49IDE0MzkzICYmXG4gICAgICAgICAgICB1cmwuaW5kZXhPZignP3RyYW5zcG9ydD11ZHAnKSA9PT0gLTE7XG4gICAgICB9KTtcblxuICAgICAgZGVsZXRlIHNlcnZlci51cmw7XG4gICAgICBzZXJ2ZXIudXJscyA9IGlzU3RyaW5nID8gdXJsc1swXSA6IHVybHM7XG4gICAgICByZXR1cm4gISF1cmxzLmxlbmd0aDtcbiAgICB9XG4gIH0pO1xufVxuXG4vLyBEZXRlcm1pbmVzIHRoZSBpbnRlcnNlY3Rpb24gb2YgbG9jYWwgYW5kIHJlbW90ZSBjYXBhYmlsaXRpZXMuXG5mdW5jdGlvbiBnZXRDb21tb25DYXBhYmlsaXRpZXMobG9jYWxDYXBhYmlsaXRpZXMsIHJlbW90ZUNhcGFiaWxpdGllcykge1xuICB2YXIgY29tbW9uQ2FwYWJpbGl0aWVzID0ge1xuICAgIGNvZGVjczogW10sXG4gICAgaGVhZGVyRXh0ZW5zaW9uczogW10sXG4gICAgZmVjTWVjaGFuaXNtczogW11cbiAgfTtcblxuICB2YXIgZmluZENvZGVjQnlQYXlsb2FkVHlwZSA9IGZ1bmN0aW9uKHB0LCBjb2RlY3MpIHtcbiAgICBwdCA9IHBhcnNlSW50KHB0LCAxMCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb2RlY3MubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChjb2RlY3NbaV0ucGF5bG9hZFR5cGUgPT09IHB0IHx8XG4gICAgICAgICAgY29kZWNzW2ldLnByZWZlcnJlZFBheWxvYWRUeXBlID09PSBwdCkge1xuICAgICAgICByZXR1cm4gY29kZWNzW2ldO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICB2YXIgcnR4Q2FwYWJpbGl0eU1hdGNoZXMgPSBmdW5jdGlvbihsUnR4LCByUnR4LCBsQ29kZWNzLCByQ29kZWNzKSB7XG4gICAgdmFyIGxDb2RlYyA9IGZpbmRDb2RlY0J5UGF5bG9hZFR5cGUobFJ0eC5wYXJhbWV0ZXJzLmFwdCwgbENvZGVjcyk7XG4gICAgdmFyIHJDb2RlYyA9IGZpbmRDb2RlY0J5UGF5bG9hZFR5cGUoclJ0eC5wYXJhbWV0ZXJzLmFwdCwgckNvZGVjcyk7XG4gICAgcmV0dXJuIGxDb2RlYyAmJiByQ29kZWMgJiZcbiAgICAgICAgbENvZGVjLm5hbWUudG9Mb3dlckNhc2UoKSA9PT0gckNvZGVjLm5hbWUudG9Mb3dlckNhc2UoKTtcbiAgfTtcblxuICBsb2NhbENhcGFiaWxpdGllcy5jb2RlY3MuZm9yRWFjaChmdW5jdGlvbihsQ29kZWMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJlbW90ZUNhcGFiaWxpdGllcy5jb2RlY3MubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciByQ29kZWMgPSByZW1vdGVDYXBhYmlsaXRpZXMuY29kZWNzW2ldO1xuICAgICAgaWYgKGxDb2RlYy5uYW1lLnRvTG93ZXJDYXNlKCkgPT09IHJDb2RlYy5uYW1lLnRvTG93ZXJDYXNlKCkgJiZcbiAgICAgICAgICBsQ29kZWMuY2xvY2tSYXRlID09PSByQ29kZWMuY2xvY2tSYXRlKSB7XG4gICAgICAgIGlmIChsQ29kZWMubmFtZS50b0xvd2VyQ2FzZSgpID09PSAncnR4JyAmJlxuICAgICAgICAgICAgbENvZGVjLnBhcmFtZXRlcnMgJiYgckNvZGVjLnBhcmFtZXRlcnMuYXB0KSB7XG4gICAgICAgICAgLy8gZm9yIFJUWCB3ZSBuZWVkIHRvIGZpbmQgdGhlIGxvY2FsIHJ0eCB0aGF0IGhhcyBhIGFwdFxuICAgICAgICAgIC8vIHdoaWNoIHBvaW50cyB0byB0aGUgc2FtZSBsb2NhbCBjb2RlYyBhcyB0aGUgcmVtb3RlIG9uZS5cbiAgICAgICAgICBpZiAoIXJ0eENhcGFiaWxpdHlNYXRjaGVzKGxDb2RlYywgckNvZGVjLFxuICAgICAgICAgICAgICBsb2NhbENhcGFiaWxpdGllcy5jb2RlY3MsIHJlbW90ZUNhcGFiaWxpdGllcy5jb2RlY3MpKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgckNvZGVjID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShyQ29kZWMpKTsgLy8gZGVlcGNvcHlcbiAgICAgICAgLy8gbnVtYmVyIG9mIGNoYW5uZWxzIGlzIHRoZSBoaWdoZXN0IGNvbW1vbiBudW1iZXIgb2YgY2hhbm5lbHNcbiAgICAgICAgckNvZGVjLm51bUNoYW5uZWxzID0gTWF0aC5taW4obENvZGVjLm51bUNoYW5uZWxzLFxuICAgICAgICAgICAgckNvZGVjLm51bUNoYW5uZWxzKTtcbiAgICAgICAgLy8gcHVzaCByQ29kZWMgc28gd2UgcmVwbHkgd2l0aCBvZmZlcmVyIHBheWxvYWQgdHlwZVxuICAgICAgICBjb21tb25DYXBhYmlsaXRpZXMuY29kZWNzLnB1c2gockNvZGVjKTtcblxuICAgICAgICAvLyBkZXRlcm1pbmUgY29tbW9uIGZlZWRiYWNrIG1lY2hhbmlzbXNcbiAgICAgICAgckNvZGVjLnJ0Y3BGZWVkYmFjayA9IHJDb2RlYy5ydGNwRmVlZGJhY2suZmlsdGVyKGZ1bmN0aW9uKGZiKSB7XG4gICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBsQ29kZWMucnRjcEZlZWRiYWNrLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICBpZiAobENvZGVjLnJ0Y3BGZWVkYmFja1tqXS50eXBlID09PSBmYi50eXBlICYmXG4gICAgICAgICAgICAgICAgbENvZGVjLnJ0Y3BGZWVkYmFja1tqXS5wYXJhbWV0ZXIgPT09IGZiLnBhcmFtZXRlcikge1xuICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9KTtcbiAgICAgICAgLy8gRklYTUU6IGFsc28gbmVlZCB0byBkZXRlcm1pbmUgLnBhcmFtZXRlcnNcbiAgICAgICAgLy8gIHNlZSBodHRwczovL2dpdGh1Yi5jb20vb3BlbnBlZXIvb3J0Yy9pc3N1ZXMvNTY5XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgbG9jYWxDYXBhYmlsaXRpZXMuaGVhZGVyRXh0ZW5zaW9ucy5mb3JFYWNoKGZ1bmN0aW9uKGxIZWFkZXJFeHRlbnNpb24pIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJlbW90ZUNhcGFiaWxpdGllcy5oZWFkZXJFeHRlbnNpb25zLmxlbmd0aDtcbiAgICAgICAgIGkrKykge1xuICAgICAgdmFyIHJIZWFkZXJFeHRlbnNpb24gPSByZW1vdGVDYXBhYmlsaXRpZXMuaGVhZGVyRXh0ZW5zaW9uc1tpXTtcbiAgICAgIGlmIChsSGVhZGVyRXh0ZW5zaW9uLnVyaSA9PT0gckhlYWRlckV4dGVuc2lvbi51cmkpIHtcbiAgICAgICAgY29tbW9uQ2FwYWJpbGl0aWVzLmhlYWRlckV4dGVuc2lvbnMucHVzaChySGVhZGVyRXh0ZW5zaW9uKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9KTtcblxuICAvLyBGSVhNRTogZmVjTWVjaGFuaXNtc1xuICByZXR1cm4gY29tbW9uQ2FwYWJpbGl0aWVzO1xufVxuXG4vLyBpcyBhY3Rpb249c2V0TG9jYWxEZXNjcmlwdGlvbiB3aXRoIHR5cGUgYWxsb3dlZCBpbiBzaWduYWxpbmdTdGF0ZVxuZnVuY3Rpb24gaXNBY3Rpb25BbGxvd2VkSW5TaWduYWxpbmdTdGF0ZShhY3Rpb24sIHR5cGUsIHNpZ25hbGluZ1N0YXRlKSB7XG4gIHJldHVybiB7XG4gICAgb2ZmZXI6IHtcbiAgICAgIHNldExvY2FsRGVzY3JpcHRpb246IFsnc3RhYmxlJywgJ2hhdmUtbG9jYWwtb2ZmZXInXSxcbiAgICAgIHNldFJlbW90ZURlc2NyaXB0aW9uOiBbJ3N0YWJsZScsICdoYXZlLXJlbW90ZS1vZmZlciddXG4gICAgfSxcbiAgICBhbnN3ZXI6IHtcbiAgICAgIHNldExvY2FsRGVzY3JpcHRpb246IFsnaGF2ZS1yZW1vdGUtb2ZmZXInLCAnaGF2ZS1sb2NhbC1wcmFuc3dlciddLFxuICAgICAgc2V0UmVtb3RlRGVzY3JpcHRpb246IFsnaGF2ZS1sb2NhbC1vZmZlcicsICdoYXZlLXJlbW90ZS1wcmFuc3dlciddXG4gICAgfVxuICB9W3R5cGVdW2FjdGlvbl0uaW5kZXhPZihzaWduYWxpbmdTdGF0ZSkgIT09IC0xO1xufVxuXG5mdW5jdGlvbiBtYXliZUFkZENhbmRpZGF0ZShpY2VUcmFuc3BvcnQsIGNhbmRpZGF0ZSkge1xuICAvLyBFZGdlJ3MgaW50ZXJuYWwgcmVwcmVzZW50YXRpb24gYWRkcyBzb21lIGZpZWxkcyB0aGVyZWZvcmVcbiAgLy8gbm90IGFsbCBmaWVsZNGVIGFyZSB0YWtlbiBpbnRvIGFjY291bnQuXG4gIHZhciBhbHJlYWR5QWRkZWQgPSBpY2VUcmFuc3BvcnQuZ2V0UmVtb3RlQ2FuZGlkYXRlcygpXG4gICAgICAuZmluZChmdW5jdGlvbihyZW1vdGVDYW5kaWRhdGUpIHtcbiAgICAgICAgcmV0dXJuIGNhbmRpZGF0ZS5mb3VuZGF0aW9uID09PSByZW1vdGVDYW5kaWRhdGUuZm91bmRhdGlvbiAmJlxuICAgICAgICAgICAgY2FuZGlkYXRlLmlwID09PSByZW1vdGVDYW5kaWRhdGUuaXAgJiZcbiAgICAgICAgICAgIGNhbmRpZGF0ZS5wb3J0ID09PSByZW1vdGVDYW5kaWRhdGUucG9ydCAmJlxuICAgICAgICAgICAgY2FuZGlkYXRlLnByaW9yaXR5ID09PSByZW1vdGVDYW5kaWRhdGUucHJpb3JpdHkgJiZcbiAgICAgICAgICAgIGNhbmRpZGF0ZS5wcm90b2NvbCA9PT0gcmVtb3RlQ2FuZGlkYXRlLnByb3RvY29sICYmXG4gICAgICAgICAgICBjYW5kaWRhdGUudHlwZSA9PT0gcmVtb3RlQ2FuZGlkYXRlLnR5cGU7XG4gICAgICB9KTtcbiAgaWYgKCFhbHJlYWR5QWRkZWQpIHtcbiAgICBpY2VUcmFuc3BvcnQuYWRkUmVtb3RlQ2FuZGlkYXRlKGNhbmRpZGF0ZSk7XG4gIH1cbiAgcmV0dXJuICFhbHJlYWR5QWRkZWQ7XG59XG5cblxuLy8gaHR0cHM6Ly93M2MuZ2l0aHViLmlvL21lZGlhY2FwdHVyZS1tYWluLyNtZWRpYXN0cmVhbVxuLy8gSGVscGVyIGZ1bmN0aW9uIHRvIGFkZCB0aGUgdHJhY2sgdG8gdGhlIHN0cmVhbSBhbmRcbi8vIGRpc3BhdGNoIHRoZSBldmVudCBvdXJzZWx2ZXMuXG5mdW5jdGlvbiBhZGRUcmFja1RvU3RyZWFtQW5kRmlyZUV2ZW50KHRyYWNrLCBzdHJlYW0pIHtcbiAgc3RyZWFtLmFkZFRyYWNrKHRyYWNrKTtcbiAgdmFyIGUgPSBuZXcgRXZlbnQoJ2FkZHRyYWNrJyk7IC8vIFRPRE86IE1lZGlhU3RyZWFtVHJhY2tFdmVudFxuICBlLnRyYWNrID0gdHJhY2s7XG4gIHN0cmVhbS5kaXNwYXRjaEV2ZW50KGUpO1xufVxuXG5mdW5jdGlvbiByZW1vdmVUcmFja0Zyb21TdHJlYW1BbmRGaXJlRXZlbnQodHJhY2ssIHN0cmVhbSkge1xuICBzdHJlYW0ucmVtb3ZlVHJhY2sodHJhY2spO1xuICB2YXIgZSA9IG5ldyBFdmVudCgncmVtb3ZldHJhY2snKTsgLy8gVE9ETzogTWVkaWFTdHJlYW1UcmFja0V2ZW50XG4gIGUudHJhY2sgPSB0cmFjaztcbiAgc3RyZWFtLmRpc3BhdGNoRXZlbnQoZSk7XG59XG5cbmZ1bmN0aW9uIGZpcmVBZGRUcmFjayhwYywgdHJhY2ssIHJlY2VpdmVyLCBzdHJlYW1zKSB7XG4gIHZhciB0cmFja0V2ZW50ID0gbmV3IEV2ZW50KCd0cmFjaycpO1xuICB0cmFja0V2ZW50LnRyYWNrID0gdHJhY2s7XG4gIHRyYWNrRXZlbnQucmVjZWl2ZXIgPSByZWNlaXZlcjtcbiAgdHJhY2tFdmVudC50cmFuc2NlaXZlciA9IHtyZWNlaXZlcjogcmVjZWl2ZXJ9O1xuICB0cmFja0V2ZW50LnN0cmVhbXMgPSBzdHJlYW1zO1xuICB3aW5kb3cuc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICBwYy5kaXNwYXRjaEV2ZW50KHRyYWNrRXZlbnQpO1xuICAgIGlmICh0eXBlb2YgcGMub250cmFjayA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgcGMub250cmFjayh0cmFja0V2ZW50KTtcbiAgICB9XG4gIH0pO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKHdpbmRvdywgZWRnZVZlcnNpb24pIHtcbiAgdmFyIFJUQ1BlZXJDb25uZWN0aW9uID0gZnVuY3Rpb24oY29uZmlnKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgdmFyIF9ldmVudFRhcmdldCA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtcbiAgICBbJ2FkZEV2ZW50TGlzdGVuZXInLCAncmVtb3ZlRXZlbnRMaXN0ZW5lcicsICdkaXNwYXRjaEV2ZW50J11cbiAgICAgICAgLmZvckVhY2goZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICAgICAgc2VsZlttZXRob2RdID0gX2V2ZW50VGFyZ2V0W21ldGhvZF0uYmluZChfZXZlbnRUYXJnZXQpO1xuICAgICAgICB9KTtcblxuICAgIHRoaXMub25pY2VjYW5kaWRhdGUgPSBudWxsO1xuICAgIHRoaXMub25hZGRzdHJlYW0gPSBudWxsO1xuICAgIHRoaXMub250cmFjayA9IG51bGw7XG4gICAgdGhpcy5vbnJlbW92ZXN0cmVhbSA9IG51bGw7XG4gICAgdGhpcy5vbnNpZ25hbGluZ3N0YXRlY2hhbmdlID0gbnVsbDtcbiAgICB0aGlzLm9uaWNlY29ubmVjdGlvbnN0YXRlY2hhbmdlID0gbnVsbDtcbiAgICB0aGlzLm9uaWNlZ2F0aGVyaW5nc3RhdGVjaGFuZ2UgPSBudWxsO1xuICAgIHRoaXMub25uZWdvdGlhdGlvbm5lZWRlZCA9IG51bGw7XG4gICAgdGhpcy5vbmRhdGFjaGFubmVsID0gbnVsbDtcbiAgICB0aGlzLmNhblRyaWNrbGVJY2VDYW5kaWRhdGVzID0gbnVsbDtcblxuICAgIHRoaXMubmVlZE5lZ290aWF0aW9uID0gZmFsc2U7XG5cbiAgICB0aGlzLmxvY2FsU3RyZWFtcyA9IFtdO1xuICAgIHRoaXMucmVtb3RlU3RyZWFtcyA9IFtdO1xuXG4gICAgdGhpcy5sb2NhbERlc2NyaXB0aW9uID0gbnVsbDtcbiAgICB0aGlzLnJlbW90ZURlc2NyaXB0aW9uID0gbnVsbDtcblxuICAgIHRoaXMuc2lnbmFsaW5nU3RhdGUgPSAnc3RhYmxlJztcbiAgICB0aGlzLmljZUNvbm5lY3Rpb25TdGF0ZSA9ICduZXcnO1xuICAgIHRoaXMuaWNlR2F0aGVyaW5nU3RhdGUgPSAnbmV3JztcblxuICAgIGNvbmZpZyA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoY29uZmlnIHx8IHt9KSk7XG5cbiAgICB0aGlzLnVzaW5nQnVuZGxlID0gY29uZmlnLmJ1bmRsZVBvbGljeSA9PT0gJ21heC1idW5kbGUnO1xuICAgIGlmIChjb25maWcucnRjcE11eFBvbGljeSA9PT0gJ25lZ290aWF0ZScpIHtcbiAgICAgIHZhciBlID0gbmV3IEVycm9yKCdydGNwTXV4UG9saWN5IFxcJ25lZ290aWF0ZVxcJyBpcyBub3Qgc3VwcG9ydGVkJyk7XG4gICAgICBlLm5hbWUgPSAnTm90U3VwcG9ydGVkRXJyb3InO1xuICAgICAgdGhyb3coZSk7XG4gICAgfSBlbHNlIGlmICghY29uZmlnLnJ0Y3BNdXhQb2xpY3kpIHtcbiAgICAgIGNvbmZpZy5ydGNwTXV4UG9saWN5ID0gJ3JlcXVpcmUnO1xuICAgIH1cblxuICAgIHN3aXRjaCAoY29uZmlnLmljZVRyYW5zcG9ydFBvbGljeSkge1xuICAgICAgY2FzZSAnYWxsJzpcbiAgICAgIGNhc2UgJ3JlbGF5JzpcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICBjb25maWcuaWNlVHJhbnNwb3J0UG9saWN5ID0gJ2FsbCc7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cblxuICAgIHN3aXRjaCAoY29uZmlnLmJ1bmRsZVBvbGljeSkge1xuICAgICAgY2FzZSAnYmFsYW5jZWQnOlxuICAgICAgY2FzZSAnbWF4LWNvbXBhdCc6XG4gICAgICBjYXNlICdtYXgtYnVuZGxlJzpcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICBjb25maWcuYnVuZGxlUG9saWN5ID0gJ2JhbGFuY2VkJztcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgY29uZmlnLmljZVNlcnZlcnMgPSBmaWx0ZXJJY2VTZXJ2ZXJzKGNvbmZpZy5pY2VTZXJ2ZXJzIHx8IFtdLCBlZGdlVmVyc2lvbik7XG5cbiAgICB0aGlzLl9pY2VHYXRoZXJlcnMgPSBbXTtcbiAgICBpZiAoY29uZmlnLmljZUNhbmRpZGF0ZVBvb2xTaXplKSB7XG4gICAgICBmb3IgKHZhciBpID0gY29uZmlnLmljZUNhbmRpZGF0ZVBvb2xTaXplOyBpID4gMDsgaS0tKSB7XG4gICAgICAgIHRoaXMuX2ljZUdhdGhlcmVycyA9IG5ldyB3aW5kb3cuUlRDSWNlR2F0aGVyZXIoe1xuICAgICAgICAgIGljZVNlcnZlcnM6IGNvbmZpZy5pY2VTZXJ2ZXJzLFxuICAgICAgICAgIGdhdGhlclBvbGljeTogY29uZmlnLmljZVRyYW5zcG9ydFBvbGljeVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY29uZmlnLmljZUNhbmRpZGF0ZVBvb2xTaXplID0gMDtcbiAgICB9XG5cbiAgICB0aGlzLl9jb25maWcgPSBjb25maWc7XG5cbiAgICAvLyBwZXItdHJhY2sgaWNlR2F0aGVycywgaWNlVHJhbnNwb3J0cywgZHRsc1RyYW5zcG9ydHMsIHJ0cFNlbmRlcnMsIC4uLlxuICAgIC8vIGV2ZXJ5dGhpbmcgdGhhdCBpcyBuZWVkZWQgdG8gZGVzY3JpYmUgYSBTRFAgbS1saW5lLlxuICAgIHRoaXMudHJhbnNjZWl2ZXJzID0gW107XG5cbiAgICB0aGlzLl9zZHBTZXNzaW9uSWQgPSBTRFBVdGlscy5nZW5lcmF0ZVNlc3Npb25JZCgpO1xuICAgIHRoaXMuX3NkcFNlc3Npb25WZXJzaW9uID0gMDtcblxuICAgIHRoaXMuX2R0bHNSb2xlID0gdW5kZWZpbmVkOyAvLyByb2xlIGZvciBhPXNldHVwIHRvIHVzZSBpbiBhbnN3ZXJzLlxuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5fZW1pdEdhdGhlcmluZ1N0YXRlQ2hhbmdlID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KCdpY2VnYXRoZXJpbmdzdGF0ZWNoYW5nZScpO1xuICAgIHRoaXMuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgaWYgKHR5cGVvZiB0aGlzLm9uaWNlZ2F0aGVyaW5nc3RhdGVjaGFuZ2UgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHRoaXMub25pY2VnYXRoZXJpbmdzdGF0ZWNoYW5nZShldmVudCk7XG4gICAgfVxuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRDb25maWd1cmF0aW9uID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuX2NvbmZpZztcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuZ2V0TG9jYWxTdHJlYW1zID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMubG9jYWxTdHJlYW1zO1xuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRSZW1vdGVTdHJlYW1zID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMucmVtb3RlU3RyZWFtcztcbiAgfTtcblxuICAvLyBpbnRlcm5hbCBoZWxwZXIgdG8gY3JlYXRlIGEgdHJhbnNjZWl2ZXIgb2JqZWN0LlxuICAvLyAod2hpaCBpcyBub3QgeWV0IHRoZSBzYW1lIGFzIHRoZSBXZWJSVEMgMS4wIHRyYW5zY2VpdmVyKVxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX2NyZWF0ZVRyYW5zY2VpdmVyID0gZnVuY3Rpb24oa2luZCkge1xuICAgIHZhciBoYXNCdW5kbGVUcmFuc3BvcnQgPSB0aGlzLnRyYW5zY2VpdmVycy5sZW5ndGggPiAwO1xuICAgIHZhciB0cmFuc2NlaXZlciA9IHtcbiAgICAgIHRyYWNrOiBudWxsLFxuICAgICAgaWNlR2F0aGVyZXI6IG51bGwsXG4gICAgICBpY2VUcmFuc3BvcnQ6IG51bGwsXG4gICAgICBkdGxzVHJhbnNwb3J0OiBudWxsLFxuICAgICAgbG9jYWxDYXBhYmlsaXRpZXM6IG51bGwsXG4gICAgICByZW1vdGVDYXBhYmlsaXRpZXM6IG51bGwsXG4gICAgICBydHBTZW5kZXI6IG51bGwsXG4gICAgICBydHBSZWNlaXZlcjogbnVsbCxcbiAgICAgIGtpbmQ6IGtpbmQsXG4gICAgICBtaWQ6IG51bGwsXG4gICAgICBzZW5kRW5jb2RpbmdQYXJhbWV0ZXJzOiBudWxsLFxuICAgICAgcmVjdkVuY29kaW5nUGFyYW1ldGVyczogbnVsbCxcbiAgICAgIHN0cmVhbTogbnVsbCxcbiAgICAgIGFzc29jaWF0ZWRSZW1vdGVNZWRpYVN0cmVhbXM6IFtdLFxuICAgICAgd2FudFJlY2VpdmU6IHRydWVcbiAgICB9O1xuICAgIGlmICh0aGlzLnVzaW5nQnVuZGxlICYmIGhhc0J1bmRsZVRyYW5zcG9ydCkge1xuICAgICAgdHJhbnNjZWl2ZXIuaWNlVHJhbnNwb3J0ID0gdGhpcy50cmFuc2NlaXZlcnNbMF0uaWNlVHJhbnNwb3J0O1xuICAgICAgdHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydCA9IHRoaXMudHJhbnNjZWl2ZXJzWzBdLmR0bHNUcmFuc3BvcnQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciB0cmFuc3BvcnRzID0gdGhpcy5fY3JlYXRlSWNlQW5kRHRsc1RyYW5zcG9ydHMoKTtcbiAgICAgIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydCA9IHRyYW5zcG9ydHMuaWNlVHJhbnNwb3J0O1xuICAgICAgdHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydCA9IHRyYW5zcG9ydHMuZHRsc1RyYW5zcG9ydDtcbiAgICB9XG4gICAgdGhpcy50cmFuc2NlaXZlcnMucHVzaCh0cmFuc2NlaXZlcik7XG4gICAgcmV0dXJuIHRyYW5zY2VpdmVyO1xuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRUcmFjayA9IGZ1bmN0aW9uKHRyYWNrLCBzdHJlYW0pIHtcbiAgICB2YXIgdHJhbnNjZWl2ZXI7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnRyYW5zY2VpdmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKCF0aGlzLnRyYW5zY2VpdmVyc1tpXS50cmFjayAmJlxuICAgICAgICAgIHRoaXMudHJhbnNjZWl2ZXJzW2ldLmtpbmQgPT09IHRyYWNrLmtpbmQpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIgPSB0aGlzLnRyYW5zY2VpdmVyc1tpXTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKCF0cmFuc2NlaXZlcikge1xuICAgICAgdHJhbnNjZWl2ZXIgPSB0aGlzLl9jcmVhdGVUcmFuc2NlaXZlcih0cmFjay5raW5kKTtcbiAgICB9XG5cbiAgICB0aGlzLl9tYXliZUZpcmVOZWdvdGlhdGlvbk5lZWRlZCgpO1xuXG4gICAgaWYgKHRoaXMubG9jYWxTdHJlYW1zLmluZGV4T2Yoc3RyZWFtKSA9PT0gLTEpIHtcbiAgICAgIHRoaXMubG9jYWxTdHJlYW1zLnB1c2goc3RyZWFtKTtcbiAgICB9XG5cbiAgICB0cmFuc2NlaXZlci50cmFjayA9IHRyYWNrO1xuICAgIHRyYW5zY2VpdmVyLnN0cmVhbSA9IHN0cmVhbTtcbiAgICB0cmFuc2NlaXZlci5ydHBTZW5kZXIgPSBuZXcgd2luZG93LlJUQ1J0cFNlbmRlcih0cmFjayxcbiAgICAgICAgdHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydCk7XG4gICAgcmV0dXJuIHRyYW5zY2VpdmVyLnJ0cFNlbmRlcjtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkU3RyZWFtID0gZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGlmIChlZGdlVmVyc2lvbiA+PSAxNTAyNSkge1xuICAgICAgc3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2spIHtcbiAgICAgICAgc2VsZi5hZGRUcmFjayh0cmFjaywgc3RyZWFtKTtcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBDbG9uZSBpcyBuZWNlc3NhcnkgZm9yIGxvY2FsIGRlbW9zIG1vc3RseSwgYXR0YWNoaW5nIGRpcmVjdGx5XG4gICAgICAvLyB0byB0d28gZGlmZmVyZW50IHNlbmRlcnMgZG9lcyBub3Qgd29yayAoYnVpbGQgMTA1NDcpLlxuICAgICAgLy8gRml4ZWQgaW4gMTUwMjUgKG9yIGVhcmxpZXIpXG4gICAgICB2YXIgY2xvbmVkU3RyZWFtID0gc3RyZWFtLmNsb25lKCk7XG4gICAgICBzdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbih0cmFjaywgaWR4KSB7XG4gICAgICAgIHZhciBjbG9uZWRUcmFjayA9IGNsb25lZFN0cmVhbS5nZXRUcmFja3MoKVtpZHhdO1xuICAgICAgICB0cmFjay5hZGRFdmVudExpc3RlbmVyKCdlbmFibGVkJywgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICAgICAgICBjbG9uZWRUcmFjay5lbmFibGVkID0gZXZlbnQuZW5hYmxlZDtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICAgIGNsb25lZFN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgICAgIHNlbGYuYWRkVHJhY2sodHJhY2ssIGNsb25lZFN0cmVhbSk7XG4gICAgICB9KTtcbiAgICB9XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLnJlbW92ZVRyYWNrID0gZnVuY3Rpb24oc2VuZGVyKSB7XG4gICAgaWYgKCEoc2VuZGVyIGluc3RhbmNlb2Ygd2luZG93LlJUQ1J0cFNlbmRlcikpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50IDEgb2YgUlRDUGVlckNvbm5lY3Rpb24ucmVtb3ZlVHJhY2sgJyArXG4gICAgICAgICAgJ2RvZXMgbm90IGltcGxlbWVudCBpbnRlcmZhY2UgUlRDUnRwU2VuZGVyLicpO1xuICAgIH1cblxuICAgIHZhciB0cmFuc2NlaXZlciA9IHRoaXMudHJhbnNjZWl2ZXJzLmZpbmQoZnVuY3Rpb24odCkge1xuICAgICAgcmV0dXJuIHQucnRwU2VuZGVyID09PSBzZW5kZXI7XG4gICAgfSk7XG5cbiAgICBpZiAoIXRyYW5zY2VpdmVyKSB7XG4gICAgICB2YXIgZXJyID0gbmV3IEVycm9yKCdTZW5kZXIgd2FzIG5vdCBjcmVhdGVkIGJ5IHRoaXMgY29ubmVjdGlvbi4nKTtcbiAgICAgIGVyci5uYW1lID0gJ0ludmFsaWRBY2Nlc3NFcnJvcic7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICAgIHZhciBzdHJlYW0gPSB0cmFuc2NlaXZlci5zdHJlYW07XG5cbiAgICB0cmFuc2NlaXZlci5ydHBTZW5kZXIuc3RvcCgpO1xuICAgIHRyYW5zY2VpdmVyLnJ0cFNlbmRlciA9IG51bGw7XG4gICAgdHJhbnNjZWl2ZXIudHJhY2sgPSBudWxsO1xuICAgIHRyYW5zY2VpdmVyLnN0cmVhbSA9IG51bGw7XG5cbiAgICAvLyByZW1vdmUgdGhlIHN0cmVhbSBmcm9tIHRoZSBzZXQgb2YgbG9jYWwgc3RyZWFtc1xuICAgIHZhciBsb2NhbFN0cmVhbXMgPSB0aGlzLnRyYW5zY2VpdmVycy5tYXAoZnVuY3Rpb24odCkge1xuICAgICAgcmV0dXJuIHQuc3RyZWFtO1xuICAgIH0pO1xuICAgIGlmIChsb2NhbFN0cmVhbXMuaW5kZXhPZihzdHJlYW0pID09PSAtMSAmJlxuICAgICAgICB0aGlzLmxvY2FsU3RyZWFtcy5pbmRleE9mKHN0cmVhbSkgPiAtMSkge1xuICAgICAgdGhpcy5sb2NhbFN0cmVhbXMuc3BsaWNlKHRoaXMubG9jYWxTdHJlYW1zLmluZGV4T2Yoc3RyZWFtKSwgMSk7XG4gICAgfVxuXG4gICAgdGhpcy5fbWF5YmVGaXJlTmVnb3RpYXRpb25OZWVkZWQoKTtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUucmVtb3ZlU3RyZWFtID0gZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgICB2YXIgc2VuZGVyID0gc2VsZi5nZXRTZW5kZXJzKCkuZmluZChmdW5jdGlvbihzKSB7XG4gICAgICAgIHJldHVybiBzLnRyYWNrID09PSB0cmFjaztcbiAgICAgIH0pO1xuICAgICAgaWYgKHNlbmRlcikge1xuICAgICAgICBzZWxmLnJlbW92ZVRyYWNrKHNlbmRlcik7XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFNlbmRlcnMgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy50cmFuc2NlaXZlcnMuZmlsdGVyKGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICByZXR1cm4gISF0cmFuc2NlaXZlci5ydHBTZW5kZXI7XG4gICAgfSlcbiAgICAubWFwKGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICByZXR1cm4gdHJhbnNjZWl2ZXIucnRwU2VuZGVyO1xuICAgIH0pO1xuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRSZWNlaXZlcnMgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy50cmFuc2NlaXZlcnMuZmlsdGVyKGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICByZXR1cm4gISF0cmFuc2NlaXZlci5ydHBSZWNlaXZlcjtcbiAgICB9KVxuICAgIC5tYXAoZnVuY3Rpb24odHJhbnNjZWl2ZXIpIHtcbiAgICAgIHJldHVybiB0cmFuc2NlaXZlci5ydHBSZWNlaXZlcjtcbiAgICB9KTtcbiAgfTtcblxuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5fY3JlYXRlSWNlR2F0aGVyZXIgPSBmdW5jdGlvbihzZHBNTGluZUluZGV4LFxuICAgICAgdXNpbmdCdW5kbGUpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgaWYgKHVzaW5nQnVuZGxlICYmIHNkcE1MaW5lSW5kZXggPiAwKSB7XG4gICAgICByZXR1cm4gdGhpcy50cmFuc2NlaXZlcnNbMF0uaWNlR2F0aGVyZXI7XG4gICAgfSBlbHNlIGlmICh0aGlzLl9pY2VHYXRoZXJlcnMubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gdGhpcy5faWNlR2F0aGVyZXJzLnNoaWZ0KCk7XG4gICAgfVxuICAgIHZhciBpY2VHYXRoZXJlciA9IG5ldyB3aW5kb3cuUlRDSWNlR2F0aGVyZXIoe1xuICAgICAgaWNlU2VydmVyczogdGhpcy5fY29uZmlnLmljZVNlcnZlcnMsXG4gICAgICBnYXRoZXJQb2xpY3k6IHRoaXMuX2NvbmZpZy5pY2VUcmFuc3BvcnRQb2xpY3lcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoaWNlR2F0aGVyZXIsICdzdGF0ZScsXG4gICAgICAgIHt2YWx1ZTogJ25ldycsIHdyaXRhYmxlOiB0cnVlfVxuICAgICk7XG5cbiAgICB0aGlzLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5jYW5kaWRhdGVzID0gW107XG4gICAgdGhpcy50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0uYnVmZmVyQ2FuZGlkYXRlcyA9IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICB2YXIgZW5kID0gIWV2ZW50LmNhbmRpZGF0ZSB8fCBPYmplY3Qua2V5cyhldmVudC5jYW5kaWRhdGUpLmxlbmd0aCA9PT0gMDtcbiAgICAgIC8vIHBvbHlmaWxsIHNpbmNlIFJUQ0ljZUdhdGhlcmVyLnN0YXRlIGlzIG5vdCBpbXBsZW1lbnRlZCBpblxuICAgICAgLy8gRWRnZSAxMDU0NyB5ZXQuXG4gICAgICBpY2VHYXRoZXJlci5zdGF0ZSA9IGVuZCA/ICdjb21wbGV0ZWQnIDogJ2dhdGhlcmluZyc7XG4gICAgICBpZiAoc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0uY2FuZGlkYXRlcyAhPT0gbnVsbCkge1xuICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5jYW5kaWRhdGVzLnB1c2goZXZlbnQuY2FuZGlkYXRlKTtcbiAgICAgIH1cbiAgICB9O1xuICAgIGljZUdhdGhlcmVyLmFkZEV2ZW50TGlzdGVuZXIoJ2xvY2FsY2FuZGlkYXRlJyxcbiAgICAgIHRoaXMudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmJ1ZmZlckNhbmRpZGF0ZXMpO1xuICAgIHJldHVybiBpY2VHYXRoZXJlcjtcbiAgfTtcblxuICAvLyBzdGFydCBnYXRoZXJpbmcgZnJvbSBhbiBSVENJY2VHYXRoZXJlci5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl9nYXRoZXIgPSBmdW5jdGlvbihtaWQsIHNkcE1MaW5lSW5kZXgpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGljZUdhdGhlcmVyID0gdGhpcy50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0uaWNlR2F0aGVyZXI7XG4gICAgaWYgKGljZUdhdGhlcmVyLm9ubG9jYWxjYW5kaWRhdGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIGNhbmRpZGF0ZXMgPSB0aGlzLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5jYW5kaWRhdGVzO1xuICAgIHRoaXMudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmNhbmRpZGF0ZXMgPSBudWxsO1xuICAgIGljZUdhdGhlcmVyLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2xvY2FsY2FuZGlkYXRlJyxcbiAgICAgIHRoaXMudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmJ1ZmZlckNhbmRpZGF0ZXMpO1xuICAgIGljZUdhdGhlcmVyLm9ubG9jYWxjYW5kaWRhdGUgPSBmdW5jdGlvbihldnQpIHtcbiAgICAgIGlmIChzZWxmLnVzaW5nQnVuZGxlICYmIHNkcE1MaW5lSW5kZXggPiAwKSB7XG4gICAgICAgIC8vIGlmIHdlIGtub3cgdGhhdCB3ZSB1c2UgYnVuZGxlIHdlIGNhbiBkcm9wIGNhbmRpZGF0ZXMgd2l0aFxuICAgICAgICAvLyDRlWRwTUxpbmVJbmRleCA+IDAuIElmIHdlIGRvbid0IGRvIHRoaXMgdGhlbiBvdXIgc3RhdGUgZ2V0c1xuICAgICAgICAvLyBjb25mdXNlZCBzaW5jZSB3ZSBkaXNwb3NlIHRoZSBleHRyYSBpY2UgZ2F0aGVyZXIuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHZhciBldmVudCA9IG5ldyBFdmVudCgnaWNlY2FuZGlkYXRlJyk7XG4gICAgICBldmVudC5jYW5kaWRhdGUgPSB7c2RwTWlkOiBtaWQsIHNkcE1MaW5lSW5kZXg6IHNkcE1MaW5lSW5kZXh9O1xuXG4gICAgICB2YXIgY2FuZCA9IGV2dC5jYW5kaWRhdGU7XG4gICAgICAvLyBFZGdlIGVtaXRzIGFuIGVtcHR5IG9iamVjdCBmb3IgUlRDSWNlQ2FuZGlkYXRlQ29tcGxldGXigKVcbiAgICAgIHZhciBlbmQgPSAhY2FuZCB8fCBPYmplY3Qua2V5cyhjYW5kKS5sZW5ndGggPT09IDA7XG4gICAgICBpZiAoZW5kKSB7XG4gICAgICAgIC8vIHBvbHlmaWxsIHNpbmNlIFJUQ0ljZUdhdGhlcmVyLnN0YXRlIGlzIG5vdCBpbXBsZW1lbnRlZCBpblxuICAgICAgICAvLyBFZGdlIDEwNTQ3IHlldC5cbiAgICAgICAgaWYgKGljZUdhdGhlcmVyLnN0YXRlID09PSAnbmV3JyB8fCBpY2VHYXRoZXJlci5zdGF0ZSA9PT0gJ2dhdGhlcmluZycpIHtcbiAgICAgICAgICBpY2VHYXRoZXJlci5zdGF0ZSA9ICdjb21wbGV0ZWQnO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoaWNlR2F0aGVyZXIuc3RhdGUgPT09ICduZXcnKSB7XG4gICAgICAgICAgaWNlR2F0aGVyZXIuc3RhdGUgPSAnZ2F0aGVyaW5nJztcbiAgICAgICAgfVxuICAgICAgICAvLyBSVENJY2VDYW5kaWRhdGUgZG9lc24ndCBoYXZlIGEgY29tcG9uZW50LCBuZWVkcyB0byBiZSBhZGRlZFxuICAgICAgICBjYW5kLmNvbXBvbmVudCA9IDE7XG4gICAgICAgIGV2ZW50LmNhbmRpZGF0ZS5jYW5kaWRhdGUgPSBTRFBVdGlscy53cml0ZUNhbmRpZGF0ZShjYW5kKTtcbiAgICAgIH1cblxuICAgICAgLy8gdXBkYXRlIGxvY2FsIGRlc2NyaXB0aW9uLlxuICAgICAgdmFyIHNlY3Rpb25zID0gU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyhzZWxmLmxvY2FsRGVzY3JpcHRpb24uc2RwKTtcbiAgICAgIGlmICghZW5kKSB7XG4gICAgICAgIHNlY3Rpb25zW2V2ZW50LmNhbmRpZGF0ZS5zZHBNTGluZUluZGV4ICsgMV0gKz1cbiAgICAgICAgICAgICdhPScgKyBldmVudC5jYW5kaWRhdGUuY2FuZGlkYXRlICsgJ1xcclxcbic7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzZWN0aW9uc1tldmVudC5jYW5kaWRhdGUuc2RwTUxpbmVJbmRleCArIDFdICs9XG4gICAgICAgICAgICAnYT1lbmQtb2YtY2FuZGlkYXRlc1xcclxcbic7XG4gICAgICB9XG4gICAgICBzZWxmLmxvY2FsRGVzY3JpcHRpb24uc2RwID0gc2VjdGlvbnMuam9pbignJyk7XG4gICAgICB2YXIgY29tcGxldGUgPSBzZWxmLnRyYW5zY2VpdmVycy5ldmVyeShmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgICByZXR1cm4gdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXIgJiZcbiAgICAgICAgICAgIHRyYW5zY2VpdmVyLmljZUdhdGhlcmVyLnN0YXRlID09PSAnY29tcGxldGVkJztcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoc2VsZi5pY2VHYXRoZXJpbmdTdGF0ZSAhPT0gJ2dhdGhlcmluZycpIHtcbiAgICAgICAgc2VsZi5pY2VHYXRoZXJpbmdTdGF0ZSA9ICdnYXRoZXJpbmcnO1xuICAgICAgICBzZWxmLl9lbWl0R2F0aGVyaW5nU3RhdGVDaGFuZ2UoKTtcbiAgICAgIH1cblxuICAgICAgLy8gRW1pdCBjYW5kaWRhdGUuIEFsc28gZW1pdCBudWxsIGNhbmRpZGF0ZSB3aGVuIGFsbCBnYXRoZXJlcnMgYXJlXG4gICAgICAvLyBjb21wbGV0ZS5cbiAgICAgIGlmICghZW5kKSB7XG4gICAgICAgIHNlbGYuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgICAgIGlmICh0eXBlb2Ygc2VsZi5vbmljZWNhbmRpZGF0ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgIHNlbGYub25pY2VjYW5kaWRhdGUoZXZlbnQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoY29tcGxldGUpIHtcbiAgICAgICAgc2VsZi5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgnaWNlY2FuZGlkYXRlJykpO1xuICAgICAgICBpZiAodHlwZW9mIHNlbGYub25pY2VjYW5kaWRhdGUgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICBzZWxmLm9uaWNlY2FuZGlkYXRlKG5ldyBFdmVudCgnaWNlY2FuZGlkYXRlJykpO1xuICAgICAgICB9XG4gICAgICAgIHNlbGYuaWNlR2F0aGVyaW5nU3RhdGUgPSAnY29tcGxldGUnO1xuICAgICAgICBzZWxmLl9lbWl0R2F0aGVyaW5nU3RhdGVDaGFuZ2UoKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgLy8gZW1pdCBhbHJlYWR5IGdhdGhlcmVkIGNhbmRpZGF0ZXMuXG4gICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICBjYW5kaWRhdGVzLmZvckVhY2goZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gICAgICAgIHZhciBlID0gbmV3IEV2ZW50KCdSVENJY2VHYXRoZXJFdmVudCcpO1xuICAgICAgICBlLmNhbmRpZGF0ZSA9IGNhbmRpZGF0ZTtcbiAgICAgICAgaWNlR2F0aGVyZXIub25sb2NhbGNhbmRpZGF0ZShlKTtcbiAgICAgIH0pO1xuICAgIH0sIDApO1xuICB9O1xuXG4gIC8vIENyZWF0ZSBJQ0UgdHJhbnNwb3J0IGFuZCBEVExTIHRyYW5zcG9ydC5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl9jcmVhdGVJY2VBbmREdGxzVHJhbnNwb3J0cyA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgaWNlVHJhbnNwb3J0ID0gbmV3IHdpbmRvdy5SVENJY2VUcmFuc3BvcnQobnVsbCk7XG4gICAgaWNlVHJhbnNwb3J0Lm9uaWNlc3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICAgIHNlbGYuX3VwZGF0ZUNvbm5lY3Rpb25TdGF0ZSgpO1xuICAgIH07XG5cbiAgICB2YXIgZHRsc1RyYW5zcG9ydCA9IG5ldyB3aW5kb3cuUlRDRHRsc1RyYW5zcG9ydChpY2VUcmFuc3BvcnQpO1xuICAgIGR0bHNUcmFuc3BvcnQub25kdGxzc3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICAgIHNlbGYuX3VwZGF0ZUNvbm5lY3Rpb25TdGF0ZSgpO1xuICAgIH07XG4gICAgZHRsc1RyYW5zcG9ydC5vbmVycm9yID0gZnVuY3Rpb24oKSB7XG4gICAgICAvLyBvbmVycm9yIGRvZXMgbm90IHNldCBzdGF0ZSB0byBmYWlsZWQgYnkgaXRzZWxmLlxuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGR0bHNUcmFuc3BvcnQsICdzdGF0ZScsXG4gICAgICAgICAge3ZhbHVlOiAnZmFpbGVkJywgd3JpdGFibGU6IHRydWV9KTtcbiAgICAgIHNlbGYuX3VwZGF0ZUNvbm5lY3Rpb25TdGF0ZSgpO1xuICAgIH07XG5cbiAgICByZXR1cm4ge1xuICAgICAgaWNlVHJhbnNwb3J0OiBpY2VUcmFuc3BvcnQsXG4gICAgICBkdGxzVHJhbnNwb3J0OiBkdGxzVHJhbnNwb3J0XG4gICAgfTtcbiAgfTtcblxuICAvLyBEZXN0cm95IElDRSBnYXRoZXJlciwgSUNFIHRyYW5zcG9ydCBhbmQgRFRMUyB0cmFuc3BvcnQuXG4gIC8vIFdpdGhvdXQgdHJpZ2dlcmluZyB0aGUgY2FsbGJhY2tzLlxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX2Rpc3Bvc2VJY2VBbmREdGxzVHJhbnNwb3J0cyA9IGZ1bmN0aW9uKFxuICAgICAgc2RwTUxpbmVJbmRleCkge1xuICAgIHZhciBpY2VHYXRoZXJlciA9IHRoaXMudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmljZUdhdGhlcmVyO1xuICAgIGlmIChpY2VHYXRoZXJlcikge1xuICAgICAgZGVsZXRlIGljZUdhdGhlcmVyLm9ubG9jYWxjYW5kaWRhdGU7XG4gICAgICBkZWxldGUgdGhpcy50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0uaWNlR2F0aGVyZXI7XG4gICAgfVxuICAgIHZhciBpY2VUcmFuc3BvcnQgPSB0aGlzLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5pY2VUcmFuc3BvcnQ7XG4gICAgaWYgKGljZVRyYW5zcG9ydCkge1xuICAgICAgZGVsZXRlIGljZVRyYW5zcG9ydC5vbmljZXN0YXRlY2hhbmdlO1xuICAgICAgZGVsZXRlIHRoaXMudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmljZVRyYW5zcG9ydDtcbiAgICB9XG4gICAgdmFyIGR0bHNUcmFuc3BvcnQgPSB0aGlzLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5kdGxzVHJhbnNwb3J0O1xuICAgIGlmIChkdGxzVHJhbnNwb3J0KSB7XG4gICAgICBkZWxldGUgZHRsc1RyYW5zcG9ydC5vbmR0bHNzdGF0ZWNoYW5nZTtcbiAgICAgIGRlbGV0ZSBkdGxzVHJhbnNwb3J0Lm9uZXJyb3I7XG4gICAgICBkZWxldGUgdGhpcy50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0uZHRsc1RyYW5zcG9ydDtcbiAgICB9XG4gIH07XG5cbiAgLy8gU3RhcnQgdGhlIFJUUCBTZW5kZXIgYW5kIFJlY2VpdmVyIGZvciBhIHRyYW5zY2VpdmVyLlxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX3RyYW5zY2VpdmUgPSBmdW5jdGlvbih0cmFuc2NlaXZlcixcbiAgICAgIHNlbmQsIHJlY3YpIHtcbiAgICB2YXIgcGFyYW1zID0gZ2V0Q29tbW9uQ2FwYWJpbGl0aWVzKHRyYW5zY2VpdmVyLmxvY2FsQ2FwYWJpbGl0aWVzLFxuICAgICAgICB0cmFuc2NlaXZlci5yZW1vdGVDYXBhYmlsaXRpZXMpO1xuICAgIGlmIChzZW5kICYmIHRyYW5zY2VpdmVyLnJ0cFNlbmRlcikge1xuICAgICAgcGFyYW1zLmVuY29kaW5ncyA9IHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnM7XG4gICAgICBwYXJhbXMucnRjcCA9IHtcbiAgICAgICAgY25hbWU6IFNEUFV0aWxzLmxvY2FsQ05hbWUsXG4gICAgICAgIGNvbXBvdW5kOiB0cmFuc2NlaXZlci5ydGNwUGFyYW1ldGVycy5jb21wb3VuZFxuICAgICAgfTtcbiAgICAgIGlmICh0cmFuc2NlaXZlci5yZWN2RW5jb2RpbmdQYXJhbWV0ZXJzLmxlbmd0aCkge1xuICAgICAgICBwYXJhbXMucnRjcC5zc3JjID0gdHJhbnNjZWl2ZXIucmVjdkVuY29kaW5nUGFyYW1ldGVyc1swXS5zc3JjO1xuICAgICAgfVxuICAgICAgdHJhbnNjZWl2ZXIucnRwU2VuZGVyLnNlbmQocGFyYW1zKTtcbiAgICB9XG4gICAgaWYgKHJlY3YgJiYgdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXIgJiYgcGFyYW1zLmNvZGVjcy5sZW5ndGggPiAwKSB7XG4gICAgICAvLyByZW1vdmUgUlRYIGZpZWxkIGluIEVkZ2UgMTQ5NDJcbiAgICAgIGlmICh0cmFuc2NlaXZlci5raW5kID09PSAndmlkZW8nXG4gICAgICAgICAgJiYgdHJhbnNjZWl2ZXIucmVjdkVuY29kaW5nUGFyYW1ldGVyc1xuICAgICAgICAgICYmIGVkZ2VWZXJzaW9uIDwgMTUwMTkpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIucmVjdkVuY29kaW5nUGFyYW1ldGVycy5mb3JFYWNoKGZ1bmN0aW9uKHApIHtcbiAgICAgICAgICBkZWxldGUgcC5ydHg7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgaWYgKHRyYW5zY2VpdmVyLnJlY3ZFbmNvZGluZ1BhcmFtZXRlcnMubGVuZ3RoKSB7XG4gICAgICAgIHBhcmFtcy5lbmNvZGluZ3MgPSB0cmFuc2NlaXZlci5yZWN2RW5jb2RpbmdQYXJhbWV0ZXJzO1xuICAgICAgfVxuICAgICAgcGFyYW1zLnJ0Y3AgPSB7XG4gICAgICAgIGNvbXBvdW5kOiB0cmFuc2NlaXZlci5ydGNwUGFyYW1ldGVycy5jb21wb3VuZFxuICAgICAgfTtcbiAgICAgIGlmICh0cmFuc2NlaXZlci5ydGNwUGFyYW1ldGVycy5jbmFtZSkge1xuICAgICAgICBwYXJhbXMucnRjcC5jbmFtZSA9IHRyYW5zY2VpdmVyLnJ0Y3BQYXJhbWV0ZXJzLmNuYW1lO1xuICAgICAgfVxuICAgICAgaWYgKHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnMubGVuZ3RoKSB7XG4gICAgICAgIHBhcmFtcy5ydGNwLnNzcmMgPSB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnNzcmM7XG4gICAgICB9XG4gICAgICB0cmFuc2NlaXZlci5ydHBSZWNlaXZlci5yZWNlaXZlKHBhcmFtcyk7XG4gICAgfVxuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5zZXRMb2NhbERlc2NyaXB0aW9uID0gZnVuY3Rpb24oZGVzY3JpcHRpb24pIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG5cbiAgICBpZiAoIWlzQWN0aW9uQWxsb3dlZEluU2lnbmFsaW5nU3RhdGUoJ3NldExvY2FsRGVzY3JpcHRpb24nLFxuICAgICAgICBkZXNjcmlwdGlvbi50eXBlLCB0aGlzLnNpZ25hbGluZ1N0YXRlKSkge1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgICB2YXIgZSA9IG5ldyBFcnJvcignQ2FuIG5vdCBzZXQgbG9jYWwgJyArIGRlc2NyaXB0aW9uLnR5cGUgK1xuICAgICAgICAgICAgJyBpbiBzdGF0ZSAnICsgc2VsZi5zaWduYWxpbmdTdGF0ZSk7XG4gICAgICAgIGUubmFtZSA9ICdJbnZhbGlkU3RhdGVFcnJvcic7XG4gICAgICAgIGlmIChhcmdzLmxlbmd0aCA+IDIgJiYgdHlwZW9mIGFyZ3NbMl0gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICBhcmdzWzJdLmFwcGx5KG51bGwsIFtlXSk7XG4gICAgICAgIH1cbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdmFyIHNlY3Rpb25zO1xuICAgIHZhciBzZXNzaW9ucGFydDtcbiAgICBpZiAoZGVzY3JpcHRpb24udHlwZSA9PT0gJ29mZmVyJykge1xuICAgICAgLy8gVkVSWSBsaW1pdGVkIHN1cHBvcnQgZm9yIFNEUCBtdW5naW5nLiBMaW1pdGVkIHRvOlxuICAgICAgLy8gKiBjaGFuZ2luZyB0aGUgb3JkZXIgb2YgY29kZWNzXG4gICAgICBzZWN0aW9ucyA9IFNEUFV0aWxzLnNwbGl0U2VjdGlvbnMoZGVzY3JpcHRpb24uc2RwKTtcbiAgICAgIHNlc3Npb25wYXJ0ID0gc2VjdGlvbnMuc2hpZnQoKTtcbiAgICAgIHNlY3Rpb25zLmZvckVhY2goZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZHBNTGluZUluZGV4KSB7XG4gICAgICAgIHZhciBjYXBzID0gU0RQVXRpbHMucGFyc2VSdHBQYXJhbWV0ZXJzKG1lZGlhU2VjdGlvbik7XG4gICAgICAgIHNlbGYudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmxvY2FsQ2FwYWJpbGl0aWVzID0gY2FwcztcbiAgICAgIH0pO1xuXG4gICAgICB0aGlzLnRyYW5zY2VpdmVycy5mb3JFYWNoKGZ1bmN0aW9uKHRyYW5zY2VpdmVyLCBzZHBNTGluZUluZGV4KSB7XG4gICAgICAgIHNlbGYuX2dhdGhlcih0cmFuc2NlaXZlci5taWQsIHNkcE1MaW5lSW5kZXgpO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIGlmIChkZXNjcmlwdGlvbi50eXBlID09PSAnYW5zd2VyJykge1xuICAgICAgc2VjdGlvbnMgPSBTRFBVdGlscy5zcGxpdFNlY3Rpb25zKHNlbGYucmVtb3RlRGVzY3JpcHRpb24uc2RwKTtcbiAgICAgIHNlc3Npb25wYXJ0ID0gc2VjdGlvbnMuc2hpZnQoKTtcbiAgICAgIHZhciBpc0ljZUxpdGUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChzZXNzaW9ucGFydCxcbiAgICAgICAgICAnYT1pY2UtbGl0ZScpLmxlbmd0aCA+IDA7XG4gICAgICBzZWN0aW9ucy5mb3JFYWNoKGZ1bmN0aW9uKG1lZGlhU2VjdGlvbiwgc2RwTUxpbmVJbmRleCkge1xuICAgICAgICB2YXIgdHJhbnNjZWl2ZXIgPSBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XTtcbiAgICAgICAgdmFyIGljZUdhdGhlcmVyID0gdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXI7XG4gICAgICAgIHZhciBpY2VUcmFuc3BvcnQgPSB0cmFuc2NlaXZlci5pY2VUcmFuc3BvcnQ7XG4gICAgICAgIHZhciBkdGxzVHJhbnNwb3J0ID0gdHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydDtcbiAgICAgICAgdmFyIGxvY2FsQ2FwYWJpbGl0aWVzID0gdHJhbnNjZWl2ZXIubG9jYWxDYXBhYmlsaXRpZXM7XG4gICAgICAgIHZhciByZW1vdGVDYXBhYmlsaXRpZXMgPSB0cmFuc2NlaXZlci5yZW1vdGVDYXBhYmlsaXRpZXM7XG5cbiAgICAgICAgLy8gdHJlYXQgYnVuZGxlLW9ubHkgYXMgbm90LXJlamVjdGVkLlxuICAgICAgICB2YXIgcmVqZWN0ZWQgPSBTRFBVdGlscy5pc1JlamVjdGVkKG1lZGlhU2VjdGlvbikgJiZcbiAgICAgICAgICAgICFTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPWJ1bmRsZS1vbmx5JykubGVuZ3RoID09PSAxO1xuXG4gICAgICAgIGlmICghcmVqZWN0ZWQgJiYgIXRyYW5zY2VpdmVyLmlzRGF0YWNoYW5uZWwpIHtcbiAgICAgICAgICB2YXIgcmVtb3RlSWNlUGFyYW1ldGVycyA9IFNEUFV0aWxzLmdldEljZVBhcmFtZXRlcnMoXG4gICAgICAgICAgICAgIG1lZGlhU2VjdGlvbiwgc2Vzc2lvbnBhcnQpO1xuICAgICAgICAgIHZhciByZW1vdGVEdGxzUGFyYW1ldGVycyA9IFNEUFV0aWxzLmdldER0bHNQYXJhbWV0ZXJzKFxuICAgICAgICAgICAgICBtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KTtcbiAgICAgICAgICBpZiAoaXNJY2VMaXRlKSB7XG4gICAgICAgICAgICByZW1vdGVEdGxzUGFyYW1ldGVycy5yb2xlID0gJ3NlcnZlcic7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFzZWxmLnVzaW5nQnVuZGxlIHx8IHNkcE1MaW5lSW5kZXggPT09IDApIHtcbiAgICAgICAgICAgIHNlbGYuX2dhdGhlcih0cmFuc2NlaXZlci5taWQsIHNkcE1MaW5lSW5kZXgpO1xuICAgICAgICAgICAgaWYgKGljZVRyYW5zcG9ydC5zdGF0ZSA9PT0gJ25ldycpIHtcbiAgICAgICAgICAgICAgaWNlVHJhbnNwb3J0LnN0YXJ0KGljZUdhdGhlcmVyLCByZW1vdGVJY2VQYXJhbWV0ZXJzLFxuICAgICAgICAgICAgICAgICAgaXNJY2VMaXRlID8gJ2NvbnRyb2xsaW5nJyA6ICdjb250cm9sbGVkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZHRsc1RyYW5zcG9ydC5zdGF0ZSA9PT0gJ25ldycpIHtcbiAgICAgICAgICAgICAgZHRsc1RyYW5zcG9ydC5zdGFydChyZW1vdGVEdGxzUGFyYW1ldGVycyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQ2FsY3VsYXRlIGludGVyc2VjdGlvbiBvZiBjYXBhYmlsaXRpZXMuXG4gICAgICAgICAgdmFyIHBhcmFtcyA9IGdldENvbW1vbkNhcGFiaWxpdGllcyhsb2NhbENhcGFiaWxpdGllcyxcbiAgICAgICAgICAgICAgcmVtb3RlQ2FwYWJpbGl0aWVzKTtcblxuICAgICAgICAgIC8vIFN0YXJ0IHRoZSBSVENSdHBTZW5kZXIuIFRoZSBSVENSdHBSZWNlaXZlciBmb3IgdGhpc1xuICAgICAgICAgIC8vIHRyYW5zY2VpdmVyIGhhcyBhbHJlYWR5IGJlZW4gc3RhcnRlZCBpbiBzZXRSZW1vdGVEZXNjcmlwdGlvbi5cbiAgICAgICAgICBzZWxmLl90cmFuc2NlaXZlKHRyYW5zY2VpdmVyLFxuICAgICAgICAgICAgICBwYXJhbXMuY29kZWNzLmxlbmd0aCA+IDAsXG4gICAgICAgICAgICAgIGZhbHNlKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdGhpcy5sb2NhbERlc2NyaXB0aW9uID0ge1xuICAgICAgdHlwZTogZGVzY3JpcHRpb24udHlwZSxcbiAgICAgIHNkcDogZGVzY3JpcHRpb24uc2RwXG4gICAgfTtcbiAgICBzd2l0Y2ggKGRlc2NyaXB0aW9uLnR5cGUpIHtcbiAgICAgIGNhc2UgJ29mZmVyJzpcbiAgICAgICAgdGhpcy5fdXBkYXRlU2lnbmFsaW5nU3RhdGUoJ2hhdmUtbG9jYWwtb2ZmZXInKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdhbnN3ZXInOlxuICAgICAgICB0aGlzLl91cGRhdGVTaWduYWxpbmdTdGF0ZSgnc3RhYmxlJyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigndW5zdXBwb3J0ZWQgdHlwZSBcIicgKyBkZXNjcmlwdGlvbi50eXBlICtcbiAgICAgICAgICAgICdcIicpO1xuICAgIH1cblxuICAgIC8vIElmIGEgc3VjY2VzcyBjYWxsYmFjayB3YXMgcHJvdmlkZWQsIGVtaXQgSUNFIGNhbmRpZGF0ZXMgYWZ0ZXIgaXRcbiAgICAvLyBoYXMgYmVlbiBleGVjdXRlZC4gT3RoZXJ3aXNlLCBlbWl0IGNhbGxiYWNrIGFmdGVyIHRoZSBQcm9taXNlIGlzXG4gICAgLy8gcmVzb2x2ZWQuXG4gICAgdmFyIGNiID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgdHlwZW9mIGFyZ3VtZW50c1sxXSA9PT0gJ2Z1bmN0aW9uJyAmJlxuICAgICAgICBhcmd1bWVudHNbMV07XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUpIHtcbiAgICAgIGlmIChjYikge1xuICAgICAgICBjYi5hcHBseShudWxsKTtcbiAgICAgIH1cbiAgICAgIHJlc29sdmUoKTtcbiAgICB9KTtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuc2V0UmVtb3RlRGVzY3JpcHRpb24gPSBmdW5jdGlvbihkZXNjcmlwdGlvbikge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgYXJncyA9IGFyZ3VtZW50cztcblxuICAgIGlmICghaXNBY3Rpb25BbGxvd2VkSW5TaWduYWxpbmdTdGF0ZSgnc2V0UmVtb3RlRGVzY3JpcHRpb24nLFxuICAgICAgICBkZXNjcmlwdGlvbi50eXBlLCB0aGlzLnNpZ25hbGluZ1N0YXRlKSkge1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgICB2YXIgZSA9IG5ldyBFcnJvcignQ2FuIG5vdCBzZXQgcmVtb3RlICcgKyBkZXNjcmlwdGlvbi50eXBlICtcbiAgICAgICAgICAgICcgaW4gc3RhdGUgJyArIHNlbGYuc2lnbmFsaW5nU3RhdGUpO1xuICAgICAgICBlLm5hbWUgPSAnSW52YWxpZFN0YXRlRXJyb3InO1xuICAgICAgICBpZiAoYXJncy5sZW5ndGggPiAyICYmIHR5cGVvZiBhcmdzWzJdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgYXJnc1syXS5hcHBseShudWxsLCBbZV0pO1xuICAgICAgICB9XG4gICAgICAgIHJlamVjdChlKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHZhciBzdHJlYW1zID0ge307XG4gICAgdGhpcy5yZW1vdGVTdHJlYW1zLmZvckVhY2goZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICBzdHJlYW1zW3N0cmVhbS5pZF0gPSBzdHJlYW07XG4gICAgfSk7XG4gICAgdmFyIHJlY2VpdmVyTGlzdCA9IFtdO1xuICAgIHZhciBzZWN0aW9ucyA9IFNEUFV0aWxzLnNwbGl0U2VjdGlvbnMoZGVzY3JpcHRpb24uc2RwKTtcbiAgICB2YXIgc2Vzc2lvbnBhcnQgPSBzZWN0aW9ucy5zaGlmdCgpO1xuICAgIHZhciBpc0ljZUxpdGUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChzZXNzaW9ucGFydCxcbiAgICAgICAgJ2E9aWNlLWxpdGUnKS5sZW5ndGggPiAwO1xuICAgIHZhciB1c2luZ0J1bmRsZSA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KHNlc3Npb25wYXJ0LFxuICAgICAgICAnYT1ncm91cDpCVU5ETEUgJykubGVuZ3RoID4gMDtcbiAgICB0aGlzLnVzaW5nQnVuZGxlID0gdXNpbmdCdW5kbGU7XG4gICAgdmFyIGljZU9wdGlvbnMgPSBTRFBVdGlscy5tYXRjaFByZWZpeChzZXNzaW9ucGFydCxcbiAgICAgICAgJ2E9aWNlLW9wdGlvbnM6JylbMF07XG4gICAgaWYgKGljZU9wdGlvbnMpIHtcbiAgICAgIHRoaXMuY2FuVHJpY2tsZUljZUNhbmRpZGF0ZXMgPSBpY2VPcHRpb25zLnN1YnN0cigxNCkuc3BsaXQoJyAnKVxuICAgICAgICAgIC5pbmRleE9mKCd0cmlja2xlJykgPj0gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5jYW5Ucmlja2xlSWNlQ2FuZGlkYXRlcyA9IGZhbHNlO1xuICAgIH1cblxuICAgIHNlY3Rpb25zLmZvckVhY2goZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZHBNTGluZUluZGV4KSB7XG4gICAgICB2YXIgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gICAgICB2YXIga2luZCA9IFNEUFV0aWxzLmdldEtpbmQobWVkaWFTZWN0aW9uKTtcbiAgICAgIC8vIHRyZWF0IGJ1bmRsZS1vbmx5IGFzIG5vdC1yZWplY3RlZC5cbiAgICAgIHZhciByZWplY3RlZCA9IFNEUFV0aWxzLmlzUmVqZWN0ZWQobWVkaWFTZWN0aW9uKSAmJlxuICAgICAgICAgICFTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPWJ1bmRsZS1vbmx5JykubGVuZ3RoID09PSAxO1xuICAgICAgdmFyIHByb3RvY29sID0gbGluZXNbMF0uc3Vic3RyKDIpLnNwbGl0KCcgJylbMl07XG5cbiAgICAgIHZhciBkaXJlY3Rpb24gPSBTRFBVdGlscy5nZXREaXJlY3Rpb24obWVkaWFTZWN0aW9uLCBzZXNzaW9ucGFydCk7XG4gICAgICB2YXIgcmVtb3RlTXNpZCA9IFNEUFV0aWxzLnBhcnNlTXNpZChtZWRpYVNlY3Rpb24pO1xuXG4gICAgICB2YXIgbWlkID0gU0RQVXRpbHMuZ2V0TWlkKG1lZGlhU2VjdGlvbikgfHwgU0RQVXRpbHMuZ2VuZXJhdGVJZGVudGlmaWVyKCk7XG5cbiAgICAgIC8vIFJlamVjdCBkYXRhY2hhbm5lbHMgd2hpY2ggYXJlIG5vdCBpbXBsZW1lbnRlZCB5ZXQuXG4gICAgICBpZiAoa2luZCA9PT0gJ2FwcGxpY2F0aW9uJyAmJiBwcm90b2NvbCA9PT0gJ0RUTFMvU0NUUCcpIHtcbiAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0gPSB7XG4gICAgICAgICAgbWlkOiBtaWQsXG4gICAgICAgICAgaXNEYXRhY2hhbm5lbDogdHJ1ZVxuICAgICAgICB9O1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciB0cmFuc2NlaXZlcjtcbiAgICAgIHZhciBpY2VHYXRoZXJlcjtcbiAgICAgIHZhciBpY2VUcmFuc3BvcnQ7XG4gICAgICB2YXIgZHRsc1RyYW5zcG9ydDtcbiAgICAgIHZhciBydHBSZWNlaXZlcjtcbiAgICAgIHZhciBzZW5kRW5jb2RpbmdQYXJhbWV0ZXJzO1xuICAgICAgdmFyIHJlY3ZFbmNvZGluZ1BhcmFtZXRlcnM7XG4gICAgICB2YXIgbG9jYWxDYXBhYmlsaXRpZXM7XG5cbiAgICAgIHZhciB0cmFjaztcbiAgICAgIC8vIEZJWE1FOiBlbnN1cmUgdGhlIG1lZGlhU2VjdGlvbiBoYXMgcnRjcC1tdXggc2V0LlxuICAgICAgdmFyIHJlbW90ZUNhcGFiaWxpdGllcyA9IFNEUFV0aWxzLnBhcnNlUnRwUGFyYW1ldGVycyhtZWRpYVNlY3Rpb24pO1xuICAgICAgdmFyIHJlbW90ZUljZVBhcmFtZXRlcnM7XG4gICAgICB2YXIgcmVtb3RlRHRsc1BhcmFtZXRlcnM7XG4gICAgICBpZiAoIXJlamVjdGVkKSB7XG4gICAgICAgIHJlbW90ZUljZVBhcmFtZXRlcnMgPSBTRFBVdGlscy5nZXRJY2VQYXJhbWV0ZXJzKG1lZGlhU2VjdGlvbixcbiAgICAgICAgICAgIHNlc3Npb25wYXJ0KTtcbiAgICAgICAgcmVtb3RlRHRsc1BhcmFtZXRlcnMgPSBTRFBVdGlscy5nZXREdGxzUGFyYW1ldGVycyhtZWRpYVNlY3Rpb24sXG4gICAgICAgICAgICBzZXNzaW9ucGFydCk7XG4gICAgICAgIHJlbW90ZUR0bHNQYXJhbWV0ZXJzLnJvbGUgPSAnY2xpZW50JztcbiAgICAgIH1cbiAgICAgIHJlY3ZFbmNvZGluZ1BhcmFtZXRlcnMgPVxuICAgICAgICAgIFNEUFV0aWxzLnBhcnNlUnRwRW5jb2RpbmdQYXJhbWV0ZXJzKG1lZGlhU2VjdGlvbik7XG5cbiAgICAgIHZhciBydGNwUGFyYW1ldGVycyA9IFNEUFV0aWxzLnBhcnNlUnRjcFBhcmFtZXRlcnMobWVkaWFTZWN0aW9uKTtcblxuICAgICAgdmFyIGlzQ29tcGxldGUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sXG4gICAgICAgICAgJ2E9ZW5kLW9mLWNhbmRpZGF0ZXMnLCBzZXNzaW9ucGFydCkubGVuZ3RoID4gMDtcbiAgICAgIHZhciBjYW5kcyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9Y2FuZGlkYXRlOicpXG4gICAgICAgICAgLm1hcChmdW5jdGlvbihjYW5kKSB7XG4gICAgICAgICAgICByZXR1cm4gU0RQVXRpbHMucGFyc2VDYW5kaWRhdGUoY2FuZCk7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuZmlsdGVyKGZ1bmN0aW9uKGNhbmQpIHtcbiAgICAgICAgICAgIHJldHVybiBjYW5kLmNvbXBvbmVudCA9PT0gMTtcbiAgICAgICAgICB9KTtcblxuICAgICAgLy8gQ2hlY2sgaWYgd2UgY2FuIHVzZSBCVU5ETEUgYW5kIGRpc3Bvc2UgdHJhbnNwb3J0cy5cbiAgICAgIGlmICgoZGVzY3JpcHRpb24udHlwZSA9PT0gJ29mZmVyJyB8fCBkZXNjcmlwdGlvbi50eXBlID09PSAnYW5zd2VyJykgJiZcbiAgICAgICAgICAhcmVqZWN0ZWQgJiYgdXNpbmdCdW5kbGUgJiYgc2RwTUxpbmVJbmRleCA+IDAgJiZcbiAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XSkge1xuICAgICAgICBzZWxmLl9kaXNwb3NlSWNlQW5kRHRsc1RyYW5zcG9ydHMoc2RwTUxpbmVJbmRleCk7XG4gICAgICAgIHNlbGYudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmljZUdhdGhlcmVyID1cbiAgICAgICAgICAgIHNlbGYudHJhbnNjZWl2ZXJzWzBdLmljZUdhdGhlcmVyO1xuICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5pY2VUcmFuc3BvcnQgPVxuICAgICAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbMF0uaWNlVHJhbnNwb3J0O1xuICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5kdGxzVHJhbnNwb3J0ID1cbiAgICAgICAgICAgIHNlbGYudHJhbnNjZWl2ZXJzWzBdLmR0bHNUcmFuc3BvcnQ7XG4gICAgICAgIGlmIChzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5ydHBTZW5kZXIpIHtcbiAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5ydHBTZW5kZXIuc2V0VHJhbnNwb3J0KFxuICAgICAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1swXS5kdGxzVHJhbnNwb3J0KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0ucnRwUmVjZWl2ZXIpIHtcbiAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5ydHBSZWNlaXZlci5zZXRUcmFuc3BvcnQoXG4gICAgICAgICAgICAgIHNlbGYudHJhbnNjZWl2ZXJzWzBdLmR0bHNUcmFuc3BvcnQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoZGVzY3JpcHRpb24udHlwZSA9PT0gJ29mZmVyJyAmJiAhcmVqZWN0ZWQpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIgPSBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XSB8fFxuICAgICAgICAgICAgc2VsZi5fY3JlYXRlVHJhbnNjZWl2ZXIoa2luZCk7XG4gICAgICAgIHRyYW5zY2VpdmVyLm1pZCA9IG1pZDtcblxuICAgICAgICBpZiAoIXRyYW5zY2VpdmVyLmljZUdhdGhlcmVyKSB7XG4gICAgICAgICAgdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXIgPSBzZWxmLl9jcmVhdGVJY2VHYXRoZXJlcihzZHBNTGluZUluZGV4LFxuICAgICAgICAgICAgICB1c2luZ0J1bmRsZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2FuZHMubGVuZ3RoICYmIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydC5zdGF0ZSA9PT0gJ25ldycpIHtcbiAgICAgICAgICBpZiAoaXNDb21wbGV0ZSAmJiAoIXVzaW5nQnVuZGxlIHx8IHNkcE1MaW5lSW5kZXggPT09IDApKSB7XG4gICAgICAgICAgICB0cmFuc2NlaXZlci5pY2VUcmFuc3BvcnQuc2V0UmVtb3RlQ2FuZGlkYXRlcyhjYW5kcyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhbmRzLmZvckVhY2goZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gICAgICAgICAgICAgIG1heWJlQWRkQ2FuZGlkYXRlKHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydCwgY2FuZGlkYXRlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxvY2FsQ2FwYWJpbGl0aWVzID0gd2luZG93LlJUQ1J0cFJlY2VpdmVyLmdldENhcGFiaWxpdGllcyhraW5kKTtcblxuICAgICAgICAvLyBmaWx0ZXIgUlRYIHVudGlsIGFkZGl0aW9uYWwgc3R1ZmYgbmVlZGVkIGZvciBSVFggaXMgaW1wbGVtZW50ZWRcbiAgICAgICAgLy8gaW4gYWRhcHRlci5qc1xuICAgICAgICBpZiAoZWRnZVZlcnNpb24gPCAxNTAxOSkge1xuICAgICAgICAgIGxvY2FsQ2FwYWJpbGl0aWVzLmNvZGVjcyA9IGxvY2FsQ2FwYWJpbGl0aWVzLmNvZGVjcy5maWx0ZXIoXG4gICAgICAgICAgICAgIGZ1bmN0aW9uKGNvZGVjKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvZGVjLm5hbWUgIT09ICdydHgnO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNlbmRFbmNvZGluZ1BhcmFtZXRlcnMgPSB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzIHx8IFt7XG4gICAgICAgICAgc3NyYzogKDIgKiBzZHBNTGluZUluZGV4ICsgMikgKiAxMDAxXG4gICAgICAgIH1dO1xuXG4gICAgICAgIC8vIFRPRE86IHJld3JpdGUgdG8gdXNlIGh0dHA6Ly93M2MuZ2l0aHViLmlvL3dlYnJ0Yy1wYy8jc2V0LWFzc29jaWF0ZWQtcmVtb3RlLXN0cmVhbXNcbiAgICAgICAgdmFyIGlzTmV3VHJhY2sgPSBmYWxzZTtcbiAgICAgICAgaWYgKGRpcmVjdGlvbiA9PT0gJ3NlbmRyZWN2JyB8fCBkaXJlY3Rpb24gPT09ICdzZW5kb25seScpIHtcbiAgICAgICAgICBpc05ld1RyYWNrID0gIXRyYW5zY2VpdmVyLnJ0cFJlY2VpdmVyO1xuICAgICAgICAgIHJ0cFJlY2VpdmVyID0gdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXIgfHxcbiAgICAgICAgICAgICAgbmV3IHdpbmRvdy5SVENSdHBSZWNlaXZlcih0cmFuc2NlaXZlci5kdGxzVHJhbnNwb3J0LCBraW5kKTtcblxuICAgICAgICAgIGlmIChpc05ld1RyYWNrKSB7XG4gICAgICAgICAgICB2YXIgc3RyZWFtO1xuICAgICAgICAgICAgdHJhY2sgPSBydHBSZWNlaXZlci50cmFjaztcbiAgICAgICAgICAgIC8vIEZJWE1FOiBkb2VzIG5vdCB3b3JrIHdpdGggUGxhbiBCLlxuICAgICAgICAgICAgaWYgKHJlbW90ZU1zaWQgJiYgcmVtb3RlTXNpZC5zdHJlYW0gPT09ICctJykge1xuICAgICAgICAgICAgICAvLyBuby1vcC4gYSBzdHJlYW0gaWQgb2YgJy0nIG1lYW5zOiBubyBhc3NvY2lhdGVkIHN0cmVhbS5cbiAgICAgICAgICAgIH0gZWxzZSBpZiAocmVtb3RlTXNpZCkge1xuICAgICAgICAgICAgICBpZiAoIXN0cmVhbXNbcmVtb3RlTXNpZC5zdHJlYW1dKSB7XG4gICAgICAgICAgICAgICAgc3RyZWFtc1tyZW1vdGVNc2lkLnN0cmVhbV0gPSBuZXcgd2luZG93Lk1lZGlhU3RyZWFtKCk7XG4gICAgICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHN0cmVhbXNbcmVtb3RlTXNpZC5zdHJlYW1dLCAnaWQnLCB7XG4gICAgICAgICAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVtb3RlTXNpZC5zdHJlYW07XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRyYWNrLCAnaWQnLCB7XG4gICAgICAgICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiByZW1vdGVNc2lkLnRyYWNrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIHN0cmVhbSA9IHN0cmVhbXNbcmVtb3RlTXNpZC5zdHJlYW1dO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgaWYgKCFzdHJlYW1zLmRlZmF1bHQpIHtcbiAgICAgICAgICAgICAgICBzdHJlYW1zLmRlZmF1bHQgPSBuZXcgd2luZG93Lk1lZGlhU3RyZWFtKCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgc3RyZWFtID0gc3RyZWFtcy5kZWZhdWx0O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHN0cmVhbSkge1xuICAgICAgICAgICAgICBhZGRUcmFja1RvU3RyZWFtQW5kRmlyZUV2ZW50KHRyYWNrLCBzdHJlYW0pO1xuICAgICAgICAgICAgICB0cmFuc2NlaXZlci5hc3NvY2lhdGVkUmVtb3RlTWVkaWFTdHJlYW1zLnB1c2goc3RyZWFtKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJlY2VpdmVyTGlzdC5wdXNoKFt0cmFjaywgcnRwUmVjZWl2ZXIsIHN0cmVhbV0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICh0cmFuc2NlaXZlci5ydHBSZWNlaXZlciAmJiB0cmFuc2NlaXZlci5ydHBSZWNlaXZlci50cmFjaykge1xuICAgICAgICAgIHRyYW5zY2VpdmVyLmFzc29jaWF0ZWRSZW1vdGVNZWRpYVN0cmVhbXMuZm9yRWFjaChmdW5jdGlvbihzKSB7XG4gICAgICAgICAgICB2YXIgbmF0aXZlVHJhY2sgPSBzLmdldFRyYWNrcygpLmZpbmQoZnVuY3Rpb24odCkge1xuICAgICAgICAgICAgICByZXR1cm4gdC5pZCA9PT0gdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXIudHJhY2suaWQ7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChuYXRpdmVUcmFjaykge1xuICAgICAgICAgICAgICByZW1vdmVUcmFja0Zyb21TdHJlYW1BbmRGaXJlRXZlbnQobmF0aXZlVHJhY2ssIHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRyYW5zY2VpdmVyLmFzc29jaWF0ZWRSZW1vdGVNZWRpYVN0cmVhbXMgPSBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyYW5zY2VpdmVyLmxvY2FsQ2FwYWJpbGl0aWVzID0gbG9jYWxDYXBhYmlsaXRpZXM7XG4gICAgICAgIHRyYW5zY2VpdmVyLnJlbW90ZUNhcGFiaWxpdGllcyA9IHJlbW90ZUNhcGFiaWxpdGllcztcbiAgICAgICAgdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXIgPSBydHBSZWNlaXZlcjtcbiAgICAgICAgdHJhbnNjZWl2ZXIucnRjcFBhcmFtZXRlcnMgPSBydGNwUGFyYW1ldGVycztcbiAgICAgICAgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVycyA9IHNlbmRFbmNvZGluZ1BhcmFtZXRlcnM7XG4gICAgICAgIHRyYW5zY2VpdmVyLnJlY3ZFbmNvZGluZ1BhcmFtZXRlcnMgPSByZWN2RW5jb2RpbmdQYXJhbWV0ZXJzO1xuXG4gICAgICAgIC8vIFN0YXJ0IHRoZSBSVENSdHBSZWNlaXZlciBub3cuIFRoZSBSVFBTZW5kZXIgaXMgc3RhcnRlZCBpblxuICAgICAgICAvLyBzZXRMb2NhbERlc2NyaXB0aW9uLlxuICAgICAgICBzZWxmLl90cmFuc2NlaXZlKHNlbGYudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICBpc05ld1RyYWNrKTtcbiAgICAgIH0gZWxzZSBpZiAoZGVzY3JpcHRpb24udHlwZSA9PT0gJ2Fuc3dlcicgJiYgIXJlamVjdGVkKSB7XG4gICAgICAgIHRyYW5zY2VpdmVyID0gc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF07XG4gICAgICAgIGljZUdhdGhlcmVyID0gdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXI7XG4gICAgICAgIGljZVRyYW5zcG9ydCA9IHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydDtcbiAgICAgICAgZHRsc1RyYW5zcG9ydCA9IHRyYW5zY2VpdmVyLmR0bHNUcmFuc3BvcnQ7XG4gICAgICAgIHJ0cFJlY2VpdmVyID0gdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXI7XG4gICAgICAgIHNlbmRFbmNvZGluZ1BhcmFtZXRlcnMgPSB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzO1xuICAgICAgICBsb2NhbENhcGFiaWxpdGllcyA9IHRyYW5zY2VpdmVyLmxvY2FsQ2FwYWJpbGl0aWVzO1xuXG4gICAgICAgIHNlbGYudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLnJlY3ZFbmNvZGluZ1BhcmFtZXRlcnMgPVxuICAgICAgICAgICAgcmVjdkVuY29kaW5nUGFyYW1ldGVycztcbiAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0ucmVtb3RlQ2FwYWJpbGl0aWVzID1cbiAgICAgICAgICAgIHJlbW90ZUNhcGFiaWxpdGllcztcbiAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0ucnRjcFBhcmFtZXRlcnMgPSBydGNwUGFyYW1ldGVycztcblxuICAgICAgICBpZiAoY2FuZHMubGVuZ3RoICYmIGljZVRyYW5zcG9ydC5zdGF0ZSA9PT0gJ25ldycpIHtcbiAgICAgICAgICBpZiAoKGlzSWNlTGl0ZSB8fCBpc0NvbXBsZXRlKSAmJlxuICAgICAgICAgICAgICAoIXVzaW5nQnVuZGxlIHx8IHNkcE1MaW5lSW5kZXggPT09IDApKSB7XG4gICAgICAgICAgICBpY2VUcmFuc3BvcnQuc2V0UmVtb3RlQ2FuZGlkYXRlcyhjYW5kcyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhbmRzLmZvckVhY2goZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gICAgICAgICAgICAgIG1heWJlQWRkQ2FuZGlkYXRlKHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydCwgY2FuZGlkYXRlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdXNpbmdCdW5kbGUgfHwgc2RwTUxpbmVJbmRleCA9PT0gMCkge1xuICAgICAgICAgIGlmIChpY2VUcmFuc3BvcnQuc3RhdGUgPT09ICduZXcnKSB7XG4gICAgICAgICAgICBpY2VUcmFuc3BvcnQuc3RhcnQoaWNlR2F0aGVyZXIsIHJlbW90ZUljZVBhcmFtZXRlcnMsXG4gICAgICAgICAgICAgICAgJ2NvbnRyb2xsaW5nJyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChkdGxzVHJhbnNwb3J0LnN0YXRlID09PSAnbmV3Jykge1xuICAgICAgICAgICAgZHRsc1RyYW5zcG9ydC5zdGFydChyZW1vdGVEdGxzUGFyYW1ldGVycyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgc2VsZi5fdHJhbnNjZWl2ZSh0cmFuc2NlaXZlcixcbiAgICAgICAgICAgIGRpcmVjdGlvbiA9PT0gJ3NlbmRyZWN2JyB8fCBkaXJlY3Rpb24gPT09ICdyZWN2b25seScsXG4gICAgICAgICAgICBkaXJlY3Rpb24gPT09ICdzZW5kcmVjdicgfHwgZGlyZWN0aW9uID09PSAnc2VuZG9ubHknKTtcblxuICAgICAgICAvLyBUT0RPOiByZXdyaXRlIHRvIHVzZSBodHRwOi8vdzNjLmdpdGh1Yi5pby93ZWJydGMtcGMvI3NldC1hc3NvY2lhdGVkLXJlbW90ZS1zdHJlYW1zXG4gICAgICAgIGlmIChydHBSZWNlaXZlciAmJlxuICAgICAgICAgICAgKGRpcmVjdGlvbiA9PT0gJ3NlbmRyZWN2JyB8fCBkaXJlY3Rpb24gPT09ICdzZW5kb25seScpKSB7XG4gICAgICAgICAgdHJhY2sgPSBydHBSZWNlaXZlci50cmFjaztcbiAgICAgICAgICBpZiAocmVtb3RlTXNpZCkge1xuICAgICAgICAgICAgaWYgKCFzdHJlYW1zW3JlbW90ZU1zaWQuc3RyZWFtXSkge1xuICAgICAgICAgICAgICBzdHJlYW1zW3JlbW90ZU1zaWQuc3RyZWFtXSA9IG5ldyB3aW5kb3cuTWVkaWFTdHJlYW0oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGFkZFRyYWNrVG9TdHJlYW1BbmRGaXJlRXZlbnQodHJhY2ssIHN0cmVhbXNbcmVtb3RlTXNpZC5zdHJlYW1dKTtcbiAgICAgICAgICAgIHJlY2VpdmVyTGlzdC5wdXNoKFt0cmFjaywgcnRwUmVjZWl2ZXIsIHN0cmVhbXNbcmVtb3RlTXNpZC5zdHJlYW1dXSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmICghc3RyZWFtcy5kZWZhdWx0KSB7XG4gICAgICAgICAgICAgIHN0cmVhbXMuZGVmYXVsdCA9IG5ldyB3aW5kb3cuTWVkaWFTdHJlYW0oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGFkZFRyYWNrVG9TdHJlYW1BbmRGaXJlRXZlbnQodHJhY2ssIHN0cmVhbXMuZGVmYXVsdCk7XG4gICAgICAgICAgICByZWNlaXZlckxpc3QucHVzaChbdHJhY2ssIHJ0cFJlY2VpdmVyLCBzdHJlYW1zLmRlZmF1bHRdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gRklYTUU6IGFjdHVhbGx5IHRoZSByZWNlaXZlciBzaG91bGQgYmUgY3JlYXRlZCBsYXRlci5cbiAgICAgICAgICBkZWxldGUgdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXI7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGlmICh0aGlzLl9kdGxzUm9sZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLl9kdGxzUm9sZSA9IGRlc2NyaXB0aW9uLnR5cGUgPT09ICdvZmZlcicgPyAnYWN0aXZlJyA6ICdwYXNzaXZlJztcbiAgICB9XG5cbiAgICB0aGlzLnJlbW90ZURlc2NyaXB0aW9uID0ge1xuICAgICAgdHlwZTogZGVzY3JpcHRpb24udHlwZSxcbiAgICAgIHNkcDogZGVzY3JpcHRpb24uc2RwXG4gICAgfTtcbiAgICBzd2l0Y2ggKGRlc2NyaXB0aW9uLnR5cGUpIHtcbiAgICAgIGNhc2UgJ29mZmVyJzpcbiAgICAgICAgdGhpcy5fdXBkYXRlU2lnbmFsaW5nU3RhdGUoJ2hhdmUtcmVtb3RlLW9mZmVyJyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnYW5zd2VyJzpcbiAgICAgICAgdGhpcy5fdXBkYXRlU2lnbmFsaW5nU3RhdGUoJ3N0YWJsZScpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3Vuc3VwcG9ydGVkIHR5cGUgXCInICsgZGVzY3JpcHRpb24udHlwZSArXG4gICAgICAgICAgICAnXCInKTtcbiAgICB9XG4gICAgT2JqZWN0LmtleXMoc3RyZWFtcykuZm9yRWFjaChmdW5jdGlvbihzaWQpIHtcbiAgICAgIHZhciBzdHJlYW0gPSBzdHJlYW1zW3NpZF07XG4gICAgICBpZiAoc3RyZWFtLmdldFRyYWNrcygpLmxlbmd0aCkge1xuICAgICAgICBpZiAoc2VsZi5yZW1vdGVTdHJlYW1zLmluZGV4T2Yoc3RyZWFtKSA9PT0gLTEpIHtcbiAgICAgICAgICBzZWxmLnJlbW90ZVN0cmVhbXMucHVzaChzdHJlYW0pO1xuICAgICAgICAgIHZhciBldmVudCA9IG5ldyBFdmVudCgnYWRkc3RyZWFtJyk7XG4gICAgICAgICAgZXZlbnQuc3RyZWFtID0gc3RyZWFtO1xuICAgICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgc2VsZi5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygc2VsZi5vbmFkZHN0cmVhbSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICBzZWxmLm9uYWRkc3RyZWFtKGV2ZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlY2VpdmVyTGlzdC5mb3JFYWNoKGZ1bmN0aW9uKGl0ZW0pIHtcbiAgICAgICAgICB2YXIgdHJhY2sgPSBpdGVtWzBdO1xuICAgICAgICAgIHZhciByZWNlaXZlciA9IGl0ZW1bMV07XG4gICAgICAgICAgaWYgKHN0cmVhbS5pZCAhPT0gaXRlbVsyXS5pZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICBmaXJlQWRkVHJhY2soc2VsZiwgdHJhY2ssIHJlY2VpdmVyLCBbc3RyZWFtXSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJlY2VpdmVyTGlzdC5mb3JFYWNoKGZ1bmN0aW9uKGl0ZW0pIHtcbiAgICAgIGlmIChpdGVtWzJdKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGZpcmVBZGRUcmFjayhzZWxmLCBpdGVtWzBdLCBpdGVtWzFdLCBbXSk7XG4gICAgfSk7XG5cbiAgICAvLyBjaGVjayB3aGV0aGVyIGFkZEljZUNhbmRpZGF0ZSh7fSkgd2FzIGNhbGxlZCB3aXRoaW4gZm91ciBzZWNvbmRzIGFmdGVyXG4gICAgLy8gc2V0UmVtb3RlRGVzY3JpcHRpb24uXG4gICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICBpZiAoIShzZWxmICYmIHNlbGYudHJhbnNjZWl2ZXJzKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBzZWxmLnRyYW5zY2VpdmVycy5mb3JFYWNoKGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICAgIGlmICh0cmFuc2NlaXZlci5pY2VUcmFuc3BvcnQgJiZcbiAgICAgICAgICAgIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydC5zdGF0ZSA9PT0gJ25ldycgJiZcbiAgICAgICAgICAgIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydC5nZXRSZW1vdGVDYW5kaWRhdGVzKCkubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGNvbnNvbGUud2FybignVGltZW91dCBmb3IgYWRkUmVtb3RlQ2FuZGlkYXRlLiBDb25zaWRlciBzZW5kaW5nICcgK1xuICAgICAgICAgICAgICAnYW4gZW5kLW9mLWNhbmRpZGF0ZXMgbm90aWZpY2F0aW9uJyk7XG4gICAgICAgICAgdHJhbnNjZWl2ZXIuaWNlVHJhbnNwb3J0LmFkZFJlbW90ZUNhbmRpZGF0ZSh7fSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0sIDQwMDApO1xuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUpIHtcbiAgICAgIGlmIChhcmdzLmxlbmd0aCA+IDEgJiYgdHlwZW9mIGFyZ3NbMV0gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgYXJnc1sxXS5hcHBseShudWxsKTtcbiAgICAgIH1cbiAgICAgIHJlc29sdmUoKTtcbiAgICB9KTtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuY2xvc2UgPSBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnRyYW5zY2VpdmVycy5mb3JFYWNoKGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICAvKiBub3QgeWV0XG4gICAgICBpZiAodHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXIpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXIuY2xvc2UoKTtcbiAgICAgIH1cbiAgICAgICovXG4gICAgICBpZiAodHJhbnNjZWl2ZXIuaWNlVHJhbnNwb3J0KSB7XG4gICAgICAgIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydC5zdG9wKCk7XG4gICAgICB9XG4gICAgICBpZiAodHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydCkge1xuICAgICAgICB0cmFuc2NlaXZlci5kdGxzVHJhbnNwb3J0LnN0b3AoKTtcbiAgICAgIH1cbiAgICAgIGlmICh0cmFuc2NlaXZlci5ydHBTZW5kZXIpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIucnRwU2VuZGVyLnN0b3AoKTtcbiAgICAgIH1cbiAgICAgIGlmICh0cmFuc2NlaXZlci5ydHBSZWNlaXZlcikge1xuICAgICAgICB0cmFuc2NlaXZlci5ydHBSZWNlaXZlci5zdG9wKCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgLy8gRklYTUU6IGNsZWFuIHVwIHRyYWNrcywgbG9jYWwgc3RyZWFtcywgcmVtb3RlIHN0cmVhbXMsIGV0Y1xuICAgIHRoaXMuX3VwZGF0ZVNpZ25hbGluZ1N0YXRlKCdjbG9zZWQnKTtcbiAgfTtcblxuICAvLyBVcGRhdGUgdGhlIHNpZ25hbGluZyBzdGF0ZS5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl91cGRhdGVTaWduYWxpbmdTdGF0ZSA9IGZ1bmN0aW9uKG5ld1N0YXRlKSB7XG4gICAgdGhpcy5zaWduYWxpbmdTdGF0ZSA9IG5ld1N0YXRlO1xuICAgIHZhciBldmVudCA9IG5ldyBFdmVudCgnc2lnbmFsaW5nc3RhdGVjaGFuZ2UnKTtcbiAgICB0aGlzLmRpc3BhdGNoRXZlbnQoZXZlbnQpO1xuICAgIGlmICh0eXBlb2YgdGhpcy5vbnNpZ25hbGluZ3N0YXRlY2hhbmdlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aGlzLm9uc2lnbmFsaW5nc3RhdGVjaGFuZ2UoZXZlbnQpO1xuICAgIH1cbiAgfTtcblxuICAvLyBEZXRlcm1pbmUgd2hldGhlciB0byBmaXJlIHRoZSBuZWdvdGlhdGlvbm5lZWRlZCBldmVudC5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl9tYXliZUZpcmVOZWdvdGlhdGlvbk5lZWRlZCA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZiAodGhpcy5zaWduYWxpbmdTdGF0ZSAhPT0gJ3N0YWJsZScgfHwgdGhpcy5uZWVkTmVnb3RpYXRpb24gPT09IHRydWUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5uZWVkTmVnb3RpYXRpb24gPSB0cnVlO1xuICAgIHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgaWYgKHNlbGYubmVlZE5lZ290aWF0aW9uID09PSBmYWxzZSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBzZWxmLm5lZWROZWdvdGlhdGlvbiA9IGZhbHNlO1xuICAgICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KCduZWdvdGlhdGlvbm5lZWRlZCcpO1xuICAgICAgc2VsZi5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICAgIGlmICh0eXBlb2Ygc2VsZi5vbm5lZ290aWF0aW9ubmVlZGVkID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHNlbGYub25uZWdvdGlhdGlvbm5lZWRlZChldmVudCk7XG4gICAgICB9XG4gICAgfSwgMCk7XG4gIH07XG5cbiAgLy8gVXBkYXRlIHRoZSBjb25uZWN0aW9uIHN0YXRlLlxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX3VwZGF0ZUNvbm5lY3Rpb25TdGF0ZSA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBuZXdTdGF0ZTtcbiAgICB2YXIgc3RhdGVzID0ge1xuICAgICAgJ25ldyc6IDAsXG4gICAgICBjbG9zZWQ6IDAsXG4gICAgICBjb25uZWN0aW5nOiAwLFxuICAgICAgY2hlY2tpbmc6IDAsXG4gICAgICBjb25uZWN0ZWQ6IDAsXG4gICAgICBjb21wbGV0ZWQ6IDAsXG4gICAgICBkaXNjb25uZWN0ZWQ6IDAsXG4gICAgICBmYWlsZWQ6IDBcbiAgICB9O1xuICAgIHRoaXMudHJhbnNjZWl2ZXJzLmZvckVhY2goZnVuY3Rpb24odHJhbnNjZWl2ZXIpIHtcbiAgICAgIHN0YXRlc1t0cmFuc2NlaXZlci5pY2VUcmFuc3BvcnQuc3RhdGVdKys7XG4gICAgICBzdGF0ZXNbdHJhbnNjZWl2ZXIuZHRsc1RyYW5zcG9ydC5zdGF0ZV0rKztcbiAgICB9KTtcbiAgICAvLyBJQ0VUcmFuc3BvcnQuY29tcGxldGVkIGFuZCBjb25uZWN0ZWQgYXJlIHRoZSBzYW1lIGZvciB0aGlzIHB1cnBvc2UuXG4gICAgc3RhdGVzLmNvbm5lY3RlZCArPSBzdGF0ZXMuY29tcGxldGVkO1xuXG4gICAgbmV3U3RhdGUgPSAnbmV3JztcbiAgICBpZiAoc3RhdGVzLmZhaWxlZCA+IDApIHtcbiAgICAgIG5ld1N0YXRlID0gJ2ZhaWxlZCc7XG4gICAgfSBlbHNlIGlmIChzdGF0ZXMuY29ubmVjdGluZyA+IDAgfHwgc3RhdGVzLmNoZWNraW5nID4gMCkge1xuICAgICAgbmV3U3RhdGUgPSAnY29ubmVjdGluZyc7XG4gICAgfSBlbHNlIGlmIChzdGF0ZXMuZGlzY29ubmVjdGVkID4gMCkge1xuICAgICAgbmV3U3RhdGUgPSAnZGlzY29ubmVjdGVkJztcbiAgICB9IGVsc2UgaWYgKHN0YXRlcy5uZXcgPiAwKSB7XG4gICAgICBuZXdTdGF0ZSA9ICduZXcnO1xuICAgIH0gZWxzZSBpZiAoc3RhdGVzLmNvbm5lY3RlZCA+IDAgfHwgc3RhdGVzLmNvbXBsZXRlZCA+IDApIHtcbiAgICAgIG5ld1N0YXRlID0gJ2Nvbm5lY3RlZCc7XG4gICAgfVxuXG4gICAgaWYgKG5ld1N0YXRlICE9PSB0aGlzLmljZUNvbm5lY3Rpb25TdGF0ZSkge1xuICAgICAgdGhpcy5pY2VDb25uZWN0aW9uU3RhdGUgPSBuZXdTdGF0ZTtcbiAgICAgIHZhciBldmVudCA9IG5ldyBFdmVudCgnaWNlY29ubmVjdGlvbnN0YXRlY2hhbmdlJyk7XG4gICAgICB0aGlzLmRpc3BhdGNoRXZlbnQoZXZlbnQpO1xuICAgICAgaWYgKHR5cGVvZiB0aGlzLm9uaWNlY29ubmVjdGlvbnN0YXRlY2hhbmdlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHRoaXMub25pY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2UoZXZlbnQpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuY3JlYXRlT2ZmZXIgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG5cbiAgICB2YXIgb2ZmZXJPcHRpb25zO1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAxICYmIHR5cGVvZiBhcmd1bWVudHNbMF0gIT09ICdmdW5jdGlvbicpIHtcbiAgICAgIG9mZmVyT3B0aW9ucyA9IGFyZ3VtZW50c1swXTtcbiAgICB9IGVsc2UgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDMpIHtcbiAgICAgIG9mZmVyT3B0aW9ucyA9IGFyZ3VtZW50c1syXTtcbiAgICB9XG5cbiAgICB2YXIgbnVtQXVkaW9UcmFja3MgPSB0aGlzLnRyYW5zY2VpdmVycy5maWx0ZXIoZnVuY3Rpb24odCkge1xuICAgICAgcmV0dXJuIHQua2luZCA9PT0gJ2F1ZGlvJztcbiAgICB9KS5sZW5ndGg7XG4gICAgdmFyIG51bVZpZGVvVHJhY2tzID0gdGhpcy50cmFuc2NlaXZlcnMuZmlsdGVyKGZ1bmN0aW9uKHQpIHtcbiAgICAgIHJldHVybiB0LmtpbmQgPT09ICd2aWRlbyc7XG4gICAgfSkubGVuZ3RoO1xuXG4gICAgLy8gRGV0ZXJtaW5lIG51bWJlciBvZiBhdWRpbyBhbmQgdmlkZW8gdHJhY2tzIHdlIG5lZWQgdG8gc2VuZC9yZWN2LlxuICAgIGlmIChvZmZlck9wdGlvbnMpIHtcbiAgICAgIC8vIFJlamVjdCBDaHJvbWUgbGVnYWN5IGNvbnN0cmFpbnRzLlxuICAgICAgaWYgKG9mZmVyT3B0aW9ucy5tYW5kYXRvcnkgfHwgb2ZmZXJPcHRpb25zLm9wdGlvbmFsKSB7XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXG4gICAgICAgICAgICAnTGVnYWN5IG1hbmRhdG9yeS9vcHRpb25hbCBjb25zdHJhaW50cyBub3Qgc3VwcG9ydGVkLicpO1xuICAgICAgfVxuICAgICAgaWYgKG9mZmVyT3B0aW9ucy5vZmZlclRvUmVjZWl2ZUF1ZGlvICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgaWYgKG9mZmVyT3B0aW9ucy5vZmZlclRvUmVjZWl2ZUF1ZGlvID09PSB0cnVlKSB7XG4gICAgICAgICAgbnVtQXVkaW9UcmFja3MgPSAxO1xuICAgICAgICB9IGVsc2UgaWYgKG9mZmVyT3B0aW9ucy5vZmZlclRvUmVjZWl2ZUF1ZGlvID09PSBmYWxzZSkge1xuICAgICAgICAgIG51bUF1ZGlvVHJhY2tzID0gMDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBudW1BdWRpb1RyYWNrcyA9IG9mZmVyT3B0aW9ucy5vZmZlclRvUmVjZWl2ZUF1ZGlvO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAob2ZmZXJPcHRpb25zLm9mZmVyVG9SZWNlaXZlVmlkZW8gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBpZiAob2ZmZXJPcHRpb25zLm9mZmVyVG9SZWNlaXZlVmlkZW8gPT09IHRydWUpIHtcbiAgICAgICAgICBudW1WaWRlb1RyYWNrcyA9IDE7XG4gICAgICAgIH0gZWxzZSBpZiAob2ZmZXJPcHRpb25zLm9mZmVyVG9SZWNlaXZlVmlkZW8gPT09IGZhbHNlKSB7XG4gICAgICAgICAgbnVtVmlkZW9UcmFja3MgPSAwO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG51bVZpZGVvVHJhY2tzID0gb2ZmZXJPcHRpb25zLm9mZmVyVG9SZWNlaXZlVmlkZW87XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLnRyYW5zY2VpdmVycy5mb3JFYWNoKGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICBpZiAodHJhbnNjZWl2ZXIua2luZCA9PT0gJ2F1ZGlvJykge1xuICAgICAgICBudW1BdWRpb1RyYWNrcy0tO1xuICAgICAgICBpZiAobnVtQXVkaW9UcmFja3MgPCAwKSB7XG4gICAgICAgICAgdHJhbnNjZWl2ZXIud2FudFJlY2VpdmUgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh0cmFuc2NlaXZlci5raW5kID09PSAndmlkZW8nKSB7XG4gICAgICAgIG51bVZpZGVvVHJhY2tzLS07XG4gICAgICAgIGlmIChudW1WaWRlb1RyYWNrcyA8IDApIHtcbiAgICAgICAgICB0cmFuc2NlaXZlci53YW50UmVjZWl2ZSA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyBDcmVhdGUgTS1saW5lcyBmb3IgcmVjdm9ubHkgc3RyZWFtcy5cbiAgICB3aGlsZSAobnVtQXVkaW9UcmFja3MgPiAwIHx8IG51bVZpZGVvVHJhY2tzID4gMCkge1xuICAgICAgaWYgKG51bUF1ZGlvVHJhY2tzID4gMCkge1xuICAgICAgICB0aGlzLl9jcmVhdGVUcmFuc2NlaXZlcignYXVkaW8nKTtcbiAgICAgICAgbnVtQXVkaW9UcmFja3MtLTtcbiAgICAgIH1cbiAgICAgIGlmIChudW1WaWRlb1RyYWNrcyA+IDApIHtcbiAgICAgICAgdGhpcy5fY3JlYXRlVHJhbnNjZWl2ZXIoJ3ZpZGVvJyk7XG4gICAgICAgIG51bVZpZGVvVHJhY2tzLS07XG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIHNkcCA9IFNEUFV0aWxzLndyaXRlU2Vzc2lvbkJvaWxlcnBsYXRlKHRoaXMuX3NkcFNlc3Npb25JZCxcbiAgICAgICAgdGhpcy5fc2RwU2Vzc2lvblZlcnNpb24rKyk7XG4gICAgdGhpcy50cmFuc2NlaXZlcnMuZm9yRWFjaChmdW5jdGlvbih0cmFuc2NlaXZlciwgc2RwTUxpbmVJbmRleCkge1xuICAgICAgLy8gRm9yIGVhY2ggdHJhY2ssIGNyZWF0ZSBhbiBpY2UgZ2F0aGVyZXIsIGljZSB0cmFuc3BvcnQsXG4gICAgICAvLyBkdGxzIHRyYW5zcG9ydCwgcG90ZW50aWFsbHkgcnRwc2VuZGVyIGFuZCBydHByZWNlaXZlci5cbiAgICAgIHZhciB0cmFjayA9IHRyYW5zY2VpdmVyLnRyYWNrO1xuICAgICAgdmFyIGtpbmQgPSB0cmFuc2NlaXZlci5raW5kO1xuICAgICAgdmFyIG1pZCA9IFNEUFV0aWxzLmdlbmVyYXRlSWRlbnRpZmllcigpO1xuICAgICAgdHJhbnNjZWl2ZXIubWlkID0gbWlkO1xuXG4gICAgICBpZiAoIXRyYW5zY2VpdmVyLmljZUdhdGhlcmVyKSB7XG4gICAgICAgIHRyYW5zY2VpdmVyLmljZUdhdGhlcmVyID0gc2VsZi5fY3JlYXRlSWNlR2F0aGVyZXIoc2RwTUxpbmVJbmRleCxcbiAgICAgICAgICAgIHNlbGYudXNpbmdCdW5kbGUpO1xuICAgICAgfVxuXG4gICAgICB2YXIgbG9jYWxDYXBhYmlsaXRpZXMgPSB3aW5kb3cuUlRDUnRwU2VuZGVyLmdldENhcGFiaWxpdGllcyhraW5kKTtcbiAgICAgIC8vIGZpbHRlciBSVFggdW50aWwgYWRkaXRpb25hbCBzdHVmZiBuZWVkZWQgZm9yIFJUWCBpcyBpbXBsZW1lbnRlZFxuICAgICAgLy8gaW4gYWRhcHRlci5qc1xuICAgICAgaWYgKGVkZ2VWZXJzaW9uIDwgMTUwMTkpIHtcbiAgICAgICAgbG9jYWxDYXBhYmlsaXRpZXMuY29kZWNzID0gbG9jYWxDYXBhYmlsaXRpZXMuY29kZWNzLmZpbHRlcihcbiAgICAgICAgICAgIGZ1bmN0aW9uKGNvZGVjKSB7XG4gICAgICAgICAgICAgIHJldHVybiBjb2RlYy5uYW1lICE9PSAncnR4JztcbiAgICAgICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgbG9jYWxDYXBhYmlsaXRpZXMuY29kZWNzLmZvckVhY2goZnVuY3Rpb24oY29kZWMpIHtcbiAgICAgICAgLy8gd29yayBhcm91bmQgaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL3dlYnJ0Yy9pc3N1ZXMvZGV0YWlsP2lkPTY1NTJcbiAgICAgICAgLy8gYnkgYWRkaW5nIGxldmVsLWFzeW1tZXRyeS1hbGxvd2VkPTFcbiAgICAgICAgaWYgKGNvZGVjLm5hbWUgPT09ICdIMjY0JyAmJlxuICAgICAgICAgICAgY29kZWMucGFyYW1ldGVyc1snbGV2ZWwtYXN5bW1ldHJ5LWFsbG93ZWQnXSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgY29kZWMucGFyYW1ldGVyc1snbGV2ZWwtYXN5bW1ldHJ5LWFsbG93ZWQnXSA9ICcxJztcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIC8vIGdlbmVyYXRlIGFuIHNzcmMgbm93LCB0byBiZSB1c2VkIGxhdGVyIGluIHJ0cFNlbmRlci5zZW5kXG4gICAgICB2YXIgc2VuZEVuY29kaW5nUGFyYW1ldGVycyA9IHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnMgfHwgW3tcbiAgICAgICAgc3NyYzogKDIgKiBzZHBNTGluZUluZGV4ICsgMSkgKiAxMDAxXG4gICAgICB9XTtcbiAgICAgIGlmICh0cmFjaykge1xuICAgICAgICAvLyBhZGQgUlRYXG4gICAgICAgIGlmIChlZGdlVmVyc2lvbiA+PSAxNTAxOSAmJiBraW5kID09PSAndmlkZW8nICYmXG4gICAgICAgICAgICAhc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHgpIHtcbiAgICAgICAgICBzZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eCA9IHtcbiAgICAgICAgICAgIHNzcmM6IHNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0uc3NyYyArIDFcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0cmFuc2NlaXZlci53YW50UmVjZWl2ZSkge1xuICAgICAgICB0cmFuc2NlaXZlci5ydHBSZWNlaXZlciA9IG5ldyB3aW5kb3cuUlRDUnRwUmVjZWl2ZXIoXG4gICAgICAgICAgICB0cmFuc2NlaXZlci5kdGxzVHJhbnNwb3J0LCBraW5kKTtcbiAgICAgIH1cblxuICAgICAgdHJhbnNjZWl2ZXIubG9jYWxDYXBhYmlsaXRpZXMgPSBsb2NhbENhcGFiaWxpdGllcztcbiAgICAgIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnMgPSBzZW5kRW5jb2RpbmdQYXJhbWV0ZXJzO1xuICAgIH0pO1xuXG4gICAgLy8gYWx3YXlzIG9mZmVyIEJVTkRMRSBhbmQgZGlzcG9zZSBvbiByZXR1cm4gaWYgbm90IHN1cHBvcnRlZC5cbiAgICBpZiAodGhpcy5fY29uZmlnLmJ1bmRsZVBvbGljeSAhPT0gJ21heC1jb21wYXQnKSB7XG4gICAgICBzZHAgKz0gJ2E9Z3JvdXA6QlVORExFICcgKyB0aGlzLnRyYW5zY2VpdmVycy5tYXAoZnVuY3Rpb24odCkge1xuICAgICAgICByZXR1cm4gdC5taWQ7XG4gICAgICB9KS5qb2luKCcgJykgKyAnXFxyXFxuJztcbiAgICB9XG4gICAgc2RwICs9ICdhPWljZS1vcHRpb25zOnRyaWNrbGVcXHJcXG4nO1xuXG4gICAgdGhpcy50cmFuc2NlaXZlcnMuZm9yRWFjaChmdW5jdGlvbih0cmFuc2NlaXZlciwgc2RwTUxpbmVJbmRleCkge1xuICAgICAgc2RwICs9IHdyaXRlTWVkaWFTZWN0aW9uKHRyYW5zY2VpdmVyLCB0cmFuc2NlaXZlci5sb2NhbENhcGFiaWxpdGllcyxcbiAgICAgICAgICAnb2ZmZXInLCB0cmFuc2NlaXZlci5zdHJlYW0sIHNlbGYuX2R0bHNSb2xlKTtcbiAgICAgIHNkcCArPSAnYT1ydGNwLXJzaXplXFxyXFxuJztcblxuICAgICAgaWYgKHRyYW5zY2VpdmVyLmljZUdhdGhlcmVyICYmIHNlbGYuaWNlR2F0aGVyaW5nU3RhdGUgIT09ICduZXcnICYmXG4gICAgICAgICAgKHNkcE1MaW5lSW5kZXggPT09IDAgfHwgIXNlbGYudXNpbmdCdW5kbGUpKSB7XG4gICAgICAgIHRyYW5zY2VpdmVyLmljZUdhdGhlcmVyLmdldExvY2FsQ2FuZGlkYXRlcygpLmZvckVhY2goZnVuY3Rpb24oY2FuZCkge1xuICAgICAgICAgIGNhbmQuY29tcG9uZW50ID0gMTtcbiAgICAgICAgICBzZHAgKz0gJ2E9JyArIFNEUFV0aWxzLndyaXRlQ2FuZGlkYXRlKGNhbmQpICsgJ1xcclxcbic7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICh0cmFuc2NlaXZlci5pY2VHYXRoZXJlci5zdGF0ZSA9PT0gJ2NvbXBsZXRlZCcpIHtcbiAgICAgICAgICBzZHAgKz0gJ2E9ZW5kLW9mLWNhbmRpZGF0ZXNcXHJcXG4nO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB2YXIgZGVzYyA9IG5ldyB3aW5kb3cuUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgIHR5cGU6ICdvZmZlcicsXG4gICAgICBzZHA6IHNkcFxuICAgIH0pO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlKSB7XG4gICAgICBpZiAoYXJncy5sZW5ndGggPiAwICYmIHR5cGVvZiBhcmdzWzBdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIGFyZ3NbMF0uYXBwbHkobnVsbCwgW2Rlc2NdKTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICByZXNvbHZlKGRlc2MpO1xuICAgIH0pO1xuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5jcmVhdGVBbnN3ZXIgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG5cbiAgICB2YXIgc2RwID0gU0RQVXRpbHMud3JpdGVTZXNzaW9uQm9pbGVycGxhdGUodGhpcy5fc2RwU2Vzc2lvbklkLFxuICAgICAgICB0aGlzLl9zZHBTZXNzaW9uVmVyc2lvbisrKTtcbiAgICBpZiAodGhpcy51c2luZ0J1bmRsZSkge1xuICAgICAgc2RwICs9ICdhPWdyb3VwOkJVTkRMRSAnICsgdGhpcy50cmFuc2NlaXZlcnMubWFwKGZ1bmN0aW9uKHQpIHtcbiAgICAgICAgcmV0dXJuIHQubWlkO1xuICAgICAgfSkuam9pbignICcpICsgJ1xcclxcbic7XG4gICAgfVxuICAgIHZhciBtZWRpYVNlY3Rpb25zSW5PZmZlciA9IFNEUFV0aWxzLnNwbGl0U2VjdGlvbnMoXG4gICAgICAgIHRoaXMucmVtb3RlRGVzY3JpcHRpb24uc2RwKS5sZW5ndGggLSAxO1xuICAgIHRoaXMudHJhbnNjZWl2ZXJzLmZvckVhY2goZnVuY3Rpb24odHJhbnNjZWl2ZXIsIHNkcE1MaW5lSW5kZXgpIHtcbiAgICAgIGlmIChzZHBNTGluZUluZGV4ICsgMSA+IG1lZGlhU2VjdGlvbnNJbk9mZmVyKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmICh0cmFuc2NlaXZlci5pc0RhdGFjaGFubmVsKSB7XG4gICAgICAgIHNkcCArPSAnbT1hcHBsaWNhdGlvbiAwIERUTFMvU0NUUCA1MDAwXFxyXFxuJyArXG4gICAgICAgICAgICAnYz1JTiBJUDQgMC4wLjAuMFxcclxcbicgK1xuICAgICAgICAgICAgJ2E9bWlkOicgKyB0cmFuc2NlaXZlci5taWQgKyAnXFxyXFxuJztcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBGSVhNRTogbG9vayBhdCBkaXJlY3Rpb24uXG4gICAgICBpZiAodHJhbnNjZWl2ZXIuc3RyZWFtKSB7XG4gICAgICAgIHZhciBsb2NhbFRyYWNrO1xuICAgICAgICBpZiAodHJhbnNjZWl2ZXIua2luZCA9PT0gJ2F1ZGlvJykge1xuICAgICAgICAgIGxvY2FsVHJhY2sgPSB0cmFuc2NlaXZlci5zdHJlYW0uZ2V0QXVkaW9UcmFja3MoKVswXTtcbiAgICAgICAgfSBlbHNlIGlmICh0cmFuc2NlaXZlci5raW5kID09PSAndmlkZW8nKSB7XG4gICAgICAgICAgbG9jYWxUcmFjayA9IHRyYW5zY2VpdmVyLnN0cmVhbS5nZXRWaWRlb1RyYWNrcygpWzBdO1xuICAgICAgICB9XG4gICAgICAgIGlmIChsb2NhbFRyYWNrKSB7XG4gICAgICAgICAgLy8gYWRkIFJUWFxuICAgICAgICAgIGlmIChlZGdlVmVyc2lvbiA+PSAxNTAxOSAmJiB0cmFuc2NlaXZlci5raW5kID09PSAndmlkZW8nICYmXG4gICAgICAgICAgICAgICF0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eCkge1xuICAgICAgICAgICAgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHggPSB7XG4gICAgICAgICAgICAgIHNzcmM6IHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0uc3NyYyArIDFcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIENhbGN1bGF0ZSBpbnRlcnNlY3Rpb24gb2YgY2FwYWJpbGl0aWVzLlxuICAgICAgdmFyIGNvbW1vbkNhcGFiaWxpdGllcyA9IGdldENvbW1vbkNhcGFiaWxpdGllcyhcbiAgICAgICAgICB0cmFuc2NlaXZlci5sb2NhbENhcGFiaWxpdGllcyxcbiAgICAgICAgICB0cmFuc2NlaXZlci5yZW1vdGVDYXBhYmlsaXRpZXMpO1xuXG4gICAgICB2YXIgaGFzUnR4ID0gY29tbW9uQ2FwYWJpbGl0aWVzLmNvZGVjcy5maWx0ZXIoZnVuY3Rpb24oYykge1xuICAgICAgICByZXR1cm4gYy5uYW1lLnRvTG93ZXJDYXNlKCkgPT09ICdydHgnO1xuICAgICAgfSkubGVuZ3RoO1xuICAgICAgaWYgKCFoYXNSdHggJiYgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHgpIHtcbiAgICAgICAgZGVsZXRlIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0ucnR4O1xuICAgICAgfVxuXG4gICAgICBzZHAgKz0gd3JpdGVNZWRpYVNlY3Rpb24odHJhbnNjZWl2ZXIsIGNvbW1vbkNhcGFiaWxpdGllcyxcbiAgICAgICAgICAnYW5zd2VyJywgdHJhbnNjZWl2ZXIuc3RyZWFtLCBzZWxmLl9kdGxzUm9sZSk7XG4gICAgICBpZiAodHJhbnNjZWl2ZXIucnRjcFBhcmFtZXRlcnMgJiZcbiAgICAgICAgICB0cmFuc2NlaXZlci5ydGNwUGFyYW1ldGVycy5yZWR1Y2VkU2l6ZSkge1xuICAgICAgICBzZHAgKz0gJ2E9cnRjcC1yc2l6ZVxcclxcbic7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB2YXIgZGVzYyA9IG5ldyB3aW5kb3cuUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgIHR5cGU6ICdhbnN3ZXInLFxuICAgICAgc2RwOiBzZHBcbiAgICB9KTtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSkge1xuICAgICAgaWYgKGFyZ3MubGVuZ3RoID4gMCAmJiB0eXBlb2YgYXJnc1swXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBhcmdzWzBdLmFwcGx5KG51bGwsIFtkZXNjXSk7XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgcmVzb2x2ZShkZXNjKTtcbiAgICB9KTtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkSWNlQ2FuZGlkYXRlID0gZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gICAgdmFyIGVycjtcbiAgICB2YXIgc2VjdGlvbnM7XG4gICAgaWYgKCFjYW5kaWRhdGUgfHwgY2FuZGlkYXRlLmNhbmRpZGF0ZSA9PT0gJycpIHtcbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgdGhpcy50cmFuc2NlaXZlcnMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKHRoaXMudHJhbnNjZWl2ZXJzW2pdLmlzRGF0YWNoYW5uZWwpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnRyYW5zY2VpdmVyc1tqXS5pY2VUcmFuc3BvcnQuYWRkUmVtb3RlQ2FuZGlkYXRlKHt9KTtcbiAgICAgICAgc2VjdGlvbnMgPSBTRFBVdGlscy5zcGxpdFNlY3Rpb25zKHRoaXMucmVtb3RlRGVzY3JpcHRpb24uc2RwKTtcbiAgICAgICAgc2VjdGlvbnNbaiArIDFdICs9ICdhPWVuZC1vZi1jYW5kaWRhdGVzXFxyXFxuJztcbiAgICAgICAgdGhpcy5yZW1vdGVEZXNjcmlwdGlvbi5zZHAgPSBzZWN0aW9ucy5qb2luKCcnKTtcbiAgICAgICAgaWYgKHRoaXMudXNpbmdCdW5kbGUpIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoIShjYW5kaWRhdGUuc2RwTUxpbmVJbmRleCAhPT0gdW5kZWZpbmVkIHx8IGNhbmRpZGF0ZS5zZHBNaWQpKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdzZHBNTGluZUluZGV4IG9yIHNkcE1pZCByZXF1aXJlZCcpO1xuICAgIH0gZWxzZSBpZiAoIXRoaXMucmVtb3RlRGVzY3JpcHRpb24pIHtcbiAgICAgIGVyciA9IG5ldyBFcnJvcignQ2FuIG5vdCBhZGQgSUNFIGNhbmRpZGF0ZSB3aXRob3V0ICcgK1xuICAgICAgICAgICdhIHJlbW90ZSBkZXNjcmlwdGlvbicpO1xuICAgICAgZXJyLm5hbWUgPSAnSW52YWxpZFN0YXRlRXJyb3InO1xuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgc2RwTUxpbmVJbmRleCA9IGNhbmRpZGF0ZS5zZHBNTGluZUluZGV4O1xuICAgICAgaWYgKGNhbmRpZGF0ZS5zZHBNaWQpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnRyYW5zY2VpdmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIGlmICh0aGlzLnRyYW5zY2VpdmVyc1tpXS5taWQgPT09IGNhbmRpZGF0ZS5zZHBNaWQpIHtcbiAgICAgICAgICAgIHNkcE1MaW5lSW5kZXggPSBpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICB2YXIgdHJhbnNjZWl2ZXIgPSB0aGlzLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XTtcbiAgICAgIGlmICh0cmFuc2NlaXZlcikge1xuICAgICAgICBpZiAodHJhbnNjZWl2ZXIuaXNEYXRhY2hhbm5lbCkge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgY2FuZCA9IE9iamVjdC5rZXlzKGNhbmRpZGF0ZS5jYW5kaWRhdGUpLmxlbmd0aCA+IDAgP1xuICAgICAgICAgICAgU0RQVXRpbHMucGFyc2VDYW5kaWRhdGUoY2FuZGlkYXRlLmNhbmRpZGF0ZSkgOiB7fTtcbiAgICAgICAgLy8gSWdub3JlIENocm9tZSdzIGludmFsaWQgY2FuZGlkYXRlcyBzaW5jZSBFZGdlIGRvZXMgbm90IGxpa2UgdGhlbS5cbiAgICAgICAgaWYgKGNhbmQucHJvdG9jb2wgPT09ICd0Y3AnICYmIChjYW5kLnBvcnQgPT09IDAgfHwgY2FuZC5wb3J0ID09PSA5KSkge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBJZ25vcmUgUlRDUCBjYW5kaWRhdGVzLCB3ZSBhc3N1bWUgUlRDUC1NVVguXG4gICAgICAgIGlmIChjYW5kLmNvbXBvbmVudCAmJiBjYW5kLmNvbXBvbmVudCAhPT0gMSkge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgICAvLyB3aGVuIHVzaW5nIGJ1bmRsZSwgYXZvaWQgYWRkaW5nIGNhbmRpZGF0ZXMgdG8gdGhlIHdyb25nXG4gICAgICAgIC8vIGljZSB0cmFuc3BvcnQuIEFuZCBhdm9pZCBhZGRpbmcgY2FuZGlkYXRlcyBhZGRlZCBpbiB0aGUgU0RQLlxuICAgICAgICBpZiAoc2RwTUxpbmVJbmRleCA9PT0gMCB8fCAoc2RwTUxpbmVJbmRleCA+IDAgJiZcbiAgICAgICAgICAgIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydCAhPT0gdGhpcy50cmFuc2NlaXZlcnNbMF0uaWNlVHJhbnNwb3J0KSkge1xuICAgICAgICAgIGlmICghbWF5YmVBZGRDYW5kaWRhdGUodHJhbnNjZWl2ZXIuaWNlVHJhbnNwb3J0LCBjYW5kKSkge1xuICAgICAgICAgICAgZXJyID0gbmV3IEVycm9yKCdDYW4gbm90IGFkZCBJQ0UgY2FuZGlkYXRlJyk7XG4gICAgICAgICAgICBlcnIubmFtZSA9ICdPcGVyYXRpb25FcnJvcic7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFlcnIpIHtcbiAgICAgICAgICAvLyB1cGRhdGUgdGhlIHJlbW90ZURlc2NyaXB0aW9uLlxuICAgICAgICAgIHZhciBjYW5kaWRhdGVTdHJpbmcgPSBjYW5kaWRhdGUuY2FuZGlkYXRlLnRyaW0oKTtcbiAgICAgICAgICBpZiAoY2FuZGlkYXRlU3RyaW5nLmluZGV4T2YoJ2E9JykgPT09IDApIHtcbiAgICAgICAgICAgIGNhbmRpZGF0ZVN0cmluZyA9IGNhbmRpZGF0ZVN0cmluZy5zdWJzdHIoMik7XG4gICAgICAgICAgfVxuICAgICAgICAgIHNlY3Rpb25zID0gU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyh0aGlzLnJlbW90ZURlc2NyaXB0aW9uLnNkcCk7XG4gICAgICAgICAgc2VjdGlvbnNbc2RwTUxpbmVJbmRleCArIDFdICs9ICdhPScgK1xuICAgICAgICAgICAgICAoY2FuZC50eXBlID8gY2FuZGlkYXRlU3RyaW5nIDogJ2VuZC1vZi1jYW5kaWRhdGVzJylcbiAgICAgICAgICAgICAgKyAnXFxyXFxuJztcbiAgICAgICAgICB0aGlzLnJlbW90ZURlc2NyaXB0aW9uLnNkcCA9IHNlY3Rpb25zLmpvaW4oJycpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlcnIgPSBuZXcgRXJyb3IoJ0NhbiBub3QgYWRkIElDRSBjYW5kaWRhdGUnKTtcbiAgICAgICAgZXJyLm5hbWUgPSAnT3BlcmF0aW9uRXJyb3InO1xuICAgICAgfVxuICAgIH1cbiAgICB2YXIgYXJncyA9IGFyZ3VtZW50cztcbiAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICBpZiAoZXJyKSB7XG4gICAgICAgIGlmIChhcmdzLmxlbmd0aCA+IDIgJiYgdHlwZW9mIGFyZ3NbMl0gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICBhcmdzWzJdLmFwcGx5KG51bGwsIFtlcnJdKTtcbiAgICAgICAgfVxuICAgICAgICByZWplY3QoZXJyKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChhcmdzLmxlbmd0aCA+IDEgJiYgdHlwZW9mIGFyZ3NbMV0gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICBhcmdzWzFdLmFwcGx5KG51bGwpO1xuICAgICAgICB9XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuZ2V0U3RhdHMgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgcHJvbWlzZXMgPSBbXTtcbiAgICB0aGlzLnRyYW5zY2VpdmVycy5mb3JFYWNoKGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICBbJ3J0cFNlbmRlcicsICdydHBSZWNlaXZlcicsICdpY2VHYXRoZXJlcicsICdpY2VUcmFuc3BvcnQnLFxuICAgICAgICAgICdkdGxzVHJhbnNwb3J0J10uZm9yRWFjaChmdW5jdGlvbihtZXRob2QpIHtcbiAgICAgICAgICAgIGlmICh0cmFuc2NlaXZlclttZXRob2RdKSB7XG4gICAgICAgICAgICAgIHByb21pc2VzLnB1c2godHJhbnNjZWl2ZXJbbWV0aG9kXS5nZXRTdGF0cygpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICB9KTtcbiAgICB2YXIgY2IgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiB0eXBlb2YgYXJndW1lbnRzWzFdID09PSAnZnVuY3Rpb24nICYmXG4gICAgICAgIGFyZ3VtZW50c1sxXTtcbiAgICB2YXIgZml4U3RhdHNUeXBlID0gZnVuY3Rpb24oc3RhdCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaW5ib3VuZHJ0cDogJ2luYm91bmQtcnRwJyxcbiAgICAgICAgb3V0Ym91bmRydHA6ICdvdXRib3VuZC1ydHAnLFxuICAgICAgICBjYW5kaWRhdGVwYWlyOiAnY2FuZGlkYXRlLXBhaXInLFxuICAgICAgICBsb2NhbGNhbmRpZGF0ZTogJ2xvY2FsLWNhbmRpZGF0ZScsXG4gICAgICAgIHJlbW90ZWNhbmRpZGF0ZTogJ3JlbW90ZS1jYW5kaWRhdGUnXG4gICAgICB9W3N0YXQudHlwZV0gfHwgc3RhdC50eXBlO1xuICAgIH07XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUpIHtcbiAgICAgIC8vIHNoaW0gZ2V0U3RhdHMgd2l0aCBtYXBsaWtlIHN1cHBvcnRcbiAgICAgIHZhciByZXN1bHRzID0gbmV3IE1hcCgpO1xuICAgICAgUHJvbWlzZS5hbGwocHJvbWlzZXMpLnRoZW4oZnVuY3Rpb24ocmVzKSB7XG4gICAgICAgIHJlcy5mb3JFYWNoKGZ1bmN0aW9uKHJlc3VsdCkge1xuICAgICAgICAgIE9iamVjdC5rZXlzKHJlc3VsdCkuZm9yRWFjaChmdW5jdGlvbihpZCkge1xuICAgICAgICAgICAgcmVzdWx0W2lkXS50eXBlID0gZml4U3RhdHNUeXBlKHJlc3VsdFtpZF0pO1xuICAgICAgICAgICAgcmVzdWx0cy5zZXQoaWQsIHJlc3VsdFtpZF0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGNiKSB7XG4gICAgICAgICAgY2IuYXBwbHkobnVsbCwgcmVzdWx0cyk7XG4gICAgICAgIH1cbiAgICAgICAgcmVzb2x2ZShyZXN1bHRzKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9O1xuICByZXR1cm4gUlRDUGVlckNvbm5lY3Rpb247XG59O1xuIiwidmFyIGdyYW1tYXIgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgdjogW3tcbiAgICAgIG5hbWU6ICd2ZXJzaW9uJyxcbiAgICAgIHJlZzogL14oXFxkKikkL1xuICB9XSxcbiAgbzogW3sgLy9vPS0gMjA1MTggMCBJTiBJUDQgMjAzLjAuMTEzLjFcbiAgICAvLyBOQjogc2Vzc2lvbklkIHdpbGwgYmUgYSBTdHJpbmcgaW4gbW9zdCBjYXNlcyBiZWNhdXNlIGl0IGlzIGh1Z2VcbiAgICBuYW1lOiAnb3JpZ2luJyxcbiAgICByZWc6IC9eKFxcUyopIChcXGQqKSAoXFxkKikgKFxcUyopIElQKFxcZCkgKFxcUyopLyxcbiAgICBuYW1lczogWyd1c2VybmFtZScsICdzZXNzaW9uSWQnLCAnc2Vzc2lvblZlcnNpb24nLCAnbmV0VHlwZScsICdpcFZlcicsICdhZGRyZXNzJ10sXG4gICAgZm9ybWF0OiBcIiVzICVzICVkICVzIElQJWQgJXNcIlxuICB9XSxcbiAgLy8gZGVmYXVsdCBwYXJzaW5nIG9mIHRoZXNlIG9ubHkgKHRob3VnaCBzb21lIG9mIHRoZXNlIGZlZWwgb3V0ZGF0ZWQpXG4gIHM6IFt7IG5hbWU6ICduYW1lJyB9XSxcbiAgaTogW3sgbmFtZTogJ2Rlc2NyaXB0aW9uJyB9XSxcbiAgdTogW3sgbmFtZTogJ3VyaScgfV0sXG4gIGU6IFt7IG5hbWU6ICdlbWFpbCcgfV0sXG4gIHA6IFt7IG5hbWU6ICdwaG9uZScgfV0sXG4gIHo6IFt7IG5hbWU6ICd0aW1lem9uZXMnIH1dLCAvLyBUT0RPOiB0aGlzIG9uZSBjYW4gYWN0dWFsbHkgYmUgcGFyc2VkIHByb3Blcmx5Li5cbiAgcjogW3sgbmFtZTogJ3JlcGVhdHMnIH1dLCAgIC8vIFRPRE86IHRoaXMgb25lIGNhbiBhbHNvIGJlIHBhcnNlZCBwcm9wZXJseVxuICAvL2s6IFt7fV0sIC8vIG91dGRhdGVkIHRoaW5nIGlnbm9yZWRcbiAgdDogW3sgLy90PTAgMFxuICAgIG5hbWU6ICd0aW1pbmcnLFxuICAgIHJlZzogL14oXFxkKikgKFxcZCopLyxcbiAgICBuYW1lczogWydzdGFydCcsICdzdG9wJ10sXG4gICAgZm9ybWF0OiBcIiVkICVkXCJcbiAgfV0sXG4gIGM6IFt7IC8vYz1JTiBJUDQgMTAuNDcuMTk3LjI2XG4gICAgICBuYW1lOiAnY29ubmVjdGlvbicsXG4gICAgICByZWc6IC9eSU4gSVAoXFxkKSAoXFxTKikvLFxuICAgICAgbmFtZXM6IFsndmVyc2lvbicsICdpcCddLFxuICAgICAgZm9ybWF0OiBcIklOIElQJWQgJXNcIlxuICB9XSxcbiAgYjogW3sgLy9iPUFTOjQwMDBcbiAgICAgIHB1c2g6ICdiYW5kd2lkdGgnLFxuICAgICAgcmVnOiAvXihUSUFTfEFTfENUfFJSfFJTKTooXFxkKikvLFxuICAgICAgbmFtZXM6IFsndHlwZScsICdsaW1pdCddLFxuICAgICAgZm9ybWF0OiBcIiVzOiVzXCJcbiAgfV0sXG4gIG06IFt7IC8vbT12aWRlbyA1MTc0NCBSVFAvQVZQIDEyNiA5NyA5OCAzNCAzMVxuICAgICAgLy8gTkI6IHNwZWNpYWwgLSBwdXNoZXMgdG8gc2Vzc2lvblxuICAgICAgLy8gVE9ETzogcnRwL2ZtdHAgc2hvdWxkIGJlIGZpbHRlcmVkIGJ5IHRoZSBwYXlsb2FkcyBmb3VuZCBoZXJlP1xuICAgICAgcmVnOiAvXihcXHcqKSAoXFxkKikgKFtcXHdcXC9dKikoPzogKC4qKSk/LyxcbiAgICAgIG5hbWVzOiBbJ3R5cGUnLCAncG9ydCcsICdwcm90b2NvbCcsICdwYXlsb2FkcyddLFxuICAgICAgZm9ybWF0OiBcIiVzICVkICVzICVzXCJcbiAgfV0sXG4gIGE6IFtcbiAgICB7IC8vYT1ydHBtYXA6MTEwIG9wdXMvNDgwMDAvMlxuICAgICAgcHVzaDogJ3J0cCcsXG4gICAgICByZWc6IC9ecnRwbWFwOihcXGQqKSAoW1xcd1xcLV0qKSg/OlxccypcXC8oXFxkKikoPzpcXHMqXFwvKFxcUyopKT8pPy8sXG4gICAgICBuYW1lczogWydwYXlsb2FkJywgJ2NvZGVjJywgJ3JhdGUnLCAnZW5jb2RpbmcnXSxcbiAgICAgIGZvcm1hdDogZnVuY3Rpb24gKG8pIHtcbiAgICAgICAgcmV0dXJuIChvLmVuY29kaW5nKSA/XG4gICAgICAgICAgXCJydHBtYXA6JWQgJXMvJXMvJXNcIjpcbiAgICAgICAgICBvLnJhdGUgP1xuICAgICAgICAgIFwicnRwbWFwOiVkICVzLyVzXCI6XG4gICAgICAgICAgXCJydHBtYXA6JWQgJXNcIjtcbiAgICAgIH1cbiAgICB9LFxuICAgIHtcbiAgICAgIC8vYT1mbXRwOjEwOCBwcm9maWxlLWxldmVsLWlkPTI0O29iamVjdD0yMztiaXRyYXRlPTY0MDAwXG4gICAgICAvL2E9Zm10cDoxMTEgbWlucHRpbWU9MTA7IHVzZWluYmFuZGZlYz0xXG4gICAgICBwdXNoOiAnZm10cCcsXG4gICAgICByZWc6IC9eZm10cDooXFxkKikgKFtcXFN8IF0qKS8sXG4gICAgICBuYW1lczogWydwYXlsb2FkJywgJ2NvbmZpZyddLFxuICAgICAgZm9ybWF0OiBcImZtdHA6JWQgJXNcIlxuICAgIH0sXG4gICAgeyAvL2E9Y29udHJvbDpzdHJlYW1pZD0wXG4gICAgICAgIG5hbWU6ICdjb250cm9sJyxcbiAgICAgICAgcmVnOiAvXmNvbnRyb2w6KC4qKS8sXG4gICAgICAgIGZvcm1hdDogXCJjb250cm9sOiVzXCJcbiAgICB9LFxuICAgIHsgLy9hPXJ0Y3A6NjUxNzkgSU4gSVA0IDE5My44NC43Ny4xOTRcbiAgICAgIG5hbWU6ICdydGNwJyxcbiAgICAgIHJlZzogL15ydGNwOihcXGQqKSg/OiAoXFxTKikgSVAoXFxkKSAoXFxTKikpPy8sXG4gICAgICBuYW1lczogWydwb3J0JywgJ25ldFR5cGUnLCAnaXBWZXInLCAnYWRkcmVzcyddLFxuICAgICAgZm9ybWF0OiBmdW5jdGlvbiAobykge1xuICAgICAgICByZXR1cm4gKG8uYWRkcmVzcyAhPSBudWxsKSA/XG4gICAgICAgICAgXCJydGNwOiVkICVzIElQJWQgJXNcIjpcbiAgICAgICAgICBcInJ0Y3A6JWRcIjtcbiAgICAgIH1cbiAgICB9LFxuICAgIHsgLy9hPXJ0Y3AtZmI6OTggdHJyLWludCAxMDBcbiAgICAgIHB1c2g6ICdydGNwRmJUcnJJbnQnLFxuICAgICAgcmVnOiAvXnJ0Y3AtZmI6KFxcKnxcXGQqKSB0cnItaW50IChcXGQqKS8sXG4gICAgICBuYW1lczogWydwYXlsb2FkJywgJ3ZhbHVlJ10sXG4gICAgICBmb3JtYXQ6IFwicnRjcC1mYjolZCB0cnItaW50ICVkXCJcbiAgICB9LFxuICAgIHsgLy9hPXJ0Y3AtZmI6OTggbmFjayBycHNpXG4gICAgICBwdXNoOiAncnRjcEZiJyxcbiAgICAgIHJlZzogL15ydGNwLWZiOihcXCp8XFxkKikgKFtcXHctX10qKSg/OiAoW1xcdy1fXSopKT8vLFxuICAgICAgbmFtZXM6IFsncGF5bG9hZCcsICd0eXBlJywgJ3N1YnR5cGUnXSxcbiAgICAgIGZvcm1hdDogZnVuY3Rpb24gKG8pIHtcbiAgICAgICAgcmV0dXJuIChvLnN1YnR5cGUgIT0gbnVsbCkgP1xuICAgICAgICAgIFwicnRjcC1mYjolcyAlcyAlc1wiOlxuICAgICAgICAgIFwicnRjcC1mYjolcyAlc1wiO1xuICAgICAgfVxuICAgIH0sXG4gICAgeyAvL2E9ZXh0bWFwOjIgdXJuOmlldGY6cGFyYW1zOnJ0cC1oZHJleHQ6dG9mZnNldFxuICAgICAgLy9hPWV4dG1hcDoxL3JlY3Zvbmx5IFVSSS1ncHMtc3RyaW5nXG4gICAgICBwdXNoOiAnZXh0JyxcbiAgICAgIHJlZzogL15leHRtYXA6KFtcXHdfXFwvXSopIChcXFMqKSg/OiAoXFxTKikpPy8sXG4gICAgICBuYW1lczogWyd2YWx1ZScsICd1cmknLCAnY29uZmlnJ10sIC8vIHZhbHVlIG1heSBpbmNsdWRlIFwiL2RpcmVjdGlvblwiIHN1ZmZpeFxuICAgICAgZm9ybWF0OiBmdW5jdGlvbiAobykge1xuICAgICAgICByZXR1cm4gKG8uY29uZmlnICE9IG51bGwpID9cbiAgICAgICAgICBcImV4dG1hcDolcyAlcyAlc1wiOlxuICAgICAgICAgIFwiZXh0bWFwOiVzICVzXCI7XG4gICAgICB9XG4gICAgfSxcbiAgICB7XG4gICAgICAvL2E9Y3J5cHRvOjEgQUVTX0NNXzEyOF9ITUFDX1NIQTFfODAgaW5saW5lOlBTMXVRQ1ZlZUNGQ2FuVm1jamtwUHl3ak5XaGNZRDBtWFh0eGFWQlJ8Ml4yMHwxOjMyXG4gICAgICBwdXNoOiAnY3J5cHRvJyxcbiAgICAgIHJlZzogL15jcnlwdG86KFxcZCopIChbXFx3X10qKSAoXFxTKikoPzogKFxcUyopKT8vLFxuICAgICAgbmFtZXM6IFsnaWQnLCAnc3VpdGUnLCAnY29uZmlnJywgJ3Nlc3Npb25Db25maWcnXSxcbiAgICAgIGZvcm1hdDogZnVuY3Rpb24gKG8pIHtcbiAgICAgICAgcmV0dXJuIChvLnNlc3Npb25Db25maWcgIT0gbnVsbCkgP1xuICAgICAgICAgIFwiY3J5cHRvOiVkICVzICVzICVzXCI6XG4gICAgICAgICAgXCJjcnlwdG86JWQgJXMgJXNcIjtcbiAgICAgIH1cbiAgICB9LFxuICAgIHsgLy9hPXNldHVwOmFjdHBhc3NcbiAgICAgIG5hbWU6ICdzZXR1cCcsXG4gICAgICByZWc6IC9ec2V0dXA6KFxcdyopLyxcbiAgICAgIGZvcm1hdDogXCJzZXR1cDolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1taWQ6MVxuICAgICAgbmFtZTogJ21pZCcsXG4gICAgICByZWc6IC9ebWlkOihbXlxcc10qKS8sXG4gICAgICBmb3JtYXQ6IFwibWlkOiVzXCJcbiAgICB9LFxuICAgIHsgLy9hPW1zaWQ6MGM4YjA2NGQtZDgwNy00M2I0LWI0MzQtZjkyYTg4OWQ4NTg3IDk4MTc4Njg1LWQ0MDktNDZlMC04ZTE2LTdlZjBkYjBkYjY0YVxuICAgICAgbmFtZTogJ21zaWQnLFxuICAgICAgcmVnOiAvXm1zaWQ6KC4qKS8sXG4gICAgICBmb3JtYXQ6IFwibXNpZDolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1wdGltZToyMFxuICAgICAgbmFtZTogJ3B0aW1lJyxcbiAgICAgIHJlZzogL15wdGltZTooXFxkKikvLFxuICAgICAgZm9ybWF0OiBcInB0aW1lOiVkXCJcbiAgICB9LFxuICAgIHsgLy9hPW1heHB0aW1lOjYwXG4gICAgICBuYW1lOiAnbWF4cHRpbWUnLFxuICAgICAgcmVnOiAvXm1heHB0aW1lOihcXGQqKS8sXG4gICAgICBmb3JtYXQ6IFwibWF4cHRpbWU6JWRcIlxuICAgIH0sXG4gICAgeyAvL2E9c2VuZHJlY3ZcbiAgICAgIG5hbWU6ICdkaXJlY3Rpb24nLFxuICAgICAgcmVnOiAvXihzZW5kcmVjdnxyZWN2b25seXxzZW5kb25seXxpbmFjdGl2ZSkvXG4gICAgfSxcbiAgICB7IC8vYT1pY2UtbGl0ZVxuICAgICAgbmFtZTogJ2ljZWxpdGUnLFxuICAgICAgcmVnOiAvXihpY2UtbGl0ZSkvXG4gICAgfSxcbiAgICB7IC8vYT1pY2UtdWZyYWc6RjdnSVxuICAgICAgbmFtZTogJ2ljZVVmcmFnJyxcbiAgICAgIHJlZzogL15pY2UtdWZyYWc6KFxcUyopLyxcbiAgICAgIGZvcm1hdDogXCJpY2UtdWZyYWc6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9aWNlLXB3ZDp4OWNtbC9ZemljaFYyK1hsaGlNdThnXG4gICAgICBuYW1lOiAnaWNlUHdkJyxcbiAgICAgIHJlZzogL15pY2UtcHdkOihcXFMqKS8sXG4gICAgICBmb3JtYXQ6IFwiaWNlLXB3ZDolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1maW5nZXJwcmludDpTSEEtMSAwMDoxMToyMjozMzo0NDo1NTo2Njo3Nzo4ODo5OTpBQTpCQjpDQzpERDpFRTpGRjowMDoxMToyMjozM1xuICAgICAgbmFtZTogJ2ZpbmdlcnByaW50JyxcbiAgICAgIHJlZzogL15maW5nZXJwcmludDooXFxTKikgKFxcUyopLyxcbiAgICAgIG5hbWVzOiBbJ3R5cGUnLCAnaGFzaCddLFxuICAgICAgZm9ybWF0OiBcImZpbmdlcnByaW50OiVzICVzXCJcbiAgICB9LFxuICAgIHtcbiAgICAgIC8vYT1jYW5kaWRhdGU6MCAxIFVEUCAyMTEzNjY3MzI3IDIwMy4wLjExMy4xIDU0NDAwIHR5cCBob3N0XG4gICAgICAvL2E9Y2FuZGlkYXRlOjExNjI4NzUwODEgMSB1ZHAgMjExMzkzNzE1MSAxOTIuMTY4LjM0Ljc1IDYwMDE3IHR5cCBob3N0IGdlbmVyYXRpb24gMFxuICAgICAgLy9hPWNhbmRpZGF0ZTozMjg5OTEyOTU3IDIgdWRwIDE4NDU1MDE2OTUgMTkzLjg0Ljc3LjE5NCA2MDAxNyB0eXAgc3JmbHggcmFkZHIgMTkyLjE2OC4zNC43NSBycG9ydCA2MDAxNyBnZW5lcmF0aW9uIDBcbiAgICAgIC8vYT1jYW5kaWRhdGU6MjI5ODE1NjIwIDEgdGNwIDE1MTgyODA0NDcgMTkyLjE2OC4xNTAuMTkgNjAwMTcgdHlwIGhvc3QgdGNwdHlwZSBhY3RpdmUgZ2VuZXJhdGlvbiAwXG4gICAgICAvL2E9Y2FuZGlkYXRlOjMyODk5MTI5NTcgMiB0Y3AgMTg0NTUwMTY5NSAxOTMuODQuNzcuMTk0IDYwMDE3IHR5cCBzcmZseCByYWRkciAxOTIuMTY4LjM0Ljc1IHJwb3J0IDYwMDE3IHRjcHR5cGUgcGFzc2l2ZSBnZW5lcmF0aW9uIDBcbiAgICAgIHB1c2g6J2NhbmRpZGF0ZXMnLFxuICAgICAgcmVnOiAvXmNhbmRpZGF0ZTooXFxTKikgKFxcZCopIChcXFMqKSAoXFxkKikgKFxcUyopIChcXGQqKSB0eXAgKFxcUyopKD86IHJhZGRyIChcXFMqKSBycG9ydCAoXFxkKikpPyg/OiB0Y3B0eXBlIChcXFMqKSk/KD86IGdlbmVyYXRpb24gKFxcZCopKT8vLFxuICAgICAgbmFtZXM6IFsnZm91bmRhdGlvbicsICdjb21wb25lbnQnLCAndHJhbnNwb3J0JywgJ3ByaW9yaXR5JywgJ2lwJywgJ3BvcnQnLCAndHlwZScsICdyYWRkcicsICdycG9ydCcsICd0Y3B0eXBlJywgJ2dlbmVyYXRpb24nXSxcbiAgICAgIGZvcm1hdDogZnVuY3Rpb24gKG8pIHtcbiAgICAgICAgdmFyIHN0ciA9IFwiY2FuZGlkYXRlOiVzICVkICVzICVkICVzICVkIHR5cCAlc1wiO1xuXG4gICAgICAgIHN0ciArPSAoby5yYWRkciAhPSBudWxsKSA/IFwiIHJhZGRyICVzIHJwb3J0ICVkXCIgOiBcIiV2JXZcIjtcblxuICAgICAgICAvLyBOQjogY2FuZGlkYXRlIGhhcyB0aHJlZSBvcHRpb25hbCBjaHVua3MsIHNvICV2b2lkIG1pZGRsZXMgb25lIGlmIGl0J3MgbWlzc2luZ1xuICAgICAgICBzdHIgKz0gKG8udGNwdHlwZSAhPSBudWxsKSA/IFwiIHRjcHR5cGUgJXNcIiA6IFwiJXZcIjtcblxuICAgICAgICBpZiAoby5nZW5lcmF0aW9uICE9IG51bGwpIHtcbiAgICAgICAgICBzdHIgKz0gXCIgZ2VuZXJhdGlvbiAlZFwiO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzdHI7XG4gICAgICB9XG4gICAgfSxcbiAgICB7IC8vYT1lbmQtb2YtY2FuZGlkYXRlcyAoa2VlcCBhZnRlciB0aGUgY2FuZGlkYXRlcyBsaW5lIGZvciByZWFkYWJpbGl0eSlcbiAgICAgIG5hbWU6ICdlbmRPZkNhbmRpZGF0ZXMnLFxuICAgICAgcmVnOiAvXihlbmQtb2YtY2FuZGlkYXRlcykvXG4gICAgfSxcbiAgICB7IC8vYT1yZW1vdGUtY2FuZGlkYXRlczoxIDIwMy4wLjExMy4xIDU0NDAwIDIgMjAzLjAuMTEzLjEgNTQ0MDEgLi4uXG4gICAgICBuYW1lOiAncmVtb3RlQ2FuZGlkYXRlcycsXG4gICAgICByZWc6IC9ecmVtb3RlLWNhbmRpZGF0ZXM6KC4qKS8sXG4gICAgICBmb3JtYXQ6IFwicmVtb3RlLWNhbmRpZGF0ZXM6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9aWNlLW9wdGlvbnM6Z29vZ2xlLWljZVxuICAgICAgbmFtZTogJ2ljZU9wdGlvbnMnLFxuICAgICAgcmVnOiAvXmljZS1vcHRpb25zOihcXFMqKS8sXG4gICAgICBmb3JtYXQ6IFwiaWNlLW9wdGlvbnM6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9c3NyYzoyNTY2MTA3NTY5IGNuYW1lOnQ5WVU4TTFVeFRGOFkxQTFcbiAgICAgIHB1c2g6IFwic3NyY3NcIixcbiAgICAgIHJlZzogL15zc3JjOihcXGQqKSAoW1xcd19dKik6KC4qKS8sXG4gICAgICBuYW1lczogWydpZCcsICdhdHRyaWJ1dGUnLCAndmFsdWUnXSxcbiAgICAgIGZvcm1hdDogXCJzc3JjOiVkICVzOiVzXCJcbiAgICB9LFxuICAgIHsgLy9hPXNzcmMtZ3JvdXA6RkVDIDEgMlxuICAgICAgcHVzaDogXCJzc3JjR3JvdXBzXCIsXG4gICAgICByZWc6IC9ec3NyYy1ncm91cDooXFx3KikgKC4qKS8sXG4gICAgICBuYW1lczogWydzZW1hbnRpY3MnLCAnc3NyY3MnXSxcbiAgICAgIGZvcm1hdDogXCJzc3JjLWdyb3VwOiVzICVzXCJcbiAgICB9LFxuICAgIHsgLy9hPW1zaWQtc2VtYW50aWM6IFdNUyBKdmxhbTVYM1NYMU9QNnBuMjB6V29ndmFLSno1SGpmOU9ubFZcbiAgICAgIG5hbWU6IFwibXNpZFNlbWFudGljXCIsXG4gICAgICByZWc6IC9ebXNpZC1zZW1hbnRpYzpcXHM/KFxcdyopIChcXFMqKS8sXG4gICAgICBuYW1lczogWydzZW1hbnRpYycsICd0b2tlbiddLFxuICAgICAgZm9ybWF0OiBcIm1zaWQtc2VtYW50aWM6ICVzICVzXCIgLy8gc3BhY2UgYWZ0ZXIgXCI6XCIgaXMgbm90IGFjY2lkZW50YWxcbiAgICB9LFxuICAgIHsgLy9hPWdyb3VwOkJVTkRMRSBhdWRpbyB2aWRlb1xuICAgICAgcHVzaDogJ2dyb3VwcycsXG4gICAgICByZWc6IC9eZ3JvdXA6KFxcdyopICguKikvLFxuICAgICAgbmFtZXM6IFsndHlwZScsICdtaWRzJ10sXG4gICAgICBmb3JtYXQ6IFwiZ3JvdXA6JXMgJXNcIlxuICAgIH0sXG4gICAgeyAvL2E9cnRjcC1tdXhcbiAgICAgIG5hbWU6ICdydGNwTXV4JyxcbiAgICAgIHJlZzogL14ocnRjcC1tdXgpL1xuICAgIH0sXG4gICAgeyAvL2E9cnRjcC1yc2l6ZVxuICAgICAgbmFtZTogJ3J0Y3BSc2l6ZScsXG4gICAgICByZWc6IC9eKHJ0Y3AtcnNpemUpL1xuICAgIH0sXG4gICAgeyAvLyBhbnkgYT0gdGhhdCB3ZSBkb24ndCB1bmRlcnN0YW5kIGlzIGtlcHRzIHZlcmJhdGltIG9uIG1lZGlhLmludmFsaWRcbiAgICAgIHB1c2g6ICdpbnZhbGlkJyxcbiAgICAgIG5hbWVzOiBbXCJ2YWx1ZVwiXVxuICAgIH1cbiAgXVxufTtcblxuLy8gc2V0IHNlbnNpYmxlIGRlZmF1bHRzIHRvIGF2b2lkIHBvbGx1dGluZyB0aGUgZ3JhbW1hciB3aXRoIGJvcmluZyBkZXRhaWxzXG5PYmplY3Qua2V5cyhncmFtbWFyKS5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHtcbiAgdmFyIG9ianMgPSBncmFtbWFyW2tleV07XG4gIG9ianMuZm9yRWFjaChmdW5jdGlvbiAob2JqKSB7XG4gICAgaWYgKCFvYmoucmVnKSB7XG4gICAgICBvYmoucmVnID0gLyguKikvO1xuICAgIH1cbiAgICBpZiAoIW9iai5mb3JtYXQpIHtcbiAgICAgIG9iai5mb3JtYXQgPSBcIiVzXCI7XG4gICAgfVxuICB9KTtcbn0pO1xuIiwidmFyIHBhcnNlciA9IHJlcXVpcmUoJy4vcGFyc2VyJyk7XG52YXIgd3JpdGVyID0gcmVxdWlyZSgnLi93cml0ZXInKTtcblxuZXhwb3J0cy53cml0ZSA9IHdyaXRlcjtcbmV4cG9ydHMucGFyc2UgPSBwYXJzZXIucGFyc2U7XG5leHBvcnRzLnBhcnNlRm10cENvbmZpZyA9IHBhcnNlci5wYXJzZUZtdHBDb25maWc7XG5leHBvcnRzLnBhcnNlUGF5bG9hZHMgPSBwYXJzZXIucGFyc2VQYXlsb2FkcztcbmV4cG9ydHMucGFyc2VSZW1vdGVDYW5kaWRhdGVzID0gcGFyc2VyLnBhcnNlUmVtb3RlQ2FuZGlkYXRlcztcbiIsInZhciB0b0ludElmSW50ID0gZnVuY3Rpb24gKHYpIHtcbiAgcmV0dXJuIFN0cmluZyhOdW1iZXIodikpID09PSB2ID8gTnVtYmVyKHYpIDogdjtcbn07XG5cbnZhciBhdHRhY2hQcm9wZXJ0aWVzID0gZnVuY3Rpb24gKG1hdGNoLCBsb2NhdGlvbiwgbmFtZXMsIHJhd05hbWUpIHtcbiAgaWYgKHJhd05hbWUgJiYgIW5hbWVzKSB7XG4gICAgbG9jYXRpb25bcmF3TmFtZV0gPSB0b0ludElmSW50KG1hdGNoWzFdKTtcbiAgfVxuICBlbHNlIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5hbWVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICBpZiAobWF0Y2hbaSsxXSAhPSBudWxsKSB7XG4gICAgICAgIGxvY2F0aW9uW25hbWVzW2ldXSA9IHRvSW50SWZJbnQobWF0Y2hbaSsxXSk7XG4gICAgICB9XG4gICAgfVxuICB9XG59O1xuXG52YXIgcGFyc2VSZWcgPSBmdW5jdGlvbiAob2JqLCBsb2NhdGlvbiwgY29udGVudCkge1xuICB2YXIgbmVlZHNCbGFuayA9IG9iai5uYW1lICYmIG9iai5uYW1lcztcbiAgaWYgKG9iai5wdXNoICYmICFsb2NhdGlvbltvYmoucHVzaF0pIHtcbiAgICBsb2NhdGlvbltvYmoucHVzaF0gPSBbXTtcbiAgfVxuICBlbHNlIGlmIChuZWVkc0JsYW5rICYmICFsb2NhdGlvbltvYmoubmFtZV0pIHtcbiAgICBsb2NhdGlvbltvYmoubmFtZV0gPSB7fTtcbiAgfVxuICB2YXIga2V5TG9jYXRpb24gPSBvYmoucHVzaCA/XG4gICAge30gOiAgLy8gYmxhbmsgb2JqZWN0IHRoYXQgd2lsbCBiZSBwdXNoZWRcbiAgICBuZWVkc0JsYW5rID8gbG9jYXRpb25bb2JqLm5hbWVdIDogbG9jYXRpb247IC8vIG90aGVyd2lzZSwgbmFtZWQgbG9jYXRpb24gb3Igcm9vdFxuXG4gIGF0dGFjaFByb3BlcnRpZXMoY29udGVudC5tYXRjaChvYmoucmVnKSwga2V5TG9jYXRpb24sIG9iai5uYW1lcywgb2JqLm5hbWUpO1xuXG4gIGlmIChvYmoucHVzaCkge1xuICAgIGxvY2F0aW9uW29iai5wdXNoXS5wdXNoKGtleUxvY2F0aW9uKTtcbiAgfVxufTtcblxudmFyIGdyYW1tYXIgPSByZXF1aXJlKCcuL2dyYW1tYXInKTtcbnZhciB2YWxpZExpbmUgPSBSZWdFeHAucHJvdG90eXBlLnRlc3QuYmluZCgvXihbYS16XSk9KC4qKS8pO1xuXG5leHBvcnRzLnBhcnNlID0gZnVuY3Rpb24gKHNkcCkge1xuICB2YXIgc2Vzc2lvbiA9IHt9XG4gICAgLCBtZWRpYSA9IFtdXG4gICAgLCBsb2NhdGlvbiA9IHNlc3Npb247IC8vIHBvaW50cyBhdCB3aGVyZSBwcm9wZXJ0aWVzIGdvIHVuZGVyIChvbmUgb2YgdGhlIGFib3ZlKVxuXG4gIC8vIHBhcnNlIGxpbmVzIHdlIHVuZGVyc3RhbmRcbiAgc2RwLnNwbGl0KC8oXFxyXFxufFxccnxcXG4pLykuZmlsdGVyKHZhbGlkTGluZSkuZm9yRWFjaChmdW5jdGlvbiAobCkge1xuICAgIHZhciB0eXBlID0gbFswXTtcbiAgICB2YXIgY29udGVudCA9IGwuc2xpY2UoMik7XG4gICAgaWYgKHR5cGUgPT09ICdtJykge1xuICAgICAgbWVkaWEucHVzaCh7cnRwOiBbXSwgZm10cDogW119KTtcbiAgICAgIGxvY2F0aW9uID0gbWVkaWFbbWVkaWEubGVuZ3RoLTFdOyAvLyBwb2ludCBhdCBsYXRlc3QgbWVkaWEgbGluZVxuICAgIH1cblxuICAgIGZvciAodmFyIGogPSAwOyBqIDwgKGdyYW1tYXJbdHlwZV0gfHwgW10pLmxlbmd0aDsgaiArPSAxKSB7XG4gICAgICB2YXIgb2JqID0gZ3JhbW1hclt0eXBlXVtqXTtcbiAgICAgIGlmIChvYmoucmVnLnRlc3QoY29udGVudCkpIHtcbiAgICAgICAgcmV0dXJuIHBhcnNlUmVnKG9iaiwgbG9jYXRpb24sIGNvbnRlbnQpO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgc2Vzc2lvbi5tZWRpYSA9IG1lZGlhOyAvLyBsaW5rIGl0IHVwXG4gIHJldHVybiBzZXNzaW9uO1xufTtcblxudmFyIGZtdHBSZWR1Y2VyID0gZnVuY3Rpb24gKGFjYywgZXhwcikge1xuICB2YXIgcyA9IGV4cHIuc3BsaXQoJz0nKTtcbiAgaWYgKHMubGVuZ3RoID09PSAyKSB7XG4gICAgYWNjW3NbMF1dID0gdG9JbnRJZkludChzWzFdKTtcbiAgfVxuICByZXR1cm4gYWNjO1xufTtcblxuZXhwb3J0cy5wYXJzZUZtdHBDb25maWcgPSBmdW5jdGlvbiAoc3RyKSB7XG4gIHJldHVybiBzdHIuc3BsaXQoL1xcO1xccz8vKS5yZWR1Y2UoZm10cFJlZHVjZXIsIHt9KTtcbn07XG5cbmV4cG9ydHMucGFyc2VQYXlsb2FkcyA9IGZ1bmN0aW9uIChzdHIpIHtcbiAgcmV0dXJuIHN0ci5zcGxpdCgnICcpLm1hcChOdW1iZXIpO1xufTtcblxuZXhwb3J0cy5wYXJzZVJlbW90ZUNhbmRpZGF0ZXMgPSBmdW5jdGlvbiAoc3RyKSB7XG4gIHZhciBjYW5kaWRhdGVzID0gW107XG4gIHZhciBwYXJ0cyA9IHN0ci5zcGxpdCgnICcpLm1hcCh0b0ludElmSW50KTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBwYXJ0cy5sZW5ndGg7IGkgKz0gMykge1xuICAgIGNhbmRpZGF0ZXMucHVzaCh7XG4gICAgICBjb21wb25lbnQ6IHBhcnRzW2ldLFxuICAgICAgaXA6IHBhcnRzW2kgKyAxXSxcbiAgICAgIHBvcnQ6IHBhcnRzW2kgKyAyXVxuICAgIH0pO1xuICB9XG4gIHJldHVybiBjYW5kaWRhdGVzO1xufTtcbiIsInZhciBncmFtbWFyID0gcmVxdWlyZSgnLi9ncmFtbWFyJyk7XG5cbi8vIGN1c3RvbWl6ZWQgdXRpbC5mb3JtYXQgLSBkaXNjYXJkcyBleGNlc3MgYXJndW1lbnRzIGFuZCBjYW4gdm9pZCBtaWRkbGUgb25lc1xudmFyIGZvcm1hdFJlZ0V4cCA9IC8lW3NkdiVdL2c7XG52YXIgZm9ybWF0ID0gZnVuY3Rpb24gKGZvcm1hdFN0cikge1xuICB2YXIgaSA9IDE7XG4gIHZhciBhcmdzID0gYXJndW1lbnRzO1xuICB2YXIgbGVuID0gYXJncy5sZW5ndGg7XG4gIHJldHVybiBmb3JtYXRTdHIucmVwbGFjZShmb3JtYXRSZWdFeHAsIGZ1bmN0aW9uICh4KSB7XG4gICAgaWYgKGkgPj0gbGVuKSB7XG4gICAgICByZXR1cm4geDsgLy8gbWlzc2luZyBhcmd1bWVudFxuICAgIH1cbiAgICB2YXIgYXJnID0gYXJnc1tpXTtcbiAgICBpICs9IDE7XG4gICAgc3dpdGNoICh4KSB7XG4gICAgICBjYXNlICclJSc6XG4gICAgICAgIHJldHVybiAnJSc7XG4gICAgICBjYXNlICclcyc6XG4gICAgICAgIHJldHVybiBTdHJpbmcoYXJnKTtcbiAgICAgIGNhc2UgJyVkJzpcbiAgICAgICAgcmV0dXJuIE51bWJlcihhcmcpO1xuICAgICAgY2FzZSAnJXYnOlxuICAgICAgICByZXR1cm4gJyc7XG4gICAgfVxuICB9KTtcbiAgLy8gTkI6IHdlIGRpc2NhcmQgZXhjZXNzIGFyZ3VtZW50cyAtIHRoZXkgYXJlIHR5cGljYWxseSB1bmRlZmluZWQgZnJvbSBtYWtlTGluZVxufTtcblxudmFyIG1ha2VMaW5lID0gZnVuY3Rpb24gKHR5cGUsIG9iaiwgbG9jYXRpb24pIHtcbiAgdmFyIHN0ciA9IG9iai5mb3JtYXQgaW5zdGFuY2VvZiBGdW5jdGlvbiA/XG4gICAgKG9iai5mb3JtYXQob2JqLnB1c2ggPyBsb2NhdGlvbiA6IGxvY2F0aW9uW29iai5uYW1lXSkpIDpcbiAgICBvYmouZm9ybWF0O1xuXG4gIHZhciBhcmdzID0gW3R5cGUgKyAnPScgKyBzdHJdO1xuICBpZiAob2JqLm5hbWVzKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvYmoubmFtZXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIHZhciBuID0gb2JqLm5hbWVzW2ldO1xuICAgICAgaWYgKG9iai5uYW1lKSB7XG4gICAgICAgIGFyZ3MucHVzaChsb2NhdGlvbltvYmoubmFtZV1bbl0pO1xuICAgICAgfVxuICAgICAgZWxzZSB7IC8vIGZvciBtTGluZSBhbmQgcHVzaCBhdHRyaWJ1dGVzXG4gICAgICAgIGFyZ3MucHVzaChsb2NhdGlvbltvYmoubmFtZXNbaV1dKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgZWxzZSB7XG4gICAgYXJncy5wdXNoKGxvY2F0aW9uW29iai5uYW1lXSk7XG4gIH1cbiAgcmV0dXJuIGZvcm1hdC5hcHBseShudWxsLCBhcmdzKTtcbn07XG5cbi8vIFJGQyBzcGVjaWZpZWQgb3JkZXJcbi8vIFRPRE86IGV4dGVuZCB0aGlzIHdpdGggYWxsIHRoZSByZXN0XG52YXIgZGVmYXVsdE91dGVyT3JkZXIgPSBbXG4gICd2JywgJ28nLCAncycsICdpJyxcbiAgJ3UnLCAnZScsICdwJywgJ2MnLFxuICAnYicsICd0JywgJ3InLCAneicsICdhJ1xuXTtcbnZhciBkZWZhdWx0SW5uZXJPcmRlciA9IFsnaScsICdjJywgJ2InLCAnYSddO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKHNlc3Npb24sIG9wdHMpIHtcbiAgb3B0cyA9IG9wdHMgfHwge307XG4gIC8vIGVuc3VyZSBjZXJ0YWluIHByb3BlcnRpZXMgZXhpc3RcbiAgaWYgKHNlc3Npb24udmVyc2lvbiA9PSBudWxsKSB7XG4gICAgc2Vzc2lvbi52ZXJzaW9uID0gMDsgLy8gXCJ2PTBcIiBtdXN0IGJlIHRoZXJlIChvbmx5IGRlZmluZWQgdmVyc2lvbiBhdG0pXG4gIH1cbiAgaWYgKHNlc3Npb24ubmFtZSA9PSBudWxsKSB7XG4gICAgc2Vzc2lvbi5uYW1lID0gXCIgXCI7IC8vIFwicz0gXCIgbXVzdCBiZSB0aGVyZSBpZiBubyBtZWFuaW5nZnVsIG5hbWUgc2V0XG4gIH1cbiAgc2Vzc2lvbi5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uIChtTGluZSkge1xuICAgIGlmIChtTGluZS5wYXlsb2FkcyA9PSBudWxsKSB7XG4gICAgICBtTGluZS5wYXlsb2FkcyA9IFwiXCI7XG4gICAgfVxuICB9KTtcblxuICB2YXIgb3V0ZXJPcmRlciA9IG9wdHMub3V0ZXJPcmRlciB8fCBkZWZhdWx0T3V0ZXJPcmRlcjtcbiAgdmFyIGlubmVyT3JkZXIgPSBvcHRzLmlubmVyT3JkZXIgfHwgZGVmYXVsdElubmVyT3JkZXI7XG4gIHZhciBzZHAgPSBbXTtcblxuICAvLyBsb29wIHRocm91Z2ggb3V0ZXJPcmRlciBmb3IgbWF0Y2hpbmcgcHJvcGVydGllcyBvbiBzZXNzaW9uXG4gIG91dGVyT3JkZXIuZm9yRWFjaChmdW5jdGlvbiAodHlwZSkge1xuICAgIGdyYW1tYXJbdHlwZV0uZm9yRWFjaChmdW5jdGlvbiAob2JqKSB7XG4gICAgICBpZiAob2JqLm5hbWUgaW4gc2Vzc2lvbiAmJiBzZXNzaW9uW29iai5uYW1lXSAhPSBudWxsKSB7XG4gICAgICAgIHNkcC5wdXNoKG1ha2VMaW5lKHR5cGUsIG9iaiwgc2Vzc2lvbikpO1xuICAgICAgfVxuICAgICAgZWxzZSBpZiAob2JqLnB1c2ggaW4gc2Vzc2lvbiAmJiBzZXNzaW9uW29iai5wdXNoXSAhPSBudWxsKSB7XG4gICAgICAgIHNlc3Npb25bb2JqLnB1c2hdLmZvckVhY2goZnVuY3Rpb24gKGVsKSB7XG4gICAgICAgICAgc2RwLnB1c2gobWFrZUxpbmUodHlwZSwgb2JqLCBlbCkpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSk7XG5cbiAgLy8gdGhlbiBmb3IgZWFjaCBtZWRpYSBsaW5lLCBmb2xsb3cgdGhlIGlubmVyT3JkZXJcbiAgc2Vzc2lvbi5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uIChtTGluZSkge1xuICAgIHNkcC5wdXNoKG1ha2VMaW5lKCdtJywgZ3JhbW1hci5tWzBdLCBtTGluZSkpO1xuXG4gICAgaW5uZXJPcmRlci5mb3JFYWNoKGZ1bmN0aW9uICh0eXBlKSB7XG4gICAgICBncmFtbWFyW3R5cGVdLmZvckVhY2goZnVuY3Rpb24gKG9iaikge1xuICAgICAgICBpZiAob2JqLm5hbWUgaW4gbUxpbmUgJiYgbUxpbmVbb2JqLm5hbWVdICE9IG51bGwpIHtcbiAgICAgICAgICBzZHAucHVzaChtYWtlTGluZSh0eXBlLCBvYmosIG1MaW5lKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAob2JqLnB1c2ggaW4gbUxpbmUgJiYgbUxpbmVbb2JqLnB1c2hdICE9IG51bGwpIHtcbiAgICAgICAgICBtTGluZVtvYmoucHVzaF0uZm9yRWFjaChmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgICAgIHNkcC5wdXNoKG1ha2VMaW5lKHR5cGUsIG9iaiwgZWwpKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIHJldHVybiBzZHAuam9pbignXFxyXFxuJykgKyAnXFxyXFxuJztcbn07XG4iLCIvKiBDb3B5cmlnaHQgQCAyMDE1IEF0bGFzc2lhbiBQdHkgTHRkXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gYXJyYXlFcXVhbHMoYXJyYXkpIHtcbiAgICAvLyBpZiB0aGUgb3RoZXIgYXJyYXkgaXMgYSBmYWxzeSB2YWx1ZSwgcmV0dXJuXG4gICAgaWYgKCFhcnJheSlcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuXG4gICAgLy8gY29tcGFyZSBsZW5ndGhzIC0gY2FuIHNhdmUgYSBsb3Qgb2YgdGltZVxuICAgIGlmICh0aGlzLmxlbmd0aCAhPSBhcnJheS5sZW5ndGgpXG4gICAgICAgIHJldHVybiBmYWxzZTtcblxuICAgIGZvciAodmFyIGkgPSAwLCBsID0gdGhpcy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgLy8gQ2hlY2sgaWYgd2UgaGF2ZSBuZXN0ZWQgYXJyYXlzXG4gICAgICAgIGlmICh0aGlzW2ldIGluc3RhbmNlb2YgQXJyYXkgJiYgYXJyYXlbaV0gaW5zdGFuY2VvZiBBcnJheSkge1xuICAgICAgICAgICAgLy8gcmVjdXJzZSBpbnRvIHRoZSBuZXN0ZWQgYXJyYXlzXG4gICAgICAgICAgICBpZiAoIWFycmF5RXF1YWxzLmFwcGx5KHRoaXNbaV0sIFthcnJheVtpXV0pKVxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzW2ldICE9IGFycmF5W2ldKSB7XG4gICAgICAgICAgICAvLyBXYXJuaW5nIC0gdHdvIGRpZmZlcmVudCBvYmplY3QgaW5zdGFuY2VzIHdpbGwgbmV2ZXIgYmUgZXF1YWw6XG4gICAgICAgICAgICAvLyB7eDoyMH0gIT0ge3g6MjB9XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59O1xuXG4iLCIvKiBDb3B5cmlnaHQgQCAyMDE1IEF0bGFzc2lhbiBQdHkgTHRkXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbmV4cG9ydHMuSW50ZXJvcCA9IHJlcXVpcmUoJy4vaW50ZXJvcCcpO1xuIiwiLyogQ29weXJpZ2h0IEAgMjAxNSBBdGxhc3NpYW4gUHR5IEx0ZFxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG4vKiBnbG9iYWwgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uICovXG4vKiBnbG9iYWwgUlRDSWNlQ2FuZGlkYXRlICovXG4vKiBqc2hpbnQgLVcwOTcgKi9cblwidXNlIHN0cmljdFwiO1xuXG52YXIgdHJhbnNmb3JtID0gcmVxdWlyZSgnLi90cmFuc2Zvcm0nKTtcbnZhciBhcnJheUVxdWFscyA9IHJlcXVpcmUoJy4vYXJyYXktZXF1YWxzJyk7XG5cbmZ1bmN0aW9uIEludGVyb3AoKSB7XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIG1hcCBob2xkcyB0aGUgbW9zdCByZWNlbnQgVW5pZmllZCBQbGFuIG9mZmVyL2Fuc3dlciBTRFAgdGhhdCB3YXNcbiAgICAgKiBjb252ZXJ0ZWQgdG8gUGxhbiBCLCB3aXRoIHRoZSBTRFAgdHlwZSAoJ29mZmVyJyBvciAnYW5zd2VyJykgYXMga2V5cyBhbmRcbiAgICAgKiB0aGUgU0RQIHN0cmluZyBhcyB2YWx1ZXMuXG4gICAgICpcbiAgICAgKiBAdHlwZSB7e319XG4gICAgICovXG4gICAgdGhpcy5jYWNoZSA9IHtcbiAgICAgICAgbWxCMlVNYXAgOiB7fSxcbiAgICAgICAgbWxVMkJNYXAgOiB7fVxuICAgIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gSW50ZXJvcDtcblxuLyoqXG4gKiBDaGFuZ2VzIHRoZSBjYW5kaWRhdGUgYXJncyB0byBtYXRjaCB3aXRoIHRoZSByZWxhdGVkIFVuaWZpZWQgUGxhblxuICovXG5JbnRlcm9wLnByb3RvdHlwZS5jYW5kaWRhdGVUb1VuaWZpZWRQbGFuID0gZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gICAgdmFyIGNhbmQgPSBuZXcgUlRDSWNlQ2FuZGlkYXRlKGNhbmRpZGF0ZSk7XG5cbiAgICBjYW5kLnNkcE1MaW5lSW5kZXggPSB0aGlzLmNhY2hlLm1sQjJVTWFwW2NhbmQuc2RwTUxpbmVJbmRleF07XG4gICAgLyogVE9ETzogY2hhbmdlIHNkcE1pZCB0byAoYXVkaW98dmlkZW8pLVNTUkMgKi9cblxuICAgIHJldHVybiBjYW5kO1xufTtcblxuLyoqXG4gKiBDaGFuZ2VzIHRoZSBjYW5kaWRhdGUgYXJncyB0byBtYXRjaCB3aXRoIHRoZSByZWxhdGVkIFBsYW4gQlxuICovXG5JbnRlcm9wLnByb3RvdHlwZS5jYW5kaWRhdGVUb1BsYW5CID0gZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gICAgdmFyIGNhbmQgPSBuZXcgUlRDSWNlQ2FuZGlkYXRlKGNhbmRpZGF0ZSk7XG5cbiAgICBpZiAoY2FuZC5zZHBNaWQuaW5kZXhPZignYXVkaW8nKSA9PT0gMCkge1xuICAgICAgY2FuZC5zZHBNaWQgPSAnYXVkaW8nO1xuICAgIH0gZWxzZSBpZiAoY2FuZC5zZHBNaWQuaW5kZXhPZigndmlkZW8nKSA9PT0gMCkge1xuICAgICAgY2FuZC5zZHBNaWQgPSAndmlkZW8nO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2NhbmRpZGF0ZSB3aXRoICcgKyBjYW5kLnNkcE1pZCArICcgbm90IGFsbG93ZWQnKTtcbiAgICB9XG5cbiAgICBjYW5kLnNkcE1MaW5lSW5kZXggPSB0aGlzLmNhY2hlLm1sVTJCTWFwW2NhbmQuc2RwTUxpbmVJbmRleF07XG5cbiAgICByZXR1cm4gY2FuZDtcbn07XG5cbi8qKlxuICogUmV0dXJucyB0aGUgaW5kZXggb2YgdGhlIGZpcnN0IG0tbGluZSB3aXRoIHRoZSBnaXZlbiBtZWRpYSB0eXBlIGFuZCB3aXRoIGFcbiAqIGRpcmVjdGlvbiB3aGljaCBhbGxvd3Mgc2VuZGluZywgaW4gdGhlIGxhc3QgVW5pZmllZCBQbGFuIGRlc2NyaXB0aW9uIHdpdGhcbiAqIHR5cGUgXCJhbnN3ZXJcIiBjb252ZXJ0ZWQgdG8gUGxhbiBCLiBSZXR1cm5zIHtudWxsfSBpZiB0aGVyZSBpcyBubyBzYXZlZFxuICogYW5zd2VyLCBvciBpZiBub25lIG9mIGl0cyBtLWxpbmVzIHdpdGggdGhlIGdpdmVuIHR5cGUgYWxsb3cgc2VuZGluZy5cbiAqIEBwYXJhbSB0eXBlIHRoZSBtZWRpYSB0eXBlIChcImF1ZGlvXCIgb3IgXCJ2aWRlb1wiKS5cbiAqIEByZXR1cm5zIHsqfVxuICovXG5JbnRlcm9wLnByb3RvdHlwZS5nZXRGaXJzdFNlbmRpbmdJbmRleEZyb21BbnN3ZXIgPSBmdW5jdGlvbih0eXBlKSB7XG4gICAgaWYgKCF0aGlzLmNhY2hlLmFuc3dlcikge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICB2YXIgc2Vzc2lvbiA9IHRyYW5zZm9ybS5wYXJzZSh0aGlzLmNhY2hlLmFuc3dlcik7XG4gICAgaWYgKHNlc3Npb24gJiYgc2Vzc2lvbi5tZWRpYSAmJiBBcnJheS5pc0FycmF5KHNlc3Npb24ubWVkaWEpKXtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzZXNzaW9uLm1lZGlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoc2Vzc2lvbi5tZWRpYVtpXS50eXBlID09IHR5cGUgJiZcbiAgICAgICAgICAgICAgICAoIXNlc3Npb24ubWVkaWFbaV0uZGlyZWN0aW9uIC8qIGRlZmF1bHQgdG8gc2VuZHJlY3YgKi8gfHxcbiAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbi5tZWRpYVtpXS5kaXJlY3Rpb24gPT09ICdzZW5kcmVjdicgfHxcbiAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbi5tZWRpYVtpXS5kaXJlY3Rpb24gPT09ICdzZW5kb25seScpKXtcbiAgICAgICAgICAgICAgICByZXR1cm4gaTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCB0cmFuc2Zvcm1zIGEgVW5pZmllZCBQbGFuIFNEUCB0byBhbiBlcXVpdmFsZW50IFBsYW4gQiBTRFAuIEFcbiAqIFBlZXJDb25uZWN0aW9uIHdyYXBwZXIgdHJhbnNmb3JtcyB0aGUgU0RQIHRvIFBsYW4gQiBiZWZvcmUgcGFzc2luZyBpdCB0byB0aGVcbiAqIGFwcGxpY2F0aW9uLlxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuSW50ZXJvcC5wcm90b3R5cGUudG9QbGFuQiA9IGZ1bmN0aW9uKGRlc2MpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgLy8jcmVnaW9uIFByZWxpbWluYXJ5IGlucHV0IHZhbGlkYXRpb24uXG5cbiAgICBpZiAodHlwZW9mIGRlc2MgIT09ICdvYmplY3QnIHx8IGRlc2MgPT09IG51bGwgfHxcbiAgICAgICAgdHlwZW9mIGRlc2Muc2RwICE9PSAnc3RyaW5nJykge1xuICAgICAgICBjb25zb2xlLndhcm4oJ0FuIGVtcHR5IGRlc2NyaXB0aW9uIHdhcyBwYXNzZWQgYXMgYW4gYXJndW1lbnQuJyk7XG4gICAgICAgIHJldHVybiBkZXNjO1xuICAgIH1cblxuICAgIC8vIE9iamVjdGlmeSB0aGUgU0RQIGZvciBlYXNpZXIgbWFuaXB1bGF0aW9uLlxuICAgIHZhciBzZXNzaW9uID0gdHJhbnNmb3JtLnBhcnNlKGRlc2Muc2RwKTtcblxuICAgIC8vIElmIHRoZSBTRFAgY29udGFpbnMgbm8gbWVkaWEsIHRoZXJlJ3Mgbm90aGluZyB0byB0cmFuc2Zvcm0uXG4gICAgaWYgKHR5cGVvZiBzZXNzaW9uLm1lZGlhID09PSAndW5kZWZpbmVkJyB8fFxuICAgICAgICAhQXJyYXkuaXNBcnJheShzZXNzaW9uLm1lZGlhKSB8fCBzZXNzaW9uLm1lZGlhLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1RoZSBkZXNjcmlwdGlvbiBoYXMgbm8gbWVkaWEuJyk7XG4gICAgICAgIHJldHVybiBkZXNjO1xuICAgIH1cblxuICAgIC8vIFRyeSBzb21lIGhldXJpc3RpY3MgdG8gXCJtYWtlIHN1cmVcIiB0aGlzIGlzIGEgVW5pZmllZCBQbGFuIFNEUC4gUGxhbiBCXG4gICAgLy8gU0RQIGhhcyBhIHZpZGVvLCBhbiBhdWRpbyBhbmQgYSBkYXRhIFwiY2hhbm5lbFwiIGF0IG1vc3QuXG4gICAgaWYgKHNlc3Npb24ubWVkaWEubGVuZ3RoIDw9IDMgJiYgc2Vzc2lvbi5tZWRpYS5ldmVyeShmdW5jdGlvbihtKSB7XG4gICAgICAgICAgICByZXR1cm4gWyd2aWRlbycsICdhdWRpbycsICdkYXRhJ10uaW5kZXhPZihtLm1pZCkgIT09IC0xO1xuICAgICAgICB9KSkge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1RoaXMgZGVzY3JpcHRpb24gZG9lcyBub3QgbG9vayBsaWtlIFVuaWZpZWQgUGxhbi4nKTtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfVxuXG4gICAgLy8jZW5kcmVnaW9uXG5cbiAgICAvLyBIQUNLIGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTExMTM0NDNcbiAgICB2YXIgc2RwID0gZGVzYy5zZHA7XG4gICAgdmFyIHJld3JpdGUgPSBmYWxzZTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlc3Npb24ubWVkaWEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHVMaW5lID0gc2Vzc2lvbi5tZWRpYVtpXTtcbiAgICAgICAgdUxpbmUucnRwLmZvckVhY2goZnVuY3Rpb24ocnRwKSB7XG4gICAgICAgICAgICBpZiAocnRwLmNvZGVjID09PSAnTlVMTCcpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgcmV3cml0ZSA9IHRydWU7XG4gICAgICAgICAgICAgICAgdmFyIG9mZmVyID0gdHJhbnNmb3JtLnBhcnNlKHNlbGYuY2FjaGUub2ZmZXIpO1xuICAgICAgICAgICAgICAgIHJ0cC5jb2RlYyA9IG9mZmVyLm1lZGlhW2ldLnJ0cFswXS5jb2RlYztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGlmIChyZXdyaXRlKSB7XG4gICAgICAgIHNkcCA9IHRyYW5zZm9ybS53cml0ZShzZXNzaW9uKTtcbiAgICB9XG5cbiAgICAvLyBVbmlmaWVkIFBsYW4gU0RQIGlzIG91ciBcInByZWNpb3VzXCIuIENhY2hlIGl0IGZvciBsYXRlciB1c2UgaW4gdGhlIFBsYW4gQlxuICAgIC8vIC0+IFVuaWZpZWQgUGxhbiB0cmFuc2Zvcm1hdGlvbi5cbiAgICB0aGlzLmNhY2hlW2Rlc2MudHlwZV0gPSBzZHA7XG5cbiAgICAvLyNyZWdpb24gQ29udmVydCBmcm9tIFVuaWZpZWQgUGxhbiB0byBQbGFuIEIuXG5cbiAgICAvLyBXZSByZWJ1aWxkIHRoZSBzZXNzaW9uLm1lZGlhIGFycmF5LlxuICAgIHZhciBtZWRpYSA9IHNlc3Npb24ubWVkaWE7XG4gICAgc2Vzc2lvbi5tZWRpYSA9IFtdO1xuXG4gICAgLy8gQXNzb2NpYXRpdmUgYXJyYXkgdGhhdCBtYXBzIGNoYW5uZWwgdHlwZXMgdG8gY2hhbm5lbCBvYmplY3RzIGZvciBmYXN0XG4gICAgLy8gYWNjZXNzIHRvIGNoYW5uZWwgb2JqZWN0cyBieSB0aGVpciB0eXBlLCBlLmcuIHR5cGUyYmxbJ2F1ZGlvJ10tPmNoYW5uZWxcbiAgICAvLyBvYmouXG4gICAgdmFyIHR5cGUyYmwgPSB7fTtcblxuICAgIC8vIFVzZWQgdG8gYnVpbGQgdGhlIGdyb3VwOkJVTkRMRSB2YWx1ZSBhZnRlciB0aGUgY2hhbm5lbHMgY29uc3RydWN0aW9uXG4gICAgLy8gbG9vcC5cbiAgICB2YXIgdHlwZXMgPSBbXTtcblxuICAgIG1lZGlhLmZvckVhY2goZnVuY3Rpb24odUxpbmUpIHtcbiAgICAgICAgLy8gcnRjcC1tdXggaXMgcmVxdWlyZWQgaW4gdGhlIFBsYW4gQiBTRFAuXG4gICAgICAgIGlmICgodHlwZW9mIHVMaW5lLnJ0Y3BNdXggIT09ICdzdHJpbmcnIHx8XG4gICAgICAgICAgICB1TGluZS5ydGNwTXV4ICE9PSAncnRjcC1tdXgnKSAmJlxuICAgICAgICAgICAgdUxpbmUuZGlyZWN0aW9uICE9PSAnaW5hY3RpdmUnKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBjb252ZXJ0IHRvIFBsYW4gQiBiZWNhdXNlIG0tbGluZXMgJyArXG4gICAgICAgICAgICAgICAgJ3dpdGhvdXQgdGhlIHJ0Y3AtbXV4IGF0dHJpYnV0ZSB3ZXJlIGZvdW5kLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSWYgd2UgZG9uJ3QgaGF2ZSBhIGNoYW5uZWwgZm9yIHRoaXMgdUxpbmUudHlwZSBPUiB0aGUgc2VsZWN0ZWQgaXNcbiAgICAgICAgLy8gaW5hY3RpdmUsIHRoZW4gc2VsZWN0IHRoaXMgdUxpbmUgYXMgdGhlIGNoYW5uZWwgYmFzaXMuXG4gICAgICAgIGlmICh0eXBlb2YgdHlwZTJibFt1TGluZS50eXBlXSA9PT0gJ3VuZGVmaW5lZCcgfHxcbiAgICAgICAgICAgIHR5cGUyYmxbdUxpbmUudHlwZV0uZGlyZWN0aW9uID09PSAnaW5hY3RpdmUnKSB7XG4gICAgICAgICAgICB0eXBlMmJsW3VMaW5lLnR5cGVdID0gdUxpbmU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodUxpbmUucHJvdG9jb2wgIT0gdHlwZTJibFt1TGluZS50eXBlXS5wcm90b2NvbCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IGNvbnZlcnQgdG8gUGxhbiBCIGJlY2F1c2UgbS1saW5lcyAnICtcbiAgICAgICAgICAgICAgJ2hhdmUgZGlmZmVyZW50IHByb3RvY29scyBhbmQgdGhpcyBsaWJyYXJ5IGRvZXMgbm90IGhhdmUgJyArXG4gICAgICAgICAgICAgICdzdXBwb3J0IGZvciB0aGF0Jyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodUxpbmUucGF5bG9hZHMgIT0gdHlwZTJibFt1TGluZS50eXBlXS5wYXlsb2Fkcykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IGNvbnZlcnQgdG8gUGxhbiBCIGJlY2F1c2UgbS1saW5lcyAnICtcbiAgICAgICAgICAgICAgJ2hhdmUgZGlmZmVyZW50IHBheWxvYWRzIGFuZCB0aGlzIGxpYnJhcnkgZG9lcyBub3QgaGF2ZSAnICtcbiAgICAgICAgICAgICAgJ3N1cHBvcnQgZm9yIHRoYXQnKTtcbiAgICAgICAgfVxuXG4gICAgfSk7XG5cbiAgICAvLyBJbXBsb2RlIHRoZSBVbmlmaWVkIFBsYW4gbS1saW5lcy90cmFja3MgaW50byBQbGFuIEIgY2hhbm5lbHMuXG4gICAgbWVkaWEuZm9yRWFjaChmdW5jdGlvbih1TGluZSkge1xuICAgICAgICBpZiAodUxpbmUudHlwZSA9PT0gJ2FwcGxpY2F0aW9uJykge1xuICAgICAgICAgICAgc2Vzc2lvbi5tZWRpYS5wdXNoKHVMaW5lKTtcbiAgICAgICAgICAgIHR5cGVzLnB1c2godUxpbmUubWlkKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFkZCBzb3VyY2VzIHRvIHRoZSBjaGFubmVsIGFuZCBoYW5kbGUgYT1tc2lkLlxuICAgICAgICBpZiAodHlwZW9mIHVMaW5lLnNvdXJjZXMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICBPYmplY3Qua2V5cyh1TGluZS5zb3VyY2VzKS5mb3JFYWNoKGZ1bmN0aW9uKHNzcmMpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHR5cGUyYmxbdUxpbmUudHlwZV0uc291cmNlcyAhPT0gJ29iamVjdCcpXG4gICAgICAgICAgICAgICAgICAgIHR5cGUyYmxbdUxpbmUudHlwZV0uc291cmNlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQXNzaWduIHRoZSBzb3VyY2VzIHRvIHRoZSBjaGFubmVsLlxuICAgICAgICAgICAgICAgIHR5cGUyYmxbdUxpbmUudHlwZV0uc291cmNlc1tzc3JjXSA9XG4gICAgICAgICAgICAgICAgICAgIHVMaW5lLnNvdXJjZXNbc3NyY107XG5cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHVMaW5lLm1zaWQgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEluIFBsYW4gQiB0aGUgbXNpZCBpcyBhbiBTU1JDIGF0dHJpYnV0ZS4gQWxzbywgd2UgZG9uJ3RcbiAgICAgICAgICAgICAgICAgICAgLy8gY2FyZSBhYm91dCB0aGUgb2Jzb2xldGUgbGFiZWwgYW5kIG1zbGFiZWwgYXR0cmlidXRlcy5cbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgLy8gTm90ZSB0aGF0IGl0IGlzIG5vdCBndWFyYW50ZWVkIHRoYXQgdGhlIHVMaW5lIHdpbGxcbiAgICAgICAgICAgICAgICAgICAgLy8gaGF2ZSBhbiBtc2lkLiByZWN2b25seSBjaGFubmVscyBpbiBwYXJ0aWN1bGFyIGRvbid0IGhhdmVcbiAgICAgICAgICAgICAgICAgICAgLy8gb25lLlxuICAgICAgICAgICAgICAgICAgICB0eXBlMmJsW3VMaW5lLnR5cGVdLnNvdXJjZXNbc3NyY10ubXNpZCA9XG4gICAgICAgICAgICAgICAgICAgICAgICB1TGluZS5tc2lkO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBOT1RFIHNzcmNzIGluIHNzcmMgZ3JvdXBzIHdpbGwgc2hhcmUgbXNpZHMsIGFzXG4gICAgICAgICAgICAgICAgLy8gZHJhZnQtdWJlcnRpLXJ0Y3dlYi1wbGFuLTAwIG1hbmRhdGVzLlxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBZGQgc3NyYyBncm91cHMgdG8gdGhlIGNoYW5uZWwuXG4gICAgICAgIGlmICh0eXBlb2YgdUxpbmUuc3NyY0dyb3VwcyAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgICAgICAgICBBcnJheS5pc0FycmF5KHVMaW5lLnNzcmNHcm91cHMpKSB7XG5cbiAgICAgICAgICAgIC8vIENyZWF0ZSB0aGUgc3NyY0dyb3VwcyBhcnJheSwgaWYgaXQncyBub3QgZGVmaW5lZC5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdHlwZTJibFt1TGluZS50eXBlXS5zc3JjR3JvdXBzID09PSAndW5kZWZpbmVkJyB8fFxuICAgICAgICAgICAgICAgICAgICAhQXJyYXkuaXNBcnJheSh0eXBlMmJsW3VMaW5lLnR5cGVdLnNzcmNHcm91cHMpKSB7XG4gICAgICAgICAgICAgICAgdHlwZTJibFt1TGluZS50eXBlXS5zc3JjR3JvdXBzID0gW107XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHR5cGUyYmxbdUxpbmUudHlwZV0uc3NyY0dyb3VwcyA9XG4gICAgICAgICAgICAgICAgdHlwZTJibFt1TGluZS50eXBlXS5zc3JjR3JvdXBzLmNvbmNhdChcbiAgICAgICAgICAgICAgICAgICAgdUxpbmUuc3NyY0dyb3Vwcyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZTJibFt1TGluZS50eXBlXSA9PT0gdUxpbmUpIHtcbiAgICAgICAgICAgIC8vIFBsYW4gQiBtaWRzIGFyZSBpbiBbJ2F1ZGlvJywgJ3ZpZGVvJywgJ2RhdGEnXVxuICAgICAgICAgICAgdUxpbmUubWlkID0gdUxpbmUudHlwZTtcblxuICAgICAgICAgICAgLy8gUGxhbiBCIGRvZXNuJ3Qgc3VwcG9ydC9uZWVkIHRoZSBidW5kbGUtb25seSBhdHRyaWJ1dGUuXG4gICAgICAgICAgICBkZWxldGUgdUxpbmUuYnVuZGxlT25seTtcblxuICAgICAgICAgICAgLy8gSW4gUGxhbiBCIHRoZSBtc2lkIGlzIGFuIFNTUkMgYXR0cmlidXRlLlxuICAgICAgICAgICAgZGVsZXRlIHVMaW5lLm1zaWQ7XG5cblx0ICAgIGlmICh1TGluZS50eXBlID09IG1lZGlhWzBdLnR5cGUpIHtcblx0ICAgICAgdHlwZXMudW5zaGlmdCh1TGluZS50eXBlKTtcblx0ICAgICAgLy8gQWRkIHRoZSBjaGFubmVsIHRvIHRoZSBuZXcgbWVkaWEgYXJyYXkuXG5cdCAgICAgIHNlc3Npb24ubWVkaWEudW5zaGlmdCh1TGluZSk7XG5cdCAgICB9IGVsc2Uge1xuXHQgICAgICB0eXBlcy5wdXNoKHVMaW5lLnR5cGUpO1xuXHQgICAgICAvLyBBZGQgdGhlIGNoYW5uZWwgdG8gdGhlIG5ldyBtZWRpYSBhcnJheS5cblx0ICAgICAgc2Vzc2lvbi5tZWRpYS5wdXNoKHVMaW5lKTtcblx0ICAgIH1cbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgaWYgKHR5cGVvZiBzZXNzaW9uLmdyb3VwcyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIC8vIFdlIHJlZ2VuZXJhdGUgdGhlIEJVTkRMRSBncm91cCB3aXRoIHRoZSBuZXcgbWlkcy5cbiAgICAgIHNlc3Npb24uZ3JvdXBzLnNvbWUoZnVuY3Rpb24oZ3JvdXApIHtcblx0ICBpZiAoZ3JvdXAudHlwZSA9PT0gJ0JVTkRMRScpIHtcblx0ICAgICAgZ3JvdXAubWlkcyA9IHR5cGVzLmpvaW4oJyAnKTtcblx0ICAgICAgcmV0dXJuIHRydWU7XG5cdCAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gbXNpZCBzZW1hbnRpY1xuICAgIHNlc3Npb24ubXNpZFNlbWFudGljID0ge1xuICAgICAgICBzZW1hbnRpYzogJ1dNUycsXG4gICAgICAgIHRva2VuOiAnKidcbiAgICB9O1xuXG4gICAgdmFyIHJlc1N0ciA9IHRyYW5zZm9ybS53cml0ZShzZXNzaW9uKTtcblxuICAgIHJldHVybiBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgICAgdHlwZTogZGVzYy50eXBlLFxuICAgICAgICBzZHA6IHJlc1N0clxuICAgIH0pO1xuXG4gICAgLy8jZW5kcmVnaW9uXG59O1xuXG4vKiBmb2xsb3cgcnVsZXMgZGVmaW5lZCBpbiBSRkM0MTQ1ICovXG5mdW5jdGlvbiBhZGRTZXR1cEF0dHIodUxpbmUpIHtcbiAgICBpZiAodHlwZW9mIHVMaW5lLnNldHVwID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHVMaW5lLnNldHVwID09PSBcImFjdGl2ZVwiKSB7XG4gICAgICAgICAgICB1TGluZS5zZXR1cCA9IFwicGFzc2l2ZVwiO1xuICAgIH0gZWxzZSBpZiAodUxpbmUuc2V0dXAgPT09IFwicGFzc2l2ZVwiKSB7XG4gICAgICAgIHVMaW5lLnNldHVwID0gXCJhY3RpdmVcIjtcbiAgICB9XG59XG5cbi8qKlxuICogVGhpcyBtZXRob2QgdHJhbnNmb3JtcyBhIFBsYW4gQiBTRFAgdG8gYW4gZXF1aXZhbGVudCBVbmlmaWVkIFBsYW4gU0RQLiBBXG4gKiBQZWVyQ29ubmVjdGlvbiB3cmFwcGVyIHRyYW5zZm9ybXMgdGhlIFNEUCB0byBVbmlmaWVkIFBsYW4gYmVmb3JlIHBhc3NpbmcgaXRcbiAqIHRvIEZGLlxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuSW50ZXJvcC5wcm90b3R5cGUudG9VbmlmaWVkUGxhbiA9IGZ1bmN0aW9uKGRlc2MpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgLy8jcmVnaW9uIFByZWxpbWluYXJ5IGlucHV0IHZhbGlkYXRpb24uXG5cbiAgICBpZiAodHlwZW9mIGRlc2MgIT09ICdvYmplY3QnIHx8IGRlc2MgPT09IG51bGwgfHxcbiAgICAgICAgdHlwZW9mIGRlc2Muc2RwICE9PSAnc3RyaW5nJykge1xuICAgICAgICBjb25zb2xlLndhcm4oJ0FuIGVtcHR5IGRlc2NyaXB0aW9uIHdhcyBwYXNzZWQgYXMgYW4gYXJndW1lbnQuJyk7XG4gICAgICAgIHJldHVybiBkZXNjO1xuICAgIH1cblxuICAgIHZhciBzZXNzaW9uID0gdHJhbnNmb3JtLnBhcnNlKGRlc2Muc2RwKTtcblxuICAgIC8vIElmIHRoZSBTRFAgY29udGFpbnMgbm8gbWVkaWEsIHRoZXJlJ3Mgbm90aGluZyB0byB0cmFuc2Zvcm0uXG4gICAgaWYgKHR5cGVvZiBzZXNzaW9uLm1lZGlhID09PSAndW5kZWZpbmVkJyB8fFxuICAgICAgICAhQXJyYXkuaXNBcnJheShzZXNzaW9uLm1lZGlhKSB8fCBzZXNzaW9uLm1lZGlhLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1RoZSBkZXNjcmlwdGlvbiBoYXMgbm8gbWVkaWEuJyk7XG4gICAgICAgIHJldHVybiBkZXNjO1xuICAgIH1cblxuICAgIC8vIFRyeSBzb21lIGhldXJpc3RpY3MgdG8gXCJtYWtlIHN1cmVcIiB0aGlzIGlzIGEgUGxhbiBCIFNEUC4gUGxhbiBCIFNEUCBoYXNcbiAgICAvLyBhIHZpZGVvLCBhbiBhdWRpbyBhbmQgYSBkYXRhIFwiY2hhbm5lbFwiIGF0IG1vc3QuXG4gICAgaWYgKHNlc3Npb24ubWVkaWEubGVuZ3RoID4gMyB8fCAhc2Vzc2lvbi5tZWRpYS5ldmVyeShmdW5jdGlvbihtKSB7XG4gICAgICAgICAgICByZXR1cm4gWyd2aWRlbycsICdhdWRpbycsICdkYXRhJ10uaW5kZXhPZihtLm1pZCkgIT09IC0xO1xuICAgICAgICB9KSkge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1RoaXMgZGVzY3JpcHRpb24gZG9lcyBub3QgbG9vayBsaWtlIFBsYW4gQi4nKTtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfVxuXG4gICAgLy8gTWFrZSBzdXJlIHRoaXMgUGxhbiBCIFNEUCBjYW4gYmUgY29udmVydGVkIHRvIGEgVW5pZmllZCBQbGFuIFNEUC5cbiAgICB2YXIgbWlkcyA9IFtdO1xuICAgIHNlc3Npb24ubWVkaWEuZm9yRWFjaChmdW5jdGlvbihtKSB7XG4gICAgICAgIG1pZHMucHVzaChtLm1pZCk7XG4gICAgfSk7XG5cbiAgICB2YXIgaGFzQnVuZGxlID0gZmFsc2U7XG4gICAgaWYgKHR5cGVvZiBzZXNzaW9uLmdyb3VwcyAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgQXJyYXkuaXNBcnJheShzZXNzaW9uLmdyb3VwcykpIHtcbiAgICAgICAgaGFzQnVuZGxlID0gc2Vzc2lvbi5ncm91cHMuZXZlcnkoZnVuY3Rpb24oZykge1xuICAgICAgICAgICAgcmV0dXJuIGcudHlwZSAhPT0gJ0JVTkRMRScgfHxcbiAgICAgICAgICAgICAgICBhcnJheUVxdWFscy5hcHBseShnLm1pZHMuc29ydCgpLCBbbWlkcy5zb3J0KCldKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKCFoYXNCdW5kbGUpIHtcbiAgICAgICAgdmFyIG11c3RCZUJ1bmRsZSA9IGZhbHNlO1xuXG4gICAgICAgIHNlc3Npb24ubWVkaWEuZm9yRWFjaChmdW5jdGlvbihtKSB7XG4gICAgICAgICAgICBpZiAobS5kaXJlY3Rpb24gIT09ICdpbmFjdGl2ZScpIHtcbiAgICAgICAgICAgICAgICBtdXN0QmVCdW5kbGUgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAobXVzdEJlQnVuZGxlKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgY29udmVydCB0byBVbmlmaWVkIFBsYW4gYmVjYXVzZSBtLWxpbmVzIHRoYXRcIiArXG4gICAgICAgICAgICAgIFwiIGFyZSBub3QgYnVuZGxlZCB3ZXJlIGZvdW5kLlwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vI2VuZHJlZ2lvblxuXG5cbiAgICAvLyNyZWdpb24gQ29udmVydCBmcm9tIFBsYW4gQiB0byBVbmlmaWVkIFBsYW4uXG5cbiAgICAvLyBVbmZvcnR1bmF0ZWx5LCBhIFBsYW4gQiBvZmZlci9hbnN3ZXIgZG9lc24ndCBoYXZlIGVub3VnaCBpbmZvcm1hdGlvbiB0b1xuICAgIC8vIHJlYnVpbGQgYW4gZXF1aXZhbGVudCBVbmlmaWVkIFBsYW4gb2ZmZXIvYW5zd2VyLlxuICAgIC8vXG4gICAgLy8gRm9yIGV4YW1wbGUsIGlmIHRoaXMgaXMgYSBsb2NhbCBhbnN3ZXIgKGluIFVuaWZpZWQgUGxhbiBzdHlsZSkgdGhhdCB3ZVxuICAgIC8vIGNvbnZlcnQgdG8gUGxhbiBCIHByaW9yIHRvIGhhbmRpbmcgaXQgb3ZlciB0byB0aGUgYXBwbGljYXRpb24gKHRoZVxuICAgIC8vIFBlZXJDb25uZWN0aW9uIHdyYXBwZXIgY2FsbGVkIHVzLCBmb3IgaW5zdGFuY2UsIGFmdGVyIGEgc3VjY2Vzc2Z1bFxuICAgIC8vIGNyZWF0ZUFuc3dlciksIHdlIHdhbnQgdG8gcmVtZW1iZXIgdGhlIG0tbGluZSBhdCB3aGljaCB3ZSd2ZSBzZWVuIHRoZVxuICAgIC8vIChsb2NhbCkgU1NSQy4gVGhhdCdzIGJlY2F1c2Ugd2hlbiB0aGUgYXBwbGljYXRpb24gd2FudHMgdG8gZG8gY2FsbCB0aGVcbiAgICAvLyBTTEQgbWV0aG9kLCBmb3JjaW5nIHVzIHRvIGRvIHRoZSBpbnZlcnNlIHRyYW5zZm9ybWF0aW9uIChmcm9tIFBsYW4gQiB0b1xuICAgIC8vIFVuaWZpZWQgUGxhbiksIHdlIG5lZWQgdG8ga25vdyB0byB3aGljaCBtLWxpbmUgdG8gYXNzaWduIHRoZSAobG9jYWwpXG4gICAgLy8gU1NSQy4gV2UgYWxzbyBuZWVkIHRvIGtub3cgYWxsIHRoZSBvdGhlciBtLWxpbmVzIHRoYXQgdGhlIG9yaWdpbmFsXG4gICAgLy8gYW5zd2VyIGhhZCBhbmQgaW5jbHVkZSB0aGVtIGluIHRoZSB0cmFuc2Zvcm1lZCBhbnN3ZXIgYXMgd2VsbC5cbiAgICAvL1xuICAgIC8vIEFub3RoZXIgZXhhbXBsZSBpcyBpZiB0aGlzIGlzIGEgcmVtb3RlIG9mZmVyIHRoYXQgd2UgY29udmVydCB0byBQbGFuIEJcbiAgICAvLyBwcmlvciB0byBnaXZpbmcgaXQgdG8gdGhlIGFwcGxpY2F0aW9uLCB3ZSB3YW50IHRvIHJlbWVtYmVyIHRoZSBtaWQgYXRcbiAgICAvLyB3aGljaCB3ZSd2ZSBzZWVuIHRoZSAocmVtb3RlKSBTU1JDLlxuICAgIC8vXG4gICAgLy8gSW4gdGhlIGl0ZXJhdGlvbiB0aGF0IGZvbGxvd3MsIHdlIHVzZSB0aGUgY2FjaGVkIFVuaWZpZWQgUGxhbiAoaWYgaXRcbiAgICAvLyBleGlzdHMpIHRvIGFzc2lnbiBtaWRzIHRvIHNzcmNzLlxuXG4gICAgdmFyIHR5cGU7XG4gICAgaWYgKGRlc2MudHlwZSA9PT0gJ2Fuc3dlcicpIHtcbiAgICAgICAgdHlwZSA9ICdvZmZlcic7XG4gICAgfSBlbHNlIGlmIChkZXNjLnR5cGUgPT09ICdvZmZlcicpIHtcbiAgICAgICAgdHlwZSA9ICdhbnN3ZXInO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlR5cGUgJ1wiICsgZGVzYy50eXBlICsgXCInIG5vdCBzdXBwb3J0ZWQuXCIpO1xuICAgIH1cblxuICAgIHZhciBjYWNoZWQ7XG4gICAgaWYgKHR5cGVvZiB0aGlzLmNhY2hlW3R5cGVdICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICBjYWNoZWQgPSB0cmFuc2Zvcm0ucGFyc2UodGhpcy5jYWNoZVt0eXBlXSk7XG4gICAgfVxuXG4gICAgdmFyIHJlY3Zvbmx5U3NyY3MgPSB7XG4gICAgICAgIGF1ZGlvOiB7fSxcbiAgICAgICAgdmlkZW86IHt9XG4gICAgfTtcblxuICAgIC8vIEEgaGVscGVyIG1hcCB0aGF0IHNlbmRzIG1pZHMgdG8gbS1saW5lIG9iamVjdHMuIFdlIHVzZSBpdCBsYXRlciB0b1xuICAgIC8vIHJlYnVpbGQgdGhlIFVuaWZpZWQgUGxhbiBzdHlsZSBzZXNzaW9uLm1lZGlhIGFycmF5LlxuICAgIHZhciBtaWQydWwgPSB7fTtcbiAgICB2YXIgYklkeCA9IDA7XG4gICAgdmFyIHVJZHggPSAwO1xuXG4gICAgdmFyIHNvdXJjZXMydWwgPSB7fTtcblxuICAgIHZhciBjYW5kaWRhdGVzO1xuICAgIHZhciBpY2VVZnJhZztcbiAgICB2YXIgaWNlUHdkO1xuICAgIHZhciBmaW5nZXJwcmludDtcbiAgICB2YXIgcGF5bG9hZHMgPSB7fTtcbiAgICB2YXIgcnRjcEZiID0ge307XG4gICAgdmFyIHJ0cCA9IHt9O1xuXG4gICAgc2Vzc2lvbi5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKGJMaW5lKSB7XG4gICAgICAgIGlmICgodHlwZW9mIGJMaW5lLnJ0Y3BNdXggIT09ICdzdHJpbmcnIHx8XG4gICAgICAgICAgICBiTGluZS5ydGNwTXV4ICE9PSAncnRjcC1tdXgnKSAmJlxuICAgICAgICAgICAgYkxpbmUuZGlyZWN0aW9uICE9PSAnaW5hY3RpdmUnKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgY29udmVydCB0byBVbmlmaWVkIFBsYW4gYmVjYXVzZSBtLWxpbmVzIFwiICtcbiAgICAgICAgICAgICAgICBcIndpdGhvdXQgdGhlIHJ0Y3AtbXV4IGF0dHJpYnV0ZSB3ZXJlIGZvdW5kLlwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChiTGluZS50eXBlID09PSAnYXBwbGljYXRpb24nKSB7XG4gICAgICAgICAgICBtaWQydWxbYkxpbmUubWlkXSA9IGJMaW5lO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gV2l0aCBydGNwLW11eCBhbmQgYnVuZGxlIGFsbCB0aGUgY2hhbm5lbHMgc2hvdWxkIGhhdmUgdGhlIHNhbWUgSUNFXG4gICAgICAgIC8vIHN0dWZmLlxuICAgICAgICB2YXIgc291cmNlcyA9IGJMaW5lLnNvdXJjZXM7XG4gICAgICAgIHZhciBzc3JjR3JvdXBzID0gYkxpbmUuc3NyY0dyb3VwcztcbiAgICAgICAgdmFyIHBvcnQgPSBiTGluZS5wb3J0O1xuXG4gICAgICAgIC8qIENocm9tZSBhZGRzIGRpZmZlcmVudCBjYW5kaWRhdGVzIGV2ZW4gdXNpbmcgYnVuZGxlLCBzbyB3ZSBjb25jYXQgdGhlIGNhbmRpZGF0ZXMgbGlzdCAqL1xuICAgICAgICBpZiAodHlwZW9mIGJMaW5lLmNhbmRpZGF0ZXMgIT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgY2FuZGlkYXRlcyAhPSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIGNhbmRpZGF0ZXMgPSBjYW5kaWRhdGVzLmNvbmNhdChiTGluZS5jYW5kaWRhdGVzKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY2FuZGlkYXRlcyA9IGJMaW5lLmNhbmRpZGF0ZXM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoKHR5cGVvZiBpY2VVZnJhZyAhPSAndW5kZWZpbmVkJykgJiYgKHR5cGVvZiBiTGluZS5pY2VVZnJhZyAhPSAndW5kZWZpbmVkJykgJiYgKGljZVVmcmFnICE9IGJMaW5lLmljZVVmcmFnKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiT25seSBCVU5ETEUgc3VwcG9ydGVkLCBpY2VVZnJhZyBtdXN0IGJlIHRoZSBzYW1lIGZvciBhbGwgbS1saW5lcy5cXG5cIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJcXHRMYXN0IGljZVVmcmFnOiBcIiArIGljZVVmcmFnICsgXCJcXG5cIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJcXHROZXcgaWNlVWZyYWc6IFwiICsgYkxpbmUuaWNlVWZyYWdcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIGJMaW5lLmljZVVmcmFnICE9ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgaWNlVWZyYWcgPSBiTGluZS5pY2VVZnJhZztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgodHlwZW9mIGljZVB3ZCAhPSAndW5kZWZpbmVkJykgJiYgKHR5cGVvZiBiTGluZS5pY2VQd2QgIT0gJ3VuZGVmaW5lZCcpICYmIChpY2VQd2QgIT0gYkxpbmUuaWNlUHdkKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiT25seSBCVU5ETEUgc3VwcG9ydGVkLCBpY2VQd2QgbXVzdCBiZSB0aGUgc2FtZSBmb3IgYWxsIG0tbGluZXMuXFxuXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiXFx0TGFzdCBpY2VQd2Q6IFwiICsgaWNlUHdkICsgXCJcXG5cIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJcXHROZXcgaWNlUHdkOiBcIiArIGJMaW5lLmljZVB3ZFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgYkxpbmUuaWNlUHdkICE9ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgaWNlUHdkID0gYkxpbmUuaWNlUHdkO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCh0eXBlb2YgZmluZ2VycHJpbnQgIT0gJ3VuZGVmaW5lZCcpICYmICh0eXBlb2YgYkxpbmUuZmluZ2VycHJpbnQgIT0gJ3VuZGVmaW5lZCcpICYmXG4gICAgICAgICAgICAoZmluZ2VycHJpbnQudHlwZSAhPSBiTGluZS5maW5nZXJwcmludC50eXBlIHx8IGZpbmdlcnByaW50Lmhhc2ggIT0gYkxpbmUuZmluZ2VycHJpbnQuaGFzaCkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk9ubHkgQlVORExFIHN1cHBvcnRlZCwgZmluZ2VycHJpbnQgbXVzdCBiZSB0aGUgc2FtZSBmb3IgYWxsIG0tbGluZXMuXFxuXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiXFx0TGFzdCBmaW5nZXJwcmludDogXCIgKyBKU09OLnN0cmluZ2lmeShmaW5nZXJwcmludCkgKyBcIlxcblwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIlxcdE5ldyBmaW5nZXJwcmludDogXCIgKyBKU09OLnN0cmluZ2lmeShiTGluZS5maW5nZXJwcmludClcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIGJMaW5lLmZpbmdlcnByaW50ICE9ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgZmluZ2VycHJpbnQgPSBiTGluZS5maW5nZXJwcmludDtcbiAgICAgICAgfVxuXG4gICAgICAgIHBheWxvYWRzW2JMaW5lLnR5cGVdID0gYkxpbmUucGF5bG9hZHM7XG4gICAgICAgIHJ0Y3BGYltiTGluZS50eXBlXSA9IGJMaW5lLnJ0Y3BGYjtcbiAgICAgICAgcnRwW2JMaW5lLnR5cGVdID0gYkxpbmUucnRwO1xuXG4gICAgICAgIC8vIGludmVydGVkIHNzcmMgZ3JvdXAgbWFwXG4gICAgICAgIHZhciBzc3JjMmdyb3VwID0ge307XG4gICAgICAgIGlmICh0eXBlb2Ygc3NyY0dyb3VwcyAhPT0gJ3VuZGVmaW5lZCcgJiYgQXJyYXkuaXNBcnJheShzc3JjR3JvdXBzKSkge1xuICAgICAgICAgICAgc3NyY0dyb3Vwcy5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjR3JvdXApIHtcbiAgICAgICAgICAgICAgICAvLyBYWFggVGhpcyBtaWdodCBicmFrZSBpZiBhbiBTU1JDIGlzIGluIG1vcmUgdGhhbiBvbmUgZ3JvdXBcbiAgICAgICAgICAgICAgICAvLyBmb3Igc29tZSByZWFzb24uXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBzc3JjR3JvdXAuc3NyY3MgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICAgICAgICAgIEFycmF5LmlzQXJyYXkoc3NyY0dyb3VwLnNzcmNzKSkge1xuICAgICAgICAgICAgICAgICAgICBzc3JjR3JvdXAuc3NyY3MuZm9yRWFjaChmdW5jdGlvbiAoc3NyYykge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBzc3JjMmdyb3VwW3NzcmNdID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcmMyZ3JvdXBbc3NyY10gPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgc3NyYzJncm91cFtzc3JjXS5wdXNoKHNzcmNHcm91cCk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gc3NyYyB0byBtLWxpbmUgaW5kZXguXG4gICAgICAgIHZhciBzc3JjMm1sID0ge307XG5cbiAgICAgICAgaWYgKHR5cGVvZiBzb3VyY2VzID09PSAnb2JqZWN0Jykge1xuXG4gICAgICAgICAgICAvLyBXZSdsbCB1c2UgdGhlIFwiYkxpbmVcIiBvYmplY3QgYXMgYSBwcm90b3R5cGUgZm9yIGVhY2ggbmV3IFwibUxpbmVcIlxuICAgICAgICAgICAgLy8gdGhhdCB3ZSBjcmVhdGUsIGJ1dCBmaXJzdCB3ZSBuZWVkIHRvIGNsZWFuIGl0IHVwIGEgYml0LlxuICAgICAgICAgICAgZGVsZXRlIGJMaW5lLnNvdXJjZXM7XG4gICAgICAgICAgICBkZWxldGUgYkxpbmUuc3NyY0dyb3VwcztcbiAgICAgICAgICAgIGRlbGV0ZSBiTGluZS5jYW5kaWRhdGVzO1xuICAgICAgICAgICAgZGVsZXRlIGJMaW5lLmljZVVmcmFnO1xuICAgICAgICAgICAgZGVsZXRlIGJMaW5lLmljZVB3ZDtcbiAgICAgICAgICAgIGRlbGV0ZSBiTGluZS5maW5nZXJwcmludDtcbiAgICAgICAgICAgIGRlbGV0ZSBiTGluZS5wb3J0O1xuICAgICAgICAgICAgZGVsZXRlIGJMaW5lLm1pZDtcblxuICAgICAgICAgICAgLy8gRXhwbG9kZSB0aGUgUGxhbiBCIGNoYW5uZWwgc291cmNlcyB3aXRoIG9uZSBtLWxpbmUgcGVyIHNvdXJjZS5cbiAgICAgICAgICAgIE9iamVjdC5rZXlzKHNvdXJjZXMpLmZvckVhY2goZnVuY3Rpb24oc3NyYykge1xuXG4gICAgICAgICAgICAgICAgLy8gVGhlICh1bmlmaWVkKSBtLWxpbmUgZm9yIHRoaXMgU1NSQy4gV2UgZWl0aGVyIGNyZWF0ZSBpdCBmcm9tXG4gICAgICAgICAgICAgICAgLy8gc2NyYXRjaCBvciwgaWYgaXQncyBhIGdyb3VwZWQgU1NSQywgd2UgcmUtdXNlIGEgcmVsYXRlZFxuICAgICAgICAgICAgICAgIC8vIG1saW5lLiBJbiBvdGhlciB3b3JkcywgaWYgdGhlIHNvdXJjZSBpcyBncm91cGVkIHdpdGggYW5vdGhlclxuICAgICAgICAgICAgICAgIC8vIHNvdXJjZSwgcHV0IHRoZSB0d28gdG9nZXRoZXIgaW4gdGhlIHNhbWUgbS1saW5lLlxuICAgICAgICAgICAgICAgIHZhciB1TGluZTtcblxuICAgICAgICAgICAgICAgIC8vIFdlIGFzc3VtZSBoZXJlIHRoYXQgd2UgYXJlIHRoZSBhbnN3ZXJlciBpbiB0aGUgTy9BLCBzbyBhbnlcbiAgICAgICAgICAgICAgICAvLyBvZmZlcnMgd2hpY2ggd2UgdHJhbnNsYXRlIGNvbWUgZnJvbSB0aGUgcmVtb3RlIHNpZGUsIHdoaWxlXG4gICAgICAgICAgICAgICAgLy8gYW5zd2VycyBhcmUgbG9jYWwuIFNvIHRoZSBjaGVjayBiZWxvdyBpcyB0byBtYWtlIHRoYXQgd2VcbiAgICAgICAgICAgICAgICAvLyBoYW5kbGUgcmVjZWl2ZS1vbmx5IFNTUkNzIGluIGEgc3BlY2lhbCB3YXkgb25seSBpZiB0aGV5IGNvbWVcbiAgICAgICAgICAgICAgICAvLyBmcm9tIHRoZSByZW1vdGUgc2lkZS5cbiAgICAgICAgICAgICAgICBpZiAoZGVzYy50eXBlPT09J29mZmVyJykge1xuICAgICAgICAgICAgICAgICAgICAvLyBXZSB3YW50IHRvIGRldGVjdCBTU1JDcyB3aGljaCBhcmUgdXNlZCBieSBhIHJlbW90ZSBwZWVyXG4gICAgICAgICAgICAgICAgICAgIC8vIGluIGFuIG0tbGluZSB3aXRoIGRpcmVjdGlvbj1yZWN2b25seSAoaS5lLiB0aGV5IGFyZVxuICAgICAgICAgICAgICAgICAgICAvLyBiZWluZyB1c2VkIGZvciBSVENQIG9ubHkpLlxuICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIGluZm9ybWF0aW9uIHdvdWxkIGhhdmUgZ290dGVuIGxvc3QgaWYgdGhlIHJlbW90ZVxuICAgICAgICAgICAgICAgICAgICAvLyBwZWVyIHVzZWQgVW5pZmllZCBQbGFuIGFuZCB0aGVpciBsb2NhbCBkZXNjcmlwdGlvbiB3YXNcbiAgICAgICAgICAgICAgICAgICAgLy8gdHJhbnNsYXRlZCB0byBQbGFuIEIuIFNvIHdlIHVzZSB0aGUgbGFjayBvZiBhbiBNU0lEXG4gICAgICAgICAgICAgICAgICAgIC8vIGF0dHJpYnV0ZSB0byBkZWR1Y2UgYSBcInJlY2VpdmUgb25seVwiIFNTUkMuXG4gICAgICAgICAgICAgICAgICAgIGlmICghc291cmNlc1tzc3JjXS5tc2lkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWN2b25seVNzcmNzW2JMaW5lLnR5cGVdW3NzcmNdID0gc291cmNlc1tzc3JjXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlY2VpdmUtb25seSBTU1JDcyBtdXN0IG5vdCBjcmVhdGUgbmV3IG0tbGluZXMuIFdlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB3aWxsIGFzc2lnbiB0aGVtIHRvIGFuIGV4aXN0aW5nIG0tbGluZSBsYXRlci5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2Ygc3NyYzJncm91cFtzc3JjXSAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgICAgICAgICAgICAgQXJyYXkuaXNBcnJheShzc3JjMmdyb3VwW3NzcmNdKSkge1xuICAgICAgICAgICAgICAgICAgICBzc3JjMmdyb3VwW3NzcmNdLnNvbWUoZnVuY3Rpb24gKHNzcmNHcm91cCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3NyY0dyb3VwLnNzcmNzICppcyogYW4gQXJyYXksIG5vIG5lZWQgdG8gY2hlY2tcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnYWluIGhlcmUuXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gc3NyY0dyb3VwLnNzcmNzLnNvbWUoZnVuY3Rpb24gKHJlbGF0ZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHNzcmMybWxbcmVsYXRlZF0gPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVMaW5lID0gc3NyYzJtbFtyZWxhdGVkXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdUxpbmUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHRoZSBtLWxpbmUgYWxyZWFkeSBleGlzdHMuIEp1c3QgYWRkIHRoZSBzb3VyY2UuXG4gICAgICAgICAgICAgICAgICAgIHVMaW5lLnNvdXJjZXNbc3NyY10gPSBzb3VyY2VzW3NzcmNdO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgc291cmNlc1tzc3JjXS5tc2lkO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFVzZSB0aGUgXCJiTGluZVwiIGFzIGEgcHJvdG90eXBlIGZvciB0aGUgXCJ1TGluZVwiLlxuICAgICAgICAgICAgICAgICAgICB1TGluZSA9IE9iamVjdC5jcmVhdGUoYkxpbmUpO1xuICAgICAgICAgICAgICAgICAgICBzc3JjMm1sW3NzcmNdID0gdUxpbmU7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBzb3VyY2VzW3NzcmNdLm1zaWQgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBBc3NpZ24gdGhlIG1zaWQgb2YgdGhlIHNvdXJjZSB0byB0aGUgbS1saW5lLiBOb3RlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGF0IGl0IGlzIG5vdCBndWFyYW50ZWVkIHRoYXQgdGhlIHNvdXJjZSB3aWxsIGhhdmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1zaWQuIEluIHBhcnRpY3VsYXIgXCJyZWN2b25seVwiIHNvdXJjZXMgZG9uJ3QgaGF2ZSBhblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbXNpZC4gTm90ZSB0aGF0IFwicmVjdm9ubHlcIiBpcyBhIHRlcm0gb25seSBkZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBmb3IgbS1saW5lcy5cbiAgICAgICAgICAgICAgICAgICAgICAgIHVMaW5lLm1zaWQgPSBzb3VyY2VzW3NzcmNdLm1zaWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgc291cmNlc1tzc3JjXS5tc2lkO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gV2UgYXNzaWduIG9uZSBTU1JDIHBlciBtZWRpYSBsaW5lLlxuICAgICAgICAgICAgICAgICAgICB1TGluZS5zb3VyY2VzID0ge307XG4gICAgICAgICAgICAgICAgICAgIHVMaW5lLnNvdXJjZXNbc3NyY10gPSBzb3VyY2VzW3NzcmNdO1xuICAgICAgICAgICAgICAgICAgICB1TGluZS5zc3JjR3JvdXBzID0gc3NyYzJncm91cFtzc3JjXTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBVc2UgdGhlIGNhY2hlZCBVbmlmaWVkIFBsYW4gU0RQIChpZiBpdCBleGlzdHMpIHRvIGFzc2lnblxuICAgICAgICAgICAgICAgICAgICAvLyBTU1JDcyB0byBtaWRzLlxuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGNhY2hlZCAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGVvZiBjYWNoZWQubWVkaWEgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICAgICAgICAgICAgICBBcnJheS5pc0FycmF5KGNhY2hlZC5tZWRpYSkpIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgY2FjaGVkLm1lZGlhLmZvckVhY2goZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIG0uc291cmNlcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT2JqZWN0LmtleXMobS5zb3VyY2VzKS5mb3JFYWNoKGZ1bmN0aW9uIChzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocyA9PT0gc3NyYykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVMaW5lLm1pZCA9IG0ubWlkO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdUxpbmUubWlkID09PSAndW5kZWZpbmVkJykge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGlzIGlzIGFuIFNTUkMgdGhhdCB3ZSBzZWUgZm9yIHRoZSBmaXJzdCB0aW1lXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhc3NpZ24gaXQgYSBuZXcgbWlkLiBUaGlzIGlzIHR5cGljYWxseSB0aGUgY2FzZSB3aGVuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGlzIG1ldGhvZCBpcyBjYWxsZWQgdG8gdHJhbnNmb3JtIGEgcmVtb3RlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBkZXNjcmlwdGlvbiBmb3IgdGhlIGZpcnN0IHRpbWUgb3Igd2hlbiB0aGVyZSBpcyBhXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBuZXcgU1NSQyBpbiB0aGUgcmVtb3RlIGRlc2NyaXB0aW9uIGJlY2F1c2UgYSBuZXdcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHBlZXIgaGFzIGpvaW5lZCB0aGUgY29uZmVyZW5jZS4gTG9jYWwgU1NSQ3Mgc2hvdWxkXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBoYXZlIGFscmVhZHkgYmVlbiBhZGRlZCB0byB0aGUgbWFwIGluIHRoZSB0b1BsYW5CXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBtZXRob2QuXG4gICAgICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQmVjYXVzZSBGRiBnZW5lcmF0ZXMgYW5zd2VycyBpbiBVbmlmaWVkIFBsYW4gc3R5bGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB3ZSBNVVNUIGFscmVhZHkgaGF2ZSBhIGNhY2hlZCBhbnN3ZXIgd2l0aCBhbGwgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBsb2NhbCBTU1JDcyBtYXBwZWQgdG8gc29tZSBtLWxpbmUvbWlkLlxuXG4gICAgICAgICAgICAgICAgICAgICAgICB1TGluZS5taWQgPSBbYkxpbmUudHlwZSwgJy0nLCBzc3JjXS5qb2luKCcnKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIEluY2x1ZGUgdGhlIGNhbmRpZGF0ZXMgaW4gdGhlIDFzdCBtZWRpYSBsaW5lLlxuICAgICAgICAgICAgICAgICAgICB1TGluZS5jYW5kaWRhdGVzID0gY2FuZGlkYXRlcztcbiAgICAgICAgICAgICAgICAgICAgdUxpbmUuaWNlVWZyYWcgPSBpY2VVZnJhZztcbiAgICAgICAgICAgICAgICAgICAgdUxpbmUuaWNlUHdkID0gaWNlUHdkO1xuICAgICAgICAgICAgICAgICAgICB1TGluZS5maW5nZXJwcmludCA9IGZpbmdlcnByaW50O1xuICAgICAgICAgICAgICAgICAgICB1TGluZS5wb3J0ID0gcG9ydDtcblxuICAgICAgICAgICAgICAgICAgICBtaWQydWxbdUxpbmUubWlkXSA9IHVMaW5lO1xuICAgICAgICAgICAgICAgICAgICBzb3VyY2VzMnVsW3VJZHhdID0gdUxpbmUuc291cmNlcztcblxuICAgICAgICAgICAgICAgICAgICBzZWxmLmNhY2hlLm1sVTJCTWFwW3VJZHhdID0gYklkeDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBzZWxmLmNhY2hlLm1sQjJVTWFwW2JJZHhdID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgICAgICAgIHNlbGYuY2FjaGUubWxCMlVNYXBbYklkeF0gPSB1SWR4O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHVJZHgrKztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB2YXIgdUxpbmUgPSBiTGluZTtcblxuICAgICAgICAgIHVMaW5lLmNhbmRpZGF0ZXMgPSBjYW5kaWRhdGVzO1xuICAgICAgICAgIHVMaW5lLmljZVVmcmFnID0gaWNlVWZyYWc7XG4gICAgICAgICAgdUxpbmUuaWNlUHdkID0gaWNlUHdkO1xuICAgICAgICAgIHVMaW5lLmZpbmdlcnByaW50ID0gZmluZ2VycHJpbnQ7XG4gICAgICAgICAgdUxpbmUucG9ydCA9IHBvcnQ7XG5cbiAgICAgICAgICBtaWQydWxbdUxpbmUubWlkXSA9IHVMaW5lO1xuXG4gICAgICAgICAgc2VsZi5jYWNoZS5tbFUyQk1hcFt1SWR4XSA9IGJJZHg7XG4gICAgICAgICAgaWYgKHR5cGVvZiBzZWxmLmNhY2hlLm1sQjJVTWFwW2JJZHhdID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgc2VsZi5jYWNoZS5tbEIyVU1hcFtiSWR4XSA9IHVJZHg7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgYklkeCsrO1xuICAgIH0pO1xuXG4gICAgLy8gUmVidWlsZCB0aGUgbWVkaWEgYXJyYXkgaW4gdGhlIHJpZ2h0IG9yZGVyIGFuZCBhZGQgdGhlIG1pc3NpbmcgbUxpbmVzXG4gICAgLy8gKG1pc3NpbmcgZnJvbSB0aGUgUGxhbiBCIFNEUCkuXG4gICAgc2Vzc2lvbi5tZWRpYSA9IFtdO1xuICAgIG1pZHMgPSBbXTsgLy8gcmV1c2VcblxuICAgIGlmIChkZXNjLnR5cGUgPT09ICdhbnN3ZXInKSB7XG5cbiAgICAgICAgLy8gVGhlIG1lZGlhIGxpbmVzIGluIHRoZSBhbnN3ZXIgbXVzdCBtYXRjaCB0aGUgbWVkaWEgbGluZXMgaW4gdGhlXG4gICAgICAgIC8vIG9mZmVyLiBUaGUgb3JkZXIgaXMgaW1wb3J0YW50IHRvby4gSGVyZSB3ZSBhc3N1bWUgdGhhdCBGaXJlZm94IGlzXG4gICAgICAgIC8vIHRoZSBhbnN3ZXJlciwgc28gd2UgbWVyZWx5IGhhdmUgdG8gdXNlIHRoZSByZWNvbnN0cnVjdGVkICh1bmlmaWVkKVxuICAgICAgICAvLyBhbnN3ZXIgdG8gdXBkYXRlIHRoZSBjYWNoZWQgKHVuaWZpZWQpIGFuc3dlciBhY2NvcmRpbmdseS5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gSW4gdGhlIGdlbmVyYWwgY2FzZSwgb25lIHdvdWxkIGhhdmUgdG8gdXNlIHRoZSBjYWNoZWQgKHVuaWZpZWQpXG4gICAgICAgIC8vIG9mZmVyIHRvIGZpbmQgdGhlIG0tbGluZXMgdGhhdCBhcmUgbWlzc2luZyBmcm9tIHRoZSByZWNvbnN0cnVjdGVkXG4gICAgICAgIC8vIGFuc3dlciwgcG90ZW50aWFsbHkgZ3JhYmJpbmcgdGhlbSBmcm9tIHRoZSBjYWNoZWQgKHVuaWZpZWQpIGFuc3dlci5cbiAgICAgICAgLy8gT25lIGhhcyB0byBiZSBjYXJlZnVsIHdpdGggdGhpcyBhcHByb2FjaCBiZWNhdXNlIGluYWN0aXZlIG0tbGluZXMgZG9cbiAgICAgICAgLy8gbm90IGFsd2F5cyBoYXZlIGFuIG1pZCwgbWFraW5nIGl0IHRyaWNreSAoaW1wb3NzaWJsZT8pIHRvIGZpbmQgd2hlcmVcbiAgICAgICAgLy8gZXhhY3RseSBhbmQgd2hpY2ggbS1saW5lcyBhcmUgbWlzc2luZyBmcm9tIHRoZSByZWNvbnN0cnVjdGVkIGFuc3dlci5cblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNhY2hlZC5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIHVMaW5lID0gY2FjaGVkLm1lZGlhW2ldO1xuXG4gICAgICAgICAgICBkZWxldGUgdUxpbmUubXNpZDtcbiAgICAgICAgICAgIGRlbGV0ZSB1TGluZS5zb3VyY2VzO1xuICAgICAgICAgICAgZGVsZXRlIHVMaW5lLnNzcmNHcm91cHM7XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2Ygc291cmNlczJ1bFtpXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgaWYgKCF1TGluZS5kaXJlY3Rpb25cbiAgICAgICAgICAgICAgICAgIHx8IHVMaW5lLmRpcmVjdGlvbiA9PT0gJ3NlbmRyZWN2JylcbiAgICAgICAgICAgICAgICAgIHVMaW5lLmRpcmVjdGlvbiA9ICdyZWN2b25seSc7XG4gICAgICAgICAgICAgIGVsc2UgaWYgKHVMaW5lLmRpcmVjdGlvbiA9PT0gJ3NlbmRvbmx5JylcbiAgICAgICAgICAgICAgICAgIHVMaW5lLmRpcmVjdGlvbiA9ICdpbmFjdGl2ZSc7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBpZiAoIXVMaW5lLmRpcmVjdGlvblxuICAgICAgICAgICAgICAgICAgfHwgdUxpbmUuZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnKVxuICAgICAgICAgICAgICAgICAgdUxpbmUuZGlyZWN0aW9uID0gJ3NlbmRyZWN2JztcbiAgICAgICAgICAgICAgZWxzZSBpZiAodUxpbmUuZGlyZWN0aW9uID09PSAncmVjdm9ubHknKVxuICAgICAgICAgICAgICAgICAgdUxpbmUuZGlyZWN0aW9uID0gJ3NlbmRvbmx5JztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdUxpbmUuc291cmNlcyA9IHNvdXJjZXMydWxbaV07XG4gICAgICAgICAgICB1TGluZS5jYW5kaWRhdGVzID0gY2FuZGlkYXRlcztcbiAgICAgICAgICAgIHVMaW5lLmljZVVmcmFnID0gaWNlVWZyYWc7XG4gICAgICAgICAgICB1TGluZS5pY2VQd2QgPSBpY2VQd2Q7XG4gICAgICAgICAgICB1TGluZS5maW5nZXJwcmludCA9IGZpbmdlcnByaW50O1xuXG4gICAgICAgICAgICB1TGluZS5ydHAgPSBydHBbdUxpbmUudHlwZV07XG4gICAgICAgICAgICB1TGluZS5wYXlsb2FkcyA9IHBheWxvYWRzW3VMaW5lLnR5cGVdO1xuICAgICAgICAgICAgdUxpbmUucnRjcEZiID0gcnRjcEZiW3VMaW5lLnR5cGVdO1xuXG4gICAgICAgICAgICBzZXNzaW9uLm1lZGlhLnB1c2godUxpbmUpO1xuXG4gICAgICAgICAgICBpZiAodHlwZW9mIHVMaW5lLm1pZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAvLyBpbmFjdGl2ZSBsaW5lcyBkb24ndC9tYXkgbm90IGhhdmUgYW4gbWlkLlxuICAgICAgICAgICAgICAgIG1pZHMucHVzaCh1TGluZS5taWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSBlbHNlIHtcblxuICAgICAgICAvLyBTRFAgb2ZmZXIvYW5zd2VyIChhbmQgdGhlIEpTRVAgc3BlYykgZm9yYmlkcyByZW1vdmluZyBhbiBtLXNlY3Rpb25cbiAgICAgICAgLy8gdW5kZXIgYW55IGNpcmN1bXN0YW5jZXMuIElmIHdlIGFyZSBubyBsb25nZXIgaW50ZXJlc3RlZCBpbiBzZW5kaW5nIGFcbiAgICAgICAgLy8gdHJhY2ssIHdlIGp1c3QgcmVtb3ZlIHRoZSBtc2lkIGFuZCBzc3JjIGF0dHJpYnV0ZXMgYW5kIHNldCBpdCB0b1xuICAgICAgICAvLyBlaXRoZXIgYT1yZWN2b25seSAoYXMgdGhlIHJlb2ZmZXJlciwgd2UgbXVzdCB1c2UgcmVjdm9ubHkgaWYgdGhlXG4gICAgICAgIC8vIG90aGVyIHNpZGUgd2FzIHByZXZpb3VzbHkgc2VuZGluZyBvbiB0aGUgbS1zZWN0aW9uLCBidXQgd2UgY2FuIGFsc29cbiAgICAgICAgLy8gbGVhdmUgdGhlIHBvc3NpYmlsaXR5IG9wZW4gaWYgaXQgd2Fzbid0IHByZXZpb3VzbHkgaW4gdXNlKSwgb3JcbiAgICAgICAgLy8gYT1pbmFjdGl2ZS5cblxuICAgICAgICBpZiAodHlwZW9mIGNhY2hlZCAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgICAgIHR5cGVvZiBjYWNoZWQubWVkaWEgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICBBcnJheS5pc0FycmF5KGNhY2hlZC5tZWRpYSkpIHtcbiAgICAgICAgICAgIGNhY2hlZC5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKHVMaW5lKSB7XG4gICAgICAgICAgICAgICAgbWlkcy5wdXNoKHVMaW5lLm1pZCk7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBtaWQydWxbdUxpbmUubWlkXSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbi5tZWRpYS5wdXNoKG1pZDJ1bFt1TGluZS5taWRdKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgdUxpbmUubXNpZDtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHVMaW5lLnNvdXJjZXM7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB1TGluZS5zc3JjR3JvdXBzO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICghdUxpbmUuZGlyZWN0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgICB8fCB1TGluZS5kaXJlY3Rpb24gPT09ICdzZW5kcmVjdicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHVMaW5lLmRpcmVjdGlvbiA9ICdzZW5kb25seSc7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKCF1TGluZS5kaXJlY3Rpb25cbiAgICAgICAgICAgICAgICAgICAgICAgIHx8IHVMaW5lLmRpcmVjdGlvbiA9PT0gJ3JlY3Zvbmx5Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdUxpbmUuZGlyZWN0aW9uID0gJ2luYWN0aXZlJztcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGFkZFNldHVwQXR0ciAodUxpbmUpO1xuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uLm1lZGlhLnB1c2godUxpbmUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQWRkIGFsbCB0aGUgcmVtYWluaW5nIChuZXcpIG0tbGluZXMgb2YgdGhlIHRyYW5zZm9ybWVkIFNEUC5cbiAgICAgICAgT2JqZWN0LmtleXMobWlkMnVsKS5mb3JFYWNoKGZ1bmN0aW9uKG1pZCkge1xuICAgICAgICAgICAgaWYgKG1pZHMuaW5kZXhPZihtaWQpID09PSAtMSkge1xuICAgICAgICAgICAgICAgIG1pZHMucHVzaChtaWQpO1xuICAgICAgICAgICAgICAgIGlmIChtaWQydWxbbWlkXS5kaXJlY3Rpb24gPT09ICdyZWN2b25seScpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhpcyBpcyBhIHJlbW90ZSByZWN2b25seSBjaGFubmVsLiBBZGQgaXRzIFNTUkMgdG8gdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIGFwcHJvcHJpYXRlIHNlbmRyZWN2IG9yIHNlbmRvbmx5IGNoYW5uZWwuXG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE8oZ3ApIHdoYXQgaWYgd2UgZG9uJ3QgaGF2ZSBzZW5kcmVjdi9zZW5kb25seVxuICAgICAgICAgICAgICAgICAgICAvLyBjaGFubmVsP1xuXG4gICAgICAgICAgICAgICAgICAgIHZhciBkb25lID0gZmFsc2U7XG5cbiAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbi5tZWRpYS5zb21lKGZ1bmN0aW9uICh1TGluZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCh1TGluZS5kaXJlY3Rpb24gPT09ICdzZW5kcmVjdicgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1TGluZS5kaXJlY3Rpb24gPT09ICdzZW5kb25seScpICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdUxpbmUudHlwZSA9PT0gbWlkMnVsW21pZF0udHlwZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1pZDJ1bFttaWRdIHNob3VsZG4ndCBoYXZlIGFueSBzc3JjLWdyb3Vwc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9iamVjdC5rZXlzKG1pZDJ1bFttaWRdLnNvdXJjZXMpLmZvckVhY2goXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVMaW5lLnNvdXJjZXNbc3NyY10gPVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWlkMnVsW21pZF0uc291cmNlc1tzc3JjXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbmUgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoIWRvbmUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlc3Npb24ubWVkaWEucHVzaChtaWQydWxbbWlkXSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uLm1lZGlhLnB1c2gobWlkMnVsW21pZF0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gQWZ0ZXIgd2UgaGF2ZSBjb25zdHJ1Y3RlZCB0aGUgUGxhbiBVbmlmaWVkIG0tbGluZXMgd2UgY2FuIGZpZ3VyZSBvdXRcbiAgICAvLyB3aGVyZSAoaW4gd2hpY2ggbS1saW5lKSB0byBwbGFjZSB0aGUgJ3JlY3Zvbmx5IFNTUkNzJy5cbiAgICAvLyBOb3RlOiB3ZSBhc3N1bWUgaGVyZSB0aGF0IHdlIGFyZSB0aGUgYW5zd2VyZXIgaW4gdGhlIE8vQSwgc28gYW55IG9mZmVyc1xuICAgIC8vIHdoaWNoIHdlIHRyYW5zbGF0ZSBjb21lIGZyb20gdGhlIHJlbW90ZSBzaWRlLCB3aGlsZSBhbnN3ZXJzIGFyZSBsb2NhbFxuICAgIC8vIChhbmQgc28gb3VyIGxhc3QgbG9jYWwgZGVzY3JpcHRpb24gaXMgY2FjaGVkIGFzIGFuICdhbnN3ZXInKS5cbiAgICBbXCJhdWRpb1wiLCBcInZpZGVvXCJdLmZvckVhY2goZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgaWYgKCFzZXNzaW9uIHx8ICFzZXNzaW9uLm1lZGlhIHx8ICFBcnJheS5pc0FycmF5KHNlc3Npb24ubWVkaWEpKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHZhciBpZHggPSBudWxsO1xuICAgICAgICBpZiAoT2JqZWN0LmtleXMocmVjdm9ubHlTc3Jjc1t0eXBlXSkubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgaWR4ID0gc2VsZi5nZXRGaXJzdFNlbmRpbmdJbmRleEZyb21BbnN3ZXIodHlwZSk7XG4gICAgICAgICAgICBpZiAoaWR4ID09PSBudWxsKXtcbiAgICAgICAgICAgICAgICAvLyBJZiB0aGlzIGlzIHRoZSBmaXJzdCBvZmZlciB3ZSByZWNlaXZlLCB3ZSBkb24ndCBoYXZlIGFcbiAgICAgICAgICAgICAgICAvLyBjYWNoZWQgYW5zd2VyLiBBc3N1bWUgdGhhdCB3ZSB3aWxsIGJlIHNlbmRpbmcgbWVkaWEgdXNpbmdcbiAgICAgICAgICAgICAgICAvLyB0aGUgZmlyc3QgbS1saW5lIGZvciBlYWNoIG1lZGlhIHR5cGUuXG5cbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlc3Npb24ubWVkaWEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHNlc3Npb24ubWVkaWFbaV0udHlwZSA9PT0gdHlwZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWR4ID0gaTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlkeCAmJiBzZXNzaW9uLm1lZGlhLmxlbmd0aCA+IGlkeCkge1xuICAgICAgICAgICAgdmFyIG1MaW5lID0gc2Vzc2lvbi5tZWRpYVtpZHhdO1xuICAgICAgICAgICAgT2JqZWN0LmtleXMocmVjdm9ubHlTc3Jjc1t0eXBlXSkuZm9yRWFjaChmdW5jdGlvbihzc3JjKSB7XG4gICAgICAgICAgICAgICAgaWYgKG1MaW5lLnNvdXJjZXMgJiYgbUxpbmUuc291cmNlc1tzc3JjXSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXCJSZXBsYWNpbmcgYW4gZXhpc3RpbmcgU1NSQy5cIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICghbUxpbmUuc291cmNlcykge1xuICAgICAgICAgICAgICAgICAgICBtTGluZS5zb3VyY2VzID0ge307XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgbUxpbmUuc291cmNlc1tzc3JjXSA9IHJlY3Zvbmx5U3NyY3NbdHlwZV1bc3NyY107XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgaWYgKHR5cGVvZiBzZXNzaW9uLmdyb3VwcyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIC8vIFdlIHJlZ2VuZXJhdGUgdGhlIEJVTkRMRSBncm91cCAoc2luY2Ugd2UgcmVnZW5lcmF0ZWQgdGhlIG1pZHMpXG4gICAgICBzZXNzaW9uLmdyb3Vwcy5zb21lKGZ1bmN0aW9uKGdyb3VwKSB7XG5cdCAgaWYgKGdyb3VwLnR5cGUgPT09ICdCVU5ETEUnKSB7XG5cdCAgICAgIGdyb3VwLm1pZHMgPSBtaWRzLmpvaW4oJyAnKTtcblx0ICAgICAgcmV0dXJuIHRydWU7XG5cdCAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gbXNpZCBzZW1hbnRpY1xuICAgIHNlc3Npb24ubXNpZFNlbWFudGljID0ge1xuICAgICAgICBzZW1hbnRpYzogJ1dNUycsXG4gICAgICAgIHRva2VuOiAnKidcbiAgICB9O1xuXG4gICAgdmFyIHJlc1N0ciA9IHRyYW5zZm9ybS53cml0ZShzZXNzaW9uKTtcblxuICAgIC8vIENhY2hlIHRoZSB0cmFuc2Zvcm1lZCBTRFAgKFVuaWZpZWQgUGxhbikgZm9yIGxhdGVyIHJlLXVzZSBpbiB0aGlzXG4gICAgLy8gZnVuY3Rpb24uXG4gICAgdGhpcy5jYWNoZVtkZXNjLnR5cGVdID0gcmVzU3RyO1xuXG4gICAgcmV0dXJuIG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgICB0eXBlOiBkZXNjLnR5cGUsXG4gICAgICAgIHNkcDogcmVzU3RyXG4gICAgfSk7XG5cbiAgICAvLyNlbmRyZWdpb25cbn07XG4iLCIvKiBDb3B5cmlnaHQgQCAyMDE1IEF0bGFzc2lhbiBQdHkgTHRkXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbnZhciB0cmFuc2Zvcm0gPSByZXF1aXJlKCdzZHAtdHJhbnNmb3JtJyk7XG5cbmV4cG9ydHMud3JpdGUgPSBmdW5jdGlvbihzZXNzaW9uLCBvcHRzKSB7XG5cbiAgaWYgKHR5cGVvZiBzZXNzaW9uICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgdHlwZW9mIHNlc3Npb24ubWVkaWEgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICBBcnJheS5pc0FycmF5KHNlc3Npb24ubWVkaWEpKSB7XG5cbiAgICBzZXNzaW9uLm1lZGlhLmZvckVhY2goZnVuY3Rpb24gKG1MaW5lKSB7XG4gICAgICAvLyBleHBhbmQgc291cmNlcyB0byBzc3Jjc1xuICAgICAgaWYgKHR5cGVvZiBtTGluZS5zb3VyY2VzICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICBPYmplY3Qua2V5cyhtTGluZS5zb3VyY2VzKS5sZW5ndGggIT09IDApIHtcbiAgICAgICAgICBtTGluZS5zc3JjcyA9IFtdO1xuICAgICAgICAgIE9iamVjdC5rZXlzKG1MaW5lLnNvdXJjZXMpLmZvckVhY2goZnVuY3Rpb24gKHNzcmMpIHtcbiAgICAgICAgICAgIHZhciBzb3VyY2UgPSBtTGluZS5zb3VyY2VzW3NzcmNdO1xuICAgICAgICAgICAgT2JqZWN0LmtleXMoc291cmNlKS5mb3JFYWNoKGZ1bmN0aW9uIChhdHRyaWJ1dGUpIHtcbiAgICAgICAgICAgICAgbUxpbmUuc3NyY3MucHVzaCh7XG4gICAgICAgICAgICAgICAgaWQ6IHNzcmMsXG4gICAgICAgICAgICAgICAgYXR0cmlidXRlOiBhdHRyaWJ1dGUsXG4gICAgICAgICAgICAgICAgdmFsdWU6IHNvdXJjZVthdHRyaWJ1dGVdXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgZGVsZXRlIG1MaW5lLnNvdXJjZXM7XG4gICAgICAgIH1cblxuICAgICAgLy8gam9pbiBzc3JjcyBpbiBzc3JjIGdyb3Vwc1xuICAgICAgaWYgKHR5cGVvZiBtTGluZS5zc3JjR3JvdXBzICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICBBcnJheS5pc0FycmF5KG1MaW5lLnNzcmNHcm91cHMpKSB7XG4gICAgICAgICAgbUxpbmUuc3NyY0dyb3Vwcy5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjR3JvdXApIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygc3NyY0dyb3VwLnNzcmNzICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgICAgIEFycmF5LmlzQXJyYXkoc3NyY0dyb3VwLnNzcmNzKSkge1xuICAgICAgICAgICAgICBzc3JjR3JvdXAuc3NyY3MgPSBzc3JjR3JvdXAuc3NyY3Muam9pbignICcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvLyBqb2luIGdyb3VwIG1pZHNcbiAgaWYgKHR5cGVvZiBzZXNzaW9uICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgdHlwZW9mIHNlc3Npb24uZ3JvdXBzICE9PSAndW5kZWZpbmVkJyAmJiBBcnJheS5pc0FycmF5KHNlc3Npb24uZ3JvdXBzKSkge1xuXG4gICAgc2Vzc2lvbi5ncm91cHMuZm9yRWFjaChmdW5jdGlvbiAoZykge1xuICAgICAgaWYgKHR5cGVvZiBnLm1pZHMgIT09ICd1bmRlZmluZWQnICYmIEFycmF5LmlzQXJyYXkoZy5taWRzKSkge1xuICAgICAgICBnLm1pZHMgPSBnLm1pZHMuam9pbignICcpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIHRyYW5zZm9ybS53cml0ZShzZXNzaW9uLCBvcHRzKTtcbn07XG5cbmV4cG9ydHMucGFyc2UgPSBmdW5jdGlvbihzZHApIHtcbiAgdmFyIHNlc3Npb24gPSB0cmFuc2Zvcm0ucGFyc2Uoc2RwKTtcblxuICBpZiAodHlwZW9mIHNlc3Npb24gIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiBzZXNzaW9uLm1lZGlhICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgQXJyYXkuaXNBcnJheShzZXNzaW9uLm1lZGlhKSkge1xuXG4gICAgc2Vzc2lvbi5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uIChtTGluZSkge1xuICAgICAgLy8gZ3JvdXAgc291cmNlcyBhdHRyaWJ1dGVzIGJ5IHNzcmNcbiAgICAgIGlmICh0eXBlb2YgbUxpbmUuc3NyY3MgIT09ICd1bmRlZmluZWQnICYmIEFycmF5LmlzQXJyYXkobUxpbmUuc3NyY3MpKSB7XG4gICAgICAgIG1MaW5lLnNvdXJjZXMgPSB7fTtcbiAgICAgICAgbUxpbmUuc3NyY3MuZm9yRWFjaChmdW5jdGlvbiAoc3NyYykge1xuICAgICAgICAgIGlmICghbUxpbmUuc291cmNlc1tzc3JjLmlkXSlcbiAgICAgICAgICBtTGluZS5zb3VyY2VzW3NzcmMuaWRdID0ge307XG4gICAgICAgIG1MaW5lLnNvdXJjZXNbc3NyYy5pZF1bc3NyYy5hdHRyaWJ1dGVdID0gc3NyYy52YWx1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgZGVsZXRlIG1MaW5lLnNzcmNzO1xuICAgICAgfVxuXG4gICAgICAvLyBzcGxpdCBzc3JjcyBpbiBzc3JjIGdyb3Vwc1xuICAgICAgaWYgKHR5cGVvZiBtTGluZS5zc3JjR3JvdXBzICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICBBcnJheS5pc0FycmF5KG1MaW5lLnNzcmNHcm91cHMpKSB7XG4gICAgICAgICAgbUxpbmUuc3NyY0dyb3Vwcy5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjR3JvdXApIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygc3NyY0dyb3VwLnNzcmNzID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICBzc3JjR3JvdXAuc3NyY3MgPSBzc3JjR3JvdXAuc3NyY3Muc3BsaXQoJyAnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH0pO1xuICB9XG4gIC8vIHNwbGl0IGdyb3VwIG1pZHNcbiAgaWYgKHR5cGVvZiBzZXNzaW9uICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgdHlwZW9mIHNlc3Npb24uZ3JvdXBzICE9PSAndW5kZWZpbmVkJyAmJiBBcnJheS5pc0FycmF5KHNlc3Npb24uZ3JvdXBzKSkge1xuXG4gICAgc2Vzc2lvbi5ncm91cHMuZm9yRWFjaChmdW5jdGlvbiAoZykge1xuICAgICAgaWYgKHR5cGVvZiBnLm1pZHMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIGcubWlkcyA9IGcubWlkcy5zcGxpdCgnICcpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIHNlc3Npb247XG59O1xuXG4iLCIgLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG5cbi8vIFNEUCBoZWxwZXJzLlxudmFyIFNEUFV0aWxzID0ge307XG5cbi8vIEdlbmVyYXRlIGFuIGFscGhhbnVtZXJpYyBpZGVudGlmaWVyIGZvciBjbmFtZSBvciBtaWRzLlxuLy8gVE9ETzogdXNlIFVVSURzIGluc3RlYWQ/IGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL2plZC85ODI4ODNcblNEUFV0aWxzLmdlbmVyYXRlSWRlbnRpZmllciA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc3Vic3RyKDIsIDEwKTtcbn07XG5cbi8vIFRoZSBSVENQIENOQU1FIHVzZWQgYnkgYWxsIHBlZXJjb25uZWN0aW9ucyBmcm9tIHRoZSBzYW1lIEpTLlxuU0RQVXRpbHMubG9jYWxDTmFtZSA9IFNEUFV0aWxzLmdlbmVyYXRlSWRlbnRpZmllcigpO1xuXG4vLyBTcGxpdHMgU0RQIGludG8gbGluZXMsIGRlYWxpbmcgd2l0aCBib3RoIENSTEYgYW5kIExGLlxuU0RQVXRpbHMuc3BsaXRMaW5lcyA9IGZ1bmN0aW9uKGJsb2IpIHtcbiAgcmV0dXJuIGJsb2IudHJpbSgpLnNwbGl0KCdcXG4nKS5tYXAoZnVuY3Rpb24obGluZSkge1xuICAgIHJldHVybiBsaW5lLnRyaW0oKTtcbiAgfSk7XG59O1xuLy8gU3BsaXRzIFNEUCBpbnRvIHNlc3Npb25wYXJ0IGFuZCBtZWRpYXNlY3Rpb25zLiBFbnN1cmVzIENSTEYuXG5TRFBVdGlscy5zcGxpdFNlY3Rpb25zID0gZnVuY3Rpb24oYmxvYikge1xuICB2YXIgcGFydHMgPSBibG9iLnNwbGl0KCdcXG5tPScpO1xuICByZXR1cm4gcGFydHMubWFwKGZ1bmN0aW9uKHBhcnQsIGluZGV4KSB7XG4gICAgcmV0dXJuIChpbmRleCA+IDAgPyAnbT0nICsgcGFydCA6IHBhcnQpLnRyaW0oKSArICdcXHJcXG4nO1xuICB9KTtcbn07XG5cbi8vIFJldHVybnMgbGluZXMgdGhhdCBzdGFydCB3aXRoIGEgY2VydGFpbiBwcmVmaXguXG5TRFBVdGlscy5tYXRjaFByZWZpeCA9IGZ1bmN0aW9uKGJsb2IsIHByZWZpeCkge1xuICByZXR1cm4gU0RQVXRpbHMuc3BsaXRMaW5lcyhibG9iKS5maWx0ZXIoZnVuY3Rpb24obGluZSkge1xuICAgIHJldHVybiBsaW5lLmluZGV4T2YocHJlZml4KSA9PT0gMDtcbiAgfSk7XG59O1xuXG4vLyBQYXJzZXMgYW4gSUNFIGNhbmRpZGF0ZSBsaW5lLiBTYW1wbGUgaW5wdXQ6XG4vLyBjYW5kaWRhdGU6NzAyNzg2MzUwIDIgdWRwIDQxODE5OTAyIDguOC44LjggNjA3NjkgdHlwIHJlbGF5IHJhZGRyIDguOC44Ljhcbi8vIHJwb3J0IDU1OTk2XCJcblNEUFV0aWxzLnBhcnNlQ2FuZGlkYXRlID0gZnVuY3Rpb24obGluZSkge1xuICB2YXIgcGFydHM7XG4gIC8vIFBhcnNlIGJvdGggdmFyaWFudHMuXG4gIGlmIChsaW5lLmluZGV4T2YoJ2E9Y2FuZGlkYXRlOicpID09PSAwKSB7XG4gICAgcGFydHMgPSBsaW5lLnN1YnN0cmluZygxMikuc3BsaXQoJyAnKTtcbiAgfSBlbHNlIHtcbiAgICBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDEwKS5zcGxpdCgnICcpO1xuICB9XG5cbiAgdmFyIGNhbmRpZGF0ZSA9IHtcbiAgICBmb3VuZGF0aW9uOiBwYXJ0c1swXSxcbiAgICBjb21wb25lbnQ6IHBhcnNlSW50KHBhcnRzWzFdLCAxMCksXG4gICAgcHJvdG9jb2w6IHBhcnRzWzJdLnRvTG93ZXJDYXNlKCksXG4gICAgcHJpb3JpdHk6IHBhcnNlSW50KHBhcnRzWzNdLCAxMCksXG4gICAgaXA6IHBhcnRzWzRdLFxuICAgIHBvcnQ6IHBhcnNlSW50KHBhcnRzWzVdLCAxMCksXG4gICAgLy8gc2tpcCBwYXJ0c1s2XSA9PSAndHlwJ1xuICAgIHR5cGU6IHBhcnRzWzddXG4gIH07XG5cbiAgZm9yICh2YXIgaSA9IDg7IGkgPCBwYXJ0cy5sZW5ndGg7IGkgKz0gMikge1xuICAgIHN3aXRjaCAocGFydHNbaV0pIHtcbiAgICAgIGNhc2UgJ3JhZGRyJzpcbiAgICAgICAgY2FuZGlkYXRlLnJlbGF0ZWRBZGRyZXNzID0gcGFydHNbaSArIDFdO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3Jwb3J0JzpcbiAgICAgICAgY2FuZGlkYXRlLnJlbGF0ZWRQb3J0ID0gcGFyc2VJbnQocGFydHNbaSArIDFdLCAxMCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAndGNwdHlwZSc6XG4gICAgICAgIGNhbmRpZGF0ZS50Y3BUeXBlID0gcGFydHNbaSArIDFdO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3VmcmFnJzpcbiAgICAgICAgY2FuZGlkYXRlLnVmcmFnID0gcGFydHNbaSArIDFdOyAvLyBmb3IgYmFja3dhcmQgY29tcGFiaWxpdHkuXG4gICAgICAgIGNhbmRpZGF0ZS51c2VybmFtZUZyYWdtZW50ID0gcGFydHNbaSArIDFdO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6IC8vIGV4dGVuc2lvbiBoYW5kbGluZywgaW4gcGFydGljdWxhciB1ZnJhZ1xuICAgICAgICBjYW5kaWRhdGVbcGFydHNbaV1dID0gcGFydHNbaSArIDFdO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNhbmRpZGF0ZTtcbn07XG5cbi8vIFRyYW5zbGF0ZXMgYSBjYW5kaWRhdGUgb2JqZWN0IGludG8gU0RQIGNhbmRpZGF0ZSBhdHRyaWJ1dGUuXG5TRFBVdGlscy53cml0ZUNhbmRpZGF0ZSA9IGZ1bmN0aW9uKGNhbmRpZGF0ZSkge1xuICB2YXIgc2RwID0gW107XG4gIHNkcC5wdXNoKGNhbmRpZGF0ZS5mb3VuZGF0aW9uKTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLmNvbXBvbmVudCk7XG4gIHNkcC5wdXNoKGNhbmRpZGF0ZS5wcm90b2NvbC50b1VwcGVyQ2FzZSgpKTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLnByaW9yaXR5KTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLmlwKTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLnBvcnQpO1xuXG4gIHZhciB0eXBlID0gY2FuZGlkYXRlLnR5cGU7XG4gIHNkcC5wdXNoKCd0eXAnKTtcbiAgc2RwLnB1c2godHlwZSk7XG4gIGlmICh0eXBlICE9PSAnaG9zdCcgJiYgY2FuZGlkYXRlLnJlbGF0ZWRBZGRyZXNzICYmXG4gICAgICBjYW5kaWRhdGUucmVsYXRlZFBvcnQpIHtcbiAgICBzZHAucHVzaCgncmFkZHInKTtcbiAgICBzZHAucHVzaChjYW5kaWRhdGUucmVsYXRlZEFkZHJlc3MpOyAvLyB3YXM6IHJlbEFkZHJcbiAgICBzZHAucHVzaCgncnBvcnQnKTtcbiAgICBzZHAucHVzaChjYW5kaWRhdGUucmVsYXRlZFBvcnQpOyAvLyB3YXM6IHJlbFBvcnRcbiAgfVxuICBpZiAoY2FuZGlkYXRlLnRjcFR5cGUgJiYgY2FuZGlkYXRlLnByb3RvY29sLnRvTG93ZXJDYXNlKCkgPT09ICd0Y3AnKSB7XG4gICAgc2RwLnB1c2goJ3RjcHR5cGUnKTtcbiAgICBzZHAucHVzaChjYW5kaWRhdGUudGNwVHlwZSk7XG4gIH1cbiAgaWYgKGNhbmRpZGF0ZS51ZnJhZykge1xuICAgIHNkcC5wdXNoKCd1ZnJhZycpO1xuICAgIHNkcC5wdXNoKGNhbmRpZGF0ZS51ZnJhZyk7XG4gIH1cbiAgcmV0dXJuICdjYW5kaWRhdGU6JyArIHNkcC5qb2luKCcgJyk7XG59O1xuXG4vLyBQYXJzZXMgYW4gaWNlLW9wdGlvbnMgbGluZSwgcmV0dXJucyBhbiBhcnJheSBvZiBvcHRpb24gdGFncy5cbi8vIGE9aWNlLW9wdGlvbnM6Zm9vIGJhclxuU0RQVXRpbHMucGFyc2VJY2VPcHRpb25zID0gZnVuY3Rpb24obGluZSkge1xuICByZXR1cm4gbGluZS5zdWJzdHIoMTQpLnNwbGl0KCcgJyk7XG59XG5cbi8vIFBhcnNlcyBhbiBydHBtYXAgbGluZSwgcmV0dXJucyBSVENSdHBDb2RkZWNQYXJhbWV0ZXJzLiBTYW1wbGUgaW5wdXQ6XG4vLyBhPXJ0cG1hcDoxMTEgb3B1cy80ODAwMC8yXG5TRFBVdGlscy5wYXJzZVJ0cE1hcCA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgdmFyIHBhcnRzID0gbGluZS5zdWJzdHIoOSkuc3BsaXQoJyAnKTtcbiAgdmFyIHBhcnNlZCA9IHtcbiAgICBwYXlsb2FkVHlwZTogcGFyc2VJbnQocGFydHMuc2hpZnQoKSwgMTApIC8vIHdhczogaWRcbiAgfTtcblxuICBwYXJ0cyA9IHBhcnRzWzBdLnNwbGl0KCcvJyk7XG5cbiAgcGFyc2VkLm5hbWUgPSBwYXJ0c1swXTtcbiAgcGFyc2VkLmNsb2NrUmF0ZSA9IHBhcnNlSW50KHBhcnRzWzFdLCAxMCk7IC8vIHdhczogY2xvY2tyYXRlXG4gIC8vIHdhczogY2hhbm5lbHNcbiAgcGFyc2VkLm51bUNoYW5uZWxzID0gcGFydHMubGVuZ3RoID09PSAzID8gcGFyc2VJbnQocGFydHNbMl0sIDEwKSA6IDE7XG4gIHJldHVybiBwYXJzZWQ7XG59O1xuXG4vLyBHZW5lcmF0ZSBhbiBhPXJ0cG1hcCBsaW5lIGZyb20gUlRDUnRwQ29kZWNDYXBhYmlsaXR5IG9yXG4vLyBSVENSdHBDb2RlY1BhcmFtZXRlcnMuXG5TRFBVdGlscy53cml0ZVJ0cE1hcCA9IGZ1bmN0aW9uKGNvZGVjKSB7XG4gIHZhciBwdCA9IGNvZGVjLnBheWxvYWRUeXBlO1xuICBpZiAoY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGUgIT09IHVuZGVmaW5lZCkge1xuICAgIHB0ID0gY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGU7XG4gIH1cbiAgcmV0dXJuICdhPXJ0cG1hcDonICsgcHQgKyAnICcgKyBjb2RlYy5uYW1lICsgJy8nICsgY29kZWMuY2xvY2tSYXRlICtcbiAgICAgIChjb2RlYy5udW1DaGFubmVscyAhPT0gMSA/ICcvJyArIGNvZGVjLm51bUNoYW5uZWxzIDogJycpICsgJ1xcclxcbic7XG59O1xuXG4vLyBQYXJzZXMgYW4gYT1leHRtYXAgbGluZSAoaGVhZGVyZXh0ZW5zaW9uIGZyb20gUkZDIDUyODUpLiBTYW1wbGUgaW5wdXQ6XG4vLyBhPWV4dG1hcDoyIHVybjppZXRmOnBhcmFtczpydHAtaGRyZXh0OnRvZmZzZXRcbi8vIGE9ZXh0bWFwOjIvc2VuZG9ubHkgdXJuOmlldGY6cGFyYW1zOnJ0cC1oZHJleHQ6dG9mZnNldFxuU0RQVXRpbHMucGFyc2VFeHRtYXAgPSBmdW5jdGlvbihsaW5lKSB7XG4gIHZhciBwYXJ0cyA9IGxpbmUuc3Vic3RyKDkpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAgaWQ6IHBhcnNlSW50KHBhcnRzWzBdLCAxMCksXG4gICAgZGlyZWN0aW9uOiBwYXJ0c1swXS5pbmRleE9mKCcvJykgPiAwID8gcGFydHNbMF0uc3BsaXQoJy8nKVsxXSA6ICdzZW5kcmVjdicsXG4gICAgdXJpOiBwYXJ0c1sxXVxuICB9O1xufTtcblxuLy8gR2VuZXJhdGVzIGE9ZXh0bWFwIGxpbmUgZnJvbSBSVENSdHBIZWFkZXJFeHRlbnNpb25QYXJhbWV0ZXJzIG9yXG4vLyBSVENSdHBIZWFkZXJFeHRlbnNpb24uXG5TRFBVdGlscy53cml0ZUV4dG1hcCA9IGZ1bmN0aW9uKGhlYWRlckV4dGVuc2lvbikge1xuICByZXR1cm4gJ2E9ZXh0bWFwOicgKyAoaGVhZGVyRXh0ZW5zaW9uLmlkIHx8IGhlYWRlckV4dGVuc2lvbi5wcmVmZXJyZWRJZCkgK1xuICAgICAgKGhlYWRlckV4dGVuc2lvbi5kaXJlY3Rpb24gJiYgaGVhZGVyRXh0ZW5zaW9uLmRpcmVjdGlvbiAhPT0gJ3NlbmRyZWN2J1xuICAgICAgICAgID8gJy8nICsgaGVhZGVyRXh0ZW5zaW9uLmRpcmVjdGlvblxuICAgICAgICAgIDogJycpICtcbiAgICAgICcgJyArIGhlYWRlckV4dGVuc2lvbi51cmkgKyAnXFxyXFxuJztcbn07XG5cbi8vIFBhcnNlcyBhbiBmdG1wIGxpbmUsIHJldHVybnMgZGljdGlvbmFyeS4gU2FtcGxlIGlucHV0OlxuLy8gYT1mbXRwOjk2IHZicj1vbjtjbmc9b25cbi8vIEFsc28gZGVhbHMgd2l0aCB2YnI9b247IGNuZz1vblxuU0RQVXRpbHMucGFyc2VGbXRwID0gZnVuY3Rpb24obGluZSkge1xuICB2YXIgcGFyc2VkID0ge307XG4gIHZhciBrdjtcbiAgdmFyIHBhcnRzID0gbGluZS5zdWJzdHIobGluZS5pbmRleE9mKCcgJykgKyAxKS5zcGxpdCgnOycpO1xuICBmb3IgKHZhciBqID0gMDsgaiA8IHBhcnRzLmxlbmd0aDsgaisrKSB7XG4gICAga3YgPSBwYXJ0c1tqXS50cmltKCkuc3BsaXQoJz0nKTtcbiAgICBwYXJzZWRba3ZbMF0udHJpbSgpXSA9IGt2WzFdO1xuICB9XG4gIHJldHVybiBwYXJzZWQ7XG59O1xuXG4vLyBHZW5lcmF0ZXMgYW4gYT1mdG1wIGxpbmUgZnJvbSBSVENSdHBDb2RlY0NhcGFiaWxpdHkgb3IgUlRDUnRwQ29kZWNQYXJhbWV0ZXJzLlxuU0RQVXRpbHMud3JpdGVGbXRwID0gZnVuY3Rpb24oY29kZWMpIHtcbiAgdmFyIGxpbmUgPSAnJztcbiAgdmFyIHB0ID0gY29kZWMucGF5bG9hZFR5cGU7XG4gIGlmIChjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcHQgPSBjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZTtcbiAgfVxuICBpZiAoY29kZWMucGFyYW1ldGVycyAmJiBPYmplY3Qua2V5cyhjb2RlYy5wYXJhbWV0ZXJzKS5sZW5ndGgpIHtcbiAgICB2YXIgcGFyYW1zID0gW107XG4gICAgT2JqZWN0LmtleXMoY29kZWMucGFyYW1ldGVycykuZm9yRWFjaChmdW5jdGlvbihwYXJhbSkge1xuICAgICAgcGFyYW1zLnB1c2gocGFyYW0gKyAnPScgKyBjb2RlYy5wYXJhbWV0ZXJzW3BhcmFtXSk7XG4gICAgfSk7XG4gICAgbGluZSArPSAnYT1mbXRwOicgKyBwdCArICcgJyArIHBhcmFtcy5qb2luKCc7JykgKyAnXFxyXFxuJztcbiAgfVxuICByZXR1cm4gbGluZTtcbn07XG5cbi8vIFBhcnNlcyBhbiBydGNwLWZiIGxpbmUsIHJldHVybnMgUlRDUFJ0Y3BGZWVkYmFjayBvYmplY3QuIFNhbXBsZSBpbnB1dDpcbi8vIGE9cnRjcC1mYjo5OCBuYWNrIHJwc2lcblNEUFV0aWxzLnBhcnNlUnRjcEZiID0gZnVuY3Rpb24obGluZSkge1xuICB2YXIgcGFydHMgPSBsaW5lLnN1YnN0cihsaW5lLmluZGV4T2YoJyAnKSArIDEpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAgdHlwZTogcGFydHMuc2hpZnQoKSxcbiAgICBwYXJhbWV0ZXI6IHBhcnRzLmpvaW4oJyAnKVxuICB9O1xufTtcbi8vIEdlbmVyYXRlIGE9cnRjcC1mYiBsaW5lcyBmcm9tIFJUQ1J0cENvZGVjQ2FwYWJpbGl0eSBvciBSVENSdHBDb2RlY1BhcmFtZXRlcnMuXG5TRFBVdGlscy53cml0ZVJ0Y3BGYiA9IGZ1bmN0aW9uKGNvZGVjKSB7XG4gIHZhciBsaW5lcyA9ICcnO1xuICB2YXIgcHQgPSBjb2RlYy5wYXlsb2FkVHlwZTtcbiAgaWYgKGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlICE9PSB1bmRlZmluZWQpIHtcbiAgICBwdCA9IGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlO1xuICB9XG4gIGlmIChjb2RlYy5ydGNwRmVlZGJhY2sgJiYgY29kZWMucnRjcEZlZWRiYWNrLmxlbmd0aCkge1xuICAgIC8vIEZJWE1FOiBzcGVjaWFsIGhhbmRsaW5nIGZvciB0cnItaW50P1xuICAgIGNvZGVjLnJ0Y3BGZWVkYmFjay5mb3JFYWNoKGZ1bmN0aW9uKGZiKSB7XG4gICAgICBsaW5lcyArPSAnYT1ydGNwLWZiOicgKyBwdCArICcgJyArIGZiLnR5cGUgK1xuICAgICAgKGZiLnBhcmFtZXRlciAmJiBmYi5wYXJhbWV0ZXIubGVuZ3RoID8gJyAnICsgZmIucGFyYW1ldGVyIDogJycpICtcbiAgICAgICAgICAnXFxyXFxuJztcbiAgICB9KTtcbiAgfVxuICByZXR1cm4gbGluZXM7XG59O1xuXG4vLyBQYXJzZXMgYW4gUkZDIDU1NzYgc3NyYyBtZWRpYSBhdHRyaWJ1dGUuIFNhbXBsZSBpbnB1dDpcbi8vIGE9c3NyYzozNzM1OTI4NTU5IGNuYW1lOnNvbWV0aGluZ1xuU0RQVXRpbHMucGFyc2VTc3JjTWVkaWEgPSBmdW5jdGlvbihsaW5lKSB7XG4gIHZhciBzcCA9IGxpbmUuaW5kZXhPZignICcpO1xuICB2YXIgcGFydHMgPSB7XG4gICAgc3NyYzogcGFyc2VJbnQobGluZS5zdWJzdHIoNywgc3AgLSA3KSwgMTApXG4gIH07XG4gIHZhciBjb2xvbiA9IGxpbmUuaW5kZXhPZignOicsIHNwKTtcbiAgaWYgKGNvbG9uID4gLTEpIHtcbiAgICBwYXJ0cy5hdHRyaWJ1dGUgPSBsaW5lLnN1YnN0cihzcCArIDEsIGNvbG9uIC0gc3AgLSAxKTtcbiAgICBwYXJ0cy52YWx1ZSA9IGxpbmUuc3Vic3RyKGNvbG9uICsgMSk7XG4gIH0gZWxzZSB7XG4gICAgcGFydHMuYXR0cmlidXRlID0gbGluZS5zdWJzdHIoc3AgKyAxKTtcbiAgfVxuICByZXR1cm4gcGFydHM7XG59O1xuXG4vLyBFeHRyYWN0cyB0aGUgTUlEIChSRkMgNTg4OCkgZnJvbSBhIG1lZGlhIHNlY3Rpb24uXG4vLyByZXR1cm5zIHRoZSBNSUQgb3IgdW5kZWZpbmVkIGlmIG5vIG1pZCBsaW5lIHdhcyBmb3VuZC5cblNEUFV0aWxzLmdldE1pZCA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICB2YXIgbWlkID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1taWQ6JylbMF07XG4gIGlmIChtaWQpIHtcbiAgICByZXR1cm4gbWlkLnN1YnN0cig2KTtcbiAgfVxufVxuXG5TRFBVdGlscy5wYXJzZUZpbmdlcnByaW50ID0gZnVuY3Rpb24obGluZSkge1xuICB2YXIgcGFydHMgPSBsaW5lLnN1YnN0cigxNCkuc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICBhbGdvcml0aG06IHBhcnRzWzBdLnRvTG93ZXJDYXNlKCksIC8vIGFsZ29yaXRobSBpcyBjYXNlLXNlbnNpdGl2ZSBpbiBFZGdlLlxuICAgIHZhbHVlOiBwYXJ0c1sxXVxuICB9O1xufTtcblxuLy8gRXh0cmFjdHMgRFRMUyBwYXJhbWV0ZXJzIGZyb20gU0RQIG1lZGlhIHNlY3Rpb24gb3Igc2Vzc2lvbnBhcnQuXG4vLyBGSVhNRTogZm9yIGNvbnNpc3RlbmN5IHdpdGggb3RoZXIgZnVuY3Rpb25zIHRoaXMgc2hvdWxkIG9ubHlcbi8vICAgZ2V0IHRoZSBmaW5nZXJwcmludCBsaW5lIGFzIGlucHV0LiBTZWUgYWxzbyBnZXRJY2VQYXJhbWV0ZXJzLlxuU0RQVXRpbHMuZ2V0RHRsc1BhcmFtZXRlcnMgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KSB7XG4gIHZhciBsaW5lcyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiArIHNlc3Npb25wYXJ0LFxuICAgICAgJ2E9ZmluZ2VycHJpbnQ6Jyk7XG4gIC8vIE5vdGU6IGE9c2V0dXAgbGluZSBpcyBpZ25vcmVkIHNpbmNlIHdlIHVzZSB0aGUgJ2F1dG8nIHJvbGUuXG4gIC8vIE5vdGUyOiAnYWxnb3JpdGhtJyBpcyBub3QgY2FzZSBzZW5zaXRpdmUgZXhjZXB0IGluIEVkZ2UuXG4gIHJldHVybiB7XG4gICAgcm9sZTogJ2F1dG8nLFxuICAgIGZpbmdlcnByaW50czogbGluZXMubWFwKFNEUFV0aWxzLnBhcnNlRmluZ2VycHJpbnQpXG4gIH07XG59O1xuXG4vLyBTZXJpYWxpemVzIERUTFMgcGFyYW1ldGVycyB0byBTRFAuXG5TRFBVdGlscy53cml0ZUR0bHNQYXJhbWV0ZXJzID0gZnVuY3Rpb24ocGFyYW1zLCBzZXR1cFR5cGUpIHtcbiAgdmFyIHNkcCA9ICdhPXNldHVwOicgKyBzZXR1cFR5cGUgKyAnXFxyXFxuJztcbiAgcGFyYW1zLmZpbmdlcnByaW50cy5mb3JFYWNoKGZ1bmN0aW9uKGZwKSB7XG4gICAgc2RwICs9ICdhPWZpbmdlcnByaW50OicgKyBmcC5hbGdvcml0aG0gKyAnICcgKyBmcC52YWx1ZSArICdcXHJcXG4nO1xuICB9KTtcbiAgcmV0dXJuIHNkcDtcbn07XG4vLyBQYXJzZXMgSUNFIGluZm9ybWF0aW9uIGZyb20gU0RQIG1lZGlhIHNlY3Rpb24gb3Igc2Vzc2lvbnBhcnQuXG4vLyBGSVhNRTogZm9yIGNvbnNpc3RlbmN5IHdpdGggb3RoZXIgZnVuY3Rpb25zIHRoaXMgc2hvdWxkIG9ubHlcbi8vICAgZ2V0IHRoZSBpY2UtdWZyYWcgYW5kIGljZS1wd2QgbGluZXMgYXMgaW5wdXQuXG5TRFBVdGlscy5nZXRJY2VQYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZXNzaW9ucGFydCkge1xuICB2YXIgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIC8vIFNlYXJjaCBpbiBzZXNzaW9uIHBhcnQsIHRvby5cbiAgbGluZXMgPSBsaW5lcy5jb25jYXQoU0RQVXRpbHMuc3BsaXRMaW5lcyhzZXNzaW9ucGFydCkpO1xuICB2YXIgaWNlUGFyYW1ldGVycyA9IHtcbiAgICB1c2VybmFtZUZyYWdtZW50OiBsaW5lcy5maWx0ZXIoZnVuY3Rpb24obGluZSkge1xuICAgICAgcmV0dXJuIGxpbmUuaW5kZXhPZignYT1pY2UtdWZyYWc6JykgPT09IDA7XG4gICAgfSlbMF0uc3Vic3RyKDEyKSxcbiAgICBwYXNzd29yZDogbGluZXMuZmlsdGVyKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICAgIHJldHVybiBsaW5lLmluZGV4T2YoJ2E9aWNlLXB3ZDonKSA9PT0gMDtcbiAgICB9KVswXS5zdWJzdHIoMTApXG4gIH07XG4gIHJldHVybiBpY2VQYXJhbWV0ZXJzO1xufTtcblxuLy8gU2VyaWFsaXplcyBJQ0UgcGFyYW1ldGVycyB0byBTRFAuXG5TRFBVdGlscy53cml0ZUljZVBhcmFtZXRlcnMgPSBmdW5jdGlvbihwYXJhbXMpIHtcbiAgcmV0dXJuICdhPWljZS11ZnJhZzonICsgcGFyYW1zLnVzZXJuYW1lRnJhZ21lbnQgKyAnXFxyXFxuJyArXG4gICAgICAnYT1pY2UtcHdkOicgKyBwYXJhbXMucGFzc3dvcmQgKyAnXFxyXFxuJztcbn07XG5cbi8vIFBhcnNlcyB0aGUgU0RQIG1lZGlhIHNlY3Rpb24gYW5kIHJldHVybnMgUlRDUnRwUGFyYW1ldGVycy5cblNEUFV0aWxzLnBhcnNlUnRwUGFyYW1ldGVycyA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICB2YXIgZGVzY3JpcHRpb24gPSB7XG4gICAgY29kZWNzOiBbXSxcbiAgICBoZWFkZXJFeHRlbnNpb25zOiBbXSxcbiAgICBmZWNNZWNoYW5pc21zOiBbXSxcbiAgICBydGNwOiBbXVxuICB9O1xuICB2YXIgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIHZhciBtbGluZSA9IGxpbmVzWzBdLnNwbGl0KCcgJyk7XG4gIGZvciAodmFyIGkgPSAzOyBpIDwgbWxpbmUubGVuZ3RoOyBpKyspIHsgLy8gZmluZCBhbGwgY29kZWNzIGZyb20gbWxpbmVbMy4uXVxuICAgIHZhciBwdCA9IG1saW5lW2ldO1xuICAgIHZhciBydHBtYXBsaW5lID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgoXG4gICAgICAgIG1lZGlhU2VjdGlvbiwgJ2E9cnRwbWFwOicgKyBwdCArICcgJylbMF07XG4gICAgaWYgKHJ0cG1hcGxpbmUpIHtcbiAgICAgIHZhciBjb2RlYyA9IFNEUFV0aWxzLnBhcnNlUnRwTWFwKHJ0cG1hcGxpbmUpO1xuICAgICAgdmFyIGZtdHBzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgoXG4gICAgICAgICAgbWVkaWFTZWN0aW9uLCAnYT1mbXRwOicgKyBwdCArICcgJyk7XG4gICAgICAvLyBPbmx5IHRoZSBmaXJzdCBhPWZtdHA6PHB0PiBpcyBjb25zaWRlcmVkLlxuICAgICAgY29kZWMucGFyYW1ldGVycyA9IGZtdHBzLmxlbmd0aCA/IFNEUFV0aWxzLnBhcnNlRm10cChmbXRwc1swXSkgOiB7fTtcbiAgICAgIGNvZGVjLnJ0Y3BGZWVkYmFjayA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KFxuICAgICAgICAgIG1lZGlhU2VjdGlvbiwgJ2E9cnRjcC1mYjonICsgcHQgKyAnICcpXG4gICAgICAgIC5tYXAoU0RQVXRpbHMucGFyc2VSdGNwRmIpO1xuICAgICAgZGVzY3JpcHRpb24uY29kZWNzLnB1c2goY29kZWMpO1xuICAgICAgLy8gcGFyc2UgRkVDIG1lY2hhbmlzbXMgZnJvbSBydHBtYXAgbGluZXMuXG4gICAgICBzd2l0Y2ggKGNvZGVjLm5hbWUudG9VcHBlckNhc2UoKSkge1xuICAgICAgICBjYXNlICdSRUQnOlxuICAgICAgICBjYXNlICdVTFBGRUMnOlxuICAgICAgICAgIGRlc2NyaXB0aW9uLmZlY01lY2hhbmlzbXMucHVzaChjb2RlYy5uYW1lLnRvVXBwZXJDYXNlKCkpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OiAvLyBvbmx5IFJFRCBhbmQgVUxQRkVDIGFyZSByZWNvZ25pemVkIGFzIEZFQyBtZWNoYW5pc21zLlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPWV4dG1hcDonKS5mb3JFYWNoKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICBkZXNjcmlwdGlvbi5oZWFkZXJFeHRlbnNpb25zLnB1c2goU0RQVXRpbHMucGFyc2VFeHRtYXAobGluZSkpO1xuICB9KTtcbiAgLy8gRklYTUU6IHBhcnNlIHJ0Y3AuXG4gIHJldHVybiBkZXNjcmlwdGlvbjtcbn07XG5cbi8vIEdlbmVyYXRlcyBwYXJ0cyBvZiB0aGUgU0RQIG1lZGlhIHNlY3Rpb24gZGVzY3JpYmluZyB0aGUgY2FwYWJpbGl0aWVzIC9cbi8vIHBhcmFtZXRlcnMuXG5TRFBVdGlscy53cml0ZVJ0cERlc2NyaXB0aW9uID0gZnVuY3Rpb24oa2luZCwgY2Fwcykge1xuICB2YXIgc2RwID0gJyc7XG5cbiAgLy8gQnVpbGQgdGhlIG1saW5lLlxuICBzZHAgKz0gJ209JyArIGtpbmQgKyAnICc7XG4gIHNkcCArPSBjYXBzLmNvZGVjcy5sZW5ndGggPiAwID8gJzknIDogJzAnOyAvLyByZWplY3QgaWYgbm8gY29kZWNzLlxuICBzZHAgKz0gJyBVRFAvVExTL1JUUC9TQVZQRiAnO1xuICBzZHAgKz0gY2Fwcy5jb2RlY3MubWFwKGZ1bmN0aW9uKGNvZGVjKSB7XG4gICAgaWYgKGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZTtcbiAgICB9XG4gICAgcmV0dXJuIGNvZGVjLnBheWxvYWRUeXBlO1xuICB9KS5qb2luKCcgJykgKyAnXFxyXFxuJztcblxuICBzZHAgKz0gJ2M9SU4gSVA0IDAuMC4wLjBcXHJcXG4nO1xuICBzZHAgKz0gJ2E9cnRjcDo5IElOIElQNCAwLjAuMC4wXFxyXFxuJztcblxuICAvLyBBZGQgYT1ydHBtYXAgbGluZXMgZm9yIGVhY2ggY29kZWMuIEFsc28gZm10cCBhbmQgcnRjcC1mYi5cbiAgY2Fwcy5jb2RlY3MuZm9yRWFjaChmdW5jdGlvbihjb2RlYykge1xuICAgIHNkcCArPSBTRFBVdGlscy53cml0ZVJ0cE1hcChjb2RlYyk7XG4gICAgc2RwICs9IFNEUFV0aWxzLndyaXRlRm10cChjb2RlYyk7XG4gICAgc2RwICs9IFNEUFV0aWxzLndyaXRlUnRjcEZiKGNvZGVjKTtcbiAgfSk7XG4gIHZhciBtYXhwdGltZSA9IDA7XG4gIGNhcHMuY29kZWNzLmZvckVhY2goZnVuY3Rpb24oY29kZWMpIHtcbiAgICBpZiAoY29kZWMubWF4cHRpbWUgPiBtYXhwdGltZSkge1xuICAgICAgbWF4cHRpbWUgPSBjb2RlYy5tYXhwdGltZTtcbiAgICB9XG4gIH0pO1xuICBpZiAobWF4cHRpbWUgPiAwKSB7XG4gICAgc2RwICs9ICdhPW1heHB0aW1lOicgKyBtYXhwdGltZSArICdcXHJcXG4nO1xuICB9XG4gIHNkcCArPSAnYT1ydGNwLW11eFxcclxcbic7XG5cbiAgY2Fwcy5oZWFkZXJFeHRlbnNpb25zLmZvckVhY2goZnVuY3Rpb24oZXh0ZW5zaW9uKSB7XG4gICAgc2RwICs9IFNEUFV0aWxzLndyaXRlRXh0bWFwKGV4dGVuc2lvbik7XG4gIH0pO1xuICAvLyBGSVhNRTogd3JpdGUgZmVjTWVjaGFuaXNtcy5cbiAgcmV0dXJuIHNkcDtcbn07XG5cbi8vIFBhcnNlcyB0aGUgU0RQIG1lZGlhIHNlY3Rpb24gYW5kIHJldHVybnMgYW4gYXJyYXkgb2Zcbi8vIFJUQ1J0cEVuY29kaW5nUGFyYW1ldGVycy5cblNEUFV0aWxzLnBhcnNlUnRwRW5jb2RpbmdQYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIHZhciBlbmNvZGluZ1BhcmFtZXRlcnMgPSBbXTtcbiAgdmFyIGRlc2NyaXB0aW9uID0gU0RQVXRpbHMucGFyc2VSdHBQYXJhbWV0ZXJzKG1lZGlhU2VjdGlvbik7XG4gIHZhciBoYXNSZWQgPSBkZXNjcmlwdGlvbi5mZWNNZWNoYW5pc21zLmluZGV4T2YoJ1JFRCcpICE9PSAtMTtcbiAgdmFyIGhhc1VscGZlYyA9IGRlc2NyaXB0aW9uLmZlY01lY2hhbmlzbXMuaW5kZXhPZignVUxQRkVDJykgIT09IC0xO1xuXG4gIC8vIGZpbHRlciBhPXNzcmM6Li4uIGNuYW1lOiwgaWdub3JlIFBsYW5CLW1zaWRcbiAgdmFyIHNzcmNzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1zc3JjOicpXG4gIC5tYXAoZnVuY3Rpb24obGluZSkge1xuICAgIHJldHVybiBTRFBVdGlscy5wYXJzZVNzcmNNZWRpYShsaW5lKTtcbiAgfSlcbiAgLmZpbHRlcihmdW5jdGlvbihwYXJ0cykge1xuICAgIHJldHVybiBwYXJ0cy5hdHRyaWJ1dGUgPT09ICdjbmFtZSc7XG4gIH0pO1xuICB2YXIgcHJpbWFyeVNzcmMgPSBzc3Jjcy5sZW5ndGggPiAwICYmIHNzcmNzWzBdLnNzcmM7XG4gIHZhciBzZWNvbmRhcnlTc3JjO1xuXG4gIHZhciBmbG93cyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9c3NyYy1ncm91cDpGSUQnKVxuICAubWFwKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICB2YXIgcGFydHMgPSBsaW5lLnNwbGl0KCcgJyk7XG4gICAgcGFydHMuc2hpZnQoKTtcbiAgICByZXR1cm4gcGFydHMubWFwKGZ1bmN0aW9uKHBhcnQpIHtcbiAgICAgIHJldHVybiBwYXJzZUludChwYXJ0LCAxMCk7XG4gICAgfSk7XG4gIH0pO1xuICBpZiAoZmxvd3MubGVuZ3RoID4gMCAmJiBmbG93c1swXS5sZW5ndGggPiAxICYmIGZsb3dzWzBdWzBdID09PSBwcmltYXJ5U3NyYykge1xuICAgIHNlY29uZGFyeVNzcmMgPSBmbG93c1swXVsxXTtcbiAgfVxuXG4gIGRlc2NyaXB0aW9uLmNvZGVjcy5mb3JFYWNoKGZ1bmN0aW9uKGNvZGVjKSB7XG4gICAgaWYgKGNvZGVjLm5hbWUudG9VcHBlckNhc2UoKSA9PT0gJ1JUWCcgJiYgY29kZWMucGFyYW1ldGVycy5hcHQpIHtcbiAgICAgIHZhciBlbmNQYXJhbSA9IHtcbiAgICAgICAgc3NyYzogcHJpbWFyeVNzcmMsXG4gICAgICAgIGNvZGVjUGF5bG9hZFR5cGU6IHBhcnNlSW50KGNvZGVjLnBhcmFtZXRlcnMuYXB0LCAxMCksXG4gICAgICAgIHJ0eDoge1xuICAgICAgICAgIHNzcmM6IHNlY29uZGFyeVNzcmNcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIGVuY29kaW5nUGFyYW1ldGVycy5wdXNoKGVuY1BhcmFtKTtcbiAgICAgIGlmIChoYXNSZWQpIHtcbiAgICAgICAgZW5jUGFyYW0gPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGVuY1BhcmFtKSk7XG4gICAgICAgIGVuY1BhcmFtLmZlYyA9IHtcbiAgICAgICAgICBzc3JjOiBzZWNvbmRhcnlTc3JjLFxuICAgICAgICAgIG1lY2hhbmlzbTogaGFzVWxwZmVjID8gJ3JlZCt1bHBmZWMnIDogJ3JlZCdcbiAgICAgICAgfTtcbiAgICAgICAgZW5jb2RpbmdQYXJhbWV0ZXJzLnB1c2goZW5jUGFyYW0pO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIGlmIChlbmNvZGluZ1BhcmFtZXRlcnMubGVuZ3RoID09PSAwICYmIHByaW1hcnlTc3JjKSB7XG4gICAgZW5jb2RpbmdQYXJhbWV0ZXJzLnB1c2goe1xuICAgICAgc3NyYzogcHJpbWFyeVNzcmNcbiAgICB9KTtcbiAgfVxuXG4gIC8vIHdlIHN1cHBvcnQgYm90aCBiPUFTIGFuZCBiPVRJQVMgYnV0IGludGVycHJldCBBUyBhcyBUSUFTLlxuICB2YXIgYmFuZHdpZHRoID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYj0nKTtcbiAgaWYgKGJhbmR3aWR0aC5sZW5ndGgpIHtcbiAgICBpZiAoYmFuZHdpZHRoWzBdLmluZGV4T2YoJ2I9VElBUzonKSA9PT0gMCkge1xuICAgICAgYmFuZHdpZHRoID0gcGFyc2VJbnQoYmFuZHdpZHRoWzBdLnN1YnN0cig3KSwgMTApO1xuICAgIH0gZWxzZSBpZiAoYmFuZHdpZHRoWzBdLmluZGV4T2YoJ2I9QVM6JykgPT09IDApIHtcbiAgICAgIC8vIHVzZSBmb3JtdWxhIGZyb20gSlNFUCB0byBjb252ZXJ0IGI9QVMgdG8gVElBUyB2YWx1ZS5cbiAgICAgIGJhbmR3aWR0aCA9IHBhcnNlSW50KGJhbmR3aWR0aFswXS5zdWJzdHIoNSksIDEwKSAqIDEwMDAgKiAwLjk1XG4gICAgICAgICAgLSAoNTAgKiA0MCAqIDgpO1xuICAgIH0gZWxzZSB7XG4gICAgICBiYW5kd2lkdGggPSB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGVuY29kaW5nUGFyYW1ldGVycy5mb3JFYWNoKGZ1bmN0aW9uKHBhcmFtcykge1xuICAgICAgcGFyYW1zLm1heEJpdHJhdGUgPSBiYW5kd2lkdGg7XG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIGVuY29kaW5nUGFyYW1ldGVycztcbn07XG5cbi8vIHBhcnNlcyBodHRwOi8vZHJhZnQub3J0Yy5vcmcvI3J0Y3J0Y3BwYXJhbWV0ZXJzKlxuU0RQVXRpbHMucGFyc2VSdGNwUGFyYW1ldGVycyA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICB2YXIgcnRjcFBhcmFtZXRlcnMgPSB7fTtcblxuICB2YXIgY25hbWU7XG4gIC8vIEdldHMgdGhlIGZpcnN0IFNTUkMuIE5vdGUgdGhhdCB3aXRoIFJUWCB0aGVyZSBtaWdodCBiZSBtdWx0aXBsZVxuICAvLyBTU1JDcy5cbiAgdmFyIHJlbW90ZVNzcmMgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXNzcmM6JylcbiAgICAgIC5tYXAoZnVuY3Rpb24obGluZSkge1xuICAgICAgICByZXR1cm4gU0RQVXRpbHMucGFyc2VTc3JjTWVkaWEobGluZSk7XG4gICAgICB9KVxuICAgICAgLmZpbHRlcihmdW5jdGlvbihvYmopIHtcbiAgICAgICAgcmV0dXJuIG9iai5hdHRyaWJ1dGUgPT09ICdjbmFtZSc7XG4gICAgICB9KVswXTtcbiAgaWYgKHJlbW90ZVNzcmMpIHtcbiAgICBydGNwUGFyYW1ldGVycy5jbmFtZSA9IHJlbW90ZVNzcmMudmFsdWU7XG4gICAgcnRjcFBhcmFtZXRlcnMuc3NyYyA9IHJlbW90ZVNzcmMuc3NyYztcbiAgfVxuXG4gIC8vIEVkZ2UgdXNlcyB0aGUgY29tcG91bmQgYXR0cmlidXRlIGluc3RlYWQgb2YgcmVkdWNlZFNpemVcbiAgLy8gY29tcG91bmQgaXMgIXJlZHVjZWRTaXplXG4gIHZhciByc2l6ZSA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9cnRjcC1yc2l6ZScpO1xuICBydGNwUGFyYW1ldGVycy5yZWR1Y2VkU2l6ZSA9IHJzaXplLmxlbmd0aCA+IDA7XG4gIHJ0Y3BQYXJhbWV0ZXJzLmNvbXBvdW5kID0gcnNpemUubGVuZ3RoID09PSAwO1xuXG4gIC8vIHBhcnNlcyB0aGUgcnRjcC1tdXggYXR0ctGWYnV0ZS5cbiAgLy8gTm90ZSB0aGF0IEVkZ2UgZG9lcyBub3Qgc3VwcG9ydCB1bm11eGVkIFJUQ1AuXG4gIHZhciBtdXggPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXJ0Y3AtbXV4Jyk7XG4gIHJ0Y3BQYXJhbWV0ZXJzLm11eCA9IG11eC5sZW5ndGggPiAwO1xuXG4gIHJldHVybiBydGNwUGFyYW1ldGVycztcbn07XG5cbi8vIHBhcnNlcyBlaXRoZXIgYT1tc2lkOiBvciBhPXNzcmM6Li4uIG1zaWQgbGluZXMgYW5kIHJldHVybnNcbi8vIHRoZSBpZCBvZiB0aGUgTWVkaWFTdHJlYW0gYW5kIE1lZGlhU3RyZWFtVHJhY2suXG5TRFBVdGlscy5wYXJzZU1zaWQgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgdmFyIHBhcnRzO1xuICB2YXIgc3BlYyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9bXNpZDonKTtcbiAgaWYgKHNwZWMubGVuZ3RoID09PSAxKSB7XG4gICAgcGFydHMgPSBzcGVjWzBdLnN1YnN0cig3KS5zcGxpdCgnICcpO1xuICAgIHJldHVybiB7c3RyZWFtOiBwYXJ0c1swXSwgdHJhY2s6IHBhcnRzWzFdfTtcbiAgfVxuICB2YXIgcGxhbkIgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXNzcmM6JylcbiAgLm1hcChmdW5jdGlvbihsaW5lKSB7XG4gICAgcmV0dXJuIFNEUFV0aWxzLnBhcnNlU3NyY01lZGlhKGxpbmUpO1xuICB9KVxuICAuZmlsdGVyKGZ1bmN0aW9uKHBhcnRzKSB7XG4gICAgcmV0dXJuIHBhcnRzLmF0dHJpYnV0ZSA9PT0gJ21zaWQnO1xuICB9KTtcbiAgaWYgKHBsYW5CLmxlbmd0aCA+IDApIHtcbiAgICBwYXJ0cyA9IHBsYW5CWzBdLnZhbHVlLnNwbGl0KCcgJyk7XG4gICAgcmV0dXJuIHtzdHJlYW06IHBhcnRzWzBdLCB0cmFjazogcGFydHNbMV19O1xuICB9XG59O1xuXG4vLyBHZW5lcmF0ZSBhIHNlc3Npb24gSUQgZm9yIFNEUC5cbi8vIGh0dHBzOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9kcmFmdC1pZXRmLXJ0Y3dlYi1qc2VwLTIwI3NlY3Rpb24tNS4yLjFcbi8vIHJlY29tbWVuZHMgdXNpbmcgYSBjcnlwdG9ncmFwaGljYWxseSByYW5kb20gK3ZlIDY0LWJpdCB2YWx1ZVxuLy8gYnV0IHJpZ2h0IG5vdyB0aGlzIHNob3VsZCBiZSBhY2NlcHRhYmxlIGFuZCB3aXRoaW4gdGhlIHJpZ2h0IHJhbmdlXG5TRFBVdGlscy5nZW5lcmF0ZVNlc3Npb25JZCA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gTWF0aC5yYW5kb20oKS50b1N0cmluZygpLnN1YnN0cigyLCAyMSk7XG59O1xuXG4vLyBXcml0ZSBib2lsZGVyIHBsYXRlIGZvciBzdGFydCBvZiBTRFBcbi8vIHNlc3NJZCBhcmd1bWVudCBpcyBvcHRpb25hbCAtIGlmIG5vdCBzdXBwbGllZCBpdCB3aWxsXG4vLyBiZSBnZW5lcmF0ZWQgcmFuZG9tbHlcbi8vIHNlc3NWZXJzaW9uIGlzIG9wdGlvbmFsIGFuZCBkZWZhdWx0cyB0byAyXG5TRFBVdGlscy53cml0ZVNlc3Npb25Cb2lsZXJwbGF0ZSA9IGZ1bmN0aW9uKHNlc3NJZCwgc2Vzc1Zlcikge1xuICB2YXIgc2Vzc2lvbklkO1xuICB2YXIgdmVyc2lvbiA9IHNlc3NWZXIgIT09IHVuZGVmaW5lZCA/IHNlc3NWZXIgOiAyO1xuICBpZiAoc2Vzc0lkKSB7XG4gICAgc2Vzc2lvbklkID0gc2Vzc0lkO1xuICB9IGVsc2Uge1xuICAgIHNlc3Npb25JZCA9IFNEUFV0aWxzLmdlbmVyYXRlU2Vzc2lvbklkKCk7XG4gIH1cbiAgLy8gRklYTUU6IHNlc3MtaWQgc2hvdWxkIGJlIGFuIE5UUCB0aW1lc3RhbXAuXG4gIHJldHVybiAndj0wXFxyXFxuJyArXG4gICAgICAnbz10aGlzaXNhZGFwdGVyb3J0YyAnICsgc2Vzc2lvbklkICsgJyAnICsgdmVyc2lvbiArICcgSU4gSVA0IDEyNy4wLjAuMVxcclxcbicgK1xuICAgICAgJ3M9LVxcclxcbicgK1xuICAgICAgJ3Q9MCAwXFxyXFxuJztcbn07XG5cblNEUFV0aWxzLndyaXRlTWVkaWFTZWN0aW9uID0gZnVuY3Rpb24odHJhbnNjZWl2ZXIsIGNhcHMsIHR5cGUsIHN0cmVhbSkge1xuICB2YXIgc2RwID0gU0RQVXRpbHMud3JpdGVSdHBEZXNjcmlwdGlvbih0cmFuc2NlaXZlci5raW5kLCBjYXBzKTtcblxuICAvLyBNYXAgSUNFIHBhcmFtZXRlcnMgKHVmcmFnLCBwd2QpIHRvIFNEUC5cbiAgc2RwICs9IFNEUFV0aWxzLndyaXRlSWNlUGFyYW1ldGVycyhcbiAgICAgIHRyYW5zY2VpdmVyLmljZUdhdGhlcmVyLmdldExvY2FsUGFyYW1ldGVycygpKTtcblxuICAvLyBNYXAgRFRMUyBwYXJhbWV0ZXJzIHRvIFNEUC5cbiAgc2RwICs9IFNEUFV0aWxzLndyaXRlRHRsc1BhcmFtZXRlcnMoXG4gICAgICB0cmFuc2NlaXZlci5kdGxzVHJhbnNwb3J0LmdldExvY2FsUGFyYW1ldGVycygpLFxuICAgICAgdHlwZSA9PT0gJ29mZmVyJyA/ICdhY3RwYXNzJyA6ICdhY3RpdmUnKTtcblxuICBzZHAgKz0gJ2E9bWlkOicgKyB0cmFuc2NlaXZlci5taWQgKyAnXFxyXFxuJztcblxuICBpZiAodHJhbnNjZWl2ZXIuZGlyZWN0aW9uKSB7XG4gICAgc2RwICs9ICdhPScgKyB0cmFuc2NlaXZlci5kaXJlY3Rpb24gKyAnXFxyXFxuJztcbiAgfSBlbHNlIGlmICh0cmFuc2NlaXZlci5ydHBTZW5kZXIgJiYgdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXIpIHtcbiAgICBzZHAgKz0gJ2E9c2VuZHJlY3ZcXHJcXG4nO1xuICB9IGVsc2UgaWYgKHRyYW5zY2VpdmVyLnJ0cFNlbmRlcikge1xuICAgIHNkcCArPSAnYT1zZW5kb25seVxcclxcbic7XG4gIH0gZWxzZSBpZiAodHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXIpIHtcbiAgICBzZHAgKz0gJ2E9cmVjdm9ubHlcXHJcXG4nO1xuICB9IGVsc2Uge1xuICAgIHNkcCArPSAnYT1pbmFjdGl2ZVxcclxcbic7XG4gIH1cblxuICBpZiAodHJhbnNjZWl2ZXIucnRwU2VuZGVyKSB7XG4gICAgLy8gc3BlYy5cbiAgICB2YXIgbXNpZCA9ICdtc2lkOicgKyBzdHJlYW0uaWQgKyAnICcgK1xuICAgICAgICB0cmFuc2NlaXZlci5ydHBTZW5kZXIudHJhY2suaWQgKyAnXFxyXFxuJztcbiAgICBzZHAgKz0gJ2E9JyArIG1zaWQ7XG5cbiAgICAvLyBmb3IgQ2hyb21lLlxuICAgIHNkcCArPSAnYT1zc3JjOicgKyB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnNzcmMgK1xuICAgICAgICAnICcgKyBtc2lkO1xuICAgIGlmICh0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eCkge1xuICAgICAgc2RwICs9ICdhPXNzcmM6JyArIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0ucnR4LnNzcmMgK1xuICAgICAgICAgICcgJyArIG1zaWQ7XG4gICAgICBzZHAgKz0gJ2E9c3NyYy1ncm91cDpGSUQgJyArXG4gICAgICAgICAgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5zc3JjICsgJyAnICtcbiAgICAgICAgICB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eC5zc3JjICtcbiAgICAgICAgICAnXFxyXFxuJztcbiAgICB9XG4gIH1cbiAgLy8gRklYTUU6IHRoaXMgc2hvdWxkIGJlIHdyaXR0ZW4gYnkgd3JpdGVSdHBEZXNjcmlwdGlvbi5cbiAgc2RwICs9ICdhPXNzcmM6JyArIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0uc3NyYyArXG4gICAgICAnIGNuYW1lOicgKyBTRFBVdGlscy5sb2NhbENOYW1lICsgJ1xcclxcbic7XG4gIGlmICh0cmFuc2NlaXZlci5ydHBTZW5kZXIgJiYgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHgpIHtcbiAgICBzZHAgKz0gJ2E9c3NyYzonICsgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHguc3NyYyArXG4gICAgICAgICcgY25hbWU6JyArIFNEUFV0aWxzLmxvY2FsQ05hbWUgKyAnXFxyXFxuJztcbiAgfVxuICByZXR1cm4gc2RwO1xufTtcblxuLy8gR2V0cyB0aGUgZGlyZWN0aW9uIGZyb20gdGhlIG1lZGlhU2VjdGlvbiBvciB0aGUgc2Vzc2lvbnBhcnQuXG5TRFBVdGlscy5nZXREaXJlY3Rpb24gPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KSB7XG4gIC8vIExvb2sgZm9yIHNlbmRyZWN2LCBzZW5kb25seSwgcmVjdm9ubHksIGluYWN0aXZlLCBkZWZhdWx0IHRvIHNlbmRyZWN2LlxuICB2YXIgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICBzd2l0Y2ggKGxpbmVzW2ldKSB7XG4gICAgICBjYXNlICdhPXNlbmRyZWN2JzpcbiAgICAgIGNhc2UgJ2E9c2VuZG9ubHknOlxuICAgICAgY2FzZSAnYT1yZWN2b25seSc6XG4gICAgICBjYXNlICdhPWluYWN0aXZlJzpcbiAgICAgICAgcmV0dXJuIGxpbmVzW2ldLnN1YnN0cigyKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIC8vIEZJWE1FOiBXaGF0IHNob3VsZCBoYXBwZW4gaGVyZT9cbiAgICB9XG4gIH1cbiAgaWYgKHNlc3Npb25wYXJ0KSB7XG4gICAgcmV0dXJuIFNEUFV0aWxzLmdldERpcmVjdGlvbihzZXNzaW9ucGFydCk7XG4gIH1cbiAgcmV0dXJuICdzZW5kcmVjdic7XG59O1xuXG5TRFBVdGlscy5nZXRLaW5kID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIHZhciBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMobWVkaWFTZWN0aW9uKTtcbiAgdmFyIG1saW5lID0gbGluZXNbMF0uc3BsaXQoJyAnKTtcbiAgcmV0dXJuIG1saW5lWzBdLnN1YnN0cigyKTtcbn07XG5cblNEUFV0aWxzLmlzUmVqZWN0ZWQgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgcmV0dXJuIG1lZGlhU2VjdGlvbi5zcGxpdCgnICcsIDIpWzFdID09PSAnMCc7XG59O1xuXG5TRFBVdGlscy5wYXJzZU1MaW5lID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIHZhciBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMobWVkaWFTZWN0aW9uKTtcbiAgdmFyIG1saW5lID0gbGluZXNbMF0uc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICBraW5kOiBtbGluZVswXS5zdWJzdHIoMiksXG4gICAgcG9ydDogcGFyc2VJbnQobWxpbmVbMV0sIDEwKSxcbiAgICBwcm90b2NvbDogbWxpbmVbMl0sXG4gICAgZm10OiBtbGluZS5zbGljZSgzKS5qb2luKCcgJylcbiAgfTtcbn07XG5cbi8vIEV4cG9zZSBwdWJsaWMgbWV0aG9kcy5cbmlmICh0eXBlb2YgbW9kdWxlID09PSAnb2JqZWN0Jykge1xuICBtb2R1bGUuZXhwb3J0cyA9IFNEUFV0aWxzO1xufVxuIiwiLyoqXG4gKiBVQVBhcnNlci5qcyB2MC43LjE3XG4gKiBMaWdodHdlaWdodCBKYXZhU2NyaXB0LWJhc2VkIFVzZXItQWdlbnQgc3RyaW5nIHBhcnNlclxuICogaHR0cHM6Ly9naXRodWIuY29tL2ZhaXNhbG1hbi91YS1wYXJzZXItanNcbiAqXG4gKiBDb3B5cmlnaHQgwqkgMjAxMi0yMDE2IEZhaXNhbCBTYWxtYW4gPGZ5emxtYW5AZ21haWwuY29tPlxuICogRHVhbCBsaWNlbnNlZCB1bmRlciBHUEx2MiAmIE1JVFxuICovXG5cbihmdW5jdGlvbiAod2luZG93LCB1bmRlZmluZWQpIHtcblxuICAgICd1c2Ugc3RyaWN0JztcblxuICAgIC8vLy8vLy8vLy8vLy8vXG4gICAgLy8gQ29uc3RhbnRzXG4gICAgLy8vLy8vLy8vLy8vL1xuXG5cbiAgICB2YXIgTElCVkVSU0lPTiAgPSAnMC43LjE3JyxcbiAgICAgICAgRU1QVFkgICAgICAgPSAnJyxcbiAgICAgICAgVU5LTk9XTiAgICAgPSAnPycsXG4gICAgICAgIEZVTkNfVFlQRSAgID0gJ2Z1bmN0aW9uJyxcbiAgICAgICAgVU5ERUZfVFlQRSAgPSAndW5kZWZpbmVkJyxcbiAgICAgICAgT0JKX1RZUEUgICAgPSAnb2JqZWN0JyxcbiAgICAgICAgU1RSX1RZUEUgICAgPSAnc3RyaW5nJyxcbiAgICAgICAgTUFKT1IgICAgICAgPSAnbWFqb3InLCAvLyBkZXByZWNhdGVkXG4gICAgICAgIE1PREVMICAgICAgID0gJ21vZGVsJyxcbiAgICAgICAgTkFNRSAgICAgICAgPSAnbmFtZScsXG4gICAgICAgIFRZUEUgICAgICAgID0gJ3R5cGUnLFxuICAgICAgICBWRU5ET1IgICAgICA9ICd2ZW5kb3InLFxuICAgICAgICBWRVJTSU9OICAgICA9ICd2ZXJzaW9uJyxcbiAgICAgICAgQVJDSElURUNUVVJFPSAnYXJjaGl0ZWN0dXJlJyxcbiAgICAgICAgQ09OU09MRSAgICAgPSAnY29uc29sZScsXG4gICAgICAgIE1PQklMRSAgICAgID0gJ21vYmlsZScsXG4gICAgICAgIFRBQkxFVCAgICAgID0gJ3RhYmxldCcsXG4gICAgICAgIFNNQVJUVFYgICAgID0gJ3NtYXJ0dHYnLFxuICAgICAgICBXRUFSQUJMRSAgICA9ICd3ZWFyYWJsZScsXG4gICAgICAgIEVNQkVEREVEICAgID0gJ2VtYmVkZGVkJztcblxuXG4gICAgLy8vLy8vLy8vLy9cbiAgICAvLyBIZWxwZXJcbiAgICAvLy8vLy8vLy8vXG5cblxuICAgIHZhciB1dGlsID0ge1xuICAgICAgICBleHRlbmQgOiBmdW5jdGlvbiAocmVnZXhlcywgZXh0ZW5zaW9ucykge1xuICAgICAgICAgICAgdmFyIG1hcmdlZFJlZ2V4ZXMgPSB7fTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgaW4gcmVnZXhlcykge1xuICAgICAgICAgICAgICAgIGlmIChleHRlbnNpb25zW2ldICYmIGV4dGVuc2lvbnNbaV0ubGVuZ3RoICUgMiA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBtYXJnZWRSZWdleGVzW2ldID0gZXh0ZW5zaW9uc1tpXS5jb25jYXQocmVnZXhlc1tpXSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbWFyZ2VkUmVnZXhlc1tpXSA9IHJlZ2V4ZXNbaV07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIG1hcmdlZFJlZ2V4ZXM7XG4gICAgICAgIH0sXG4gICAgICAgIGhhcyA6IGZ1bmN0aW9uIChzdHIxLCBzdHIyKSB7XG4gICAgICAgICAgaWYgKHR5cGVvZiBzdHIxID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICByZXR1cm4gc3RyMi50b0xvd2VyQ2FzZSgpLmluZGV4T2Yoc3RyMS50b0xvd2VyQ2FzZSgpKSAhPT0gLTE7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGxvd2VyaXplIDogZnVuY3Rpb24gKHN0cikge1xuICAgICAgICAgICAgcmV0dXJuIHN0ci50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB9LFxuICAgICAgICBtYWpvciA6IGZ1bmN0aW9uICh2ZXJzaW9uKSB7XG4gICAgICAgICAgICByZXR1cm4gdHlwZW9mKHZlcnNpb24pID09PSBTVFJfVFlQRSA/IHZlcnNpb24ucmVwbGFjZSgvW15cXGRcXC5dL2csJycpLnNwbGl0KFwiLlwiKVswXSA6IHVuZGVmaW5lZDtcbiAgICAgICAgfSxcbiAgICAgICAgdHJpbSA6IGZ1bmN0aW9uIChzdHIpIHtcbiAgICAgICAgICByZXR1cm4gc3RyLnJlcGxhY2UoL15bXFxzXFx1RkVGRlxceEEwXSt8W1xcc1xcdUZFRkZcXHhBMF0rJC9nLCAnJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG5cbiAgICAvLy8vLy8vLy8vLy8vLy9cbiAgICAvLyBNYXAgaGVscGVyXG4gICAgLy8vLy8vLy8vLy8vLy9cblxuXG4gICAgdmFyIG1hcHBlciA9IHtcblxuICAgICAgICByZ3ggOiBmdW5jdGlvbiAodWEsIGFycmF5cykge1xuXG4gICAgICAgICAgICAvL3ZhciByZXN1bHQgPSB7fSxcbiAgICAgICAgICAgIHZhciBpID0gMCwgaiwgaywgcCwgcSwgbWF0Y2hlcywgbWF0Y2g7Ly8sIGFyZ3MgPSBhcmd1bWVudHM7XG5cbiAgICAgICAgICAgIC8qLy8gY29uc3RydWN0IG9iamVjdCBiYXJlYm9uZXNcbiAgICAgICAgICAgIGZvciAocCA9IDA7IHAgPCBhcmdzWzFdLmxlbmd0aDsgcCsrKSB7XG4gICAgICAgICAgICAgICAgcSA9IGFyZ3NbMV1bcF07XG4gICAgICAgICAgICAgICAgcmVzdWx0W3R5cGVvZiBxID09PSBPQkpfVFlQRSA/IHFbMF0gOiBxXSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH0qL1xuXG4gICAgICAgICAgICAvLyBsb29wIHRocm91Z2ggYWxsIHJlZ2V4ZXMgbWFwc1xuICAgICAgICAgICAgd2hpbGUgKGkgPCBhcnJheXMubGVuZ3RoICYmICFtYXRjaGVzKSB7XG5cbiAgICAgICAgICAgICAgICB2YXIgcmVnZXggPSBhcnJheXNbaV0sICAgICAgIC8vIGV2ZW4gc2VxdWVuY2UgKDAsMiw0LC4uKVxuICAgICAgICAgICAgICAgICAgICBwcm9wcyA9IGFycmF5c1tpICsgMV07ICAgLy8gb2RkIHNlcXVlbmNlICgxLDMsNSwuLilcbiAgICAgICAgICAgICAgICBqID0gayA9IDA7XG5cbiAgICAgICAgICAgICAgICAvLyB0cnkgbWF0Y2hpbmcgdWFzdHJpbmcgd2l0aCByZWdleGVzXG4gICAgICAgICAgICAgICAgd2hpbGUgKGogPCByZWdleC5sZW5ndGggJiYgIW1hdGNoZXMpIHtcblxuICAgICAgICAgICAgICAgICAgICBtYXRjaGVzID0gcmVnZXhbaisrXS5leGVjKHVhKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoISFtYXRjaGVzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKHAgPSAwOyBwIDwgcHJvcHMubGVuZ3RoOyBwKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaCA9IG1hdGNoZXNbKytrXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBxID0gcHJvcHNbcF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2hlY2sgaWYgZ2l2ZW4gcHJvcGVydHkgaXMgYWN0dWFsbHkgYXJyYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHEgPT09IE9CSl9UWVBFICYmIHEubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocS5sZW5ndGggPT0gMikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBxWzFdID09IEZVTkNfVFlQRSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFzc2lnbiBtb2RpZmllZCBtYXRjaFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXNbcVswXV0gPSBxWzFdLmNhbGwodGhpcywgbWF0Y2gpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhc3NpZ24gZ2l2ZW4gdmFsdWUsIGlnbm9yZSByZWdleCBtYXRjaFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXNbcVswXV0gPSBxWzFdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHEubGVuZ3RoID09IDMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNoZWNrIHdoZXRoZXIgZnVuY3Rpb24gb3IgcmVnZXhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgcVsxXSA9PT0gRlVOQ19UWVBFICYmICEocVsxXS5leGVjICYmIHFbMV0udGVzdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjYWxsIGZ1bmN0aW9uICh1c3VhbGx5IHN0cmluZyBtYXBwZXIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpc1txWzBdXSA9IG1hdGNoID8gcVsxXS5jYWxsKHRoaXMsIG1hdGNoLCBxWzJdKSA6IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc2FuaXRpemUgbWF0Y2ggdXNpbmcgZ2l2ZW4gcmVnZXhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzW3FbMF1dID0gbWF0Y2ggPyBtYXRjaC5yZXBsYWNlKHFbMV0sIHFbMl0pIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHEubGVuZ3RoID09IDQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzW3FbMF1dID0gbWF0Y2ggPyBxWzNdLmNhbGwodGhpcywgbWF0Y2gucmVwbGFjZShxWzFdLCBxWzJdKSkgOiB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzW3FdID0gbWF0Y2ggPyBtYXRjaCA6IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaSArPSAyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gY29uc29sZS5sb2codGhpcyk7XG4gICAgICAgICAgICAvL3JldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIHN0ciA6IGZ1bmN0aW9uIChzdHIsIG1hcCkge1xuXG4gICAgICAgICAgICBmb3IgKHZhciBpIGluIG1hcCkge1xuICAgICAgICAgICAgICAgIC8vIGNoZWNrIGlmIGFycmF5XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBtYXBbaV0gPT09IE9CSl9UWVBFICYmIG1hcFtpXS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbWFwW2ldLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodXRpbC5oYXMobWFwW2ldW2pdLCBzdHIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChpID09PSBVTktOT1dOKSA/IHVuZGVmaW5lZCA6IGk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHV0aWwuaGFzKG1hcFtpXSwgc3RyKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gKGkgPT09IFVOS05PV04pID8gdW5kZWZpbmVkIDogaTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gc3RyO1xuICAgICAgICB9XG4gICAgfTtcblxuXG4gICAgLy8vLy8vLy8vLy8vLy8vXG4gICAgLy8gU3RyaW5nIG1hcFxuICAgIC8vLy8vLy8vLy8vLy8vXG5cblxuICAgIHZhciBtYXBzID0ge1xuXG4gICAgICAgIGJyb3dzZXIgOiB7XG4gICAgICAgICAgICBvbGRzYWZhcmkgOiB7XG4gICAgICAgICAgICAgICAgdmVyc2lvbiA6IHtcbiAgICAgICAgICAgICAgICAgICAgJzEuMCcgICA6ICcvOCcsXG4gICAgICAgICAgICAgICAgICAgICcxLjInICAgOiAnLzEnLFxuICAgICAgICAgICAgICAgICAgICAnMS4zJyAgIDogJy8zJyxcbiAgICAgICAgICAgICAgICAgICAgJzIuMCcgICA6ICcvNDEyJyxcbiAgICAgICAgICAgICAgICAgICAgJzIuMC4yJyA6ICcvNDE2JyxcbiAgICAgICAgICAgICAgICAgICAgJzIuMC4zJyA6ICcvNDE3JyxcbiAgICAgICAgICAgICAgICAgICAgJzIuMC40JyA6ICcvNDE5JyxcbiAgICAgICAgICAgICAgICAgICAgJz8nICAgICA6ICcvJ1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICBkZXZpY2UgOiB7XG4gICAgICAgICAgICBhbWF6b24gOiB7XG4gICAgICAgICAgICAgICAgbW9kZWwgOiB7XG4gICAgICAgICAgICAgICAgICAgICdGaXJlIFBob25lJyA6IFsnU0QnLCAnS0YnXVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzcHJpbnQgOiB7XG4gICAgICAgICAgICAgICAgbW9kZWwgOiB7XG4gICAgICAgICAgICAgICAgICAgICdFdm8gU2hpZnQgNEcnIDogJzczNzNLVCdcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHZlbmRvciA6IHtcbiAgICAgICAgICAgICAgICAgICAgJ0hUQycgICAgICAgOiAnQVBBJyxcbiAgICAgICAgICAgICAgICAgICAgJ1NwcmludCcgICAgOiAnU3ByaW50J1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICBvcyA6IHtcbiAgICAgICAgICAgIHdpbmRvd3MgOiB7XG4gICAgICAgICAgICAgICAgdmVyc2lvbiA6IHtcbiAgICAgICAgICAgICAgICAgICAgJ01FJyAgICAgICAgOiAnNC45MCcsXG4gICAgICAgICAgICAgICAgICAgICdOVCAzLjExJyAgIDogJ05UMy41MScsXG4gICAgICAgICAgICAgICAgICAgICdOVCA0LjAnICAgIDogJ05UNC4wJyxcbiAgICAgICAgICAgICAgICAgICAgJzIwMDAnICAgICAgOiAnTlQgNS4wJyxcbiAgICAgICAgICAgICAgICAgICAgJ1hQJyAgICAgICAgOiBbJ05UIDUuMScsICdOVCA1LjInXSxcbiAgICAgICAgICAgICAgICAgICAgJ1Zpc3RhJyAgICAgOiAnTlQgNi4wJyxcbiAgICAgICAgICAgICAgICAgICAgJzcnICAgICAgICAgOiAnTlQgNi4xJyxcbiAgICAgICAgICAgICAgICAgICAgJzgnICAgICAgICAgOiAnTlQgNi4yJyxcbiAgICAgICAgICAgICAgICAgICAgJzguMScgICAgICAgOiAnTlQgNi4zJyxcbiAgICAgICAgICAgICAgICAgICAgJzEwJyAgICAgICAgOiBbJ05UIDYuNCcsICdOVCAxMC4wJ10sXG4gICAgICAgICAgICAgICAgICAgICdSVCcgICAgICAgIDogJ0FSTSdcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG5cbiAgICAvLy8vLy8vLy8vLy8vL1xuICAgIC8vIFJlZ2V4IG1hcFxuICAgIC8vLy8vLy8vLy8vLy9cblxuXG4gICAgdmFyIHJlZ2V4ZXMgPSB7XG5cbiAgICAgICAgYnJvd3NlciA6IFtbXG5cbiAgICAgICAgICAgIC8vIFByZXN0byBiYXNlZFxuICAgICAgICAgICAgLyhvcGVyYVxcc21pbmkpXFwvKFtcXHdcXC4tXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BlcmEgTWluaVxuICAgICAgICAgICAgLyhvcGVyYVxcc1ttb2JpbGV0YWJdKykuK3ZlcnNpb25cXC8oW1xcd1xcLi1dKykvaSwgICAgICAgICAgICAgICAgICAgICAgLy8gT3BlcmEgTW9iaS9UYWJsZXRcbiAgICAgICAgICAgIC8ob3BlcmEpLit2ZXJzaW9uXFwvKFtcXHdcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BlcmEgPiA5LjgwXG4gICAgICAgICAgICAvKG9wZXJhKVtcXC9cXHNdKyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPcGVyYSA8IDkuODBcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKG9waW9zKVtcXC9cXHNdKyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPcGVyYSBtaW5pIG9uIGlwaG9uZSA+PSA4LjBcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ09wZXJhIE1pbmknXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgL1xccyhvcHIpXFwvKFtcXHdcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BlcmEgV2Via2l0XG4gICAgICAgICAgICBdLCBbW05BTUUsICdPcGVyYSddLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvLyBNaXhlZFxuICAgICAgICAgICAgLyhraW5kbGUpXFwvKFtcXHdcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBLaW5kbGVcbiAgICAgICAgICAgIC8obHVuYXNjYXBlfG1heHRob258bmV0ZnJvbnR8amFzbWluZXxibGF6ZXIpW1xcL1xcc10/KFtcXHdcXC5dKykqL2ksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEx1bmFzY2FwZS9NYXh0aG9uL05ldGZyb250L0phc21pbmUvQmxhemVyXG5cbiAgICAgICAgICAgIC8vIFRyaWRlbnQgYmFzZWRcbiAgICAgICAgICAgIC8oYXZhbnRcXHN8aWVtb2JpbGV8c2xpbXxiYWlkdSkoPzpicm93c2VyKT9bXFwvXFxzXT8oW1xcd1xcLl0qKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBdmFudC9JRU1vYmlsZS9TbGltQnJvd3Nlci9CYWlkdVxuICAgICAgICAgICAgLyg/Om1zfFxcKCkoaWUpXFxzKFtcXHdcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSW50ZXJuZXQgRXhwbG9yZXJcblxuICAgICAgICAgICAgLy8gV2Via2l0L0tIVE1MIGJhc2VkXG4gICAgICAgICAgICAvKHJla29ucSlcXC8oW1xcd1xcLl0rKSovaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJla29ucVxuICAgICAgICAgICAgLyhjaHJvbWl1bXxmbG9ja3xyb2NrbWVsdHxtaWRvcml8ZXBpcGhhbnl8c2lsa3xza3lmaXJlfG92aWJyb3dzZXJ8Ym9sdHxpcm9ufHZpdmFsZGl8aXJpZGl1bXxwaGFudG9tanN8Ym93c2VyKVxcLyhbXFx3XFwuLV0rKS9pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIENocm9taXVtL0Zsb2NrL1JvY2tNZWx0L01pZG9yaS9FcGlwaGFueS9TaWxrL1NreWZpcmUvQm9sdC9Jcm9uL0lyaWRpdW0vUGhhbnRvbUpTL0Jvd3NlclxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8odHJpZGVudCkuK3J2WzpcXHNdKFtcXHdcXC5dKykuK2xpa2VcXHNnZWNrby9pICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElFMTFcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ0lFJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oZWRnZSlcXC8oKFxcZCspP1tcXHdcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1pY3Jvc29mdCBFZGdlXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyh5YWJyb3dzZXIpXFwvKFtcXHdcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBZYW5kZXhcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ1lhbmRleCddLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKHB1ZmZpbilcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFB1ZmZpblxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnUHVmZmluJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oKD86W1xcc1xcL10pdWM/XFxzP2Jyb3dzZXJ8KD86anVjLispdWN3ZWIpW1xcL1xcc10/KFtcXHdcXC5dKykvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBVQ0Jyb3dzZXJcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ1VDQnJvd3NlciddLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKGNvbW9kb19kcmFnb24pXFwvKFtcXHdcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIENvbW9kbyBEcmFnb25cbiAgICAgICAgICAgIF0sIFtbTkFNRSwgL18vZywgJyAnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhtaWNyb21lc3NlbmdlcilcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBXZUNoYXRcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ1dlQ2hhdCddLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKFFRKVxcLyhbXFxkXFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFFRLCBha2EgU2hvdVFcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvbT8ocXFicm93c2VyKVtcXC9cXHNdPyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBRUUJyb3dzZXJcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAveGlhb21pXFwvbWl1aWJyb3dzZXJcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNSVVJIEJyb3dzZXJcbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBbTkFNRSwgJ01JVUkgQnJvd3NlciddXSwgW1xuXG4gICAgICAgICAgICAvO2ZiYXZcXC8oW1xcd1xcLl0rKTsvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZhY2Vib29rIEFwcCBmb3IgaU9TICYgQW5kcm9pZFxuICAgICAgICAgICAgXSwgW1ZFUlNJT04sIFtOQU1FLCAnRmFjZWJvb2snXV0sIFtcblxuICAgICAgICAgICAgL2hlYWRsZXNzY2hyb21lKD86XFwvKFtcXHdcXC5dKyl8XFxzKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2hyb21lIEhlYWRsZXNzXG4gICAgICAgICAgICBdLCBbVkVSU0lPTiwgW05BTUUsICdDaHJvbWUgSGVhZGxlc3MnXV0sIFtcblxuICAgICAgICAgICAgL1xcc3d2XFwpLisoY2hyb21lKVxcLyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIENocm9tZSBXZWJWaWV3XG4gICAgICAgICAgICBdLCBbW05BTUUsIC8oLispLywgJyQxIFdlYlZpZXcnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLygoPzpvY3VsdXN8c2Ftc3VuZylicm93c2VyKVxcLyhbXFx3XFwuXSspL2lcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgLyguKyg/Omd8dXMpKSguKykvLCAnJDEgJDInXSwgVkVSU0lPTl0sIFsgICAgICAgICAgICAgICAgLy8gT2N1bHVzIC8gU2Ftc3VuZyBCcm93c2VyXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLit2ZXJzaW9uXFwvKFtcXHdcXC5dKylcXHMrKD86bW9iaWxlXFxzP3NhZmFyaXxzYWZhcmkpKi9pICAgICAgICAvLyBBbmRyb2lkIEJyb3dzZXJcbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBbTkFNRSwgJ0FuZHJvaWQgQnJvd3NlciddXSwgW1xuXG4gICAgICAgICAgICAvKGNocm9tZXxvbW5pd2VifGFyb3JhfFt0aXplbm9rYV17NX1cXHM/YnJvd3NlcilcXC92PyhbXFx3XFwuXSspL2lcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2hyb21lL09tbmlXZWIvQXJvcmEvVGl6ZW4vTm9raWFcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKGRvbGZpbilcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIERvbHBoaW5cbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ0RvbHBoaW4nXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLygoPzphbmRyb2lkLispY3Jtb3xjcmlvcylcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDaHJvbWUgZm9yIEFuZHJvaWQvaU9TXG4gICAgICAgICAgICBdLCBbW05BTUUsICdDaHJvbWUnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhjb2FzdClcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPcGVyYSBDb2FzdFxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnT3BlcmEgQ29hc3QnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgL2Z4aW9zXFwvKFtcXHdcXC4tXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGaXJlZm94IGZvciBpT1NcbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBbTkFNRSwgJ0ZpcmVmb3gnXV0sIFtcblxuICAgICAgICAgICAgL3ZlcnNpb25cXC8oW1xcd1xcLl0rKS4rP21vYmlsZVxcL1xcdytcXHMoc2FmYXJpKS9pICAgICAgICAgICAgICAgICAgICAgICAvLyBNb2JpbGUgU2FmYXJpXG4gICAgICAgICAgICBdLCBbVkVSU0lPTiwgW05BTUUsICdNb2JpbGUgU2FmYXJpJ11dLCBbXG5cbiAgICAgICAgICAgIC92ZXJzaW9uXFwvKFtcXHdcXC5dKykuKz8obW9iaWxlXFxzP3NhZmFyaXxzYWZhcmkpL2kgICAgICAgICAgICAgICAgICAgIC8vIFNhZmFyaSAmIFNhZmFyaSBNb2JpbGVcbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBOQU1FXSwgW1xuXG4gICAgICAgICAgICAvd2Via2l0Lis/KGdzYSlcXC8oW1xcd1xcLl0rKS4rPyhtb2JpbGVcXHM/c2FmYXJpfHNhZmFyaSkoXFwvW1xcd1xcLl0rKS9pICAvLyBHb29nbGUgU2VhcmNoIEFwcGxpYW5jZSBvbiBpT1NcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ0dTQSddLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvd2Via2l0Lis/KG1vYmlsZVxccz9zYWZhcml8c2FmYXJpKShcXC9bXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAvLyBTYWZhcmkgPCAzLjBcbiAgICAgICAgICAgIF0sIFtOQU1FLCBbVkVSU0lPTiwgbWFwcGVyLnN0ciwgbWFwcy5icm93c2VyLm9sZHNhZmFyaS52ZXJzaW9uXV0sIFtcblxuICAgICAgICAgICAgLyhrb25xdWVyb3IpXFwvKFtcXHdcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBLb25xdWVyb3JcbiAgICAgICAgICAgIC8od2Via2l0fGtodG1sKVxcLyhbXFx3XFwuXSspL2lcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvLyBHZWNrbyBiYXNlZFxuICAgICAgICAgICAgLyhuYXZpZ2F0b3J8bmV0c2NhcGUpXFwvKFtcXHdcXC4tXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOZXRzY2FwZVxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnTmV0c2NhcGUnXSwgVkVSU0lPTl0sIFtcbiAgICAgICAgICAgIC8oc3dpZnRmb3gpL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3dpZnRmb3hcbiAgICAgICAgICAgIC8oaWNlZHJhZ29ufGljZXdlYXNlbHxjYW1pbm98Y2hpbWVyYXxmZW5uZWN8bWFlbW9cXHNicm93c2VyfG1pbmltb3xjb25rZXJvcilbXFwvXFxzXT8oW1xcd1xcLlxcK10rKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJY2VEcmFnb24vSWNld2Vhc2VsL0NhbWluby9DaGltZXJhL0Zlbm5lYy9NYWVtby9NaW5pbW8vQ29ua2Vyb3JcbiAgICAgICAgICAgIC8oZmlyZWZveHxzZWFtb25rZXl8ay1tZWxlb258aWNlY2F0fGljZWFwZXxmaXJlYmlyZHxwaG9lbml4KVxcLyhbXFx3XFwuLV0rKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGaXJlZm94L1NlYU1vbmtleS9LLU1lbGVvbi9JY2VDYXQvSWNlQXBlL0ZpcmViaXJkL1Bob2VuaXhcbiAgICAgICAgICAgIC8obW96aWxsYSlcXC8oW1xcd1xcLl0rKS4rcnZcXDouK2dlY2tvXFwvXFxkKy9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTW96aWxsYVxuXG4gICAgICAgICAgICAvLyBPdGhlclxuICAgICAgICAgICAgLyhwb2xhcmlzfGx5bnh8ZGlsbG98aWNhYnxkb3Jpc3xhbWF5YXx3M218bmV0c3VyZnxzbGVpcG5pcilbXFwvXFxzXT8oW1xcd1xcLl0rKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQb2xhcmlzL0x5bngvRGlsbG8vaUNhYi9Eb3Jpcy9BbWF5YS93M20vTmV0U3VyZi9TbGVpcG5pclxuICAgICAgICAgICAgLyhsaW5rcylcXHNcXCgoW1xcd1xcLl0rKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTGlua3NcbiAgICAgICAgICAgIC8oZ29icm93c2VyKVxcLz8oW1xcd1xcLl0rKSovaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR29Ccm93c2VyXG4gICAgICAgICAgICAvKGljZVxccz9icm93c2VyKVxcL3Y/KFtcXHdcXC5fXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJQ0UgQnJvd3NlclxuICAgICAgICAgICAgLyhtb3NhaWMpW1xcL1xcc10oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTW9zYWljXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl1cblxuICAgICAgICAgICAgLyogLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG4gICAgICAgICAgICAvLyBNZWRpYSBwbGF5ZXJzIEJFR0lOXG4gICAgICAgICAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cblxuICAgICAgICAgICAgLCBbXG5cbiAgICAgICAgICAgIC8oYXBwbGUoPzpjb3JlbWVkaWF8KSlcXC8oKFxcZCspW1xcd1xcLl9dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdlbmVyaWMgQXBwbGUgQ29yZU1lZGlhXG4gICAgICAgICAgICAvKGNvcmVtZWRpYSkgdigoXFxkKylbXFx3XFwuX10rKS9pXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhhcXVhbHVuZ3xseXNzbmF8YnNwbGF5ZXIpXFwvKChcXGQrKT9bXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgICAgLy8gQXF1YWx1bmcvTHlzc25hL0JTUGxheWVyXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhhcmVzfG9zc3Byb3h5KVxccygoXFxkKylbXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQXJlcy9PU1NQcm94eVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oYXVkYWNpb3VzfGF1ZGltdXNpY3N0cmVhbXxhbWFyb2t8YmFzc3xjb3JlfGRhbHZpa3xnbm9tZW1wbGF5ZXJ8bXVzaWMgb24gY29uc29sZXxuc3BsYXllcnxwc3AtaW50ZXJuZXRyYWRpb3BsYXllcnx2aWRlb3MpXFwvKChcXGQrKVtcXHdcXC4tXSspL2ksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEF1ZGFjaW91cy9BdWRpTXVzaWNTdHJlYW0vQW1hcm9rL0JBU1MvT3BlbkNPUkUvRGFsdmlrL0dub21lTXBsYXllci9Nb0NcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTlNQbGF5ZXIvUFNQLUludGVybmV0UmFkaW9QbGF5ZXIvVmlkZW9zXG4gICAgICAgICAgICAvKGNsZW1lbnRpbmV8bXVzaWMgcGxheWVyIGRhZW1vbilcXHMoKFxcZCspW1xcd1xcLi1dKykvaSwgICAgICAgICAgICAgICAvLyBDbGVtZW50aW5lL01QRFxuICAgICAgICAgICAgLyhsZyBwbGF5ZXJ8bmV4cGxheWVyKVxccygoXFxkKylbXFxkXFwuXSspL2ksXG4gICAgICAgICAgICAvcGxheWVyXFwvKG5leHBsYXllcnxsZyBwbGF5ZXIpXFxzKChcXGQrKVtcXHdcXC4tXSspL2kgICAgICAgICAgICAgICAgICAgLy8gTmV4UGxheWVyL0xHIFBsYXllclxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG4gICAgICAgICAgICAvKG5leHBsYXllcilcXHMoKFxcZCspW1xcd1xcLi1dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOZXhwbGF5ZXJcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKGZscnApXFwvKChcXGQrKVtcXHdcXC4tXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGbGlwIFBsYXllclxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnRmxpcCBQbGF5ZXInXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhmc3RyZWFtfG5hdGl2ZWhvc3R8cXVlcnlzZWVrc3BpZGVyfGlhLWFyY2hpdmVyfGZhY2Vib29rZXh0ZXJuYWxoaXQpL2lcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRlN0cmVhbS9OYXRpdmVIb3N0L1F1ZXJ5U2Vla1NwaWRlci9JQSBBcmNoaXZlci9mYWNlYm9va2V4dGVybmFsaGl0XG4gICAgICAgICAgICBdLCBbTkFNRV0sIFtcblxuICAgICAgICAgICAgLyhnc3RyZWFtZXIpIHNvdXBodHRwc3JjICg/OlxcKFteXFwpXStcXCkpezAsMX0gbGlic291cFxcLygoXFxkKylbXFx3XFwuLV0rKS9pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdzdHJlYW1lclxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oaHRjIHN0cmVhbWluZyBwbGF5ZXIpXFxzW1xcd19dK1xcc1xcL1xccygoXFxkKylbXFxkXFwuXSspL2ksICAgICAgICAgICAgICAvLyBIVEMgU3RyZWFtaW5nIFBsYXllclxuICAgICAgICAgICAgLyhqYXZhfHB5dGhvbi11cmxsaWJ8cHl0aG9uLXJlcXVlc3RzfHdnZXR8bGliY3VybClcXC8oKFxcZCspW1xcd1xcLi1fXSspL2ksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEphdmEvdXJsbGliL3JlcXVlc3RzL3dnZXQvY1VSTFxuICAgICAgICAgICAgLyhsYXZmKSgoXFxkKylbXFxkXFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBMYXZmIChGRk1QRUcpXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhodGNfb25lX3MpXFwvKChcXGQrKVtcXGRcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSFRDIE9uZSBTXG4gICAgICAgICAgICBdLCBbW05BTUUsIC9fL2csICcgJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8obXBsYXllcikoPzpcXHN8XFwvKSg/Oig/OnNoZXJweWEtKXswLDF9c3ZuKSg/Oi18XFxzKShyXFxkKyg/Oi1cXGQrW1xcd1xcLi1dKyl7MCwxfSkvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNUGxheWVyIFNWTlxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8obXBsYXllcikoPzpcXHN8XFwvfFt1bmtvdy1dKykoKFxcZCspW1xcd1xcLi1dKykvaSAgICAgICAgICAgICAgICAgICAgICAvLyBNUGxheWVyXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhtcGxheWVyKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNUGxheWVyIChubyBvdGhlciBpbmZvKVxuICAgICAgICAgICAgLyh5b3VybXV6ZSkvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBZb3VyTXV6ZVxuICAgICAgICAgICAgLyhtZWRpYSBwbGF5ZXIgY2xhc3NpY3xuZXJvIHNob3d0aW1lKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNZWRpYSBQbGF5ZXIgQ2xhc3NpYy9OZXJvIFNob3dUaW1lXG4gICAgICAgICAgICBdLCBbTkFNRV0sIFtcblxuICAgICAgICAgICAgLyhuZXJvICg/OmhvbWV8c2NvdXQpKVxcLygoXFxkKylbXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTmVybyBIb21lL05lcm8gU2NvdXRcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKG5va2lhXFxkKylcXC8oKFxcZCspW1xcd1xcLi1dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTm9raWFcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvXFxzKHNvbmdiaXJkKVxcLygoXFxkKylbXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU29uZ2JpcmQvUGhpbGlwcy1Tb25nYmlyZFxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8od2luYW1wKTMgdmVyc2lvbiAoKFxcZCspW1xcd1xcLi1dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2luYW1wXG4gICAgICAgICAgICAvKHdpbmFtcClcXHMoKFxcZCspW1xcd1xcLi1dKykvaSxcbiAgICAgICAgICAgIC8od2luYW1wKW1wZWdcXC8oKFxcZCspW1xcd1xcLi1dKykvaVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8ob2Ntcy1ib3R8dGFwaW5yYWRpb3x0dW5laW4gcmFkaW98dW5rbm93bnx3aW5hbXB8aW5saWdodCByYWRpbykvaSAgLy8gT0NNUy1ib3QvdGFwIGluIHJhZGlvL3R1bmVpbi91bmtub3duL3dpbmFtcCAobm8gb3RoZXIgaW5mbylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW5saWdodCByYWRpb1xuICAgICAgICAgICAgXSwgW05BTUVdLCBbXG5cbiAgICAgICAgICAgIC8ocXVpY2t0aW1lfHJtYXxyYWRpb2FwcHxyYWRpb2NsaWVudGFwcGxpY2F0aW9ufHNvdW5kdGFwfHRvdGVtfHN0YWdlZnJpZ2h0fHN0cmVhbWl1bSlcXC8oKFxcZCspW1xcd1xcLi1dKykvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBRdWlja1RpbWUvUmVhbE1lZGlhL1JhZGlvQXBwL1JhZGlvQ2xpZW50QXBwbGljYXRpb24vXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvdW5kVGFwL1RvdGVtL1N0YWdlZnJpZ2h0L1N0cmVhbWl1bVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oc21wKSgoXFxkKylbXFxkXFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU01QXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyh2bGMpIG1lZGlhIHBsYXllciAtIHZlcnNpb24gKChcXGQrKVtcXHdcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAvLyBWTEMgVmlkZW9sYW5cbiAgICAgICAgICAgIC8odmxjKVxcLygoXFxkKylbXFx3XFwuLV0rKS9pLFxuICAgICAgICAgICAgLyh4Ym1jfGd2ZnN8eGluZXx4bW1zfGlyYXBwKVxcLygoXFxkKylbXFx3XFwuLV0rKS9pLCAgICAgICAgICAgICAgICAgICAgLy8gWEJNQy9ndmZzL1hpbmUvWE1NUy9pcmFwcFxuICAgICAgICAgICAgLyhmb29iYXIyMDAwKVxcLygoXFxkKylbXFxkXFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRm9vYmFyMjAwMFxuICAgICAgICAgICAgLyhpdHVuZXMpXFwvKChcXGQrKVtcXGRcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaVR1bmVzXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyh3bXBsYXllcilcXC8oKFxcZCspW1xcd1xcLi1dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2luZG93cyBNZWRpYSBQbGF5ZXJcbiAgICAgICAgICAgIC8od2luZG93cy1tZWRpYS1wbGF5ZXIpXFwvKChcXGQrKVtcXHdcXC4tXSspL2lcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgLy0vZywgJyAnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgL3dpbmRvd3NcXC8oKFxcZCspW1xcd1xcLi1dKykgdXBucFxcL1tcXGRcXC5dKyBkbG5hZG9jXFwvW1xcZFxcLl0rIChob21lIG1lZGlhIHNlcnZlcikvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBXaW5kb3dzIE1lZGlhIFNlcnZlclxuICAgICAgICAgICAgXSwgW1ZFUlNJT04sIFtOQU1FLCAnV2luZG93cyddXSwgW1xuXG4gICAgICAgICAgICAvKGNvbVxcLnJpc2V1cHJhZGlvYWxhcm0pXFwvKChcXGQrKVtcXGRcXC5dKikvaSAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmlzZVVQIFJhZGlvIEFsYXJtXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhyYWQuaW8pXFxzKChcXGQrKVtcXGRcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmFkLmlvXG4gICAgICAgICAgICAvKHJhZGlvLig/OmRlfGF0fGZyKSlcXHMoKFxcZCspW1xcZFxcLl0rKS9pXG4gICAgICAgICAgICBdLCBbW05BTUUsICdyYWQuaW8nXSwgVkVSU0lPTl1cblxuICAgICAgICAgICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgICAgICAgICAgLy8gTWVkaWEgcGxheWVycyBFTkRcbiAgICAgICAgICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vKi9cblxuICAgICAgICBdLFxuXG4gICAgICAgIGNwdSA6IFtbXG5cbiAgICAgICAgICAgIC8oPzooYW1kfHgoPzooPzo4Nnw2NClbXy1dKT98d293fHdpbik2NClbO1xcKV0vaSAgICAgICAgICAgICAgICAgICAgIC8vIEFNRDY0XG4gICAgICAgICAgICBdLCBbW0FSQ0hJVEVDVFVSRSwgJ2FtZDY0J11dLCBbXG5cbiAgICAgICAgICAgIC8oaWEzMig/PTspKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSUEzMiAocXVpY2t0aW1lKVxuICAgICAgICAgICAgXSwgW1tBUkNISVRFQ1RVUkUsIHV0aWwubG93ZXJpemVdXSwgW1xuXG4gICAgICAgICAgICAvKCg/OmlbMzQ2XXx4KTg2KVs7XFwpXS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJQTMyXG4gICAgICAgICAgICBdLCBbW0FSQ0hJVEVDVFVSRSwgJ2lhMzInXV0sIFtcblxuICAgICAgICAgICAgLy8gUG9ja2V0UEMgbWlzdGFrZW5seSBpZGVudGlmaWVkIGFzIFBvd2VyUENcbiAgICAgICAgICAgIC93aW5kb3dzXFxzKGNlfG1vYmlsZSk7XFxzcHBjOy9pXG4gICAgICAgICAgICBdLCBbW0FSQ0hJVEVDVFVSRSwgJ2FybSddXSwgW1xuXG4gICAgICAgICAgICAvKCg/OnBwY3xwb3dlcnBjKSg/OjY0KT8pKD86XFxzbWFjfDt8XFwpKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUG93ZXJQQ1xuICAgICAgICAgICAgXSwgW1tBUkNISVRFQ1RVUkUsIC9vd2VyLywgJycsIHV0aWwubG93ZXJpemVdXSwgW1xuXG4gICAgICAgICAgICAvKHN1bjRcXHcpWztcXCldL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU1BBUkNcbiAgICAgICAgICAgIF0sIFtbQVJDSElURUNUVVJFLCAnc3BhcmMnXV0sIFtcblxuICAgICAgICAgICAgLygoPzphdnIzMnxpYTY0KD89OykpfDY4ayg/PVxcKSl8YXJtKD86NjR8KD89dlxcZCs7KSl8KD89YXRtZWxcXHMpYXZyfCg/OmlyaXh8bWlwc3xzcGFyYykoPzo2NCk/KD89Oyl8cGEtcmlzYykvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJQTY0LCA2OEssIEFSTS82NCwgQVZSLzMyLCBJUklYLzY0LCBNSVBTLzY0LCBTUEFSQy82NCwgUEEtUklTQ1xuICAgICAgICAgICAgXSwgW1tBUkNISVRFQ1RVUkUsIHV0aWwubG93ZXJpemVdXVxuICAgICAgICBdLFxuXG4gICAgICAgIGRldmljZSA6IFtbXG5cbiAgICAgICAgICAgIC9cXCgoaXBhZHxwbGF5Ym9vayk7W1xcd1xcc1xcKTstXSsocmltfGFwcGxlKS9pICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlQYWQvUGxheUJvb2tcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgVkVORE9SLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgL2FwcGxlY29yZW1lZGlhXFwvW1xcd1xcLl0rIFxcKChpcGFkKS8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaVBhZFxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnQXBwbGUnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC8oYXBwbGVcXHN7MCwxfXR2KS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFwcGxlIFRWXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnQXBwbGUgVFYnXSwgW1ZFTkRPUiwgJ0FwcGxlJ11dLCBbXG5cbiAgICAgICAgICAgIC8oYXJjaG9zKVxccyhnYW1lcGFkMj8pL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFyY2hvc1xuICAgICAgICAgICAgLyhocCkuKyh0b3VjaHBhZCkvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIUCBUb3VjaFBhZFxuICAgICAgICAgICAgLyhocCkuKyh0YWJsZXQpL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIUCBUYWJsZXRcbiAgICAgICAgICAgIC8oa2luZGxlKVxcLyhbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gS2luZGxlXG4gICAgICAgICAgICAvXFxzKG5vb2spW1xcd1xcc10rYnVpbGRcXC8oXFx3KykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTm9va1xuICAgICAgICAgICAgLyhkZWxsKVxccyhzdHJlYVtrcHJcXHNcXGRdKltcXGRrb10pL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRGVsbCBTdHJlYWtcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIE1PREVMLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgLyhrZltBLXpdKylcXHNidWlsZFxcL1tcXHdcXC5dKy4qc2lsa1xcLy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEtpbmRsZSBGaXJlIEhEXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdBbWF6b24nXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG4gICAgICAgICAgICAvKHNkfGtmKVswMzQ5aGlqb3JzdHV3XStcXHNidWlsZFxcL1tcXHdcXC5dKy4qc2lsa1xcLy9pICAgICAgICAgICAgICAgICAgLy8gRmlyZSBQaG9uZVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgbWFwcGVyLnN0ciwgbWFwcy5kZXZpY2UuYW1hem9uLm1vZGVsXSwgW1ZFTkRPUiwgJ0FtYXpvbiddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgL1xcKChpcFtob25lZHxcXHNcXHcqXSspOy4rKGFwcGxlKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpUG9kL2lQaG9uZVxuICAgICAgICAgICAgXSwgW01PREVMLCBWRU5ET1IsIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgL1xcKChpcFtob25lZHxcXHNcXHcqXSspOy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpUG9kL2lQaG9uZVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnQXBwbGUnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8oYmxhY2tiZXJyeSlbXFxzLV0/KFxcdyspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBCbGFja0JlcnJ5XG4gICAgICAgICAgICAvKGJsYWNrYmVycnl8YmVucXxwYWxtKD89XFwtKXxzb255ZXJpY3Nzb258YWNlcnxhc3VzfGRlbGx8bWVpenV8bW90b3JvbGF8cG9seXRyb24pW1xcc18tXT8oW1xcdy1dKykqL2ksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEJlblEvUGFsbS9Tb255LUVyaWNzc29uL0FjZXIvQXN1cy9EZWxsL01laXp1L01vdG9yb2xhL1BvbHl0cm9uXG4gICAgICAgICAgICAvKGhwKVxccyhbXFx3XFxzXStcXHcpL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIUCBpUEFRXG4gICAgICAgICAgICAvKGFzdXMpLT8oXFx3KykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBc3VzXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvXFwoYmIxMDtcXHMoXFx3KykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEJsYWNrQmVycnkgMTBcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0JsYWNrQmVycnknXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFzdXMgVGFibGV0c1xuICAgICAgICAgICAgL2FuZHJvaWQuKyh0cmFuc2ZvW3ByaW1lXFxzXXs0LDEwfVxcc1xcdyt8ZWVlcGN8c2xpZGVyXFxzXFx3K3xuZXh1cyA3fHBhZGZvbmUpL2lcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0FzdXMnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC8oc29ueSlcXHModGFibGV0XFxzW3BzXSlcXHNidWlsZFxcLy9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTb255XG4gICAgICAgICAgICAvKHNvbnkpPyg/OnNncC4rKVxcc2J1aWxkXFwvL2lcbiAgICAgICAgICAgIF0sIFtbVkVORE9SLCAnU29ueSddLCBbTU9ERUwsICdYcGVyaWEgVGFibGV0J10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuICAgICAgICAgICAgL2FuZHJvaWQuK1xccyhbYy1nXVxcZHs0fXxzb1stbF1cXHcrKVxcc2J1aWxkXFwvL2lcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ1NvbnknXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC9cXHMob3V5YSlcXHMvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPdXlhXG4gICAgICAgICAgICAvKG5pbnRlbmRvKVxccyhbd2lkczN1XSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOaW50ZW5kb1xuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgTU9ERUwsIFtUWVBFLCBDT05TT0xFXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuKztcXHMoc2hpZWxkKVxcc2J1aWxkL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE52aWRpYVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnTnZpZGlhJ10sIFtUWVBFLCBDT05TT0xFXV0sIFtcblxuICAgICAgICAgICAgLyhwbGF5c3RhdGlvblxcc1szNHBvcnRhYmxldmldKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUGxheXN0YXRpb25cbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ1NvbnknXSwgW1RZUEUsIENPTlNPTEVdXSwgW1xuXG4gICAgICAgICAgICAvKHNwcmludFxccyhcXHcrKSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3ByaW50IFBob25lc1xuICAgICAgICAgICAgXSwgW1tWRU5ET1IsIG1hcHBlci5zdHIsIG1hcHMuZGV2aWNlLnNwcmludC52ZW5kb3JdLCBbTU9ERUwsIG1hcHBlci5zdHIsIG1hcHMuZGV2aWNlLnNwcmludC5tb2RlbF0sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKGxlbm92bylcXHM/KFMoPzo1MDAwfDYwMDApKyg/OlstXVtcXHcrXSkpL2kgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTGVub3ZvIHRhYmxldHNcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIE1PREVMLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgLyhodGMpWztfXFxzLV0rKFtcXHdcXHNdKyg/PVxcKSl8XFx3KykqL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEhUQ1xuICAgICAgICAgICAgLyh6dGUpLShcXHcrKSovaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gWlRFXG4gICAgICAgICAgICAvKGFsY2F0ZWx8Z2Vla3NwaG9uZXxsZW5vdm98bmV4aWFufHBhbmFzb25pY3woPz07XFxzKXNvbnkpW19cXHMtXT8oW1xcdy1dKykqL2lcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWxjYXRlbC9HZWVrc1Bob25lL0xlbm92by9OZXhpYW4vUGFuYXNvbmljL1NvbnlcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIFtNT0RFTCwgL18vZywgJyAnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8obmV4dXNcXHM5KS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEhUQyBOZXh1cyA5XG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdIVEMnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9kXFwvaHVhd2VpKFtcXHdcXHMtXSspWztcXCldL2ksXG4gICAgICAgICAgICAvKG5leHVzXFxzNnApL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIdWF3ZWlcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0h1YXdlaSddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgLyhtaWNyb3NvZnQpO1xccyhsdW1pYVtcXHNcXHddKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNaWNyb3NvZnQgTHVtaWFcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIE1PREVMLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgL1tcXHNcXCg7XSh4Ym94KD86XFxzb25lKT8pW1xcc1xcKTtdL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1pY3Jvc29mdCBYYm94XG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdNaWNyb3NvZnQnXSwgW1RZUEUsIENPTlNPTEVdXSwgW1xuICAgICAgICAgICAgLyhraW5cXC5bb25ldHddezN9KS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTWljcm9zb2Z0IEtpblxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgL1xcLi9nLCAnICddLCBbVkVORE9SLCAnTWljcm9zb2Z0J10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1vdG9yb2xhXG4gICAgICAgICAgICAvXFxzKG1pbGVzdG9uZXxkcm9pZCg/OlsyLTR4XXxcXHMoPzpiaW9uaWN8eDJ8cHJvfHJhenIpKT8oOj9cXHM0Zyk/KVtcXHdcXHNdK2J1aWxkXFwvL2ksXG4gICAgICAgICAgICAvbW90W1xccy1dPyhcXHcrKSovaSxcbiAgICAgICAgICAgIC8oWFRcXGR7Myw0fSkgYnVpbGRcXC8vaSxcbiAgICAgICAgICAgIC8obmV4dXNcXHM2KS9pXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdNb3Rvcm9sYSddLCBbVFlQRSwgTU9CSUxFXV0sIFtcbiAgICAgICAgICAgIC9hbmRyb2lkLitcXHMobXo2MFxcZHx4b29tW1xcczJdezAsMn0pXFxzYnVpbGRcXC8vaVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnTW90b3JvbGEnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9oYmJ0dlxcL1xcZCtcXC5cXGQrXFwuXFxkK1xccytcXChbXFx3XFxzXSo7XFxzKihcXHdbXjtdKik7KFteO10qKS9pICAgICAgICAgICAgLy8gSGJiVFYgZGV2aWNlc1xuICAgICAgICAgICAgXSwgW1tWRU5ET1IsIHV0aWwudHJpbV0sIFtNT0RFTCwgdXRpbC50cmltXSwgW1RZUEUsIFNNQVJUVFZdXSwgW1xuXG4gICAgICAgICAgICAvaGJidHYuK21hcGxlOyhcXGQrKS9pXG4gICAgICAgICAgICBdLCBbW01PREVMLCAvXi8sICdTbWFydFRWJ10sIFtWRU5ET1IsICdTYW1zdW5nJ10sIFtUWVBFLCBTTUFSVFRWXV0sIFtcblxuICAgICAgICAgICAgL1xcKGR0dltcXCk7XS4rKGFxdW9zKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNoYXJwXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdTaGFycCddLCBbVFlQRSwgU01BUlRUVl1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLisoKHNjaC1pWzg5XTBcXGR8c2h3LW0zODBzfGd0LXBcXGR7NH18Z3QtblxcZCt8c2doLXQ4WzU2XTl8bmV4dXMgMTApKS9pLFxuICAgICAgICAgICAgLygoU00tVFxcdyspKS9pXG4gICAgICAgICAgICBdLCBbW1ZFTkRPUiwgJ1NhbXN1bmcnXSwgTU9ERUwsIFtUWVBFLCBUQUJMRVRdXSwgWyAgICAgICAgICAgICAgICAgIC8vIFNhbXN1bmdcbiAgICAgICAgICAgIC9zbWFydC10di4rKHNhbXN1bmcpL2lcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIFtUWVBFLCBTTUFSVFRWXSwgTU9ERUxdLCBbXG4gICAgICAgICAgICAvKChzW2NncF1oLVxcdyt8Z3QtXFx3K3xnYWxheHlcXHNuZXh1c3xzbS1cXHdbXFx3XFxkXSspKS9pLFxuICAgICAgICAgICAgLyhzYW1bc3VuZ10qKVtcXHMtXSooXFx3Ky0/W1xcdy1dKikqL2ksXG4gICAgICAgICAgICAvc2VjLSgoc2doXFx3KykpL2lcbiAgICAgICAgICAgIF0sIFtbVkVORE9SLCAnU2Ftc3VuZyddLCBNT0RFTCwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC9zaWUtKFxcdyspKi9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNpZW1lbnNcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ1NpZW1lbnMnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8obWFlbW98bm9raWEpLioobjkwMHxsdW1pYVxcc1xcZCspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOb2tpYVxuICAgICAgICAgICAgLyhub2tpYSlbXFxzXy1dPyhbXFx3LV0rKSovaVxuICAgICAgICAgICAgXSwgW1tWRU5ET1IsICdOb2tpYSddLCBNT0RFTCwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkXFxzM1xcLltcXHNcXHc7LV17MTB9KGFcXGR7M30pL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBY2VyXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdBY2VyJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuXG4gICAgICAgICAgICAvYW5kcm9pZC4rKFt2bF1rXFwtP1xcZHszfSlcXHMrYnVpbGQvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExHIFRhYmxldFxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnTEcnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG4gICAgICAgICAgICAvYW5kcm9pZFxcczNcXC5bXFxzXFx3Oy1dezEwfShsZz8pLShbMDZjdjldezMsNH0pL2kgICAgICAgICAgICAgICAgICAgICAvLyBMRyBUYWJsZXRcbiAgICAgICAgICAgIF0sIFtbVkVORE9SLCAnTEcnXSwgTU9ERUwsIFtUWVBFLCBUQUJMRVRdXSwgW1xuICAgICAgICAgICAgLyhsZykgbmV0Y2FzdFxcLnR2L2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTEcgU21hcnRUVlxuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgTU9ERUwsIFtUWVBFLCBTTUFSVFRWXV0sIFtcbiAgICAgICAgICAgIC8obmV4dXNcXHNbNDVdKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExHXG4gICAgICAgICAgICAvbGdbZTtcXHNcXC8tXSsoXFx3KykqL2ksXG4gICAgICAgICAgICAvYW5kcm9pZC4rbGcoXFwtP1tcXGRcXHddKylcXHMrYnVpbGQvaVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnTEcnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLisoaWRlYXRhYlthLXowLTlcXC1cXHNdKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBMZW5vdm9cbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0xlbm92byddLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgL2xpbnV4Oy4rKChqb2xsYSkpOy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBKb2xsYVxuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgTU9ERUwsIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKChwZWJibGUpKWFwcFxcL1tcXGRcXC5dK1xccy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQZWJibGVcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIE1PREVMLCBbVFlQRSwgV0VBUkFCTEVdXSwgW1xuXG4gICAgICAgICAgICAvYW5kcm9pZC4rO1xccyhvcHBvKVxccz8oW1xcd1xcc10rKVxcc2J1aWxkL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT1BQT1xuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgTU9ERUwsIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvY3JrZXkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdvb2dsZSBDaHJvbWVjYXN0XG4gICAgICAgICAgICBdLCBbW01PREVMLCAnQ2hyb21lY2FzdCddLCBbVkVORE9SLCAnR29vZ2xlJ11dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLis7XFxzKGdsYXNzKVxcc1xcZC9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR29vZ2xlIEdsYXNzXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdHb29nbGUnXSwgW1RZUEUsIFdFQVJBQkxFXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuKztcXHMocGl4ZWwgYylcXHMvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdvb2dsZSBQaXhlbCBDXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdHb29nbGUnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLis7XFxzKHBpeGVsIHhsfHBpeGVsKVxccy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHb29nbGUgUGl4ZWxcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0dvb2dsZSddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuKyhcXHcrKVxccytidWlsZFxcL2htXFwxL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gWGlhb21pIEhvbmdtaSAnbnVtZXJpYycgbW9kZWxzXG4gICAgICAgICAgICAvYW5kcm9pZC4rKGhtW1xcc1xcLV9dKm5vdGU/W1xcc19dKig/OlxcZFxcdyk/KVxccytidWlsZC9pLCAgICAgICAgICAgICAgIC8vIFhpYW9taSBIb25nbWlcbiAgICAgICAgICAgIC9hbmRyb2lkLisobWlbXFxzXFwtX10qKD86b25lfG9uZVtcXHNfXXBsdXN8bm90ZSBsdGUpP1tcXHNfXSooPzpcXGRcXHcpPylcXHMrYnVpbGQvaSwgICAgLy8gWGlhb21pIE1pXG4gICAgICAgICAgICAvYW5kcm9pZC4rKHJlZG1pW1xcc1xcLV9dKig/Om5vdGUpPyg/OltcXHNfXSpbXFx3XFxzXSspPylcXHMrYnVpbGQvaSAgICAgIC8vIFJlZG1pIFBob25lc1xuICAgICAgICAgICAgXSwgW1tNT0RFTCwgL18vZywgJyAnXSwgW1ZFTkRPUiwgJ1hpYW9taSddLCBbVFlQRSwgTU9CSUxFXV0sIFtcbiAgICAgICAgICAgIC9hbmRyb2lkLisobWlbXFxzXFwtX10qKD86cGFkKT8oPzpbXFxzX10qW1xcd1xcc10rKT8pXFxzK2J1aWxkL2kgICAgICAgICAgLy8gTWkgUGFkIHRhYmxldHNcbiAgICAgICAgICAgIF0sW1tNT0RFTCwgL18vZywgJyAnXSwgW1ZFTkRPUiwgJ1hpYW9taSddLCBbVFlQRSwgVEFCTEVUXV0sIFtcbiAgICAgICAgICAgIC9hbmRyb2lkLis7XFxzKG1bMS01XVxcc25vdGUpXFxzYnVpbGQvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTWVpenUgVGFibGV0XG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdNZWl6dSddLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuK2EwMDAoMSlcXHMrYnVpbGQvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT25lUGx1c1xuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnT25lUGx1cyddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuK1s7XFwvXVxccyooUkNUW1xcZFxcd10rKVxccytidWlsZC9pICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJDQSBUYWJsZXRzXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdSQ0EnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLitbO1xcL11cXHMqKFZlbnVlW1xcZFxcc10qKVxccytidWlsZC9pICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBEZWxsIFZlbnVlIFRhYmxldHNcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0RlbGwnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLitbO1xcL11cXHMqKFFbVHxNXVtcXGRcXHddKylcXHMrYnVpbGQvaSAgICAgICAgICAgICAgICAgICAgICAgICAvLyBWZXJpem9uIFRhYmxldFxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnVmVyaXpvbiddLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuK1s7XFwvXVxccysoQmFybmVzWyZcXHNdK05vYmxlXFxzK3xCTltSVF0pKFY/LiopXFxzK2J1aWxkL2kgICAgIC8vIEJhcm5lcyAmIE5vYmxlIFRhYmxldFxuICAgICAgICAgICAgXSwgW1tWRU5ET1IsICdCYXJuZXMgJiBOb2JsZSddLCBNT0RFTCwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLitbO1xcL11cXHMrKFRNXFxkezN9LipcXGIpXFxzK2J1aWxkL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBCYXJuZXMgJiBOb2JsZSBUYWJsZXRcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ051VmlzaW9uJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuXG4gICAgICAgICAgICAvYW5kcm9pZC4rWztcXC9dXFxzKih6dGUpPy4rKGtcXGR7Mn0pXFxzK2J1aWxkL2kgICAgICAgICAgICAgICAgICAgICAgICAvLyBaVEUgSyBTZXJpZXMgVGFibGV0XG4gICAgICAgICAgICBdLCBbW1ZFTkRPUiwgJ1pURSddLCBNT0RFTCwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLitbO1xcL11cXHMqKGdlblxcZHszfSlcXHMrYnVpbGQuKjQ5aC9pICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFN3aXNzIEdFTiBNb2JpbGVcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ1N3aXNzJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvYW5kcm9pZC4rWztcXC9dXFxzKih6dXJcXGR7M30pXFxzK2J1aWxkL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTd2lzcyBaVVIgVGFibGV0XG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdTd2lzcyddLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuK1s7XFwvXVxccyooKFpla2kpP1RCLipcXGIpXFxzK2J1aWxkL2kgICAgICAgICAgICAgICAgICAgICAgICAgLy8gWmVraSBUYWJsZXRzXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdaZWtpJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuXG4gICAgICAgICAgICAvKGFuZHJvaWQpLitbO1xcL11cXHMrKFtZUl1cXGR7Mn14Py4qKVxccytidWlsZC9pLFxuICAgICAgICAgICAgL2FuZHJvaWQuK1s7XFwvXVxccysoRHJhZ29uW1xcLVxcc10rVG91Y2hcXHMrfERUKSguKylcXHMrYnVpbGQvaSAgICAgICAgICAvLyBEcmFnb24gVG91Y2ggVGFibGV0XG4gICAgICAgICAgICBdLCBbW1ZFTkRPUiwgJ0RyYWdvbiBUb3VjaCddLCBNT0RFTCwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLitbO1xcL11cXHMqKE5TLT8uKylcXHMrYnVpbGQvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSW5zaWduaWEgVGFibGV0c1xuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnSW5zaWduaWEnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLitbO1xcL11cXHMqKChOWHxOZXh0KS0/LispXFxzK2J1aWxkL2kgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTmV4dEJvb2sgVGFibGV0c1xuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnTmV4dEJvb2snXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLitbO1xcL11cXHMqKFh0cmVtZVxcXz8pPyhWKDFbMDQ1XXwyWzAxNV18MzB8NDB8NjB8N1swNV18OTApKVxccytidWlsZC9pXG4gICAgICAgICAgICBdLCBbW1ZFTkRPUiwgJ1ZvaWNlJ10sIE1PREVMLCBbVFlQRSwgTU9CSUxFXV0sIFsgICAgICAgICAgICAgICAgICAgIC8vIFZvaWNlIFh0cmVtZSBQaG9uZXNcblxuICAgICAgICAgICAgL2FuZHJvaWQuK1s7XFwvXVxccyooTFZURUxcXC0/KT8oVjFbMTJdKVxccytidWlsZC9pICAgICAgICAgICAgICAgICAgICAgLy8gTHZUZWwgUGhvbmVzXG4gICAgICAgICAgICBdLCBbW1ZFTkRPUiwgJ0x2VGVsJ10sIE1PREVMLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuK1s7XFwvXVxccyooVigxMDBNRHw3MDBOQXw3MDExfDkxN0cpLipcXGIpXFxzK2J1aWxkL2kgICAgICAgICAgLy8gRW52aXplbiBUYWJsZXRzXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdFbnZpemVuJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuXG4gICAgICAgICAgICAvYW5kcm9pZC4rWztcXC9dXFxzKihMZVtcXHNcXC1dK1BhbilbXFxzXFwtXSsoLipcXGIpXFxzK2J1aWxkL2kgICAgICAgICAgICAgLy8gTGUgUGFuIFRhYmxldHNcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIE1PREVMLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuK1s7XFwvXVxccyooVHJpb1tcXHNcXC1dKi4qKVxccytidWlsZC9pICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1hY2hTcGVlZCBUYWJsZXRzXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdNYWNoU3BlZWQnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLitbO1xcL11cXHMqKFRyaW5pdHkpW1xcLVxcc10qKFRcXGR7M30pXFxzK2J1aWxkL2kgICAgICAgICAgICAgICAgLy8gVHJpbml0eSBUYWJsZXRzXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLitbO1xcL11cXHMqVFVfKDE0OTEpXFxzK2J1aWxkL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUm90b3IgVGFibGV0c1xuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnUm90b3InXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLisoS1MoLispKVxccytidWlsZC9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFtYXpvbiBLaW5kbGUgVGFibGV0c1xuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnQW1hem9uJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuXG4gICAgICAgICAgICAvYW5kcm9pZC4rKEdpZ2FzZXQpW1xcc1xcLV0rKFEuKylcXHMrYnVpbGQvaSAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdpZ2FzZXQgVGFibGV0c1xuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgTU9ERUwsIFtUWVBFLCBUQUJMRVRdXSwgW1xuXG4gICAgICAgICAgICAvXFxzKHRhYmxldHx0YWIpWztcXC9dL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVW5pZGVudGlmaWFibGUgVGFibGV0XG4gICAgICAgICAgICAvXFxzKG1vYmlsZSkoPzpbO1xcL118XFxzc2FmYXJpKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVuaWRlbnRpZmlhYmxlIE1vYmlsZVxuICAgICAgICAgICAgXSwgW1tUWVBFLCB1dGlsLmxvd2VyaXplXSwgVkVORE9SLCBNT0RFTF0sIFtcblxuICAgICAgICAgICAgLyhhbmRyb2lkLispWztcXC9dLitidWlsZC9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR2VuZXJpYyBBbmRyb2lkIERldmljZVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnR2VuZXJpYyddXVxuXG5cbiAgICAgICAgLyovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgICAgICAgICAgLy8gVE9ETzogbW92ZSB0byBzdHJpbmcgbWFwXG4gICAgICAgICAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbiAgICAgICAgICAgIC8oQzY2MDMpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU29ueSBYcGVyaWEgWiBDNjYwM1xuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ1hwZXJpYSBaIEM2NjAzJ10sIFtWRU5ET1IsICdTb255J10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgLyhDNjkwMykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTb255IFhwZXJpYSBaIDFcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdYcGVyaWEgWiAxJ10sIFtWRU5ET1IsICdTb255J10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKFNNLUc5MDBbRnxIXSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNhbXN1bmcgR2FsYXh5IFM1XG4gICAgICAgICAgICBdLCBbW01PREVMLCAnR2FsYXh5IFM1J10sIFtWRU5ET1IsICdTYW1zdW5nJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgLyhTTS1HNzEwMikvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTYW1zdW5nIEdhbGF4eSBHcmFuZCAyXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnR2FsYXh5IEdyYW5kIDInXSwgW1ZFTkRPUiwgJ1NhbXN1bmcnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKFNNLUc1MzBIKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNhbXN1bmcgR2FsYXh5IEdyYW5kIFByaW1lXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnR2FsYXh5IEdyYW5kIFByaW1lJ10sIFtWRU5ET1IsICdTYW1zdW5nJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgLyhTTS1HMzEzSFopL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTYW1zdW5nIEdhbGF4eSBWXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnR2FsYXh5IFYnXSwgW1ZFTkRPUiwgJ1NhbXN1bmcnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKFNNLVQ4MDUpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNhbXN1bmcgR2FsYXh5IFRhYiBTIDEwLjVcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdHYWxheHkgVGFiIFMgMTAuNSddLCBbVkVORE9SLCAnU2Ftc3VuZyddLCBbVFlQRSwgVEFCTEVUXV0sIFtcbiAgICAgICAgICAgIC8oU00tRzgwMEYpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2Ftc3VuZyBHYWxheHkgUzUgTWluaVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ0dhbGF4eSBTNSBNaW5pJ10sIFtWRU5ET1IsICdTYW1zdW5nJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgLyhTTS1UMzExKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTYW1zdW5nIEdhbGF4eSBUYWIgMyA4LjBcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdHYWxheHkgVGFiIDMgOC4wJ10sIFtWRU5ET1IsICdTYW1zdW5nJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuXG4gICAgICAgICAgICAvKFQzQykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFkdmFuIFZhbmRyb2lkIFQzQ1xuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnQWR2YW4nXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG4gICAgICAgICAgICAvKEFEVkFOIFQxSlxcKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBZHZhbiBWYW5kcm9pZCBUMUorXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnVmFuZHJvaWQgVDFKKyddLCBbVkVORE9SLCAnQWR2YW4nXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG4gICAgICAgICAgICAvKEFEVkFOIFM0QSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFkdmFuIFZhbmRyb2lkIFM0QVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ1ZhbmRyb2lkIFM0QSddLCBbVkVORE9SLCAnQWR2YW4nXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8oVjk3Mk0pL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gWlRFIFY5NzJNXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdaVEUnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8oaS1tb2JpbGUpXFxzKElRXFxzW1xcZFxcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGktbW9iaWxlIElRXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKElRNi4zKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGktbW9iaWxlIElRIElRIDYuM1xuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ0lRIDYuMyddLCBbVkVORE9SLCAnaS1tb2JpbGUnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKGktbW9iaWxlKVxccyhpLXN0eWxlXFxzW1xcZFxcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpLW1vYmlsZSBpLVNUWUxFXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKGktU1RZTEUyLjEpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGktbW9iaWxlIGktU1RZTEUgMi4xXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnaS1TVFlMRSAyLjEnXSwgW1ZFTkRPUiwgJ2ktbW9iaWxlJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKG1vYmlpc3RhciB0b3VjaCBMQUkgNTEyKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1vYmlpc3RhciB0b3VjaCBMQUkgNTEyXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnVG91Y2ggTEFJIDUxMiddLCBbVkVORE9SLCAnbW9iaWlzdGFyJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvLy8vLy8vLy8vLy8vXG4gICAgICAgICAgICAvLyBFTkQgVE9ET1xuICAgICAgICAgICAgLy8vLy8vLy8vLy8qL1xuXG4gICAgICAgIF0sXG5cbiAgICAgICAgZW5naW5lIDogW1tcblxuICAgICAgICAgICAgL3dpbmRvd3MuK1xcc2VkZ2VcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWRnZUhUTUxcbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBbTkFNRSwgJ0VkZ2VIVE1MJ11dLCBbXG5cbiAgICAgICAgICAgIC8ocHJlc3RvKVxcLyhbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUHJlc3RvXG4gICAgICAgICAgICAvKHdlYmtpdHx0cmlkZW50fG5ldGZyb250fG5ldHN1cmZ8YW1heWF8bHlueHx3M20pXFwvKFtcXHdcXC5dKykvaSwgICAgIC8vIFdlYktpdC9UcmlkZW50L05ldEZyb250L05ldFN1cmYvQW1heWEvTHlueC93M21cbiAgICAgICAgICAgIC8oa2h0bWx8dGFzbWFufGxpbmtzKVtcXC9cXHNdXFwoPyhbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBLSFRNTC9UYXNtYW4vTGlua3NcbiAgICAgICAgICAgIC8oaWNhYilbXFwvXFxzXShbMjNdXFwuW1xcZFxcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpQ2FiXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgL3J2XFw6KFtcXHdcXC5dKykuKihnZWNrbykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHZWNrb1xuICAgICAgICAgICAgXSwgW1ZFUlNJT04sIE5BTUVdXG4gICAgICAgIF0sXG5cbiAgICAgICAgb3MgOiBbW1xuXG4gICAgICAgICAgICAvLyBXaW5kb3dzIGJhc2VkXG4gICAgICAgICAgICAvbWljcm9zb2Z0XFxzKHdpbmRvd3MpXFxzKHZpc3RhfHhwKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2luZG93cyAoaVR1bmVzKVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG4gICAgICAgICAgICAvKHdpbmRvd3MpXFxzbnRcXHM2XFwuMjtcXHMoYXJtKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBXaW5kb3dzIFJUXG4gICAgICAgICAgICAvKHdpbmRvd3NcXHNwaG9uZSg/Olxcc29zKSopW1xcc1xcL10/KFtcXGRcXC5cXHNdK1xcdykqL2ksICAgICAgICAgICAgICAgICAgLy8gV2luZG93cyBQaG9uZVxuICAgICAgICAgICAgLyh3aW5kb3dzXFxzbW9iaWxlfHdpbmRvd3MpW1xcc1xcL10/KFtudGNlXFxkXFwuXFxzXStcXHcpL2lcbiAgICAgICAgICAgIF0sIFtOQU1FLCBbVkVSU0lPTiwgbWFwcGVyLnN0ciwgbWFwcy5vcy53aW5kb3dzLnZlcnNpb25dXSwgW1xuICAgICAgICAgICAgLyh3aW4oPz0zfDl8bil8d2luXFxzOXhcXHMpKFtudFxcZFxcLl0rKS9pXG4gICAgICAgICAgICBdLCBbW05BTUUsICdXaW5kb3dzJ10sIFtWRVJTSU9OLCBtYXBwZXIuc3RyLCBtYXBzLm9zLndpbmRvd3MudmVyc2lvbl1dLCBbXG5cbiAgICAgICAgICAgIC8vIE1vYmlsZS9FbWJlZGRlZCBPU1xuICAgICAgICAgICAgL1xcKChiYikoMTApOy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQmxhY2tCZXJyeSAxMFxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnQmxhY2tCZXJyeSddLCBWRVJTSU9OXSwgW1xuICAgICAgICAgICAgLyhibGFja2JlcnJ5KVxcdypcXC8/KFtcXHdcXC5dKykqL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQmxhY2tiZXJyeVxuICAgICAgICAgICAgLyh0aXplbilbXFwvXFxzXShbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGl6ZW5cbiAgICAgICAgICAgIC8oYW5kcm9pZHx3ZWJvc3xwYWxtXFxzb3N8cW54fGJhZGF8cmltXFxzdGFibGV0XFxzb3N8bWVlZ298Y29udGlraSlbXFwvXFxzLV0/KFtcXHdcXC5dKykqL2ksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFuZHJvaWQvV2ViT1MvUGFsbS9RTlgvQmFkYS9SSU0vTWVlR28vQ29udGlraVxuICAgICAgICAgICAgL2xpbnV4Oy4rKHNhaWxmaXNoKTsvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTYWlsZmlzaCBPU1xuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG4gICAgICAgICAgICAvKHN5bWJpYW5cXHM/b3N8c3ltYm9zfHM2MCg/PTspKVtcXC9cXHMtXT8oW1xcd1xcLl0rKSovaSAgICAgICAgICAgICAgICAgLy8gU3ltYmlhblxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnU3ltYmlhbiddLCBWRVJTSU9OXSwgW1xuICAgICAgICAgICAgL1xcKChzZXJpZXM0MCk7L2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2VyaWVzIDQwXG4gICAgICAgICAgICBdLCBbTkFNRV0sIFtcbiAgICAgICAgICAgIC9tb3ppbGxhLitcXChtb2JpbGU7LitnZWNrby4rZmlyZWZveC9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZpcmVmb3ggT1NcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ0ZpcmVmb3ggT1MnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLy8gQ29uc29sZVxuICAgICAgICAgICAgLyhuaW50ZW5kb3xwbGF5c3RhdGlvbilcXHMoW3dpZHMzNHBvcnRhYmxldnVdKykvaSwgICAgICAgICAgICAgICAgICAgLy8gTmludGVuZG8vUGxheXN0YXRpb25cblxuICAgICAgICAgICAgLy8gR05VL0xpbnV4IGJhc2VkXG4gICAgICAgICAgICAvKG1pbnQpW1xcL1xcc1xcKF0/KFxcdyspKi9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNaW50XG4gICAgICAgICAgICAvKG1hZ2VpYXx2ZWN0b3JsaW51eClbO1xcc10vaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNYWdlaWEvVmVjdG9yTGludXhcbiAgICAgICAgICAgIC8oam9saXxba3hsbl0/dWJ1bnR1fGRlYmlhbnxbb3Blbl0qc3VzZXxnZW50b298KD89XFxzKWFyY2h8c2xhY2t3YXJlfGZlZG9yYXxtYW5kcml2YXxjZW50b3N8cGNsaW51eG9zfHJlZGhhdHx6ZW53YWxrfGxpbnB1cylbXFwvXFxzLV0/KD8hY2hyb20pKFtcXHdcXC4tXSspKi9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBKb2xpL1VidW50dS9EZWJpYW4vU1VTRS9HZW50b28vQXJjaC9TbGFja3dhcmVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRmVkb3JhL01hbmRyaXZhL0NlbnRPUy9QQ0xpbnV4T1MvUmVkSGF0L1plbndhbGsvTGlucHVzXG4gICAgICAgICAgICAvKGh1cmR8bGludXgpXFxzPyhbXFx3XFwuXSspKi9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEh1cmQvTGludXhcbiAgICAgICAgICAgIC8oZ251KVxccz8oW1xcd1xcLl0rKSovaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR05VXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhjcm9zKVxcc1tcXHddK1xccyhbXFx3XFwuXStcXHcpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDaHJvbWl1bSBPU1xuICAgICAgICAgICAgXSwgW1tOQU1FLCAnQ2hyb21pdW0gT1MnXSwgVkVSU0lPTl0sW1xuXG4gICAgICAgICAgICAvLyBTb2xhcmlzXG4gICAgICAgICAgICAvKHN1bm9zKVxccz8oW1xcd1xcLl0rXFxkKSovaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTb2xhcmlzXG4gICAgICAgICAgICBdLCBbW05BTUUsICdTb2xhcmlzJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8vIEJTRCBiYXNlZFxuICAgICAgICAgICAgL1xccyhbZnJlbnRvcGMtXXswLDR9YnNkfGRyYWdvbmZseSlcXHM/KFtcXHdcXC5dKykqL2kgICAgICAgICAgICAgICAgICAgLy8gRnJlZUJTRC9OZXRCU0QvT3BlbkJTRC9QQy1CU0QvRHJhZ29uRmx5XG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sW1xuXG4gICAgICAgICAgICAvKGhhaWt1KVxccyhcXHcrKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIYWlrdVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLFtcblxuICAgICAgICAgICAgL2NmbmV0d29ya1xcLy4rZGFyd2luL2ksXG4gICAgICAgICAgICAvaXBbaG9uZWFkXSsoPzouKm9zXFxzKFtcXHddKylcXHNsaWtlXFxzbWFjfDtcXHNvcGVyYSkvaSAgICAgICAgICAgICAgICAgLy8gaU9TXG4gICAgICAgICAgICBdLCBbW1ZFUlNJT04sIC9fL2csICcuJ10sIFtOQU1FLCAnaU9TJ11dLCBbXG5cbiAgICAgICAgICAgIC8obWFjXFxzb3NcXHN4KVxccz8oW1xcd1xcc1xcLl0rXFx3KSovaSxcbiAgICAgICAgICAgIC8obWFjaW50b3NofG1hYyg/PV9wb3dlcnBjKVxccykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1hYyBPU1xuICAgICAgICAgICAgXSwgW1tOQU1FLCAnTWFjIE9TJ10sIFtWRVJTSU9OLCAvXy9nLCAnLiddXSwgW1xuXG4gICAgICAgICAgICAvLyBPdGhlclxuICAgICAgICAgICAgLygoPzpvcGVuKT9zb2xhcmlzKVtcXC9cXHMtXT8oW1xcd1xcLl0rKSovaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU29sYXJpc1xuICAgICAgICAgICAgLyhhaXgpXFxzKChcXGQpKD89XFwufFxcKXxcXHMpW1xcd1xcLl0qKSovaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQUlYXG4gICAgICAgICAgICAvKHBsYW5cXHM5fG1pbml4fGJlb3N8b3NcXC8yfGFtaWdhb3N8bW9ycGhvc3xyaXNjXFxzb3N8b3BlbnZtcykvaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUGxhbjkvTWluaXgvQmVPUy9PUzIvQW1pZ2FPUy9Nb3JwaE9TL1JJU0NPUy9PcGVuVk1TXG4gICAgICAgICAgICAvKHVuaXgpXFxzPyhbXFx3XFwuXSspKi9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVOSVhcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXVxuICAgICAgICBdXG4gICAgfTtcblxuXG4gICAgLy8vLy8vLy8vLy8vLy8vLy9cbiAgICAvLyBDb25zdHJ1Y3RvclxuICAgIC8vLy8vLy8vLy8vLy8vLy9cbiAgICAvKlxuICAgIHZhciBCcm93c2VyID0gZnVuY3Rpb24gKG5hbWUsIHZlcnNpb24pIHtcbiAgICAgICAgdGhpc1tOQU1FXSA9IG5hbWU7XG4gICAgICAgIHRoaXNbVkVSU0lPTl0gPSB2ZXJzaW9uO1xuICAgIH07XG4gICAgdmFyIENQVSA9IGZ1bmN0aW9uIChhcmNoKSB7XG4gICAgICAgIHRoaXNbQVJDSElURUNUVVJFXSA9IGFyY2g7XG4gICAgfTtcbiAgICB2YXIgRGV2aWNlID0gZnVuY3Rpb24gKHZlbmRvciwgbW9kZWwsIHR5cGUpIHtcbiAgICAgICAgdGhpc1tWRU5ET1JdID0gdmVuZG9yO1xuICAgICAgICB0aGlzW01PREVMXSA9IG1vZGVsO1xuICAgICAgICB0aGlzW1RZUEVdID0gdHlwZTtcbiAgICB9O1xuICAgIHZhciBFbmdpbmUgPSBCcm93c2VyO1xuICAgIHZhciBPUyA9IEJyb3dzZXI7XG4gICAgKi9cbiAgICB2YXIgVUFQYXJzZXIgPSBmdW5jdGlvbiAodWFzdHJpbmcsIGV4dGVuc2lvbnMpIHtcblxuICAgICAgICBpZiAodHlwZW9mIHVhc3RyaW5nID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgZXh0ZW5zaW9ucyA9IHVhc3RyaW5nO1xuICAgICAgICAgICAgdWFzdHJpbmcgPSB1bmRlZmluZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoISh0aGlzIGluc3RhbmNlb2YgVUFQYXJzZXIpKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFVBUGFyc2VyKHVhc3RyaW5nLCBleHRlbnNpb25zKS5nZXRSZXN1bHQoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB1YSA9IHVhc3RyaW5nIHx8ICgod2luZG93ICYmIHdpbmRvdy5uYXZpZ2F0b3IgJiYgd2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQpID8gd2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQgOiBFTVBUWSk7XG4gICAgICAgIHZhciByZ3htYXAgPSBleHRlbnNpb25zID8gdXRpbC5leHRlbmQocmVnZXhlcywgZXh0ZW5zaW9ucykgOiByZWdleGVzO1xuICAgICAgICAvL3ZhciBicm93c2VyID0gbmV3IEJyb3dzZXIoKTtcbiAgICAgICAgLy92YXIgY3B1ID0gbmV3IENQVSgpO1xuICAgICAgICAvL3ZhciBkZXZpY2UgPSBuZXcgRGV2aWNlKCk7XG4gICAgICAgIC8vdmFyIGVuZ2luZSA9IG5ldyBFbmdpbmUoKTtcbiAgICAgICAgLy92YXIgb3MgPSBuZXcgT1MoKTtcblxuICAgICAgICB0aGlzLmdldEJyb3dzZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYnJvd3NlciA9IHsgbmFtZTogdW5kZWZpbmVkLCB2ZXJzaW9uOiB1bmRlZmluZWQgfTtcbiAgICAgICAgICAgIG1hcHBlci5yZ3guY2FsbChicm93c2VyLCB1YSwgcmd4bWFwLmJyb3dzZXIpO1xuICAgICAgICAgICAgYnJvd3Nlci5tYWpvciA9IHV0aWwubWFqb3IoYnJvd3Nlci52ZXJzaW9uKTsgLy8gZGVwcmVjYXRlZFxuICAgICAgICAgICAgcmV0dXJuIGJyb3dzZXI7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZ2V0Q1BVID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGNwdSA9IHsgYXJjaGl0ZWN0dXJlOiB1bmRlZmluZWQgfTtcbiAgICAgICAgICAgIG1hcHBlci5yZ3guY2FsbChjcHUsIHVhLCByZ3htYXAuY3B1KTtcbiAgICAgICAgICAgIHJldHVybiBjcHU7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZ2V0RGV2aWNlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGRldmljZSA9IHsgdmVuZG9yOiB1bmRlZmluZWQsIG1vZGVsOiB1bmRlZmluZWQsIHR5cGU6IHVuZGVmaW5lZCB9O1xuICAgICAgICAgICAgbWFwcGVyLnJneC5jYWxsKGRldmljZSwgdWEsIHJneG1hcC5kZXZpY2UpO1xuICAgICAgICAgICAgcmV0dXJuIGRldmljZTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5nZXRFbmdpbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgZW5naW5lID0geyBuYW1lOiB1bmRlZmluZWQsIHZlcnNpb246IHVuZGVmaW5lZCB9O1xuICAgICAgICAgICAgbWFwcGVyLnJneC5jYWxsKGVuZ2luZSwgdWEsIHJneG1hcC5lbmdpbmUpO1xuICAgICAgICAgICAgcmV0dXJuIGVuZ2luZTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5nZXRPUyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBvcyA9IHsgbmFtZTogdW5kZWZpbmVkLCB2ZXJzaW9uOiB1bmRlZmluZWQgfTtcbiAgICAgICAgICAgIG1hcHBlci5yZ3guY2FsbChvcywgdWEsIHJneG1hcC5vcyk7XG4gICAgICAgICAgICByZXR1cm4gb3M7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZ2V0UmVzdWx0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB1YSAgICAgIDogdGhpcy5nZXRVQSgpLFxuICAgICAgICAgICAgICAgIGJyb3dzZXIgOiB0aGlzLmdldEJyb3dzZXIoKSxcbiAgICAgICAgICAgICAgICBlbmdpbmUgIDogdGhpcy5nZXRFbmdpbmUoKSxcbiAgICAgICAgICAgICAgICBvcyAgICAgIDogdGhpcy5nZXRPUygpLFxuICAgICAgICAgICAgICAgIGRldmljZSAgOiB0aGlzLmdldERldmljZSgpLFxuICAgICAgICAgICAgICAgIGNwdSAgICAgOiB0aGlzLmdldENQVSgpXG4gICAgICAgICAgICB9O1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmdldFVBID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHVhO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLnNldFVBID0gZnVuY3Rpb24gKHVhc3RyaW5nKSB7XG4gICAgICAgICAgICB1YSA9IHVhc3RyaW5nO1xuICAgICAgICAgICAgLy9icm93c2VyID0gbmV3IEJyb3dzZXIoKTtcbiAgICAgICAgICAgIC8vY3B1ID0gbmV3IENQVSgpO1xuICAgICAgICAgICAgLy9kZXZpY2UgPSBuZXcgRGV2aWNlKCk7XG4gICAgICAgICAgICAvL2VuZ2luZSA9IG5ldyBFbmdpbmUoKTtcbiAgICAgICAgICAgIC8vb3MgPSBuZXcgT1MoKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuXG4gICAgVUFQYXJzZXIuVkVSU0lPTiA9IExJQlZFUlNJT047XG4gICAgVUFQYXJzZXIuQlJPV1NFUiA9IHtcbiAgICAgICAgTkFNRSAgICA6IE5BTUUsXG4gICAgICAgIE1BSk9SICAgOiBNQUpPUiwgLy8gZGVwcmVjYXRlZFxuICAgICAgICBWRVJTSU9OIDogVkVSU0lPTlxuICAgIH07XG4gICAgVUFQYXJzZXIuQ1BVID0ge1xuICAgICAgICBBUkNISVRFQ1RVUkUgOiBBUkNISVRFQ1RVUkVcbiAgICB9O1xuICAgIFVBUGFyc2VyLkRFVklDRSA9IHtcbiAgICAgICAgTU9ERUwgICA6IE1PREVMLFxuICAgICAgICBWRU5ET1IgIDogVkVORE9SLFxuICAgICAgICBUWVBFICAgIDogVFlQRSxcbiAgICAgICAgQ09OU09MRSA6IENPTlNPTEUsXG4gICAgICAgIE1PQklMRSAgOiBNT0JJTEUsXG4gICAgICAgIFNNQVJUVFYgOiBTTUFSVFRWLFxuICAgICAgICBUQUJMRVQgIDogVEFCTEVULFxuICAgICAgICBXRUFSQUJMRTogV0VBUkFCTEUsXG4gICAgICAgIEVNQkVEREVEOiBFTUJFRERFRFxuICAgIH07XG4gICAgVUFQYXJzZXIuRU5HSU5FID0ge1xuICAgICAgICBOQU1FICAgIDogTkFNRSxcbiAgICAgICAgVkVSU0lPTiA6IFZFUlNJT05cbiAgICB9O1xuICAgIFVBUGFyc2VyLk9TID0ge1xuICAgICAgICBOQU1FICAgIDogTkFNRSxcbiAgICAgICAgVkVSU0lPTiA6IFZFUlNJT05cbiAgICB9O1xuICAgIC8vVUFQYXJzZXIuVXRpbHMgPSB1dGlsO1xuXG4gICAgLy8vLy8vLy8vLy9cbiAgICAvLyBFeHBvcnRcbiAgICAvLy8vLy8vLy8vXG5cblxuICAgIC8vIGNoZWNrIGpzIGVudmlyb25tZW50XG4gICAgaWYgKHR5cGVvZihleHBvcnRzKSAhPT0gVU5ERUZfVFlQRSkge1xuICAgICAgICAvLyBub2RlanMgZW52XG4gICAgICAgIGlmICh0eXBlb2YgbW9kdWxlICE9PSBVTkRFRl9UWVBFICYmIG1vZHVsZS5leHBvcnRzKSB7XG4gICAgICAgICAgICBleHBvcnRzID0gbW9kdWxlLmV4cG9ydHMgPSBVQVBhcnNlcjtcbiAgICAgICAgfVxuICAgICAgICAvLyBUT0RPOiB0ZXN0ISEhISEhISFcbiAgICAgICAgLypcbiAgICAgICAgaWYgKHJlcXVpcmUgJiYgcmVxdWlyZS5tYWluID09PSBtb2R1bGUgJiYgcHJvY2Vzcykge1xuICAgICAgICAgICAgLy8gY2xpXG4gICAgICAgICAgICB2YXIganNvbml6ZSA9IGZ1bmN0aW9uIChhcnIpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzID0gW107XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSBpbiBhcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzLnB1c2gobmV3IFVBUGFyc2VyKGFycltpXSkuZ2V0UmVzdWx0KCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBwcm9jZXNzLnN0ZG91dC53cml0ZShKU09OLnN0cmluZ2lmeShyZXMsIG51bGwsIDIpICsgJ1xcbicpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmIChwcm9jZXNzLnN0ZGluLmlzVFRZKSB7XG4gICAgICAgICAgICAgICAgLy8gdmlhIGFyZ3NcbiAgICAgICAgICAgICAgICBqc29uaXplKHByb2Nlc3MuYXJndi5zbGljZSgyKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHZpYSBwaXBlXG4gICAgICAgICAgICAgICAgdmFyIHN0ciA9ICcnO1xuICAgICAgICAgICAgICAgIHByb2Nlc3Muc3RkaW4ub24oJ3JlYWRhYmxlJywgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciByZWFkID0gcHJvY2Vzcy5zdGRpbi5yZWFkKCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChyZWFkICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzdHIgKz0gcmVhZDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHByb2Nlc3Muc3RkaW4ub24oJ2VuZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAganNvbml6ZShzdHIucmVwbGFjZSgvXFxuJC8sICcnKS5zcGxpdCgnXFxuJykpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgICovXG4gICAgICAgIGV4cG9ydHMuVUFQYXJzZXIgPSBVQVBhcnNlcjtcbiAgICB9IGVsc2Uge1xuICAgICAgICAvLyByZXF1aXJlanMgZW52IChvcHRpb25hbClcbiAgICAgICAgaWYgKHR5cGVvZihkZWZpbmUpID09PSBGVU5DX1RZUEUgJiYgZGVmaW5lLmFtZCkge1xuICAgICAgICAgICAgZGVmaW5lKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gVUFQYXJzZXI7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmICh3aW5kb3cpIHtcbiAgICAgICAgICAgIC8vIGJyb3dzZXIgZW52XG4gICAgICAgICAgICB3aW5kb3cuVUFQYXJzZXIgPSBVQVBhcnNlcjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIGpRdWVyeS9aZXB0byBzcGVjaWZpYyAob3B0aW9uYWwpXG4gICAgLy8gTm90ZTpcbiAgICAvLyAgIEluIEFNRCBlbnYgdGhlIGdsb2JhbCBzY29wZSBzaG91bGQgYmUga2VwdCBjbGVhbiwgYnV0IGpRdWVyeSBpcyBhbiBleGNlcHRpb24uXG4gICAgLy8gICBqUXVlcnkgYWx3YXlzIGV4cG9ydHMgdG8gZ2xvYmFsIHNjb3BlLCB1bmxlc3MgalF1ZXJ5Lm5vQ29uZmxpY3QodHJ1ZSkgaXMgdXNlZCxcbiAgICAvLyAgIGFuZCB3ZSBzaG91bGQgY2F0Y2ggdGhhdC5cbiAgICB2YXIgJCA9IHdpbmRvdyAmJiAod2luZG93LmpRdWVyeSB8fCB3aW5kb3cuWmVwdG8pO1xuICAgIGlmICh0eXBlb2YgJCAhPT0gVU5ERUZfVFlQRSkge1xuICAgICAgICB2YXIgcGFyc2VyID0gbmV3IFVBUGFyc2VyKCk7XG4gICAgICAgICQudWEgPSBwYXJzZXIuZ2V0UmVzdWx0KCk7XG4gICAgICAgICQudWEuZ2V0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHBhcnNlci5nZXRVQSgpO1xuICAgICAgICB9O1xuICAgICAgICAkLnVhLnNldCA9IGZ1bmN0aW9uICh1YXN0cmluZykge1xuICAgICAgICAgICAgcGFyc2VyLnNldFVBKHVhc3RyaW5nKTtcbiAgICAgICAgICAgIHZhciByZXN1bHQgPSBwYXJzZXIuZ2V0UmVzdWx0KCk7XG4gICAgICAgICAgICBmb3IgKHZhciBwcm9wIGluIHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICQudWFbcHJvcF0gPSByZXN1bHRbcHJvcF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuXG59KSh0eXBlb2Ygd2luZG93ID09PSAnb2JqZWN0JyA/IHdpbmRvdyA6IHRoaXMpO1xuIiwiXG52YXIgcm5nO1xuXG52YXIgY3J5cHRvID0gZ2xvYmFsLmNyeXB0byB8fCBnbG9iYWwubXNDcnlwdG87IC8vIGZvciBJRSAxMVxuaWYgKGNyeXB0byAmJiBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKSB7XG4gIC8vIFdIQVRXRyBjcnlwdG8tYmFzZWQgUk5HIC0gaHR0cDovL3dpa2kud2hhdHdnLm9yZy93aWtpL0NyeXB0b1xuICAvLyBNb2RlcmF0ZWx5IGZhc3QsIGhpZ2ggcXVhbGl0eVxuICB2YXIgX3JuZHM4ID0gbmV3IFVpbnQ4QXJyYXkoMTYpO1xuICBybmcgPSBmdW5jdGlvbiB3aGF0d2dSTkcoKSB7XG4gICAgY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhfcm5kczgpO1xuICAgIHJldHVybiBfcm5kczg7XG4gIH07XG59XG5cbmlmICghcm5nKSB7XG4gIC8vIE1hdGgucmFuZG9tKCktYmFzZWQgKFJORylcbiAgLy9cbiAgLy8gSWYgYWxsIGVsc2UgZmFpbHMsIHVzZSBNYXRoLnJhbmRvbSgpLiAgSXQncyBmYXN0LCBidXQgaXMgb2YgdW5zcGVjaWZpZWRcbiAgLy8gcXVhbGl0eS5cbiAgdmFyICBfcm5kcyA9IG5ldyBBcnJheSgxNik7XG4gIHJuZyA9IGZ1bmN0aW9uKCkge1xuICAgIGZvciAodmFyIGkgPSAwLCByOyBpIDwgMTY7IGkrKykge1xuICAgICAgaWYgKChpICYgMHgwMykgPT09IDApIHIgPSBNYXRoLnJhbmRvbSgpICogMHgxMDAwMDAwMDA7XG4gICAgICBfcm5kc1tpXSA9IHIgPj4+ICgoaSAmIDB4MDMpIDw8IDMpICYgMHhmZjtcbiAgICB9XG5cbiAgICByZXR1cm4gX3JuZHM7XG4gIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gcm5nO1xuXG4iLCIvLyAgICAgdXVpZC5qc1xuLy9cbi8vICAgICBDb3B5cmlnaHQgKGMpIDIwMTAtMjAxMiBSb2JlcnQgS2llZmZlclxuLy8gICAgIE1JVCBMaWNlbnNlIC0gaHR0cDovL29wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL21pdC1saWNlbnNlLnBocFxuXG4vLyBVbmlxdWUgSUQgY3JlYXRpb24gcmVxdWlyZXMgYSBoaWdoIHF1YWxpdHkgcmFuZG9tICMgZ2VuZXJhdG9yLiAgV2UgZmVhdHVyZVxuLy8gZGV0ZWN0IHRvIGRldGVybWluZSB0aGUgYmVzdCBSTkcgc291cmNlLCBub3JtYWxpemluZyB0byBhIGZ1bmN0aW9uIHRoYXRcbi8vIHJldHVybnMgMTI4LWJpdHMgb2YgcmFuZG9tbmVzcywgc2luY2UgdGhhdCdzIHdoYXQncyB1c3VhbGx5IHJlcXVpcmVkXG52YXIgX3JuZyA9IHJlcXVpcmUoJy4vcm5nJyk7XG5cbi8vIE1hcHMgZm9yIG51bWJlciA8LT4gaGV4IHN0cmluZyBjb252ZXJzaW9uXG52YXIgX2J5dGVUb0hleCA9IFtdO1xudmFyIF9oZXhUb0J5dGUgPSB7fTtcbmZvciAodmFyIGkgPSAwOyBpIDwgMjU2OyBpKyspIHtcbiAgX2J5dGVUb0hleFtpXSA9IChpICsgMHgxMDApLnRvU3RyaW5nKDE2KS5zdWJzdHIoMSk7XG4gIF9oZXhUb0J5dGVbX2J5dGVUb0hleFtpXV0gPSBpO1xufVxuXG4vLyAqKmBwYXJzZSgpYCAtIFBhcnNlIGEgVVVJRCBpbnRvIGl0J3MgY29tcG9uZW50IGJ5dGVzKipcbmZ1bmN0aW9uIHBhcnNlKHMsIGJ1Ziwgb2Zmc2V0KSB7XG4gIHZhciBpID0gKGJ1ZiAmJiBvZmZzZXQpIHx8IDAsIGlpID0gMDtcblxuICBidWYgPSBidWYgfHwgW107XG4gIHMudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9bMC05YS1mXXsyfS9nLCBmdW5jdGlvbihvY3QpIHtcbiAgICBpZiAoaWkgPCAxNikgeyAvLyBEb24ndCBvdmVyZmxvdyFcbiAgICAgIGJ1ZltpICsgaWkrK10gPSBfaGV4VG9CeXRlW29jdF07XG4gICAgfVxuICB9KTtcblxuICAvLyBaZXJvIG91dCByZW1haW5pbmcgYnl0ZXMgaWYgc3RyaW5nIHdhcyBzaG9ydFxuICB3aGlsZSAoaWkgPCAxNikge1xuICAgIGJ1ZltpICsgaWkrK10gPSAwO1xuICB9XG5cbiAgcmV0dXJuIGJ1Zjtcbn1cblxuLy8gKipgdW5wYXJzZSgpYCAtIENvbnZlcnQgVVVJRCBieXRlIGFycmF5IChhbGEgcGFyc2UoKSkgaW50byBhIHN0cmluZyoqXG5mdW5jdGlvbiB1bnBhcnNlKGJ1Ziwgb2Zmc2V0KSB7XG4gIHZhciBpID0gb2Zmc2V0IHx8IDAsIGJ0aCA9IF9ieXRlVG9IZXg7XG4gIHJldHVybiAgYnRoW2J1ZltpKytdXSArIGJ0aFtidWZbaSsrXV0gK1xuICAgICAgICAgIGJ0aFtidWZbaSsrXV0gKyBidGhbYnVmW2krK11dICsgJy0nICtcbiAgICAgICAgICBidGhbYnVmW2krK11dICsgYnRoW2J1ZltpKytdXSArICctJyArXG4gICAgICAgICAgYnRoW2J1ZltpKytdXSArIGJ0aFtidWZbaSsrXV0gKyAnLScgK1xuICAgICAgICAgIGJ0aFtidWZbaSsrXV0gKyBidGhbYnVmW2krK11dICsgJy0nICtcbiAgICAgICAgICBidGhbYnVmW2krK11dICsgYnRoW2J1ZltpKytdXSArXG4gICAgICAgICAgYnRoW2J1ZltpKytdXSArIGJ0aFtidWZbaSsrXV0gK1xuICAgICAgICAgIGJ0aFtidWZbaSsrXV0gKyBidGhbYnVmW2krK11dO1xufVxuXG4vLyAqKmB2MSgpYCAtIEdlbmVyYXRlIHRpbWUtYmFzZWQgVVVJRCoqXG4vL1xuLy8gSW5zcGlyZWQgYnkgaHR0cHM6Ly9naXRodWIuY29tL0xpb3NLL1VVSUQuanNcbi8vIGFuZCBodHRwOi8vZG9jcy5weXRob24ub3JnL2xpYnJhcnkvdXVpZC5odG1sXG5cbi8vIHJhbmRvbSAjJ3Mgd2UgbmVlZCB0byBpbml0IG5vZGUgYW5kIGNsb2Nrc2VxXG52YXIgX3NlZWRCeXRlcyA9IF9ybmcoKTtcblxuLy8gUGVyIDQuNSwgY3JlYXRlIGFuZCA0OC1iaXQgbm9kZSBpZCwgKDQ3IHJhbmRvbSBiaXRzICsgbXVsdGljYXN0IGJpdCA9IDEpXG52YXIgX25vZGVJZCA9IFtcbiAgX3NlZWRCeXRlc1swXSB8IDB4MDEsXG4gIF9zZWVkQnl0ZXNbMV0sIF9zZWVkQnl0ZXNbMl0sIF9zZWVkQnl0ZXNbM10sIF9zZWVkQnl0ZXNbNF0sIF9zZWVkQnl0ZXNbNV1cbl07XG5cbi8vIFBlciA0LjIuMiwgcmFuZG9taXplICgxNCBiaXQpIGNsb2Nrc2VxXG52YXIgX2Nsb2Nrc2VxID0gKF9zZWVkQnl0ZXNbNl0gPDwgOCB8IF9zZWVkQnl0ZXNbN10pICYgMHgzZmZmO1xuXG4vLyBQcmV2aW91cyB1dWlkIGNyZWF0aW9uIHRpbWVcbnZhciBfbGFzdE1TZWNzID0gMCwgX2xhc3ROU2VjcyA9IDA7XG5cbi8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vYnJvb2ZhL25vZGUtdXVpZCBmb3IgQVBJIGRldGFpbHNcbmZ1bmN0aW9uIHYxKG9wdGlvbnMsIGJ1Ziwgb2Zmc2V0KSB7XG4gIHZhciBpID0gYnVmICYmIG9mZnNldCB8fCAwO1xuICB2YXIgYiA9IGJ1ZiB8fCBbXTtcblxuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICB2YXIgY2xvY2tzZXEgPSBvcHRpb25zLmNsb2Nrc2VxICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmNsb2Nrc2VxIDogX2Nsb2Nrc2VxO1xuXG4gIC8vIFVVSUQgdGltZXN0YW1wcyBhcmUgMTAwIG5hbm8tc2Vjb25kIHVuaXRzIHNpbmNlIHRoZSBHcmVnb3JpYW4gZXBvY2gsXG4gIC8vICgxNTgyLTEwLTE1IDAwOjAwKS4gIEpTTnVtYmVycyBhcmVuJ3QgcHJlY2lzZSBlbm91Z2ggZm9yIHRoaXMsIHNvXG4gIC8vIHRpbWUgaXMgaGFuZGxlZCBpbnRlcm5hbGx5IGFzICdtc2VjcycgKGludGVnZXIgbWlsbGlzZWNvbmRzKSBhbmQgJ25zZWNzJ1xuICAvLyAoMTAwLW5hbm9zZWNvbmRzIG9mZnNldCBmcm9tIG1zZWNzKSBzaW5jZSB1bml4IGVwb2NoLCAxOTcwLTAxLTAxIDAwOjAwLlxuICB2YXIgbXNlY3MgPSBvcHRpb25zLm1zZWNzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLm1zZWNzIDogbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgLy8gUGVyIDQuMi4xLjIsIHVzZSBjb3VudCBvZiB1dWlkJ3MgZ2VuZXJhdGVkIGR1cmluZyB0aGUgY3VycmVudCBjbG9ja1xuICAvLyBjeWNsZSB0byBzaW11bGF0ZSBoaWdoZXIgcmVzb2x1dGlvbiBjbG9ja1xuICB2YXIgbnNlY3MgPSBvcHRpb25zLm5zZWNzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLm5zZWNzIDogX2xhc3ROU2VjcyArIDE7XG5cbiAgLy8gVGltZSBzaW5jZSBsYXN0IHV1aWQgY3JlYXRpb24gKGluIG1zZWNzKVxuICB2YXIgZHQgPSAobXNlY3MgLSBfbGFzdE1TZWNzKSArIChuc2VjcyAtIF9sYXN0TlNlY3MpLzEwMDAwO1xuXG4gIC8vIFBlciA0LjIuMS4yLCBCdW1wIGNsb2Nrc2VxIG9uIGNsb2NrIHJlZ3Jlc3Npb25cbiAgaWYgKGR0IDwgMCAmJiBvcHRpb25zLmNsb2Nrc2VxID09PSB1bmRlZmluZWQpIHtcbiAgICBjbG9ja3NlcSA9IGNsb2Nrc2VxICsgMSAmIDB4M2ZmZjtcbiAgfVxuXG4gIC8vIFJlc2V0IG5zZWNzIGlmIGNsb2NrIHJlZ3Jlc3NlcyAobmV3IGNsb2Nrc2VxKSBvciB3ZSd2ZSBtb3ZlZCBvbnRvIGEgbmV3XG4gIC8vIHRpbWUgaW50ZXJ2YWxcbiAgaWYgKChkdCA8IDAgfHwgbXNlY3MgPiBfbGFzdE1TZWNzKSAmJiBvcHRpb25zLm5zZWNzID09PSB1bmRlZmluZWQpIHtcbiAgICBuc2VjcyA9IDA7XG4gIH1cblxuICAvLyBQZXIgNC4yLjEuMiBUaHJvdyBlcnJvciBpZiB0b28gbWFueSB1dWlkcyBhcmUgcmVxdWVzdGVkXG4gIGlmIChuc2VjcyA+PSAxMDAwMCkge1xuICAgIHRocm93IG5ldyBFcnJvcigndXVpZC52MSgpOiBDYW5cXCd0IGNyZWF0ZSBtb3JlIHRoYW4gMTBNIHV1aWRzL3NlYycpO1xuICB9XG5cbiAgX2xhc3RNU2VjcyA9IG1zZWNzO1xuICBfbGFzdE5TZWNzID0gbnNlY3M7XG4gIF9jbG9ja3NlcSA9IGNsb2Nrc2VxO1xuXG4gIC8vIFBlciA0LjEuNCAtIENvbnZlcnQgZnJvbSB1bml4IGVwb2NoIHRvIEdyZWdvcmlhbiBlcG9jaFxuICBtc2VjcyArPSAxMjIxOTI5MjgwMDAwMDtcblxuICAvLyBgdGltZV9sb3dgXG4gIHZhciB0bCA9ICgobXNlY3MgJiAweGZmZmZmZmYpICogMTAwMDAgKyBuc2VjcykgJSAweDEwMDAwMDAwMDtcbiAgYltpKytdID0gdGwgPj4+IDI0ICYgMHhmZjtcbiAgYltpKytdID0gdGwgPj4+IDE2ICYgMHhmZjtcbiAgYltpKytdID0gdGwgPj4+IDggJiAweGZmO1xuICBiW2krK10gPSB0bCAmIDB4ZmY7XG5cbiAgLy8gYHRpbWVfbWlkYFxuICB2YXIgdG1oID0gKG1zZWNzIC8gMHgxMDAwMDAwMDAgKiAxMDAwMCkgJiAweGZmZmZmZmY7XG4gIGJbaSsrXSA9IHRtaCA+Pj4gOCAmIDB4ZmY7XG4gIGJbaSsrXSA9IHRtaCAmIDB4ZmY7XG5cbiAgLy8gYHRpbWVfaGlnaF9hbmRfdmVyc2lvbmBcbiAgYltpKytdID0gdG1oID4+PiAyNCAmIDB4ZiB8IDB4MTA7IC8vIGluY2x1ZGUgdmVyc2lvblxuICBiW2krK10gPSB0bWggPj4+IDE2ICYgMHhmZjtcblxuICAvLyBgY2xvY2tfc2VxX2hpX2FuZF9yZXNlcnZlZGAgKFBlciA0LjIuMiAtIGluY2x1ZGUgdmFyaWFudClcbiAgYltpKytdID0gY2xvY2tzZXEgPj4+IDggfCAweDgwO1xuXG4gIC8vIGBjbG9ja19zZXFfbG93YFxuICBiW2krK10gPSBjbG9ja3NlcSAmIDB4ZmY7XG5cbiAgLy8gYG5vZGVgXG4gIHZhciBub2RlID0gb3B0aW9ucy5ub2RlIHx8IF9ub2RlSWQ7XG4gIGZvciAodmFyIG4gPSAwOyBuIDwgNjsgbisrKSB7XG4gICAgYltpICsgbl0gPSBub2RlW25dO1xuICB9XG5cbiAgcmV0dXJuIGJ1ZiA/IGJ1ZiA6IHVucGFyc2UoYik7XG59XG5cbi8vICoqYHY0KClgIC0gR2VuZXJhdGUgcmFuZG9tIFVVSUQqKlxuXG4vLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2Jyb29mYS9ub2RlLXV1aWQgZm9yIEFQSSBkZXRhaWxzXG5mdW5jdGlvbiB2NChvcHRpb25zLCBidWYsIG9mZnNldCkge1xuICAvLyBEZXByZWNhdGVkIC0gJ2Zvcm1hdCcgYXJndW1lbnQsIGFzIHN1cHBvcnRlZCBpbiB2MS4yXG4gIHZhciBpID0gYnVmICYmIG9mZnNldCB8fCAwO1xuXG4gIGlmICh0eXBlb2Yob3B0aW9ucykgPT0gJ3N0cmluZycpIHtcbiAgICBidWYgPSBvcHRpb25zID09ICdiaW5hcnknID8gbmV3IEFycmF5KDE2KSA6IG51bGw7XG4gICAgb3B0aW9ucyA9IG51bGw7XG4gIH1cbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgdmFyIHJuZHMgPSBvcHRpb25zLnJhbmRvbSB8fCAob3B0aW9ucy5ybmcgfHwgX3JuZykoKTtcblxuICAvLyBQZXIgNC40LCBzZXQgYml0cyBmb3IgdmVyc2lvbiBhbmQgYGNsb2NrX3NlcV9oaV9hbmRfcmVzZXJ2ZWRgXG4gIHJuZHNbNl0gPSAocm5kc1s2XSAmIDB4MGYpIHwgMHg0MDtcbiAgcm5kc1s4XSA9IChybmRzWzhdICYgMHgzZikgfCAweDgwO1xuXG4gIC8vIENvcHkgYnl0ZXMgdG8gYnVmZmVyLCBpZiBwcm92aWRlZFxuICBpZiAoYnVmKSB7XG4gICAgZm9yICh2YXIgaWkgPSAwOyBpaSA8IDE2OyBpaSsrKSB7XG4gICAgICBidWZbaSArIGlpXSA9IHJuZHNbaWldO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBidWYgfHwgdW5wYXJzZShybmRzKTtcbn1cblxuLy8gRXhwb3J0IHB1YmxpYyBBUElcbnZhciB1dWlkID0gdjQ7XG51dWlkLnYxID0gdjE7XG51dWlkLnY0ID0gdjQ7XG51dWlkLnBhcnNlID0gcGFyc2U7XG51dWlkLnVucGFyc2UgPSB1bnBhcnNlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHV1aWQ7XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgYWRhcHRlckZhY3RvcnkgPSByZXF1aXJlKCcuL2FkYXB0ZXJfZmFjdG9yeS5qcycpO1xubW9kdWxlLmV4cG9ydHMgPSBhZGFwdGVyRmFjdG9yeSh7d2luZG93OiBnbG9iYWwud2luZG93fSk7XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzJyk7XG4vLyBTaGltbWluZyBzdGFydHMgaGVyZS5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oZGVwZW5kZW5jaWVzLCBvcHRzKSB7XG4gIHZhciB3aW5kb3cgPSBkZXBlbmRlbmNpZXMgJiYgZGVwZW5kZW5jaWVzLndpbmRvdztcblxuICB2YXIgb3B0aW9ucyA9IHtcbiAgICBzaGltQ2hyb21lOiB0cnVlLFxuICAgIHNoaW1GaXJlZm94OiB0cnVlLFxuICAgIHNoaW1FZGdlOiB0cnVlLFxuICAgIHNoaW1TYWZhcmk6IHRydWUsXG4gIH07XG5cbiAgZm9yICh2YXIga2V5IGluIG9wdHMpIHtcbiAgICBpZiAoaGFzT3duUHJvcGVydHkuY2FsbChvcHRzLCBrZXkpKSB7XG4gICAgICBvcHRpb25zW2tleV0gPSBvcHRzW2tleV07XG4gICAgfVxuICB9XG5cbiAgLy8gVXRpbHMuXG4gIHZhciBsb2dnaW5nID0gdXRpbHMubG9nO1xuICB2YXIgYnJvd3NlckRldGFpbHMgPSB1dGlscy5kZXRlY3RCcm93c2VyKHdpbmRvdyk7XG5cbiAgLy8gRXhwb3J0IHRvIHRoZSBhZGFwdGVyIGdsb2JhbCBvYmplY3QgdmlzaWJsZSBpbiB0aGUgYnJvd3Nlci5cbiAgdmFyIGFkYXB0ZXIgPSB7XG4gICAgYnJvd3NlckRldGFpbHM6IGJyb3dzZXJEZXRhaWxzLFxuICAgIGV4dHJhY3RWZXJzaW9uOiB1dGlscy5leHRyYWN0VmVyc2lvbixcbiAgICBkaXNhYmxlTG9nOiB1dGlscy5kaXNhYmxlTG9nLFxuICAgIGRpc2FibGVXYXJuaW5nczogdXRpbHMuZGlzYWJsZVdhcm5pbmdzXG4gIH07XG5cbiAgLy8gVW5jb21tZW50IHRoZSBsaW5lIGJlbG93IGlmIHlvdSB3YW50IGxvZ2dpbmcgdG8gb2NjdXIsIGluY2x1ZGluZyBsb2dnaW5nXG4gIC8vIGZvciB0aGUgc3dpdGNoIHN0YXRlbWVudCBiZWxvdy4gQ2FuIGFsc28gYmUgdHVybmVkIG9uIGluIHRoZSBicm93c2VyIHZpYVxuICAvLyBhZGFwdGVyLmRpc2FibGVMb2coZmFsc2UpLCBidXQgdGhlbiBsb2dnaW5nIGZyb20gdGhlIHN3aXRjaCBzdGF0ZW1lbnQgYmVsb3dcbiAgLy8gd2lsbCBub3QgYXBwZWFyLlxuICAvLyByZXF1aXJlKCcuL3V0aWxzJykuZGlzYWJsZUxvZyhmYWxzZSk7XG5cbiAgLy8gQnJvd3NlciBzaGltcy5cbiAgdmFyIGNocm9tZVNoaW0gPSByZXF1aXJlKCcuL2Nocm9tZS9jaHJvbWVfc2hpbScpIHx8IG51bGw7XG4gIHZhciBlZGdlU2hpbSA9IHJlcXVpcmUoJy4vZWRnZS9lZGdlX3NoaW0nKSB8fCBudWxsO1xuICB2YXIgZmlyZWZveFNoaW0gPSByZXF1aXJlKCcuL2ZpcmVmb3gvZmlyZWZveF9zaGltJykgfHwgbnVsbDtcbiAgdmFyIHNhZmFyaVNoaW0gPSByZXF1aXJlKCcuL3NhZmFyaS9zYWZhcmlfc2hpbScpIHx8IG51bGw7XG4gIHZhciBjb21tb25TaGltID0gcmVxdWlyZSgnLi9jb21tb25fc2hpbScpIHx8IG51bGw7XG5cbiAgLy8gU2hpbSBicm93c2VyIGlmIGZvdW5kLlxuICBzd2l0Y2ggKGJyb3dzZXJEZXRhaWxzLmJyb3dzZXIpIHtcbiAgICBjYXNlICdjaHJvbWUnOlxuICAgICAgaWYgKCFjaHJvbWVTaGltIHx8ICFjaHJvbWVTaGltLnNoaW1QZWVyQ29ubmVjdGlvbiB8fFxuICAgICAgICAgICFvcHRpb25zLnNoaW1DaHJvbWUpIHtcbiAgICAgICAgbG9nZ2luZygnQ2hyb21lIHNoaW0gaXMgbm90IGluY2x1ZGVkIGluIHRoaXMgYWRhcHRlciByZWxlYXNlLicpO1xuICAgICAgICByZXR1cm4gYWRhcHRlcjtcbiAgICAgIH1cbiAgICAgIGxvZ2dpbmcoJ2FkYXB0ZXIuanMgc2hpbW1pbmcgY2hyb21lLicpO1xuICAgICAgLy8gRXhwb3J0IHRvIHRoZSBhZGFwdGVyIGdsb2JhbCBvYmplY3QgdmlzaWJsZSBpbiB0aGUgYnJvd3Nlci5cbiAgICAgIGFkYXB0ZXIuYnJvd3NlclNoaW0gPSBjaHJvbWVTaGltO1xuICAgICAgY29tbW9uU2hpbS5zaGltQ3JlYXRlT2JqZWN0VVJMKHdpbmRvdyk7XG5cbiAgICAgIGNocm9tZVNoaW0uc2hpbUdldFVzZXJNZWRpYSh3aW5kb3cpO1xuICAgICAgY2hyb21lU2hpbS5zaGltTWVkaWFTdHJlYW0od2luZG93KTtcbiAgICAgIGNocm9tZVNoaW0uc2hpbVNvdXJjZU9iamVjdCh3aW5kb3cpO1xuICAgICAgY2hyb21lU2hpbS5zaGltUGVlckNvbm5lY3Rpb24od2luZG93KTtcbiAgICAgIGNocm9tZVNoaW0uc2hpbU9uVHJhY2sod2luZG93KTtcbiAgICAgIGNocm9tZVNoaW0uc2hpbUFkZFRyYWNrUmVtb3ZlVHJhY2sod2luZG93KTtcbiAgICAgIGNocm9tZVNoaW0uc2hpbUdldFNlbmRlcnNXaXRoRHRtZih3aW5kb3cpO1xuXG4gICAgICBjb21tb25TaGltLnNoaW1SVENJY2VDYW5kaWRhdGUod2luZG93KTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgJ2ZpcmVmb3gnOlxuICAgICAgaWYgKCFmaXJlZm94U2hpbSB8fCAhZmlyZWZveFNoaW0uc2hpbVBlZXJDb25uZWN0aW9uIHx8XG4gICAgICAgICAgIW9wdGlvbnMuc2hpbUZpcmVmb3gpIHtcbiAgICAgICAgbG9nZ2luZygnRmlyZWZveCBzaGltIGlzIG5vdCBpbmNsdWRlZCBpbiB0aGlzIGFkYXB0ZXIgcmVsZWFzZS4nKTtcbiAgICAgICAgcmV0dXJuIGFkYXB0ZXI7XG4gICAgICB9XG4gICAgICBsb2dnaW5nKCdhZGFwdGVyLmpzIHNoaW1taW5nIGZpcmVmb3guJyk7XG4gICAgICAvLyBFeHBvcnQgdG8gdGhlIGFkYXB0ZXIgZ2xvYmFsIG9iamVjdCB2aXNpYmxlIGluIHRoZSBicm93c2VyLlxuICAgICAgYWRhcHRlci5icm93c2VyU2hpbSA9IGZpcmVmb3hTaGltO1xuICAgICAgY29tbW9uU2hpbS5zaGltQ3JlYXRlT2JqZWN0VVJMKHdpbmRvdyk7XG5cbiAgICAgIGZpcmVmb3hTaGltLnNoaW1HZXRVc2VyTWVkaWEod2luZG93KTtcbiAgICAgIGZpcmVmb3hTaGltLnNoaW1Tb3VyY2VPYmplY3Qod2luZG93KTtcbiAgICAgIGZpcmVmb3hTaGltLnNoaW1QZWVyQ29ubmVjdGlvbih3aW5kb3cpO1xuICAgICAgZmlyZWZveFNoaW0uc2hpbU9uVHJhY2sod2luZG93KTtcblxuICAgICAgY29tbW9uU2hpbS5zaGltUlRDSWNlQ2FuZGlkYXRlKHdpbmRvdyk7XG4gICAgICBicmVhaztcbiAgICBjYXNlICdlZGdlJzpcbiAgICAgIGlmICghZWRnZVNoaW0gfHwgIWVkZ2VTaGltLnNoaW1QZWVyQ29ubmVjdGlvbiB8fCAhb3B0aW9ucy5zaGltRWRnZSkge1xuICAgICAgICBsb2dnaW5nKCdNUyBlZGdlIHNoaW0gaXMgbm90IGluY2x1ZGVkIGluIHRoaXMgYWRhcHRlciByZWxlYXNlLicpO1xuICAgICAgICByZXR1cm4gYWRhcHRlcjtcbiAgICAgIH1cbiAgICAgIGxvZ2dpbmcoJ2FkYXB0ZXIuanMgc2hpbW1pbmcgZWRnZS4nKTtcbiAgICAgIC8vIEV4cG9ydCB0byB0aGUgYWRhcHRlciBnbG9iYWwgb2JqZWN0IHZpc2libGUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICBhZGFwdGVyLmJyb3dzZXJTaGltID0gZWRnZVNoaW07XG4gICAgICBjb21tb25TaGltLnNoaW1DcmVhdGVPYmplY3RVUkwod2luZG93KTtcblxuICAgICAgZWRnZVNoaW0uc2hpbUdldFVzZXJNZWRpYSh3aW5kb3cpO1xuICAgICAgZWRnZVNoaW0uc2hpbVBlZXJDb25uZWN0aW9uKHdpbmRvdyk7XG4gICAgICBlZGdlU2hpbS5zaGltUmVwbGFjZVRyYWNrKHdpbmRvdyk7XG5cbiAgICAgIC8vIHRoZSBlZGdlIHNoaW0gaW1wbGVtZW50cyB0aGUgZnVsbCBSVENJY2VDYW5kaWRhdGUgb2JqZWN0LlxuICAgICAgYnJlYWs7XG4gICAgY2FzZSAnc2FmYXJpJzpcbiAgICAgIGlmICghc2FmYXJpU2hpbSB8fCAhb3B0aW9ucy5zaGltU2FmYXJpKSB7XG4gICAgICAgIGxvZ2dpbmcoJ1NhZmFyaSBzaGltIGlzIG5vdCBpbmNsdWRlZCBpbiB0aGlzIGFkYXB0ZXIgcmVsZWFzZS4nKTtcbiAgICAgICAgcmV0dXJuIGFkYXB0ZXI7XG4gICAgICB9XG4gICAgICBsb2dnaW5nKCdhZGFwdGVyLmpzIHNoaW1taW5nIHNhZmFyaS4nKTtcbiAgICAgIC8vIEV4cG9ydCB0byB0aGUgYWRhcHRlciBnbG9iYWwgb2JqZWN0IHZpc2libGUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICBhZGFwdGVyLmJyb3dzZXJTaGltID0gc2FmYXJpU2hpbTtcbiAgICAgIGNvbW1vblNoaW0uc2hpbUNyZWF0ZU9iamVjdFVSTCh3aW5kb3cpO1xuXG4gICAgICBzYWZhcmlTaGltLnNoaW1SVENJY2VTZXJ2ZXJVcmxzKHdpbmRvdyk7XG4gICAgICBzYWZhcmlTaGltLnNoaW1DYWxsYmFja3NBUEkod2luZG93KTtcbiAgICAgIHNhZmFyaVNoaW0uc2hpbUxvY2FsU3RyZWFtc0FQSSh3aW5kb3cpO1xuICAgICAgc2FmYXJpU2hpbS5zaGltUmVtb3RlU3RyZWFtc0FQSSh3aW5kb3cpO1xuICAgICAgc2FmYXJpU2hpbS5zaGltVHJhY2tFdmVudFRyYW5zY2VpdmVyKHdpbmRvdyk7XG4gICAgICBzYWZhcmlTaGltLnNoaW1HZXRVc2VyTWVkaWEod2luZG93KTtcblxuICAgICAgY29tbW9uU2hpbS5zaGltUlRDSWNlQ2FuZGlkYXRlKHdpbmRvdyk7XG4gICAgICBicmVhaztcbiAgICBkZWZhdWx0OlxuICAgICAgbG9nZ2luZygnVW5zdXBwb3J0ZWQgYnJvd3NlciEnKTtcbiAgICAgIGJyZWFrO1xuICB9XG5cbiAgcmV0dXJuIGFkYXB0ZXI7XG59O1xuIiwiXG4vKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzLmpzJyk7XG52YXIgbG9nZ2luZyA9IHV0aWxzLmxvZztcblxudmFyIGNocm9tZVNoaW0gPSB7XG4gIHNoaW1NZWRpYVN0cmVhbTogZnVuY3Rpb24od2luZG93KSB7XG4gICAgd2luZG93Lk1lZGlhU3RyZWFtID0gd2luZG93Lk1lZGlhU3RyZWFtIHx8IHdpbmRvdy53ZWJraXRNZWRpYVN0cmVhbTtcbiAgfSxcblxuICBzaGltT25UcmFjazogZnVuY3Rpb24od2luZG93KSB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnICYmIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbiAmJiAhKCdvbnRyYWNrJyBpblxuICAgICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlKSkge1xuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUsICdvbnRyYWNrJywge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHJldHVybiB0aGlzLl9vbnRyYWNrO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uKGYpIHtcbiAgICAgICAgICBpZiAodGhpcy5fb250cmFjaykge1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVyKCd0cmFjaycsIHRoaXMuX29udHJhY2spO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXIoJ3RyYWNrJywgdGhpcy5fb250cmFjayA9IGYpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHZhciBvcmlnU2V0UmVtb3RlRGVzY3JpcHRpb24gPVxuICAgICAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuc2V0UmVtb3RlRGVzY3JpcHRpb247XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLnNldFJlbW90ZURlc2NyaXB0aW9uID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBwYyA9IHRoaXM7XG4gICAgICAgIGlmICghcGMuX29udHJhY2twb2x5KSB7XG4gICAgICAgICAgcGMuX29udHJhY2twb2x5ID0gZnVuY3Rpb24oZSkge1xuICAgICAgICAgICAgLy8gb25hZGRzdHJlYW0gZG9lcyBub3QgZmlyZSB3aGVuIGEgdHJhY2sgaXMgYWRkZWQgdG8gYW4gZXhpc3RpbmdcbiAgICAgICAgICAgIC8vIHN0cmVhbS4gQnV0IHN0cmVhbS5vbmFkZHRyYWNrIGlzIGltcGxlbWVudGVkIHNvIHdlIHVzZSB0aGF0LlxuICAgICAgICAgICAgZS5zdHJlYW0uYWRkRXZlbnRMaXN0ZW5lcignYWRkdHJhY2snLCBmdW5jdGlvbih0ZSkge1xuICAgICAgICAgICAgICB2YXIgcmVjZWl2ZXI7XG4gICAgICAgICAgICAgIGlmICh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFJlY2VpdmVycykge1xuICAgICAgICAgICAgICAgIHJlY2VpdmVyID0gcGMuZ2V0UmVjZWl2ZXJzKCkuZmluZChmdW5jdGlvbihyKSB7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gci50cmFjayAmJiByLnRyYWNrLmlkID09PSB0ZS50cmFjay5pZDtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZWNlaXZlciA9IHt0cmFjazogdGUudHJhY2t9O1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KCd0cmFjaycpO1xuICAgICAgICAgICAgICBldmVudC50cmFjayA9IHRlLnRyYWNrO1xuICAgICAgICAgICAgICBldmVudC5yZWNlaXZlciA9IHJlY2VpdmVyO1xuICAgICAgICAgICAgICBldmVudC50cmFuc2NlaXZlciA9IHtyZWNlaXZlcjogcmVjZWl2ZXJ9O1xuICAgICAgICAgICAgICBldmVudC5zdHJlYW1zID0gW2Uuc3RyZWFtXTtcbiAgICAgICAgICAgICAgcGMuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGUuc3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2spIHtcbiAgICAgICAgICAgICAgdmFyIHJlY2VpdmVyO1xuICAgICAgICAgICAgICBpZiAod2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRSZWNlaXZlcnMpIHtcbiAgICAgICAgICAgICAgICByZWNlaXZlciA9IHBjLmdldFJlY2VpdmVycygpLmZpbmQoZnVuY3Rpb24ocikge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIHIudHJhY2sgJiYgci50cmFjay5pZCA9PT0gdHJhY2suaWQ7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVjZWl2ZXIgPSB7dHJhY2s6IHRyYWNrfTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB2YXIgZXZlbnQgPSBuZXcgRXZlbnQoJ3RyYWNrJyk7XG4gICAgICAgICAgICAgIGV2ZW50LnRyYWNrID0gdHJhY2s7XG4gICAgICAgICAgICAgIGV2ZW50LnJlY2VpdmVyID0gcmVjZWl2ZXI7XG4gICAgICAgICAgICAgIGV2ZW50LnRyYW5zY2VpdmVyID0ge3JlY2VpdmVyOiByZWNlaXZlcn07XG4gICAgICAgICAgICAgIGV2ZW50LnN0cmVhbXMgPSBbZS5zdHJlYW1dO1xuICAgICAgICAgICAgICBwYy5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH07XG4gICAgICAgICAgcGMuYWRkRXZlbnRMaXN0ZW5lcignYWRkc3RyZWFtJywgcGMuX29udHJhY2twb2x5KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3JpZ1NldFJlbW90ZURlc2NyaXB0aW9uLmFwcGx5KHBjLCBhcmd1bWVudHMpO1xuICAgICAgfTtcbiAgICB9XG4gIH0sXG5cbiAgc2hpbUdldFNlbmRlcnNXaXRoRHRtZjogZnVuY3Rpb24od2luZG93KSB7XG4gICAgLy8gT3ZlcnJpZGVzIGFkZFRyYWNrL3JlbW92ZVRyYWNrLCBkZXBlbmRzIG9uIHNoaW1BZGRUcmFja1JlbW92ZVRyYWNrLlxuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAnb2JqZWN0JyAmJiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gJiZcbiAgICAgICAgISgnZ2V0U2VuZGVycycgaW4gd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZSkgJiZcbiAgICAgICAgJ2NyZWF0ZURUTUZTZW5kZXInIGluIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUpIHtcbiAgICAgIHZhciBzaGltU2VuZGVyV2l0aER0bWYgPSBmdW5jdGlvbihwYywgdHJhY2spIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB0cmFjazogdHJhY2ssXG4gICAgICAgICAgZ2V0IGR0bWYoKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5fZHRtZiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgIGlmICh0cmFjay5raW5kID09PSAnYXVkaW8nKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fZHRtZiA9IHBjLmNyZWF0ZURUTUZTZW5kZXIodHJhY2spO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuX2R0bWYgPSBudWxsO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZHRtZjtcbiAgICAgICAgICB9LFxuICAgICAgICAgIF9wYzogcGNcbiAgICAgICAgfTtcbiAgICAgIH07XG5cbiAgICAgIC8vIGF1Z21lbnQgYWRkVHJhY2sgd2hlbiBnZXRTZW5kZXJzIGlzIG5vdCBhdmFpbGFibGUuXG4gICAgICBpZiAoIXdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuZ2V0U2VuZGVycykge1xuICAgICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFNlbmRlcnMgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICB0aGlzLl9zZW5kZXJzID0gdGhpcy5fc2VuZGVycyB8fCBbXTtcbiAgICAgICAgICByZXR1cm4gdGhpcy5fc2VuZGVycy5zbGljZSgpOyAvLyByZXR1cm4gYSBjb3B5IG9mIHRoZSBpbnRlcm5hbCBzdGF0ZS5cbiAgICAgICAgfTtcbiAgICAgICAgdmFyIG9yaWdBZGRUcmFjayA9IHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkVHJhY2s7XG4gICAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkVHJhY2sgPSBmdW5jdGlvbih0cmFjaywgc3RyZWFtKSB7XG4gICAgICAgICAgdmFyIHBjID0gdGhpcztcbiAgICAgICAgICB2YXIgc2VuZGVyID0gb3JpZ0FkZFRyYWNrLmFwcGx5KHBjLCBhcmd1bWVudHMpO1xuICAgICAgICAgIGlmICghc2VuZGVyKSB7XG4gICAgICAgICAgICBzZW5kZXIgPSBzaGltU2VuZGVyV2l0aER0bWYocGMsIHRyYWNrKTtcbiAgICAgICAgICAgIHBjLl9zZW5kZXJzLnB1c2goc2VuZGVyKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHNlbmRlcjtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ1JlbW92ZVRyYWNrID0gd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5yZW1vdmVUcmFjaztcbiAgICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5yZW1vdmVUcmFjayA9IGZ1bmN0aW9uKHNlbmRlcikge1xuICAgICAgICAgIHZhciBwYyA9IHRoaXM7XG4gICAgICAgICAgb3JpZ1JlbW92ZVRyYWNrLmFwcGx5KHBjLCBhcmd1bWVudHMpO1xuICAgICAgICAgIHZhciBpZHggPSBwYy5fc2VuZGVycy5pbmRleE9mKHNlbmRlcik7XG4gICAgICAgICAgaWYgKGlkeCAhPT0gLTEpIHtcbiAgICAgICAgICAgIHBjLl9zZW5kZXJzLnNwbGljZShpZHgsIDEpO1xuICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIHZhciBvcmlnQWRkU3RyZWFtID0gd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRTdHJlYW07XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZFN0cmVhbSA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICB2YXIgcGMgPSB0aGlzO1xuICAgICAgICBwYy5fc2VuZGVycyA9IHBjLl9zZW5kZXJzIHx8IFtdO1xuICAgICAgICBvcmlnQWRkU3RyZWFtLmFwcGx5KHBjLCBbc3RyZWFtXSk7XG4gICAgICAgIHN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgICAgICAgcGMuX3NlbmRlcnMucHVzaChzaGltU2VuZGVyV2l0aER0bWYocGMsIHRyYWNrKSk7XG4gICAgICAgIH0pO1xuICAgICAgfTtcblxuICAgICAgdmFyIG9yaWdSZW1vdmVTdHJlYW0gPSB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLnJlbW92ZVN0cmVhbTtcbiAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUucmVtb3ZlU3RyZWFtID0gZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgIHZhciBwYyA9IHRoaXM7XG4gICAgICAgIHBjLl9zZW5kZXJzID0gcGMuX3NlbmRlcnMgfHwgW107XG4gICAgICAgIG9yaWdSZW1vdmVTdHJlYW0uYXBwbHkocGMsIFsocGMuX3N0cmVhbXNbc3RyZWFtLmlkXSB8fCBzdHJlYW0pXSk7XG5cbiAgICAgICAgc3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2spIHtcbiAgICAgICAgICB2YXIgc2VuZGVyID0gcGMuX3NlbmRlcnMuZmluZChmdW5jdGlvbihzKSB7XG4gICAgICAgICAgICByZXR1cm4gcy50cmFjayA9PT0gdHJhY2s7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKHNlbmRlcikge1xuICAgICAgICAgICAgcGMuX3NlbmRlcnMuc3BsaWNlKHBjLl9zZW5kZXJzLmluZGV4T2Yoc2VuZGVyKSwgMSk7IC8vIHJlbW92ZSBzZW5kZXJcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnICYmIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbiAmJlxuICAgICAgICAgICAgICAgJ2dldFNlbmRlcnMnIGluIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUgJiZcbiAgICAgICAgICAgICAgICdjcmVhdGVEVE1GU2VuZGVyJyBpbiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlICYmXG4gICAgICAgICAgICAgICB3aW5kb3cuUlRDUnRwU2VuZGVyICYmXG4gICAgICAgICAgICAgICAhKCdkdG1mJyBpbiB3aW5kb3cuUlRDUnRwU2VuZGVyLnByb3RvdHlwZSkpIHtcbiAgICAgIHZhciBvcmlnR2V0U2VuZGVycyA9IHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuZ2V0U2VuZGVycztcbiAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuZ2V0U2VuZGVycyA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcGMgPSB0aGlzO1xuICAgICAgICB2YXIgc2VuZGVycyA9IG9yaWdHZXRTZW5kZXJzLmFwcGx5KHBjLCBbXSk7XG4gICAgICAgIHNlbmRlcnMuZm9yRWFjaChmdW5jdGlvbihzZW5kZXIpIHtcbiAgICAgICAgICBzZW5kZXIuX3BjID0gcGM7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gc2VuZGVycztcbiAgICAgIH07XG5cbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUnRwU2VuZGVyLnByb3RvdHlwZSwgJ2R0bWYnLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgaWYgKHRoaXMuX2R0bWYgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgaWYgKHRoaXMudHJhY2sua2luZCA9PT0gJ2F1ZGlvJykge1xuICAgICAgICAgICAgICB0aGlzLl9kdG1mID0gdGhpcy5fcGMuY3JlYXRlRFRNRlNlbmRlcih0aGlzLnRyYWNrKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHRoaXMuX2R0bWYgPSBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdGhpcy5fZHRtZjtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9LFxuXG4gIHNoaW1Tb3VyY2VPYmplY3Q6IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIHZhciBVUkwgPSB3aW5kb3cgJiYgd2luZG93LlVSTDtcblxuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAnb2JqZWN0Jykge1xuICAgICAgaWYgKHdpbmRvdy5IVE1MTWVkaWFFbGVtZW50ICYmXG4gICAgICAgICEoJ3NyY09iamVjdCcgaW4gd2luZG93LkhUTUxNZWRpYUVsZW1lbnQucHJvdG90eXBlKSkge1xuICAgICAgICAvLyBTaGltIHRoZSBzcmNPYmplY3QgcHJvcGVydHksIG9uY2UsIHdoZW4gSFRNTE1lZGlhRWxlbWVudCBpcyBmb3VuZC5cbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdy5IVE1MTWVkaWFFbGVtZW50LnByb3RvdHlwZSwgJ3NyY09iamVjdCcsIHtcbiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3NyY09iamVjdDtcbiAgICAgICAgICB9LFxuICAgICAgICAgIHNldDogZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgICAgICAvLyBVc2UgX3NyY09iamVjdCBhcyBhIHByaXZhdGUgcHJvcGVydHkgZm9yIHRoaXMgc2hpbVxuICAgICAgICAgICAgdGhpcy5fc3JjT2JqZWN0ID0gc3RyZWFtO1xuICAgICAgICAgICAgaWYgKHRoaXMuc3JjKSB7XG4gICAgICAgICAgICAgIFVSTC5yZXZva2VPYmplY3RVUkwodGhpcy5zcmMpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIXN0cmVhbSkge1xuICAgICAgICAgICAgICB0aGlzLnNyYyA9ICcnO1xuICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5zcmMgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKHN0cmVhbSk7XG4gICAgICAgICAgICAvLyBXZSBuZWVkIHRvIHJlY3JlYXRlIHRoZSBibG9iIHVybCB3aGVuIGEgdHJhY2sgaXMgYWRkZWQgb3JcbiAgICAgICAgICAgIC8vIHJlbW92ZWQuIERvaW5nIGl0IG1hbnVhbGx5IHNpbmNlIHdlIHdhbnQgdG8gYXZvaWQgYSByZWN1cnNpb24uXG4gICAgICAgICAgICBzdHJlYW0uYWRkRXZlbnRMaXN0ZW5lcignYWRkdHJhY2snLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgaWYgKHNlbGYuc3JjKSB7XG4gICAgICAgICAgICAgICAgVVJMLnJldm9rZU9iamVjdFVSTChzZWxmLnNyYyk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgc2VsZi5zcmMgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKHN0cmVhbSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHN0cmVhbS5hZGRFdmVudExpc3RlbmVyKCdyZW1vdmV0cmFjaycsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICBpZiAoc2VsZi5zcmMpIHtcbiAgICAgICAgICAgICAgICBVUkwucmV2b2tlT2JqZWN0VVJMKHNlbGYuc3JjKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBzZWxmLnNyYyA9IFVSTC5jcmVhdGVPYmplY3RVUkwoc3RyZWFtKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9LFxuXG4gIHNoaW1BZGRUcmFja1JlbW92ZVRyYWNrOiBmdW5jdGlvbih3aW5kb3cpIHtcbiAgICB2YXIgYnJvd3NlckRldGFpbHMgPSB1dGlscy5kZXRlY3RCcm93c2VyKHdpbmRvdyk7XG4gICAgLy8gc2hpbSBhZGRUcmFjayBhbmQgcmVtb3ZlVHJhY2suXG4gICAgaWYgKHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkVHJhY2sgJiZcbiAgICAgICAgYnJvd3NlckRldGFpbHMudmVyc2lvbiA+PSA2Mikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIGFsc28gc2hpbSBwYy5nZXRMb2NhbFN0cmVhbXMgd2hlbiBhZGRUcmFjayBpcyBzaGltbWVkXG4gICAgLy8gdG8gcmV0dXJuIHRoZSBvcmlnaW5hbCBzdHJlYW1zLlxuICAgIHZhciBvcmlnR2V0TG9jYWxTdHJlYW1zID0gd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVxuICAgICAgICAuZ2V0TG9jYWxTdHJlYW1zO1xuICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuZ2V0TG9jYWxTdHJlYW1zID0gZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICB2YXIgbmF0aXZlU3RyZWFtcyA9IG9yaWdHZXRMb2NhbFN0cmVhbXMuYXBwbHkodGhpcyk7XG4gICAgICBzZWxmLl9yZXZlcnNlU3RyZWFtcyA9IHNlbGYuX3JldmVyc2VTdHJlYW1zIHx8IHt9O1xuICAgICAgcmV0dXJuIG5hdGl2ZVN0cmVhbXMubWFwKGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICByZXR1cm4gc2VsZi5fcmV2ZXJzZVN0cmVhbXNbc3RyZWFtLmlkXTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB2YXIgb3JpZ0FkZFN0cmVhbSA9IHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkU3RyZWFtO1xuICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkU3RyZWFtID0gZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICB2YXIgcGMgPSB0aGlzO1xuICAgICAgcGMuX3N0cmVhbXMgPSBwYy5fc3RyZWFtcyB8fCB7fTtcbiAgICAgIHBjLl9yZXZlcnNlU3RyZWFtcyA9IHBjLl9yZXZlcnNlU3RyZWFtcyB8fCB7fTtcblxuICAgICAgc3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2spIHtcbiAgICAgICAgdmFyIGFscmVhZHlFeGlzdHMgPSBwYy5nZXRTZW5kZXJzKCkuZmluZChmdW5jdGlvbihzKSB7XG4gICAgICAgICAgcmV0dXJuIHMudHJhY2sgPT09IHRyYWNrO1xuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGFscmVhZHlFeGlzdHMpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRE9NRXhjZXB0aW9uKCdUcmFjayBhbHJlYWR5IGV4aXN0cy4nLFxuICAgICAgICAgICAgICAnSW52YWxpZEFjY2Vzc0Vycm9yJyk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgLy8gQWRkIGlkZW50aXR5IG1hcHBpbmcgZm9yIGNvbnNpc3RlbmN5IHdpdGggYWRkVHJhY2suXG4gICAgICAvLyBVbmxlc3MgdGhpcyBpcyBiZWluZyB1c2VkIHdpdGggYSBzdHJlYW0gZnJvbSBhZGRUcmFjay5cbiAgICAgIGlmICghcGMuX3JldmVyc2VTdHJlYW1zW3N0cmVhbS5pZF0pIHtcbiAgICAgICAgdmFyIG5ld1N0cmVhbSA9IG5ldyB3aW5kb3cuTWVkaWFTdHJlYW0oc3RyZWFtLmdldFRyYWNrcygpKTtcbiAgICAgICAgcGMuX3N0cmVhbXNbc3RyZWFtLmlkXSA9IG5ld1N0cmVhbTtcbiAgICAgICAgcGMuX3JldmVyc2VTdHJlYW1zW25ld1N0cmVhbS5pZF0gPSBzdHJlYW07XG4gICAgICAgIHN0cmVhbSA9IG5ld1N0cmVhbTtcbiAgICAgIH1cbiAgICAgIG9yaWdBZGRTdHJlYW0uYXBwbHkocGMsIFtzdHJlYW1dKTtcbiAgICB9O1xuXG4gICAgdmFyIG9yaWdSZW1vdmVTdHJlYW0gPSB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLnJlbW92ZVN0cmVhbTtcbiAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLnJlbW92ZVN0cmVhbSA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgdmFyIHBjID0gdGhpcztcbiAgICAgIHBjLl9zdHJlYW1zID0gcGMuX3N0cmVhbXMgfHwge307XG4gICAgICBwYy5fcmV2ZXJzZVN0cmVhbXMgPSBwYy5fcmV2ZXJzZVN0cmVhbXMgfHwge307XG5cbiAgICAgIG9yaWdSZW1vdmVTdHJlYW0uYXBwbHkocGMsIFsocGMuX3N0cmVhbXNbc3RyZWFtLmlkXSB8fCBzdHJlYW0pXSk7XG4gICAgICBkZWxldGUgcGMuX3JldmVyc2VTdHJlYW1zWyhwYy5fc3RyZWFtc1tzdHJlYW0uaWRdID9cbiAgICAgICAgICBwYy5fc3RyZWFtc1tzdHJlYW0uaWRdLmlkIDogc3RyZWFtLmlkKV07XG4gICAgICBkZWxldGUgcGMuX3N0cmVhbXNbc3RyZWFtLmlkXTtcbiAgICB9O1xuXG4gICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRUcmFjayA9IGZ1bmN0aW9uKHRyYWNrLCBzdHJlYW0pIHtcbiAgICAgIHZhciBwYyA9IHRoaXM7XG4gICAgICBpZiAocGMuc2lnbmFsaW5nU3RhdGUgPT09ICdjbG9zZWQnKSB7XG4gICAgICAgIHRocm93IG5ldyBET01FeGNlcHRpb24oXG4gICAgICAgICAgJ1RoZSBSVENQZWVyQ29ubmVjdGlvblxcJ3Mgc2lnbmFsaW5nU3RhdGUgaXMgXFwnY2xvc2VkXFwnLicsXG4gICAgICAgICAgJ0ludmFsaWRTdGF0ZUVycm9yJyk7XG4gICAgICB9XG4gICAgICB2YXIgc3RyZWFtcyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgIGlmIChzdHJlYW1zLmxlbmd0aCAhPT0gMSB8fFxuICAgICAgICAgICFzdHJlYW1zWzBdLmdldFRyYWNrcygpLmZpbmQoZnVuY3Rpb24odCkge1xuICAgICAgICAgICAgcmV0dXJuIHQgPT09IHRyYWNrO1xuICAgICAgICAgIH0pKSB7XG4gICAgICAgIC8vIHRoaXMgaXMgbm90IGZ1bGx5IGNvcnJlY3QgYnV0IGFsbCB3ZSBjYW4gbWFuYWdlIHdpdGhvdXRcbiAgICAgICAgLy8gW1thc3NvY2lhdGVkIE1lZGlhU3RyZWFtc11dIGludGVybmFsIHNsb3QuXG4gICAgICAgIHRocm93IG5ldyBET01FeGNlcHRpb24oXG4gICAgICAgICAgJ1RoZSBhZGFwdGVyLmpzIGFkZFRyYWNrIHBvbHlmaWxsIG9ubHkgc3VwcG9ydHMgYSBzaW5nbGUgJyArXG4gICAgICAgICAgJyBzdHJlYW0gd2hpY2ggaXMgYXNzb2NpYXRlZCB3aXRoIHRoZSBzcGVjaWZpZWQgdHJhY2suJyxcbiAgICAgICAgICAnTm90U3VwcG9ydGVkRXJyb3InKTtcbiAgICAgIH1cblxuICAgICAgdmFyIGFscmVhZHlFeGlzdHMgPSBwYy5nZXRTZW5kZXJzKCkuZmluZChmdW5jdGlvbihzKSB7XG4gICAgICAgIHJldHVybiBzLnRyYWNrID09PSB0cmFjaztcbiAgICAgIH0pO1xuICAgICAgaWYgKGFscmVhZHlFeGlzdHMpIHtcbiAgICAgICAgdGhyb3cgbmV3IERPTUV4Y2VwdGlvbignVHJhY2sgYWxyZWFkeSBleGlzdHMuJyxcbiAgICAgICAgICAgICdJbnZhbGlkQWNjZXNzRXJyb3InKTtcbiAgICAgIH1cblxuICAgICAgcGMuX3N0cmVhbXMgPSBwYy5fc3RyZWFtcyB8fCB7fTtcbiAgICAgIHBjLl9yZXZlcnNlU3RyZWFtcyA9IHBjLl9yZXZlcnNlU3RyZWFtcyB8fCB7fTtcbiAgICAgIHZhciBvbGRTdHJlYW0gPSBwYy5fc3RyZWFtc1tzdHJlYW0uaWRdO1xuICAgICAgaWYgKG9sZFN0cmVhbSkge1xuICAgICAgICAvLyB0aGlzIGlzIHVzaW5nIG9kZCBDaHJvbWUgYmVoYXZpb3VyLCB1c2Ugd2l0aCBjYXV0aW9uOlxuICAgICAgICAvLyBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3Avd2VicnRjL2lzc3Vlcy9kZXRhaWw/aWQ9NzgxNVxuICAgICAgICAvLyBOb3RlOiB3ZSByZWx5IG9uIHRoZSBoaWdoLWxldmVsIGFkZFRyYWNrL2R0bWYgc2hpbSB0b1xuICAgICAgICAvLyBjcmVhdGUgdGhlIHNlbmRlciB3aXRoIGEgZHRtZiBzZW5kZXIuXG4gICAgICAgIG9sZFN0cmVhbS5hZGRUcmFjayh0cmFjayk7XG5cbiAgICAgICAgLy8gVHJpZ2dlciBPTk4gYXN5bmMuXG4gICAgICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oZnVuY3Rpb24oKSB7XG4gICAgICAgICAgcGMuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoJ25lZ290aWF0aW9ubmVlZGVkJykpO1xuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBuZXdTdHJlYW0gPSBuZXcgd2luZG93Lk1lZGlhU3RyZWFtKFt0cmFja10pO1xuICAgICAgICBwYy5fc3RyZWFtc1tzdHJlYW0uaWRdID0gbmV3U3RyZWFtO1xuICAgICAgICBwYy5fcmV2ZXJzZVN0cmVhbXNbbmV3U3RyZWFtLmlkXSA9IHN0cmVhbTtcbiAgICAgICAgcGMuYWRkU3RyZWFtKG5ld1N0cmVhbSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcGMuZ2V0U2VuZGVycygpLmZpbmQoZnVuY3Rpb24ocykge1xuICAgICAgICByZXR1cm4gcy50cmFjayA9PT0gdHJhY2s7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgLy8gcmVwbGFjZSB0aGUgaW50ZXJuYWwgc3RyZWFtIGlkIHdpdGggdGhlIGV4dGVybmFsIG9uZSBhbmRcbiAgICAvLyB2aWNlIHZlcnNhLlxuICAgIGZ1bmN0aW9uIHJlcGxhY2VJbnRlcm5hbFN0cmVhbUlkKHBjLCBkZXNjcmlwdGlvbikge1xuICAgICAgdmFyIHNkcCA9IGRlc2NyaXB0aW9uLnNkcDtcbiAgICAgIE9iamVjdC5rZXlzKHBjLl9yZXZlcnNlU3RyZWFtcyB8fCBbXSkuZm9yRWFjaChmdW5jdGlvbihpbnRlcm5hbElkKSB7XG4gICAgICAgIHZhciBleHRlcm5hbFN0cmVhbSA9IHBjLl9yZXZlcnNlU3RyZWFtc1tpbnRlcm5hbElkXTtcbiAgICAgICAgdmFyIGludGVybmFsU3RyZWFtID0gcGMuX3N0cmVhbXNbZXh0ZXJuYWxTdHJlYW0uaWRdO1xuICAgICAgICBzZHAgPSBzZHAucmVwbGFjZShuZXcgUmVnRXhwKGludGVybmFsU3RyZWFtLmlkLCAnZycpLFxuICAgICAgICAgICAgZXh0ZXJuYWxTdHJlYW0uaWQpO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICAgIHR5cGU6IGRlc2NyaXB0aW9uLnR5cGUsXG4gICAgICAgIHNkcDogc2RwXG4gICAgICB9KTtcbiAgICB9XG4gICAgZnVuY3Rpb24gcmVwbGFjZUV4dGVybmFsU3RyZWFtSWQocGMsIGRlc2NyaXB0aW9uKSB7XG4gICAgICB2YXIgc2RwID0gZGVzY3JpcHRpb24uc2RwO1xuICAgICAgT2JqZWN0LmtleXMocGMuX3JldmVyc2VTdHJlYW1zIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uKGludGVybmFsSWQpIHtcbiAgICAgICAgdmFyIGV4dGVybmFsU3RyZWFtID0gcGMuX3JldmVyc2VTdHJlYW1zW2ludGVybmFsSWRdO1xuICAgICAgICB2YXIgaW50ZXJuYWxTdHJlYW0gPSBwYy5fc3RyZWFtc1tleHRlcm5hbFN0cmVhbS5pZF07XG4gICAgICAgIHNkcCA9IHNkcC5yZXBsYWNlKG5ldyBSZWdFeHAoZXh0ZXJuYWxTdHJlYW0uaWQsICdnJyksXG4gICAgICAgICAgICBpbnRlcm5hbFN0cmVhbS5pZCk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgICAgdHlwZTogZGVzY3JpcHRpb24udHlwZSxcbiAgICAgICAgc2RwOiBzZHBcbiAgICAgIH0pO1xuICAgIH1cbiAgICBbJ2NyZWF0ZU9mZmVyJywgJ2NyZWF0ZUFuc3dlciddLmZvckVhY2goZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICB2YXIgbmF0aXZlTWV0aG9kID0gd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdO1xuICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBwYyA9IHRoaXM7XG4gICAgICAgIHZhciBhcmdzID0gYXJndW1lbnRzO1xuICAgICAgICB2YXIgaXNMZWdhY3lDYWxsID0gYXJndW1lbnRzLmxlbmd0aCAmJlxuICAgICAgICAgICAgdHlwZW9mIGFyZ3VtZW50c1swXSA9PT0gJ2Z1bmN0aW9uJztcbiAgICAgICAgaWYgKGlzTGVnYWN5Q2FsbCkge1xuICAgICAgICAgIHJldHVybiBuYXRpdmVNZXRob2QuYXBwbHkocGMsIFtcbiAgICAgICAgICAgIGZ1bmN0aW9uKGRlc2NyaXB0aW9uKSB7XG4gICAgICAgICAgICAgIHZhciBkZXNjID0gcmVwbGFjZUludGVybmFsU3RyZWFtSWQocGMsIGRlc2NyaXB0aW9uKTtcbiAgICAgICAgICAgICAgYXJnc1swXS5hcHBseShudWxsLCBbZGVzY10pO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uKGVycikge1xuICAgICAgICAgICAgICBpZiAoYXJnc1sxXSkge1xuICAgICAgICAgICAgICAgIGFyZ3NbMV0uYXBwbHkobnVsbCwgZXJyKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgYXJndW1lbnRzWzJdXG4gICAgICAgICAgXSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5hdGl2ZU1ldGhvZC5hcHBseShwYywgYXJndW1lbnRzKVxuICAgICAgICAudGhlbihmdW5jdGlvbihkZXNjcmlwdGlvbikge1xuICAgICAgICAgIHJldHVybiByZXBsYWNlSW50ZXJuYWxTdHJlYW1JZChwYywgZGVzY3JpcHRpb24pO1xuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgfSk7XG5cbiAgICB2YXIgb3JpZ1NldExvY2FsRGVzY3JpcHRpb24gPVxuICAgICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLnNldExvY2FsRGVzY3JpcHRpb247XG4gICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5zZXRMb2NhbERlc2NyaXB0aW9uID0gZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgcGMgPSB0aGlzO1xuICAgICAgaWYgKCFhcmd1bWVudHMubGVuZ3RoIHx8ICFhcmd1bWVudHNbMF0udHlwZSkge1xuICAgICAgICByZXR1cm4gb3JpZ1NldExvY2FsRGVzY3JpcHRpb24uYXBwbHkocGMsIGFyZ3VtZW50cyk7XG4gICAgICB9XG4gICAgICBhcmd1bWVudHNbMF0gPSByZXBsYWNlRXh0ZXJuYWxTdHJlYW1JZChwYywgYXJndW1lbnRzWzBdKTtcbiAgICAgIHJldHVybiBvcmlnU2V0TG9jYWxEZXNjcmlwdGlvbi5hcHBseShwYywgYXJndW1lbnRzKTtcbiAgICB9O1xuXG4gICAgLy8gVE9ETzogbWFuZ2xlIGdldFN0YXRzOiBodHRwczovL3czYy5naXRodWIuaW8vd2VicnRjLXN0YXRzLyNkb20tcnRjbWVkaWFzdHJlYW1zdGF0cy1zdHJlYW1pZGVudGlmaWVyXG5cbiAgICB2YXIgb3JpZ0xvY2FsRGVzY3JpcHRpb24gPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKFxuICAgICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLCAnbG9jYWxEZXNjcmlwdGlvbicpO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLFxuICAgICAgICAnbG9jYWxEZXNjcmlwdGlvbicsIHtcbiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIHBjID0gdGhpcztcbiAgICAgICAgICAgIHZhciBkZXNjcmlwdGlvbiA9IG9yaWdMb2NhbERlc2NyaXB0aW9uLmdldC5hcHBseSh0aGlzKTtcbiAgICAgICAgICAgIGlmIChkZXNjcmlwdGlvbi50eXBlID09PSAnJykge1xuICAgICAgICAgICAgICByZXR1cm4gZGVzY3JpcHRpb247XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcmVwbGFjZUludGVybmFsU3RyZWFtSWQocGMsIGRlc2NyaXB0aW9uKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5yZW1vdmVUcmFjayA9IGZ1bmN0aW9uKHNlbmRlcikge1xuICAgICAgdmFyIHBjID0gdGhpcztcbiAgICAgIGlmIChwYy5zaWduYWxpbmdTdGF0ZSA9PT0gJ2Nsb3NlZCcpIHtcbiAgICAgICAgdGhyb3cgbmV3IERPTUV4Y2VwdGlvbihcbiAgICAgICAgICAnVGhlIFJUQ1BlZXJDb25uZWN0aW9uXFwncyBzaWduYWxpbmdTdGF0ZSBpcyBcXCdjbG9zZWRcXCcuJyxcbiAgICAgICAgICAnSW52YWxpZFN0YXRlRXJyb3InKTtcbiAgICAgIH1cbiAgICAgIC8vIFdlIGNhbiBub3QgeWV0IGNoZWNrIGZvciBzZW5kZXIgaW5zdGFuY2VvZiBSVENSdHBTZW5kZXJcbiAgICAgIC8vIHNpbmNlIHdlIHNoaW0gUlRQU2VuZGVyLiBTbyB3ZSBjaGVjayBpZiBzZW5kZXIuX3BjIGlzIHNldC5cbiAgICAgIGlmICghc2VuZGVyLl9wYykge1xuICAgICAgICB0aHJvdyBuZXcgRE9NRXhjZXB0aW9uKCdBcmd1bWVudCAxIG9mIFJUQ1BlZXJDb25uZWN0aW9uLnJlbW92ZVRyYWNrICcgK1xuICAgICAgICAgICAgJ2RvZXMgbm90IGltcGxlbWVudCBpbnRlcmZhY2UgUlRDUnRwU2VuZGVyLicsICdUeXBlRXJyb3InKTtcbiAgICAgIH1cbiAgICAgIHZhciBpc0xvY2FsID0gc2VuZGVyLl9wYyA9PT0gcGM7XG4gICAgICBpZiAoIWlzTG9jYWwpIHtcbiAgICAgICAgdGhyb3cgbmV3IERPTUV4Y2VwdGlvbignU2VuZGVyIHdhcyBub3QgY3JlYXRlZCBieSB0aGlzIGNvbm5lY3Rpb24uJyxcbiAgICAgICAgICAgICdJbnZhbGlkQWNjZXNzRXJyb3InKTtcbiAgICAgIH1cblxuICAgICAgLy8gU2VhcmNoIGZvciB0aGUgbmF0aXZlIHN0cmVhbSB0aGUgc2VuZGVycyB0cmFjayBiZWxvbmdzIHRvLlxuICAgICAgcGMuX3N0cmVhbXMgPSBwYy5fc3RyZWFtcyB8fCB7fTtcbiAgICAgIHZhciBzdHJlYW07XG4gICAgICBPYmplY3Qua2V5cyhwYy5fc3RyZWFtcykuZm9yRWFjaChmdW5jdGlvbihzdHJlYW1pZCkge1xuICAgICAgICB2YXIgaGFzVHJhY2sgPSBwYy5fc3RyZWFtc1tzdHJlYW1pZF0uZ2V0VHJhY2tzKCkuZmluZChmdW5jdGlvbih0cmFjaykge1xuICAgICAgICAgIHJldHVybiBzZW5kZXIudHJhY2sgPT09IHRyYWNrO1xuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGhhc1RyYWNrKSB7XG4gICAgICAgICAgc3RyZWFtID0gcGMuX3N0cmVhbXNbc3RyZWFtaWRdO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgaWYgKHN0cmVhbSkge1xuICAgICAgICBpZiAoc3RyZWFtLmdldFRyYWNrcygpLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIC8vIGlmIHRoaXMgaXMgdGhlIGxhc3QgdHJhY2sgb2YgdGhlIHN0cmVhbSwgcmVtb3ZlIHRoZSBzdHJlYW0uIFRoaXNcbiAgICAgICAgICAvLyB0YWtlcyBjYXJlIG9mIGFueSBzaGltbWVkIF9zZW5kZXJzLlxuICAgICAgICAgIHBjLnJlbW92ZVN0cmVhbShzdHJlYW0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIHJlbHlpbmcgb24gdGhlIHNhbWUgb2RkIGNocm9tZSBiZWhhdmlvdXIgYXMgYWJvdmUuXG4gICAgICAgICAgc3RyZWFtLnJlbW92ZVRyYWNrKHNlbmRlci50cmFjayk7XG4gICAgICAgIH1cbiAgICAgICAgcGMuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoJ25lZ290aWF0aW9ubmVlZGVkJykpO1xuICAgICAgfVxuICAgIH07XG4gIH0sXG5cbiAgc2hpbVBlZXJDb25uZWN0aW9uOiBmdW5jdGlvbih3aW5kb3cpIHtcbiAgICB2YXIgYnJvd3NlckRldGFpbHMgPSB1dGlscy5kZXRlY3RCcm93c2VyKHdpbmRvdyk7XG5cbiAgICAvLyBUaGUgUlRDUGVlckNvbm5lY3Rpb24gb2JqZWN0LlxuICAgIGlmICghd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uKSB7XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gPSBmdW5jdGlvbihwY0NvbmZpZywgcGNDb25zdHJhaW50cykge1xuICAgICAgICAvLyBUcmFuc2xhdGUgaWNlVHJhbnNwb3J0UG9saWN5IHRvIGljZVRyYW5zcG9ydHMsXG4gICAgICAgIC8vIHNlZSBodHRwczovL2NvZGUuZ29vZ2xlLmNvbS9wL3dlYnJ0Yy9pc3N1ZXMvZGV0YWlsP2lkPTQ4NjlcbiAgICAgICAgLy8gdGhpcyB3YXMgZml4ZWQgaW4gTTU2IGFsb25nIHdpdGggdW5wcmVmaXhpbmcgUlRDUGVlckNvbm5lY3Rpb24uXG4gICAgICAgIGxvZ2dpbmcoJ1BlZXJDb25uZWN0aW9uJyk7XG4gICAgICAgIGlmIChwY0NvbmZpZyAmJiBwY0NvbmZpZy5pY2VUcmFuc3BvcnRQb2xpY3kpIHtcbiAgICAgICAgICBwY0NvbmZpZy5pY2VUcmFuc3BvcnRzID0gcGNDb25maWcuaWNlVHJhbnNwb3J0UG9saWN5O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ldyB3aW5kb3cud2Via2l0UlRDUGVlckNvbm5lY3Rpb24ocGNDb25maWcsIHBjQ29uc3RyYWludHMpO1xuICAgICAgfTtcbiAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUgPVxuICAgICAgICAgIHdpbmRvdy53ZWJraXRSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGU7XG4gICAgICAvLyB3cmFwIHN0YXRpYyBtZXRob2RzLiBDdXJyZW50bHkganVzdCBnZW5lcmF0ZUNlcnRpZmljYXRlLlxuICAgICAgaWYgKHdpbmRvdy53ZWJraXRSVENQZWVyQ29ubmVjdGlvbi5nZW5lcmF0ZUNlcnRpZmljYXRlKSB7XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24sICdnZW5lcmF0ZUNlcnRpZmljYXRlJywge1xuICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gd2luZG93LndlYmtpdFJUQ1BlZXJDb25uZWN0aW9uLmdlbmVyYXRlQ2VydGlmaWNhdGU7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gbWlncmF0ZSBmcm9tIG5vbi1zcGVjIFJUQ0ljZVNlcnZlci51cmwgdG8gUlRDSWNlU2VydmVyLnVybHNcbiAgICAgIHZhciBPcmlnUGVlckNvbm5lY3Rpb24gPSB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb247XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gPSBmdW5jdGlvbihwY0NvbmZpZywgcGNDb25zdHJhaW50cykge1xuICAgICAgICBpZiAocGNDb25maWcgJiYgcGNDb25maWcuaWNlU2VydmVycykge1xuICAgICAgICAgIHZhciBuZXdJY2VTZXJ2ZXJzID0gW107XG4gICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwY0NvbmZpZy5pY2VTZXJ2ZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB2YXIgc2VydmVyID0gcGNDb25maWcuaWNlU2VydmVyc1tpXTtcbiAgICAgICAgICAgIGlmICghc2VydmVyLmhhc093blByb3BlcnR5KCd1cmxzJykgJiZcbiAgICAgICAgICAgICAgICBzZXJ2ZXIuaGFzT3duUHJvcGVydHkoJ3VybCcpKSB7XG4gICAgICAgICAgICAgIHV0aWxzLmRlcHJlY2F0ZWQoJ1JUQ0ljZVNlcnZlci51cmwnLCAnUlRDSWNlU2VydmVyLnVybHMnKTtcbiAgICAgICAgICAgICAgc2VydmVyID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShzZXJ2ZXIpKTtcbiAgICAgICAgICAgICAgc2VydmVyLnVybHMgPSBzZXJ2ZXIudXJsO1xuICAgICAgICAgICAgICBuZXdJY2VTZXJ2ZXJzLnB1c2goc2VydmVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIG5ld0ljZVNlcnZlcnMucHVzaChwY0NvbmZpZy5pY2VTZXJ2ZXJzW2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgcGNDb25maWcuaWNlU2VydmVycyA9IG5ld0ljZVNlcnZlcnM7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5ldyBPcmlnUGVlckNvbm5lY3Rpb24ocGNDb25maWcsIHBjQ29uc3RyYWludHMpO1xuICAgICAgfTtcbiAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUgPSBPcmlnUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlO1xuICAgICAgLy8gd3JhcCBzdGF0aWMgbWV0aG9kcy4gQ3VycmVudGx5IGp1c3QgZ2VuZXJhdGVDZXJ0aWZpY2F0ZS5cbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24sICdnZW5lcmF0ZUNlcnRpZmljYXRlJywge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHJldHVybiBPcmlnUGVlckNvbm5lY3Rpb24uZ2VuZXJhdGVDZXJ0aWZpY2F0ZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdmFyIG9yaWdHZXRTdGF0cyA9IHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuZ2V0U3RhdHM7XG4gICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRTdGF0cyA9IGZ1bmN0aW9uKHNlbGVjdG9yLFxuICAgICAgICBzdWNjZXNzQ2FsbGJhY2ssIGVycm9yQ2FsbGJhY2spIHtcbiAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgIHZhciBhcmdzID0gYXJndW1lbnRzO1xuXG4gICAgICAvLyBJZiBzZWxlY3RvciBpcyBhIGZ1bmN0aW9uIHRoZW4gd2UgYXJlIGluIHRoZSBvbGQgc3R5bGUgc3RhdHMgc28ganVzdFxuICAgICAgLy8gcGFzcyBiYWNrIHRoZSBvcmlnaW5hbCBnZXRTdGF0cyBmb3JtYXQgdG8gYXZvaWQgYnJlYWtpbmcgb2xkIHVzZXJzLlxuICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAwICYmIHR5cGVvZiBzZWxlY3RvciA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICByZXR1cm4gb3JpZ0dldFN0YXRzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICB9XG5cbiAgICAgIC8vIFdoZW4gc3BlYy1zdHlsZSBnZXRTdGF0cyBpcyBzdXBwb3J0ZWQsIHJldHVybiB0aG9zZSB3aGVuIGNhbGxlZCB3aXRoXG4gICAgICAvLyBlaXRoZXIgbm8gYXJndW1lbnRzIG9yIHRoZSBzZWxlY3RvciBhcmd1bWVudCBpcyBudWxsLlxuICAgICAgaWYgKG9yaWdHZXRTdGF0cy5sZW5ndGggPT09IDAgJiYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDAgfHxcbiAgICAgICAgICB0eXBlb2YgYXJndW1lbnRzWzBdICE9PSAnZnVuY3Rpb24nKSkge1xuICAgICAgICByZXR1cm4gb3JpZ0dldFN0YXRzLmFwcGx5KHRoaXMsIFtdKTtcbiAgICAgIH1cblxuICAgICAgdmFyIGZpeENocm9tZVN0YXRzXyA9IGZ1bmN0aW9uKHJlc3BvbnNlKSB7XG4gICAgICAgIHZhciBzdGFuZGFyZFJlcG9ydCA9IHt9O1xuICAgICAgICB2YXIgcmVwb3J0cyA9IHJlc3BvbnNlLnJlc3VsdCgpO1xuICAgICAgICByZXBvcnRzLmZvckVhY2goZnVuY3Rpb24ocmVwb3J0KSB7XG4gICAgICAgICAgdmFyIHN0YW5kYXJkU3RhdHMgPSB7XG4gICAgICAgICAgICBpZDogcmVwb3J0LmlkLFxuICAgICAgICAgICAgdGltZXN0YW1wOiByZXBvcnQudGltZXN0YW1wLFxuICAgICAgICAgICAgdHlwZToge1xuICAgICAgICAgICAgICBsb2NhbGNhbmRpZGF0ZTogJ2xvY2FsLWNhbmRpZGF0ZScsXG4gICAgICAgICAgICAgIHJlbW90ZWNhbmRpZGF0ZTogJ3JlbW90ZS1jYW5kaWRhdGUnXG4gICAgICAgICAgICB9W3JlcG9ydC50eXBlXSB8fCByZXBvcnQudHlwZVxuICAgICAgICAgIH07XG4gICAgICAgICAgcmVwb3J0Lm5hbWVzKCkuZm9yRWFjaChmdW5jdGlvbihuYW1lKSB7XG4gICAgICAgICAgICBzdGFuZGFyZFN0YXRzW25hbWVdID0gcmVwb3J0LnN0YXQobmFtZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgc3RhbmRhcmRSZXBvcnRbc3RhbmRhcmRTdGF0cy5pZF0gPSBzdGFuZGFyZFN0YXRzO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gc3RhbmRhcmRSZXBvcnQ7XG4gICAgICB9O1xuXG4gICAgICAvLyBzaGltIGdldFN0YXRzIHdpdGggbWFwbGlrZSBzdXBwb3J0XG4gICAgICB2YXIgbWFrZU1hcFN0YXRzID0gZnVuY3Rpb24oc3RhdHMpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBNYXAoT2JqZWN0LmtleXMoc3RhdHMpLm1hcChmdW5jdGlvbihrZXkpIHtcbiAgICAgICAgICByZXR1cm4gW2tleSwgc3RhdHNba2V5XV07XG4gICAgICAgIH0pKTtcbiAgICAgIH07XG5cbiAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID49IDIpIHtcbiAgICAgICAgdmFyIHN1Y2Nlc3NDYWxsYmFja1dyYXBwZXJfID0gZnVuY3Rpb24ocmVzcG9uc2UpIHtcbiAgICAgICAgICBhcmdzWzFdKG1ha2VNYXBTdGF0cyhmaXhDaHJvbWVTdGF0c18ocmVzcG9uc2UpKSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIG9yaWdHZXRTdGF0cy5hcHBseSh0aGlzLCBbc3VjY2Vzc0NhbGxiYWNrV3JhcHBlcl8sXG4gICAgICAgICAgYXJndW1lbnRzWzBdXSk7XG4gICAgICB9XG5cbiAgICAgIC8vIHByb21pc2Utc3VwcG9ydFxuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgICBvcmlnR2V0U3RhdHMuYXBwbHkoc2VsZiwgW1xuICAgICAgICAgIGZ1bmN0aW9uKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICByZXNvbHZlKG1ha2VNYXBTdGF0cyhmaXhDaHJvbWVTdGF0c18ocmVzcG9uc2UpKSk7XG4gICAgICAgICAgfSwgcmVqZWN0XSk7XG4gICAgICB9KS50aGVuKHN1Y2Nlc3NDYWxsYmFjaywgZXJyb3JDYWxsYmFjayk7XG4gICAgfTtcblxuICAgIC8vIGFkZCBwcm9taXNlIHN1cHBvcnQgLS0gbmF0aXZlbHkgYXZhaWxhYmxlIGluIENocm9tZSA1MVxuICAgIGlmIChicm93c2VyRGV0YWlscy52ZXJzaW9uIDwgNTEpIHtcbiAgICAgIFsnc2V0TG9jYWxEZXNjcmlwdGlvbicsICdzZXRSZW1vdGVEZXNjcmlwdGlvbicsICdhZGRJY2VDYW5kaWRhdGUnXVxuICAgICAgICAgIC5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZCkge1xuICAgICAgICAgICAgdmFyIG5hdGl2ZU1ldGhvZCA9IHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGVbbWV0aG9kXTtcbiAgICAgICAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGVbbWV0aG9kXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICB2YXIgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAgICAgICB2YXIgcHJvbWlzZSA9IG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgICAgICAgICAgIG5hdGl2ZU1ldGhvZC5hcHBseShzZWxmLCBbYXJnc1swXSwgcmVzb2x2ZSwgcmVqZWN0XSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICBpZiAoYXJncy5sZW5ndGggPCAyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHByb21pc2U7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgcmV0dXJuIHByb21pc2UudGhlbihmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICBhcmdzWzFdLmFwcGx5KG51bGwsIFtdKTtcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgZnVuY3Rpb24oZXJyKSB7XG4gICAgICAgICAgICAgICAgaWYgKGFyZ3MubGVuZ3RoID49IDMpIHtcbiAgICAgICAgICAgICAgICAgIGFyZ3NbMl0uYXBwbHkobnVsbCwgW2Vycl0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIHByb21pc2Ugc3VwcG9ydCBmb3IgY3JlYXRlT2ZmZXIgYW5kIGNyZWF0ZUFuc3dlci4gQXZhaWxhYmxlICh3aXRob3V0XG4gICAgLy8gYnVncykgc2luY2UgTTUyOiBjcmJ1Zy82MTkyODlcbiAgICBpZiAoYnJvd3NlckRldGFpbHMudmVyc2lvbiA8IDUyKSB7XG4gICAgICBbJ2NyZWF0ZU9mZmVyJywgJ2NyZWF0ZUFuc3dlciddLmZvckVhY2goZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICAgIHZhciBuYXRpdmVNZXRob2QgPSB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlW21ldGhvZF07XG4gICAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGVbbWV0aG9kXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA8IDEgfHwgKGFyZ3VtZW50cy5sZW5ndGggPT09IDEgJiZcbiAgICAgICAgICAgICAgdHlwZW9mIGFyZ3VtZW50c1swXSA9PT0gJ29iamVjdCcpKSB7XG4gICAgICAgICAgICB2YXIgb3B0cyA9IGFyZ3VtZW50cy5sZW5ndGggPT09IDEgPyBhcmd1bWVudHNbMF0gOiB1bmRlZmluZWQ7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICAgICAgICAgIG5hdGl2ZU1ldGhvZC5hcHBseShzZWxmLCBbcmVzb2x2ZSwgcmVqZWN0LCBvcHRzXSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIG5hdGl2ZU1ldGhvZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gc2hpbSBpbXBsaWNpdCBjcmVhdGlvbiBvZiBSVENTZXNzaW9uRGVzY3JpcHRpb24vUlRDSWNlQ2FuZGlkYXRlXG4gICAgWydzZXRMb2NhbERlc2NyaXB0aW9uJywgJ3NldFJlbW90ZURlc2NyaXB0aW9uJywgJ2FkZEljZUNhbmRpZGF0ZSddXG4gICAgICAgIC5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZCkge1xuICAgICAgICAgIHZhciBuYXRpdmVNZXRob2QgPSB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlW21ldGhvZF07XG4gICAgICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBhcmd1bWVudHNbMF0gPSBuZXcgKChtZXRob2QgPT09ICdhZGRJY2VDYW5kaWRhdGUnKSA/XG4gICAgICAgICAgICAgICAgd2luZG93LlJUQ0ljZUNhbmRpZGF0ZSA6XG4gICAgICAgICAgICAgICAgd2luZG93LlJUQ1Nlc3Npb25EZXNjcmlwdGlvbikoYXJndW1lbnRzWzBdKTtcbiAgICAgICAgICAgIHJldHVybiBuYXRpdmVNZXRob2QuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICB9O1xuICAgICAgICB9KTtcblxuICAgIC8vIHN1cHBvcnQgZm9yIGFkZEljZUNhbmRpZGF0ZShudWxsIG9yIHVuZGVmaW5lZClcbiAgICB2YXIgbmF0aXZlQWRkSWNlQ2FuZGlkYXRlID1cbiAgICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRJY2VDYW5kaWRhdGU7XG4gICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRJY2VDYW5kaWRhdGUgPSBmdW5jdGlvbigpIHtcbiAgICAgIGlmICghYXJndW1lbnRzWzBdKSB7XG4gICAgICAgIGlmIChhcmd1bWVudHNbMV0pIHtcbiAgICAgICAgICBhcmd1bWVudHNbMV0uYXBwbHkobnVsbCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5hdGl2ZUFkZEljZUNhbmRpZGF0ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH07XG4gIH1cbn07XG5cblxuLy8gRXhwb3NlIHB1YmxpYyBtZXRob2RzLlxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHNoaW1NZWRpYVN0cmVhbTogY2hyb21lU2hpbS5zaGltTWVkaWFTdHJlYW0sXG4gIHNoaW1PblRyYWNrOiBjaHJvbWVTaGltLnNoaW1PblRyYWNrLFxuICBzaGltQWRkVHJhY2tSZW1vdmVUcmFjazogY2hyb21lU2hpbS5zaGltQWRkVHJhY2tSZW1vdmVUcmFjayxcbiAgc2hpbUdldFNlbmRlcnNXaXRoRHRtZjogY2hyb21lU2hpbS5zaGltR2V0U2VuZGVyc1dpdGhEdG1mLFxuICBzaGltU291cmNlT2JqZWN0OiBjaHJvbWVTaGltLnNoaW1Tb3VyY2VPYmplY3QsXG4gIHNoaW1QZWVyQ29ubmVjdGlvbjogY2hyb21lU2hpbS5zaGltUGVlckNvbm5lY3Rpb24sXG4gIHNoaW1HZXRVc2VyTWVkaWE6IHJlcXVpcmUoJy4vZ2V0dXNlcm1lZGlhJylcbn07XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzLmpzJyk7XG52YXIgbG9nZ2luZyA9IHV0aWxzLmxvZztcblxuLy8gRXhwb3NlIHB1YmxpYyBtZXRob2RzLlxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbih3aW5kb3cpIHtcbiAgdmFyIGJyb3dzZXJEZXRhaWxzID0gdXRpbHMuZGV0ZWN0QnJvd3Nlcih3aW5kb3cpO1xuICB2YXIgbmF2aWdhdG9yID0gd2luZG93ICYmIHdpbmRvdy5uYXZpZ2F0b3I7XG5cbiAgdmFyIGNvbnN0cmFpbnRzVG9DaHJvbWVfID0gZnVuY3Rpb24oYykge1xuICAgIGlmICh0eXBlb2YgYyAhPT0gJ29iamVjdCcgfHwgYy5tYW5kYXRvcnkgfHwgYy5vcHRpb25hbCkge1xuICAgICAgcmV0dXJuIGM7XG4gICAgfVxuICAgIHZhciBjYyA9IHt9O1xuICAgIE9iamVjdC5rZXlzKGMpLmZvckVhY2goZnVuY3Rpb24oa2V5KSB7XG4gICAgICBpZiAoa2V5ID09PSAncmVxdWlyZScgfHwga2V5ID09PSAnYWR2YW5jZWQnIHx8IGtleSA9PT0gJ21lZGlhU291cmNlJykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB2YXIgciA9ICh0eXBlb2YgY1trZXldID09PSAnb2JqZWN0JykgPyBjW2tleV0gOiB7aWRlYWw6IGNba2V5XX07XG4gICAgICBpZiAoci5leGFjdCAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiByLmV4YWN0ID09PSAnbnVtYmVyJykge1xuICAgICAgICByLm1pbiA9IHIubWF4ID0gci5leGFjdDtcbiAgICAgIH1cbiAgICAgIHZhciBvbGRuYW1lXyA9IGZ1bmN0aW9uKHByZWZpeCwgbmFtZSkge1xuICAgICAgICBpZiAocHJlZml4KSB7XG4gICAgICAgICAgcmV0dXJuIHByZWZpeCArIG5hbWUuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyBuYW1lLnNsaWNlKDEpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAobmFtZSA9PT0gJ2RldmljZUlkJykgPyAnc291cmNlSWQnIDogbmFtZTtcbiAgICAgIH07XG4gICAgICBpZiAoci5pZGVhbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNjLm9wdGlvbmFsID0gY2Mub3B0aW9uYWwgfHwgW107XG4gICAgICAgIHZhciBvYyA9IHt9O1xuICAgICAgICBpZiAodHlwZW9mIHIuaWRlYWwgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgb2Nbb2xkbmFtZV8oJ21pbicsIGtleSldID0gci5pZGVhbDtcbiAgICAgICAgICBjYy5vcHRpb25hbC5wdXNoKG9jKTtcbiAgICAgICAgICBvYyA9IHt9O1xuICAgICAgICAgIG9jW29sZG5hbWVfKCdtYXgnLCBrZXkpXSA9IHIuaWRlYWw7XG4gICAgICAgICAgY2Mub3B0aW9uYWwucHVzaChvYyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgb2Nbb2xkbmFtZV8oJycsIGtleSldID0gci5pZGVhbDtcbiAgICAgICAgICBjYy5vcHRpb25hbC5wdXNoKG9jKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKHIuZXhhY3QgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygci5leGFjdCAhPT0gJ251bWJlcicpIHtcbiAgICAgICAgY2MubWFuZGF0b3J5ID0gY2MubWFuZGF0b3J5IHx8IHt9O1xuICAgICAgICBjYy5tYW5kYXRvcnlbb2xkbmFtZV8oJycsIGtleSldID0gci5leGFjdDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIFsnbWluJywgJ21heCddLmZvckVhY2goZnVuY3Rpb24obWl4KSB7XG4gICAgICAgICAgaWYgKHJbbWl4XSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBjYy5tYW5kYXRvcnkgPSBjYy5tYW5kYXRvcnkgfHwge307XG4gICAgICAgICAgICBjYy5tYW5kYXRvcnlbb2xkbmFtZV8obWl4LCBrZXkpXSA9IHJbbWl4XTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGlmIChjLmFkdmFuY2VkKSB7XG4gICAgICBjYy5vcHRpb25hbCA9IChjYy5vcHRpb25hbCB8fCBbXSkuY29uY2F0KGMuYWR2YW5jZWQpO1xuICAgIH1cbiAgICByZXR1cm4gY2M7XG4gIH07XG5cbiAgdmFyIHNoaW1Db25zdHJhaW50c18gPSBmdW5jdGlvbihjb25zdHJhaW50cywgZnVuYykge1xuICAgIGNvbnN0cmFpbnRzID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShjb25zdHJhaW50cykpO1xuICAgIGlmIChjb25zdHJhaW50cyAmJiB0eXBlb2YgY29uc3RyYWludHMuYXVkaW8gPT09ICdvYmplY3QnKSB7XG4gICAgICB2YXIgcmVtYXAgPSBmdW5jdGlvbihvYmosIGEsIGIpIHtcbiAgICAgICAgaWYgKGEgaW4gb2JqICYmICEoYiBpbiBvYmopKSB7XG4gICAgICAgICAgb2JqW2JdID0gb2JqW2FdO1xuICAgICAgICAgIGRlbGV0ZSBvYmpbYV07XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICBjb25zdHJhaW50cyA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoY29uc3RyYWludHMpKTtcbiAgICAgIHJlbWFwKGNvbnN0cmFpbnRzLmF1ZGlvLCAnYXV0b0dhaW5Db250cm9sJywgJ2dvb2dBdXRvR2FpbkNvbnRyb2wnKTtcbiAgICAgIHJlbWFwKGNvbnN0cmFpbnRzLmF1ZGlvLCAnbm9pc2VTdXBwcmVzc2lvbicsICdnb29nTm9pc2VTdXBwcmVzc2lvbicpO1xuICAgICAgY29uc3RyYWludHMuYXVkaW8gPSBjb25zdHJhaW50c1RvQ2hyb21lXyhjb25zdHJhaW50cy5hdWRpbyk7XG4gICAgfVxuICAgIGlmIChjb25zdHJhaW50cyAmJiB0eXBlb2YgY29uc3RyYWludHMudmlkZW8gPT09ICdvYmplY3QnKSB7XG4gICAgICAvLyBTaGltIGZhY2luZ01vZGUgZm9yIG1vYmlsZSAmIHN1cmZhY2UgcHJvLlxuICAgICAgdmFyIGZhY2UgPSBjb25zdHJhaW50cy52aWRlby5mYWNpbmdNb2RlO1xuICAgICAgZmFjZSA9IGZhY2UgJiYgKCh0eXBlb2YgZmFjZSA9PT0gJ29iamVjdCcpID8gZmFjZSA6IHtpZGVhbDogZmFjZX0pO1xuICAgICAgdmFyIGdldFN1cHBvcnRlZEZhY2luZ01vZGVMaWVzID0gYnJvd3NlckRldGFpbHMudmVyc2lvbiA8IDYxO1xuXG4gICAgICBpZiAoKGZhY2UgJiYgKGZhY2UuZXhhY3QgPT09ICd1c2VyJyB8fCBmYWNlLmV4YWN0ID09PSAnZW52aXJvbm1lbnQnIHx8XG4gICAgICAgICAgICAgICAgICAgIGZhY2UuaWRlYWwgPT09ICd1c2VyJyB8fCBmYWNlLmlkZWFsID09PSAnZW52aXJvbm1lbnQnKSkgJiZcbiAgICAgICAgICAhKG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0U3VwcG9ydGVkQ29uc3RyYWludHMgJiZcbiAgICAgICAgICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0U3VwcG9ydGVkQ29uc3RyYWludHMoKS5mYWNpbmdNb2RlICYmXG4gICAgICAgICAgICAhZ2V0U3VwcG9ydGVkRmFjaW5nTW9kZUxpZXMpKSB7XG4gICAgICAgIGRlbGV0ZSBjb25zdHJhaW50cy52aWRlby5mYWNpbmdNb2RlO1xuICAgICAgICB2YXIgbWF0Y2hlcztcbiAgICAgICAgaWYgKGZhY2UuZXhhY3QgPT09ICdlbnZpcm9ubWVudCcgfHwgZmFjZS5pZGVhbCA9PT0gJ2Vudmlyb25tZW50Jykge1xuICAgICAgICAgIG1hdGNoZXMgPSBbJ2JhY2snLCAncmVhciddO1xuICAgICAgICB9IGVsc2UgaWYgKGZhY2UuZXhhY3QgPT09ICd1c2VyJyB8fCBmYWNlLmlkZWFsID09PSAndXNlcicpIHtcbiAgICAgICAgICBtYXRjaGVzID0gWydmcm9udCddO1xuICAgICAgICB9XG4gICAgICAgIGlmIChtYXRjaGVzKSB7XG4gICAgICAgICAgLy8gTG9vayBmb3IgbWF0Y2hlcyBpbiBsYWJlbCwgb3IgdXNlIGxhc3QgY2FtIGZvciBiYWNrICh0eXBpY2FsKS5cbiAgICAgICAgICByZXR1cm4gbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzKClcbiAgICAgICAgICAudGhlbihmdW5jdGlvbihkZXZpY2VzKSB7XG4gICAgICAgICAgICBkZXZpY2VzID0gZGV2aWNlcy5maWx0ZXIoZnVuY3Rpb24oZCkge1xuICAgICAgICAgICAgICByZXR1cm4gZC5raW5kID09PSAndmlkZW9pbnB1dCc7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHZhciBkZXYgPSBkZXZpY2VzLmZpbmQoZnVuY3Rpb24oZCkge1xuICAgICAgICAgICAgICByZXR1cm4gbWF0Y2hlcy5zb21lKGZ1bmN0aW9uKG1hdGNoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGQubGFiZWwudG9Mb3dlckNhc2UoKS5pbmRleE9mKG1hdGNoKSAhPT0gLTE7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAoIWRldiAmJiBkZXZpY2VzLmxlbmd0aCAmJiBtYXRjaGVzLmluZGV4T2YoJ2JhY2snKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgZGV2ID0gZGV2aWNlc1tkZXZpY2VzLmxlbmd0aCAtIDFdOyAvLyBtb3JlIGxpa2VseSB0aGUgYmFjayBjYW1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkZXYpIHtcbiAgICAgICAgICAgICAgY29uc3RyYWludHMudmlkZW8uZGV2aWNlSWQgPSBmYWNlLmV4YWN0ID8ge2V4YWN0OiBkZXYuZGV2aWNlSWR9IDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge2lkZWFsOiBkZXYuZGV2aWNlSWR9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3RyYWludHMudmlkZW8gPSBjb25zdHJhaW50c1RvQ2hyb21lXyhjb25zdHJhaW50cy52aWRlbyk7XG4gICAgICAgICAgICBsb2dnaW5nKCdjaHJvbWU6ICcgKyBKU09OLnN0cmluZ2lmeShjb25zdHJhaW50cykpO1xuICAgICAgICAgICAgcmV0dXJuIGZ1bmMoY29uc3RyYWludHMpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjb25zdHJhaW50cy52aWRlbyA9IGNvbnN0cmFpbnRzVG9DaHJvbWVfKGNvbnN0cmFpbnRzLnZpZGVvKTtcbiAgICB9XG4gICAgbG9nZ2luZygnY2hyb21lOiAnICsgSlNPTi5zdHJpbmdpZnkoY29uc3RyYWludHMpKTtcbiAgICByZXR1cm4gZnVuYyhjb25zdHJhaW50cyk7XG4gIH07XG5cbiAgdmFyIHNoaW1FcnJvcl8gPSBmdW5jdGlvbihlKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6IHtcbiAgICAgICAgUGVybWlzc2lvbkRlbmllZEVycm9yOiAnTm90QWxsb3dlZEVycm9yJyxcbiAgICAgICAgSW52YWxpZFN0YXRlRXJyb3I6ICdOb3RSZWFkYWJsZUVycm9yJyxcbiAgICAgICAgRGV2aWNlc05vdEZvdW5kRXJyb3I6ICdOb3RGb3VuZEVycm9yJyxcbiAgICAgICAgQ29uc3RyYWludE5vdFNhdGlzZmllZEVycm9yOiAnT3ZlcmNvbnN0cmFpbmVkRXJyb3InLFxuICAgICAgICBUcmFja1N0YXJ0RXJyb3I6ICdOb3RSZWFkYWJsZUVycm9yJyxcbiAgICAgICAgTWVkaWFEZXZpY2VGYWlsZWREdWVUb1NodXRkb3duOiAnTm90UmVhZGFibGVFcnJvcicsXG4gICAgICAgIE1lZGlhRGV2aWNlS2lsbFN3aXRjaE9uOiAnTm90UmVhZGFibGVFcnJvcidcbiAgICAgIH1bZS5uYW1lXSB8fCBlLm5hbWUsXG4gICAgICBtZXNzYWdlOiBlLm1lc3NhZ2UsXG4gICAgICBjb25zdHJhaW50OiBlLmNvbnN0cmFpbnROYW1lLFxuICAgICAgdG9TdHJpbmc6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5uYW1lICsgKHRoaXMubWVzc2FnZSAmJiAnOiAnKSArIHRoaXMubWVzc2FnZTtcbiAgICAgIH1cbiAgICB9O1xuICB9O1xuXG4gIHZhciBnZXRVc2VyTWVkaWFfID0gZnVuY3Rpb24oY29uc3RyYWludHMsIG9uU3VjY2Vzcywgb25FcnJvcikge1xuICAgIHNoaW1Db25zdHJhaW50c18oY29uc3RyYWludHMsIGZ1bmN0aW9uKGMpIHtcbiAgICAgIG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEoYywgb25TdWNjZXNzLCBmdW5jdGlvbihlKSB7XG4gICAgICAgIGlmIChvbkVycm9yKSB7XG4gICAgICAgICAgb25FcnJvcihzaGltRXJyb3JfKGUpKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH07XG5cbiAgbmF2aWdhdG9yLmdldFVzZXJNZWRpYSA9IGdldFVzZXJNZWRpYV87XG5cbiAgLy8gUmV0dXJucyB0aGUgcmVzdWx0IG9mIGdldFVzZXJNZWRpYSBhcyBhIFByb21pc2UuXG4gIHZhciBnZXRVc2VyTWVkaWFQcm9taXNlXyA9IGZ1bmN0aW9uKGNvbnN0cmFpbnRzKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgbmF2aWdhdG9yLmdldFVzZXJNZWRpYShjb25zdHJhaW50cywgcmVzb2x2ZSwgcmVqZWN0KTtcbiAgICB9KTtcbiAgfTtcblxuICBpZiAoIW5hdmlnYXRvci5tZWRpYURldmljZXMpIHtcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzID0ge1xuICAgICAgZ2V0VXNlck1lZGlhOiBnZXRVc2VyTWVkaWFQcm9taXNlXyxcbiAgICAgIGVudW1lcmF0ZURldmljZXM6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSkge1xuICAgICAgICAgIHZhciBraW5kcyA9IHthdWRpbzogJ2F1ZGlvaW5wdXQnLCB2aWRlbzogJ3ZpZGVvaW5wdXQnfTtcbiAgICAgICAgICByZXR1cm4gd2luZG93Lk1lZGlhU3RyZWFtVHJhY2suZ2V0U291cmNlcyhmdW5jdGlvbihkZXZpY2VzKSB7XG4gICAgICAgICAgICByZXNvbHZlKGRldmljZXMubWFwKGZ1bmN0aW9uKGRldmljZSkge1xuICAgICAgICAgICAgICByZXR1cm4ge2xhYmVsOiBkZXZpY2UubGFiZWwsXG4gICAgICAgICAgICAgICAga2luZDoga2luZHNbZGV2aWNlLmtpbmRdLFxuICAgICAgICAgICAgICAgIGRldmljZUlkOiBkZXZpY2UuaWQsXG4gICAgICAgICAgICAgICAgZ3JvdXBJZDogJyd9O1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgICBnZXRTdXBwb3J0ZWRDb25zdHJhaW50czogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZGV2aWNlSWQ6IHRydWUsIGVjaG9DYW5jZWxsYXRpb246IHRydWUsIGZhY2luZ01vZGU6IHRydWUsXG4gICAgICAgICAgZnJhbWVSYXRlOiB0cnVlLCBoZWlnaHQ6IHRydWUsIHdpZHRoOiB0cnVlXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIC8vIEEgc2hpbSBmb3IgZ2V0VXNlck1lZGlhIG1ldGhvZCBvbiB0aGUgbWVkaWFEZXZpY2VzIG9iamVjdC5cbiAgLy8gVE9ETyhLYXB0ZW5KYW5zc29uKSByZW1vdmUgb25jZSBpbXBsZW1lbnRlZCBpbiBDaHJvbWUgc3RhYmxlLlxuICBpZiAoIW5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKSB7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEgPSBmdW5jdGlvbihjb25zdHJhaW50cykge1xuICAgICAgcmV0dXJuIGdldFVzZXJNZWRpYVByb21pc2VfKGNvbnN0cmFpbnRzKTtcbiAgICB9O1xuICB9IGVsc2Uge1xuICAgIC8vIEV2ZW4gdGhvdWdoIENocm9tZSA0NSBoYXMgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcyBhbmQgYSBnZXRVc2VyTWVkaWFcbiAgICAvLyBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGEgUHJvbWlzZSwgaXQgZG9lcyBub3QgYWNjZXB0IHNwZWMtc3R5bGVcbiAgICAvLyBjb25zdHJhaW50cy5cbiAgICB2YXIgb3JpZ0dldFVzZXJNZWRpYSA9IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhLlxuICAgICAgICBiaW5kKG5hdmlnYXRvci5tZWRpYURldmljZXMpO1xuICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhID0gZnVuY3Rpb24oY3MpIHtcbiAgICAgIHJldHVybiBzaGltQ29uc3RyYWludHNfKGNzLCBmdW5jdGlvbihjKSB7XG4gICAgICAgIHJldHVybiBvcmlnR2V0VXNlck1lZGlhKGMpLnRoZW4oZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgICAgaWYgKGMuYXVkaW8gJiYgIXN0cmVhbS5nZXRBdWRpb1RyYWNrcygpLmxlbmd0aCB8fFxuICAgICAgICAgICAgICBjLnZpZGVvICYmICFzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGgpIHtcbiAgICAgICAgICAgIHN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgICAgICAgICAgIHRyYWNrLnN0b3AoKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhyb3cgbmV3IERPTUV4Y2VwdGlvbignJywgJ05vdEZvdW5kRXJyb3InKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHN0cmVhbTtcbiAgICAgICAgfSwgZnVuY3Rpb24oZSkge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChzaGltRXJyb3JfKGUpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9O1xuICB9XG5cbiAgLy8gRHVtbXkgZGV2aWNlY2hhbmdlIGV2ZW50IG1ldGhvZHMuXG4gIC8vIFRPRE8oS2FwdGVuSmFuc3NvbikgcmVtb3ZlIG9uY2UgaW1wbGVtZW50ZWQgaW4gQ2hyb21lIHN0YWJsZS5cbiAgaWYgKHR5cGVvZiBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmFkZEV2ZW50TGlzdGVuZXIgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5hZGRFdmVudExpc3RlbmVyID0gZnVuY3Rpb24oKSB7XG4gICAgICBsb2dnaW5nKCdEdW1teSBtZWRpYURldmljZXMuYWRkRXZlbnRMaXN0ZW5lciBjYWxsZWQuJyk7XG4gICAgfTtcbiAgfVxuICBpZiAodHlwZW9mIG5hdmlnYXRvci5tZWRpYURldmljZXMucmVtb3ZlRXZlbnRMaXN0ZW5lciA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLnJlbW92ZUV2ZW50TGlzdGVuZXIgPSBmdW5jdGlvbigpIHtcbiAgICAgIGxvZ2dpbmcoJ0R1bW15IG1lZGlhRGV2aWNlcy5yZW1vdmVFdmVudExpc3RlbmVyIGNhbGxlZC4nKTtcbiAgICB9O1xuICB9XG59O1xuIiwiLypcbiAqICBDb3B5cmlnaHQgKGMpIDIwMTcgVGhlIFdlYlJUQyBwcm9qZWN0IGF1dGhvcnMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlIGxpY2Vuc2VcbiAqICB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGluIHRoZSByb290IG9mIHRoZSBzb3VyY2VcbiAqICB0cmVlLlxuICovXG4gLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG5cbnZhciBTRFBVdGlscyA9IHJlcXVpcmUoJ3NkcCcpO1xudmFyIHV0aWxzID0gcmVxdWlyZSgnLi91dGlscycpO1xuXG4vLyBXcmFwcyB0aGUgcGVlcmNvbm5lY3Rpb24gZXZlbnQgZXZlbnROYW1lVG9XcmFwIGluIGEgZnVuY3Rpb25cbi8vIHdoaWNoIHJldHVybnMgdGhlIG1vZGlmaWVkIGV2ZW50IG9iamVjdC5cbmZ1bmN0aW9uIHdyYXBQZWVyQ29ubmVjdGlvbkV2ZW50KHdpbmRvdywgZXZlbnROYW1lVG9XcmFwLCB3cmFwcGVyKSB7XG4gIGlmICghd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBwcm90byA9IHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGU7XG4gIHZhciBuYXRpdmVBZGRFdmVudExpc3RlbmVyID0gcHJvdG8uYWRkRXZlbnRMaXN0ZW5lcjtcbiAgcHJvdG8uYWRkRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKG5hdGl2ZUV2ZW50TmFtZSwgY2IpIHtcbiAgICBpZiAobmF0aXZlRXZlbnROYW1lICE9PSBldmVudE5hbWVUb1dyYXApIHtcbiAgICAgIHJldHVybiBuYXRpdmVBZGRFdmVudExpc3RlbmVyLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgfVxuICAgIHZhciB3cmFwcGVkQ2FsbGJhY2sgPSBmdW5jdGlvbihlKSB7XG4gICAgICBjYih3cmFwcGVyKGUpKTtcbiAgICB9O1xuICAgIHRoaXMuX2V2ZW50TWFwID0gdGhpcy5fZXZlbnRNYXAgfHwge307XG4gICAgdGhpcy5fZXZlbnRNYXBbY2JdID0gd3JhcHBlZENhbGxiYWNrO1xuICAgIHJldHVybiBuYXRpdmVBZGRFdmVudExpc3RlbmVyLmFwcGx5KHRoaXMsIFtuYXRpdmVFdmVudE5hbWUsXG4gICAgICB3cmFwcGVkQ2FsbGJhY2tdKTtcbiAgfTtcblxuICB2YXIgbmF0aXZlUmVtb3ZlRXZlbnRMaXN0ZW5lciA9IHByb3RvLnJlbW92ZUV2ZW50TGlzdGVuZXI7XG4gIHByb3RvLnJlbW92ZUV2ZW50TGlzdGVuZXIgPSBmdW5jdGlvbihuYXRpdmVFdmVudE5hbWUsIGNiKSB7XG4gICAgaWYgKG5hdGl2ZUV2ZW50TmFtZSAhPT0gZXZlbnROYW1lVG9XcmFwIHx8ICF0aGlzLl9ldmVudE1hcFxuICAgICAgICB8fCAhdGhpcy5fZXZlbnRNYXBbY2JdKSB7XG4gICAgICByZXR1cm4gbmF0aXZlUmVtb3ZlRXZlbnRMaXN0ZW5lci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH1cbiAgICB2YXIgdW53cmFwcGVkQ2IgPSB0aGlzLl9ldmVudE1hcFtjYl07XG4gICAgZGVsZXRlIHRoaXMuX2V2ZW50TWFwW2NiXTtcbiAgICByZXR1cm4gbmF0aXZlUmVtb3ZlRXZlbnRMaXN0ZW5lci5hcHBseSh0aGlzLCBbbmF0aXZlRXZlbnROYW1lLFxuICAgICAgdW53cmFwcGVkQ2JdKTtcbiAgfTtcblxuICBPYmplY3QuZGVmaW5lUHJvcGVydHkocHJvdG8sICdvbicgKyBldmVudE5hbWVUb1dyYXAsIHtcbiAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIHRoaXNbJ19vbicgKyBldmVudE5hbWVUb1dyYXBdO1xuICAgIH0sXG4gICAgc2V0OiBmdW5jdGlvbihjYikge1xuICAgICAgaWYgKHRoaXNbJ19vbicgKyBldmVudE5hbWVUb1dyYXBdKSB7XG4gICAgICAgIHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudE5hbWVUb1dyYXAsXG4gICAgICAgICAgICB0aGlzWydfb24nICsgZXZlbnROYW1lVG9XcmFwXSk7XG4gICAgICAgIGRlbGV0ZSB0aGlzWydfb24nICsgZXZlbnROYW1lVG9XcmFwXTtcbiAgICAgIH1cbiAgICAgIGlmIChjYikge1xuICAgICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXIoZXZlbnROYW1lVG9XcmFwLFxuICAgICAgICAgICAgdGhpc1snX29uJyArIGV2ZW50TmFtZVRvV3JhcF0gPSBjYik7XG4gICAgICB9XG4gICAgfVxuICB9KTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHNoaW1SVENJY2VDYW5kaWRhdGU6IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIC8vIGZvdW5kYXRpb24gaXMgYXJiaXRyYXJpbHkgY2hvc2VuIGFzIGFuIGluZGljYXRvciBmb3IgZnVsbCBzdXBwb3J0IGZvclxuICAgIC8vIGh0dHBzOi8vdzNjLmdpdGh1Yi5pby93ZWJydGMtcGMvI3J0Y2ljZWNhbmRpZGF0ZS1pbnRlcmZhY2VcbiAgICBpZiAod2luZG93LlJUQ0ljZUNhbmRpZGF0ZSAmJiAnZm91bmRhdGlvbicgaW5cbiAgICAgICAgd2luZG93LlJUQ0ljZUNhbmRpZGF0ZS5wcm90b3R5cGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgTmF0aXZlUlRDSWNlQ2FuZGlkYXRlID0gd2luZG93LlJUQ0ljZUNhbmRpZGF0ZTtcbiAgICB3aW5kb3cuUlRDSWNlQ2FuZGlkYXRlID0gZnVuY3Rpb24oYXJncykge1xuICAgICAgLy8gUmVtb3ZlIHRoZSBhPSB3aGljaCBzaG91bGRuJ3QgYmUgcGFydCBvZiB0aGUgY2FuZGlkYXRlIHN0cmluZy5cbiAgICAgIGlmICh0eXBlb2YgYXJncyA9PT0gJ29iamVjdCcgJiYgYXJncy5jYW5kaWRhdGUgJiZcbiAgICAgICAgICBhcmdzLmNhbmRpZGF0ZS5pbmRleE9mKCdhPScpID09PSAwKSB7XG4gICAgICAgIGFyZ3MgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGFyZ3MpKTtcbiAgICAgICAgYXJncy5jYW5kaWRhdGUgPSBhcmdzLmNhbmRpZGF0ZS5zdWJzdHIoMik7XG4gICAgICB9XG5cbiAgICAgIC8vIEF1Z21lbnQgdGhlIG5hdGl2ZSBjYW5kaWRhdGUgd2l0aCB0aGUgcGFyc2VkIGZpZWxkcy5cbiAgICAgIHZhciBuYXRpdmVDYW5kaWRhdGUgPSBuZXcgTmF0aXZlUlRDSWNlQ2FuZGlkYXRlKGFyZ3MpO1xuICAgICAgdmFyIHBhcnNlZENhbmRpZGF0ZSA9IFNEUFV0aWxzLnBhcnNlQ2FuZGlkYXRlKGFyZ3MuY2FuZGlkYXRlKTtcbiAgICAgIHZhciBhdWdtZW50ZWRDYW5kaWRhdGUgPSBPYmplY3QuYXNzaWduKG5hdGl2ZUNhbmRpZGF0ZSxcbiAgICAgICAgICBwYXJzZWRDYW5kaWRhdGUpO1xuXG4gICAgICAvLyBBZGQgYSBzZXJpYWxpemVyIHRoYXQgZG9lcyBub3Qgc2VyaWFsaXplIHRoZSBleHRyYSBhdHRyaWJ1dGVzLlxuICAgICAgYXVnbWVudGVkQ2FuZGlkYXRlLnRvSlNPTiA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGNhbmRpZGF0ZTogYXVnbWVudGVkQ2FuZGlkYXRlLmNhbmRpZGF0ZSxcbiAgICAgICAgICBzZHBNaWQ6IGF1Z21lbnRlZENhbmRpZGF0ZS5zZHBNaWQsXG4gICAgICAgICAgc2RwTUxpbmVJbmRleDogYXVnbWVudGVkQ2FuZGlkYXRlLnNkcE1MaW5lSW5kZXgsXG4gICAgICAgICAgdXNlcm5hbWVGcmFnbWVudDogYXVnbWVudGVkQ2FuZGlkYXRlLnVzZXJuYW1lRnJhZ21lbnQsXG4gICAgICAgIH07XG4gICAgICB9O1xuICAgICAgcmV0dXJuIGF1Z21lbnRlZENhbmRpZGF0ZTtcbiAgICB9O1xuXG4gICAgLy8gSG9vayB1cCB0aGUgYXVnbWVudGVkIGNhbmRpZGF0ZSBpbiBvbmljZWNhbmRpZGF0ZSBhbmRcbiAgICAvLyBhZGRFdmVudExpc3RlbmVyKCdpY2VjYW5kaWRhdGUnLCAuLi4pXG4gICAgd3JhcFBlZXJDb25uZWN0aW9uRXZlbnQod2luZG93LCAnaWNlY2FuZGlkYXRlJywgZnVuY3Rpb24oZSkge1xuICAgICAgaWYgKGUuY2FuZGlkYXRlKSB7XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCAnY2FuZGlkYXRlJywge1xuICAgICAgICAgIHZhbHVlOiBuZXcgd2luZG93LlJUQ0ljZUNhbmRpZGF0ZShlLmNhbmRpZGF0ZSksXG4gICAgICAgICAgd3JpdGFibGU6ICdmYWxzZSdcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZTtcbiAgICB9KTtcbiAgfSxcblxuICAvLyBzaGltQ3JlYXRlT2JqZWN0VVJMIG11c3QgYmUgY2FsbGVkIGJlZm9yZSBzaGltU291cmNlT2JqZWN0IHRvIGF2b2lkIGxvb3AuXG5cbiAgc2hpbUNyZWF0ZU9iamVjdFVSTDogZnVuY3Rpb24od2luZG93KSB7XG4gICAgdmFyIFVSTCA9IHdpbmRvdyAmJiB3aW5kb3cuVVJMO1xuXG4gICAgaWYgKCEodHlwZW9mIHdpbmRvdyA9PT0gJ29iamVjdCcgJiYgd2luZG93LkhUTUxNZWRpYUVsZW1lbnQgJiZcbiAgICAgICAgICAnc3JjT2JqZWN0JyBpbiB3aW5kb3cuSFRNTE1lZGlhRWxlbWVudC5wcm90b3R5cGUgJiZcbiAgICAgICAgVVJMLmNyZWF0ZU9iamVjdFVSTCAmJiBVUkwucmV2b2tlT2JqZWN0VVJMKSkge1xuICAgICAgLy8gT25seSBzaGltIENyZWF0ZU9iamVjdFVSTCB1c2luZyBzcmNPYmplY3QgaWYgc3JjT2JqZWN0IGV4aXN0cy5cbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgdmFyIG5hdGl2ZUNyZWF0ZU9iamVjdFVSTCA9IFVSTC5jcmVhdGVPYmplY3RVUkwuYmluZChVUkwpO1xuICAgIHZhciBuYXRpdmVSZXZva2VPYmplY3RVUkwgPSBVUkwucmV2b2tlT2JqZWN0VVJMLmJpbmQoVVJMKTtcbiAgICB2YXIgc3RyZWFtcyA9IG5ldyBNYXAoKSwgbmV3SWQgPSAwO1xuXG4gICAgVVJMLmNyZWF0ZU9iamVjdFVSTCA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgaWYgKCdnZXRUcmFja3MnIGluIHN0cmVhbSkge1xuICAgICAgICB2YXIgdXJsID0gJ3BvbHlibG9iOicgKyAoKytuZXdJZCk7XG4gICAgICAgIHN0cmVhbXMuc2V0KHVybCwgc3RyZWFtKTtcbiAgICAgICAgdXRpbHMuZGVwcmVjYXRlZCgnVVJMLmNyZWF0ZU9iamVjdFVSTChzdHJlYW0pJyxcbiAgICAgICAgICAgICdlbGVtLnNyY09iamVjdCA9IHN0cmVhbScpO1xuICAgICAgICByZXR1cm4gdXJsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5hdGl2ZUNyZWF0ZU9iamVjdFVSTChzdHJlYW0pO1xuICAgIH07XG4gICAgVVJMLnJldm9rZU9iamVjdFVSTCA9IGZ1bmN0aW9uKHVybCkge1xuICAgICAgbmF0aXZlUmV2b2tlT2JqZWN0VVJMKHVybCk7XG4gICAgICBzdHJlYW1zLmRlbGV0ZSh1cmwpO1xuICAgIH07XG5cbiAgICB2YXIgZHNjID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih3aW5kb3cuSFRNTE1lZGlhRWxlbWVudC5wcm90b3R5cGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3NyYycpO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuSFRNTE1lZGlhRWxlbWVudC5wcm90b3R5cGUsICdzcmMnLCB7XG4gICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gZHNjLmdldC5hcHBseSh0aGlzKTtcbiAgICAgIH0sXG4gICAgICBzZXQ6IGZ1bmN0aW9uKHVybCkge1xuICAgICAgICB0aGlzLnNyY09iamVjdCA9IHN0cmVhbXMuZ2V0KHVybCkgfHwgbnVsbDtcbiAgICAgICAgcmV0dXJuIGRzYy5zZXQuYXBwbHkodGhpcywgW3VybF0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIG5hdGl2ZVNldEF0dHJpYnV0ZSA9IHdpbmRvdy5IVE1MTWVkaWFFbGVtZW50LnByb3RvdHlwZS5zZXRBdHRyaWJ1dGU7XG4gICAgd2luZG93LkhUTUxNZWRpYUVsZW1lbnQucHJvdG90eXBlLnNldEF0dHJpYnV0ZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDIgJiZcbiAgICAgICAgICAoJycgKyBhcmd1bWVudHNbMF0pLnRvTG93ZXJDYXNlKCkgPT09ICdzcmMnKSB7XG4gICAgICAgIHRoaXMuc3JjT2JqZWN0ID0gc3RyZWFtcy5nZXQoYXJndW1lbnRzWzFdKSB8fCBudWxsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5hdGl2ZVNldEF0dHJpYnV0ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH07XG4gIH1cbn07XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMnKTtcbnZhciBzaGltUlRDUGVlckNvbm5lY3Rpb24gPSByZXF1aXJlKCdydGNwZWVyY29ubmVjdGlvbi1zaGltJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBzaGltR2V0VXNlck1lZGlhOiByZXF1aXJlKCcuL2dldHVzZXJtZWRpYScpLFxuICBzaGltUGVlckNvbm5lY3Rpb246IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIHZhciBicm93c2VyRGV0YWlscyA9IHV0aWxzLmRldGVjdEJyb3dzZXIod2luZG93KTtcblxuICAgIGlmICh3aW5kb3cuUlRDSWNlR2F0aGVyZXIpIHtcbiAgICAgIC8vIE9SVEMgZGVmaW5lcyBhbiBSVENJY2VDYW5kaWRhdGUgb2JqZWN0IGJ1dCBubyBjb25zdHJ1Y3Rvci5cbiAgICAgIC8vIE5vdCBpbXBsZW1lbnRlZCBpbiBFZGdlLlxuICAgICAgaWYgKCF3aW5kb3cuUlRDSWNlQ2FuZGlkYXRlKSB7XG4gICAgICAgIHdpbmRvdy5SVENJY2VDYW5kaWRhdGUgPSBmdW5jdGlvbihhcmdzKSB7XG4gICAgICAgICAgcmV0dXJuIGFyZ3M7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICAvLyBPUlRDIGRvZXMgbm90IGhhdmUgYSBzZXNzaW9uIGRlc2NyaXB0aW9uIG9iamVjdCBidXRcbiAgICAgIC8vIG90aGVyIGJyb3dzZXJzIChpLmUuIENocm9tZSkgdGhhdCB3aWxsIHN1cHBvcnQgYm90aCBQQyBhbmQgT1JUQ1xuICAgICAgLy8gaW4gdGhlIGZ1dHVyZSBtaWdodCBoYXZlIHRoaXMgZGVmaW5lZCBhbHJlYWR5LlxuICAgICAgaWYgKCF3aW5kb3cuUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKSB7XG4gICAgICAgIHdpbmRvdy5SVENTZXNzaW9uRGVzY3JpcHRpb24gPSBmdW5jdGlvbihhcmdzKSB7XG4gICAgICAgICAgcmV0dXJuIGFyZ3M7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICAvLyB0aGlzIGFkZHMgYW4gYWRkaXRpb25hbCBldmVudCBsaXN0ZW5lciB0byBNZWRpYVN0cmFja1RyYWNrIHRoYXQgc2lnbmFsc1xuICAgICAgLy8gd2hlbiBhIHRyYWNrcyBlbmFibGVkIHByb3BlcnR5IHdhcyBjaGFuZ2VkLiBXb3JrYXJvdW5kIGZvciBhIGJ1ZyBpblxuICAgICAgLy8gYWRkU3RyZWFtLCBzZWUgYmVsb3cuIE5vIGxvbmdlciByZXF1aXJlZCBpbiAxNTAyNStcbiAgICAgIGlmIChicm93c2VyRGV0YWlscy52ZXJzaW9uIDwgMTUwMjUpIHtcbiAgICAgICAgdmFyIG9yaWdNU1RFbmFibGVkID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihcbiAgICAgICAgICAgIHdpbmRvdy5NZWRpYVN0cmVhbVRyYWNrLnByb3RvdHlwZSwgJ2VuYWJsZWQnKTtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdy5NZWRpYVN0cmVhbVRyYWNrLnByb3RvdHlwZSwgJ2VuYWJsZWQnLCB7XG4gICAgICAgICAgc2V0OiBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICAgICAgb3JpZ01TVEVuYWJsZWQuc2V0LmNhbGwodGhpcywgdmFsdWUpO1xuICAgICAgICAgICAgdmFyIGV2ID0gbmV3IEV2ZW50KCdlbmFibGVkJyk7XG4gICAgICAgICAgICBldi5lbmFibGVkID0gdmFsdWU7XG4gICAgICAgICAgICB0aGlzLmRpc3BhdGNoRXZlbnQoZXYpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gT1JUQyBkZWZpbmVzIHRoZSBEVE1GIHNlbmRlciBhIGJpdCBkaWZmZXJlbnQuXG4gICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL3czYy9vcnRjL2lzc3Vlcy83MTRcbiAgICBpZiAod2luZG93LlJUQ1J0cFNlbmRlciAmJiAhKCdkdG1mJyBpbiB3aW5kb3cuUlRDUnRwU2VuZGVyLnByb3RvdHlwZSkpIHtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUnRwU2VuZGVyLnByb3RvdHlwZSwgJ2R0bWYnLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgaWYgKHRoaXMuX2R0bWYgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgaWYgKHRoaXMudHJhY2sua2luZCA9PT0gJ2F1ZGlvJykge1xuICAgICAgICAgICAgICB0aGlzLl9kdG1mID0gbmV3IHdpbmRvdy5SVENEdG1mU2VuZGVyKHRoaXMpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLnRyYWNrLmtpbmQgPT09ICd2aWRlbycpIHtcbiAgICAgICAgICAgICAgdGhpcy5fZHRtZiA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0aGlzLl9kdG1mO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gPVxuICAgICAgICBzaGltUlRDUGVlckNvbm5lY3Rpb24od2luZG93LCBicm93c2VyRGV0YWlscy52ZXJzaW9uKTtcbiAgfSxcbiAgc2hpbVJlcGxhY2VUcmFjazogZnVuY3Rpb24od2luZG93KSB7XG4gICAgLy8gT1JUQyBoYXMgcmVwbGFjZVRyYWNrIC0tIGh0dHBzOi8vZ2l0aHViLmNvbS93M2Mvb3J0Yy9pc3N1ZXMvNjE0XG4gICAgaWYgKHdpbmRvdy5SVENSdHBTZW5kZXIgJiZcbiAgICAgICAgISgncmVwbGFjZVRyYWNrJyBpbiB3aW5kb3cuUlRDUnRwU2VuZGVyLnByb3RvdHlwZSkpIHtcbiAgICAgIHdpbmRvdy5SVENSdHBTZW5kZXIucHJvdG90eXBlLnJlcGxhY2VUcmFjayA9XG4gICAgICAgICAgd2luZG93LlJUQ1J0cFNlbmRlci5wcm90b3R5cGUuc2V0VHJhY2s7XG4gICAgfVxuICB9XG59O1xuIiwiLypcbiAqICBDb3B5cmlnaHQgKGMpIDIwMTYgVGhlIFdlYlJUQyBwcm9qZWN0IGF1dGhvcnMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlIGxpY2Vuc2VcbiAqICB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGluIHRoZSByb290IG9mIHRoZSBzb3VyY2VcbiAqICB0cmVlLlxuICovXG4gLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG5cbi8vIEV4cG9zZSBwdWJsaWMgbWV0aG9kcy5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24od2luZG93KSB7XG4gIHZhciBuYXZpZ2F0b3IgPSB3aW5kb3cgJiYgd2luZG93Lm5hdmlnYXRvcjtcblxuICB2YXIgc2hpbUVycm9yXyA9IGZ1bmN0aW9uKGUpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbmFtZToge1Blcm1pc3Npb25EZW5pZWRFcnJvcjogJ05vdEFsbG93ZWRFcnJvcid9W2UubmFtZV0gfHwgZS5uYW1lLFxuICAgICAgbWVzc2FnZTogZS5tZXNzYWdlLFxuICAgICAgY29uc3RyYWludDogZS5jb25zdHJhaW50LFxuICAgICAgdG9TdHJpbmc6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5uYW1lO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgLy8gZ2V0VXNlck1lZGlhIGVycm9yIHNoaW0uXG4gIHZhciBvcmlnR2V0VXNlck1lZGlhID0gbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEuXG4gICAgICBiaW5kKG5hdmlnYXRvci5tZWRpYURldmljZXMpO1xuICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYSA9IGZ1bmN0aW9uKGMpIHtcbiAgICByZXR1cm4gb3JpZ0dldFVzZXJNZWRpYShjKS5jYXRjaChmdW5jdGlvbihlKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3Qoc2hpbUVycm9yXyhlKSk7XG4gICAgfSk7XG4gIH07XG59O1xuIiwiLypcbiAqICBDb3B5cmlnaHQgKGMpIDIwMTYgVGhlIFdlYlJUQyBwcm9qZWN0IGF1dGhvcnMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlIGxpY2Vuc2VcbiAqICB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGluIHRoZSByb290IG9mIHRoZSBzb3VyY2VcbiAqICB0cmVlLlxuICovXG4gLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG5cbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzJyk7XG5cbnZhciBmaXJlZm94U2hpbSA9IHtcbiAgc2hpbU9uVHJhY2s6IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAnb2JqZWN0JyAmJiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gJiYgISgnb250cmFjaycgaW5cbiAgICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZSkpIHtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLCAnb250cmFjaycsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5fb250cmFjaztcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbihmKSB7XG4gICAgICAgICAgaWYgKHRoaXMuX29udHJhY2spIHtcbiAgICAgICAgICAgIHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcigndHJhY2snLCB0aGlzLl9vbnRyYWNrKTtcbiAgICAgICAgICAgIHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcignYWRkc3RyZWFtJywgdGhpcy5fb250cmFja3BvbHkpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXIoJ3RyYWNrJywgdGhpcy5fb250cmFjayA9IGYpO1xuICAgICAgICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lcignYWRkc3RyZWFtJywgdGhpcy5fb250cmFja3BvbHkgPSBmdW5jdGlvbihlKSB7XG4gICAgICAgICAgICBlLnN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgICAgICAgICAgIHZhciBldmVudCA9IG5ldyBFdmVudCgndHJhY2snKTtcbiAgICAgICAgICAgICAgZXZlbnQudHJhY2sgPSB0cmFjaztcbiAgICAgICAgICAgICAgZXZlbnQucmVjZWl2ZXIgPSB7dHJhY2s6IHRyYWNrfTtcbiAgICAgICAgICAgICAgZXZlbnQudHJhbnNjZWl2ZXIgPSB7cmVjZWl2ZXI6IGV2ZW50LnJlY2VpdmVyfTtcbiAgICAgICAgICAgICAgZXZlbnQuc3RyZWFtcyA9IFtlLnN0cmVhbV07XG4gICAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIHdpbmRvdyA9PT0gJ29iamVjdCcgJiYgd2luZG93LlJUQ1RyYWNrRXZlbnQgJiZcbiAgICAgICAgKCdyZWNlaXZlcicgaW4gd2luZG93LlJUQ1RyYWNrRXZlbnQucHJvdG90eXBlKSAmJlxuICAgICAgICAhKCd0cmFuc2NlaXZlcicgaW4gd2luZG93LlJUQ1RyYWNrRXZlbnQucHJvdG90eXBlKSkge1xuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdy5SVENUcmFja0V2ZW50LnByb3RvdHlwZSwgJ3RyYW5zY2VpdmVyJywge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHJldHVybiB7cmVjZWl2ZXI6IHRoaXMucmVjZWl2ZXJ9O1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH0sXG5cbiAgc2hpbVNvdXJjZU9iamVjdDogZnVuY3Rpb24od2luZG93KSB7XG4gICAgLy8gRmlyZWZveCBoYXMgc3VwcG9ydGVkIG1velNyY09iamVjdCBzaW5jZSBGRjIyLCB1bnByZWZpeGVkIGluIDQyLlxuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAnb2JqZWN0Jykge1xuICAgICAgaWYgKHdpbmRvdy5IVE1MTWVkaWFFbGVtZW50ICYmXG4gICAgICAgICEoJ3NyY09iamVjdCcgaW4gd2luZG93LkhUTUxNZWRpYUVsZW1lbnQucHJvdG90eXBlKSkge1xuICAgICAgICAvLyBTaGltIHRoZSBzcmNPYmplY3QgcHJvcGVydHksIG9uY2UsIHdoZW4gSFRNTE1lZGlhRWxlbWVudCBpcyBmb3VuZC5cbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdy5IVE1MTWVkaWFFbGVtZW50LnByb3RvdHlwZSwgJ3NyY09iamVjdCcsIHtcbiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMubW96U3JjT2JqZWN0O1xuICAgICAgICAgIH0sXG4gICAgICAgICAgc2V0OiBmdW5jdGlvbihzdHJlYW0pIHtcbiAgICAgICAgICAgIHRoaXMubW96U3JjT2JqZWN0ID0gc3RyZWFtO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9LFxuXG4gIHNoaW1QZWVyQ29ubmVjdGlvbjogZnVuY3Rpb24od2luZG93KSB7XG4gICAgdmFyIGJyb3dzZXJEZXRhaWxzID0gdXRpbHMuZGV0ZWN0QnJvd3Nlcih3aW5kb3cpO1xuXG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgIT09ICdvYmplY3QnIHx8ICEod2luZG93LlJUQ1BlZXJDb25uZWN0aW9uIHx8XG4gICAgICAgIHdpbmRvdy5tb3pSVENQZWVyQ29ubmVjdGlvbikpIHtcbiAgICAgIHJldHVybjsgLy8gcHJvYmFibHkgbWVkaWEucGVlcmNvbm5lY3Rpb24uZW5hYmxlZD1mYWxzZSBpbiBhYm91dDpjb25maWdcbiAgICB9XG4gICAgLy8gVGhlIFJUQ1BlZXJDb25uZWN0aW9uIG9iamVjdC5cbiAgICBpZiAoIXdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbikge1xuICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uID0gZnVuY3Rpb24ocGNDb25maWcsIHBjQ29uc3RyYWludHMpIHtcbiAgICAgICAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCAzOCkge1xuICAgICAgICAgIC8vIC51cmxzIGlzIG5vdCBzdXBwb3J0ZWQgaW4gRkYgPCAzOC5cbiAgICAgICAgICAvLyBjcmVhdGUgUlRDSWNlU2VydmVycyB3aXRoIGEgc2luZ2xlIHVybC5cbiAgICAgICAgICBpZiAocGNDb25maWcgJiYgcGNDb25maWcuaWNlU2VydmVycykge1xuICAgICAgICAgICAgdmFyIG5ld0ljZVNlcnZlcnMgPSBbXTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcGNDb25maWcuaWNlU2VydmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICB2YXIgc2VydmVyID0gcGNDb25maWcuaWNlU2VydmVyc1tpXTtcbiAgICAgICAgICAgICAgaWYgKHNlcnZlci5oYXNPd25Qcm9wZXJ0eSgndXJscycpKSB7XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBzZXJ2ZXIudXJscy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgICAgdmFyIG5ld1NlcnZlciA9IHtcbiAgICAgICAgICAgICAgICAgICAgdXJsOiBzZXJ2ZXIudXJsc1tqXVxuICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgIGlmIChzZXJ2ZXIudXJsc1tqXS5pbmRleE9mKCd0dXJuJykgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgbmV3U2VydmVyLnVzZXJuYW1lID0gc2VydmVyLnVzZXJuYW1lO1xuICAgICAgICAgICAgICAgICAgICBuZXdTZXJ2ZXIuY3JlZGVudGlhbCA9IHNlcnZlci5jcmVkZW50aWFsO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgbmV3SWNlU2VydmVycy5wdXNoKG5ld1NlcnZlcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG5ld0ljZVNlcnZlcnMucHVzaChwY0NvbmZpZy5pY2VTZXJ2ZXJzW2ldKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcGNDb25maWcuaWNlU2VydmVycyA9IG5ld0ljZVNlcnZlcnM7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgd2luZG93Lm1velJUQ1BlZXJDb25uZWN0aW9uKHBjQ29uZmlnLCBwY0NvbnN0cmFpbnRzKTtcbiAgICAgIH07XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlID1cbiAgICAgICAgICB3aW5kb3cubW96UlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlO1xuXG4gICAgICAvLyB3cmFwIHN0YXRpYyBtZXRob2RzLiBDdXJyZW50bHkganVzdCBnZW5lcmF0ZUNlcnRpZmljYXRlLlxuICAgICAgaWYgKHdpbmRvdy5tb3pSVENQZWVyQ29ubmVjdGlvbi5nZW5lcmF0ZUNlcnRpZmljYXRlKSB7XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24sICdnZW5lcmF0ZUNlcnRpZmljYXRlJywge1xuICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gd2luZG93Lm1velJUQ1BlZXJDb25uZWN0aW9uLmdlbmVyYXRlQ2VydGlmaWNhdGU7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgd2luZG93LlJUQ1Nlc3Npb25EZXNjcmlwdGlvbiA9IHdpbmRvdy5tb3pSVENTZXNzaW9uRGVzY3JpcHRpb247XG4gICAgICB3aW5kb3cuUlRDSWNlQ2FuZGlkYXRlID0gd2luZG93Lm1velJUQ0ljZUNhbmRpZGF0ZTtcbiAgICB9XG5cbiAgICAvLyBzaGltIGF3YXkgbmVlZCBmb3Igb2Jzb2xldGUgUlRDSWNlQ2FuZGlkYXRlL1JUQ1Nlc3Npb25EZXNjcmlwdGlvbi5cbiAgICBbJ3NldExvY2FsRGVzY3JpcHRpb24nLCAnc2V0UmVtb3RlRGVzY3JpcHRpb24nLCAnYWRkSWNlQ2FuZGlkYXRlJ11cbiAgICAgICAgLmZvckVhY2goZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICAgICAgdmFyIG5hdGl2ZU1ldGhvZCA9IHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGVbbWV0aG9kXTtcbiAgICAgICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlW21ldGhvZF0gPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGFyZ3VtZW50c1swXSA9IG5ldyAoKG1ldGhvZCA9PT0gJ2FkZEljZUNhbmRpZGF0ZScpID9cbiAgICAgICAgICAgICAgICB3aW5kb3cuUlRDSWNlQ2FuZGlkYXRlIDpcbiAgICAgICAgICAgICAgICB3aW5kb3cuUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKShhcmd1bWVudHNbMF0pO1xuICAgICAgICAgICAgcmV0dXJuIG5hdGl2ZU1ldGhvZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuXG4gICAgLy8gc3VwcG9ydCBmb3IgYWRkSWNlQ2FuZGlkYXRlKG51bGwgb3IgdW5kZWZpbmVkKVxuICAgIHZhciBuYXRpdmVBZGRJY2VDYW5kaWRhdGUgPVxuICAgICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZEljZUNhbmRpZGF0ZTtcbiAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZEljZUNhbmRpZGF0ZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgaWYgKCFhcmd1bWVudHNbMF0pIHtcbiAgICAgICAgaWYgKGFyZ3VtZW50c1sxXSkge1xuICAgICAgICAgIGFyZ3VtZW50c1sxXS5hcHBseShudWxsKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbmF0aXZlQWRkSWNlQ2FuZGlkYXRlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgfTtcblxuICAgIC8vIHNoaW0gZ2V0U3RhdHMgd2l0aCBtYXBsaWtlIHN1cHBvcnRcbiAgICB2YXIgbWFrZU1hcFN0YXRzID0gZnVuY3Rpb24oc3RhdHMpIHtcbiAgICAgIHZhciBtYXAgPSBuZXcgTWFwKCk7XG4gICAgICBPYmplY3Qua2V5cyhzdGF0cykuZm9yRWFjaChmdW5jdGlvbihrZXkpIHtcbiAgICAgICAgbWFwLnNldChrZXksIHN0YXRzW2tleV0pO1xuICAgICAgICBtYXBba2V5XSA9IHN0YXRzW2tleV07XG4gICAgICB9KTtcbiAgICAgIHJldHVybiBtYXA7XG4gICAgfTtcblxuICAgIHZhciBtb2Rlcm5TdGF0c1R5cGVzID0ge1xuICAgICAgaW5ib3VuZHJ0cDogJ2luYm91bmQtcnRwJyxcbiAgICAgIG91dGJvdW5kcnRwOiAnb3V0Ym91bmQtcnRwJyxcbiAgICAgIGNhbmRpZGF0ZXBhaXI6ICdjYW5kaWRhdGUtcGFpcicsXG4gICAgICBsb2NhbGNhbmRpZGF0ZTogJ2xvY2FsLWNhbmRpZGF0ZScsXG4gICAgICByZW1vdGVjYW5kaWRhdGU6ICdyZW1vdGUtY2FuZGlkYXRlJ1xuICAgIH07XG5cbiAgICB2YXIgbmF0aXZlR2V0U3RhdHMgPSB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFN0YXRzO1xuICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuZ2V0U3RhdHMgPSBmdW5jdGlvbihcbiAgICAgIHNlbGVjdG9yLFxuICAgICAgb25TdWNjLFxuICAgICAgb25FcnJcbiAgICApIHtcbiAgICAgIHJldHVybiBuYXRpdmVHZXRTdGF0cy5hcHBseSh0aGlzLCBbc2VsZWN0b3IgfHwgbnVsbF0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uKHN0YXRzKSB7XG4gICAgICAgICAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCA0OCkge1xuICAgICAgICAgICAgc3RhdHMgPSBtYWtlTWFwU3RhdHMoc3RhdHMpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoYnJvd3NlckRldGFpbHMudmVyc2lvbiA8IDUzICYmICFvblN1Y2MpIHtcbiAgICAgICAgICAgIC8vIFNoaW0gb25seSBwcm9taXNlIGdldFN0YXRzIHdpdGggc3BlYy1oeXBoZW5zIGluIHR5cGUgbmFtZXNcbiAgICAgICAgICAgIC8vIExlYXZlIGNhbGxiYWNrIHZlcnNpb24gYWxvbmU7IG1pc2Mgb2xkIHVzZXMgb2YgZm9yRWFjaCBiZWZvcmUgTWFwXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBzdGF0cy5mb3JFYWNoKGZ1bmN0aW9uKHN0YXQpIHtcbiAgICAgICAgICAgICAgICBzdGF0LnR5cGUgPSBtb2Rlcm5TdGF0c1R5cGVzW3N0YXQudHlwZV0gfHwgc3RhdC50eXBlO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgaWYgKGUubmFtZSAhPT0gJ1R5cGVFcnJvcicpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIC8vIEF2b2lkIFR5cGVFcnJvcjogXCJ0eXBlXCIgaXMgcmVhZC1vbmx5LCBpbiBvbGQgdmVyc2lvbnMuIDM0LTQzaXNoXG4gICAgICAgICAgICAgIHN0YXRzLmZvckVhY2goZnVuY3Rpb24oc3RhdCwgaSkge1xuICAgICAgICAgICAgICAgIHN0YXRzLnNldChpLCBPYmplY3QuYXNzaWduKHt9LCBzdGF0LCB7XG4gICAgICAgICAgICAgICAgICB0eXBlOiBtb2Rlcm5TdGF0c1R5cGVzW3N0YXQudHlwZV0gfHwgc3RhdC50eXBlXG4gICAgICAgICAgICAgICAgfSkpO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHN0YXRzO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihvblN1Y2MsIG9uRXJyKTtcbiAgICB9O1xuICB9XG59O1xuXG4vLyBFeHBvc2UgcHVibGljIG1ldGhvZHMuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgc2hpbU9uVHJhY2s6IGZpcmVmb3hTaGltLnNoaW1PblRyYWNrLFxuICBzaGltU291cmNlT2JqZWN0OiBmaXJlZm94U2hpbS5zaGltU291cmNlT2JqZWN0LFxuICBzaGltUGVlckNvbm5lY3Rpb246IGZpcmVmb3hTaGltLnNoaW1QZWVyQ29ubmVjdGlvbixcbiAgc2hpbUdldFVzZXJNZWRpYTogcmVxdWlyZSgnLi9nZXR1c2VybWVkaWEnKVxufTtcbiIsIi8qXG4gKiAgQ29weXJpZ2h0IChjKSAyMDE2IFRoZSBXZWJSVEMgcHJvamVjdCBhdXRob3JzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqICBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhIEJTRC1zdHlsZSBsaWNlbnNlXG4gKiAgdGhhdCBjYW4gYmUgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBvZiB0aGUgc291cmNlXG4gKiAgdHJlZS5cbiAqL1xuIC8qIGVzbGludC1lbnYgbm9kZSAqL1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscycpO1xudmFyIGxvZ2dpbmcgPSB1dGlscy5sb2c7XG5cbi8vIEV4cG9zZSBwdWJsaWMgbWV0aG9kcy5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24od2luZG93KSB7XG4gIHZhciBicm93c2VyRGV0YWlscyA9IHV0aWxzLmRldGVjdEJyb3dzZXIod2luZG93KTtcbiAgdmFyIG5hdmlnYXRvciA9IHdpbmRvdyAmJiB3aW5kb3cubmF2aWdhdG9yO1xuICB2YXIgTWVkaWFTdHJlYW1UcmFjayA9IHdpbmRvdyAmJiB3aW5kb3cuTWVkaWFTdHJlYW1UcmFjaztcblxuICB2YXIgc2hpbUVycm9yXyA9IGZ1bmN0aW9uKGUpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbmFtZToge1xuICAgICAgICBJbnRlcm5hbEVycm9yOiAnTm90UmVhZGFibGVFcnJvcicsXG4gICAgICAgIE5vdFN1cHBvcnRlZEVycm9yOiAnVHlwZUVycm9yJyxcbiAgICAgICAgUGVybWlzc2lvbkRlbmllZEVycm9yOiAnTm90QWxsb3dlZEVycm9yJyxcbiAgICAgICAgU2VjdXJpdHlFcnJvcjogJ05vdEFsbG93ZWRFcnJvcidcbiAgICAgIH1bZS5uYW1lXSB8fCBlLm5hbWUsXG4gICAgICBtZXNzYWdlOiB7XG4gICAgICAgICdUaGUgb3BlcmF0aW9uIGlzIGluc2VjdXJlLic6ICdUaGUgcmVxdWVzdCBpcyBub3QgYWxsb3dlZCBieSB0aGUgJyArXG4gICAgICAgICd1c2VyIGFnZW50IG9yIHRoZSBwbGF0Zm9ybSBpbiB0aGUgY3VycmVudCBjb250ZXh0LidcbiAgICAgIH1bZS5tZXNzYWdlXSB8fCBlLm1lc3NhZ2UsXG4gICAgICBjb25zdHJhaW50OiBlLmNvbnN0cmFpbnQsXG4gICAgICB0b1N0cmluZzogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm5hbWUgKyAodGhpcy5tZXNzYWdlICYmICc6ICcpICsgdGhpcy5tZXNzYWdlO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgLy8gZ2V0VXNlck1lZGlhIGNvbnN0cmFpbnRzIHNoaW0uXG4gIHZhciBnZXRVc2VyTWVkaWFfID0gZnVuY3Rpb24oY29uc3RyYWludHMsIG9uU3VjY2Vzcywgb25FcnJvcikge1xuICAgIHZhciBjb25zdHJhaW50c1RvRkYzN18gPSBmdW5jdGlvbihjKSB7XG4gICAgICBpZiAodHlwZW9mIGMgIT09ICdvYmplY3QnIHx8IGMucmVxdWlyZSkge1xuICAgICAgICByZXR1cm4gYztcbiAgICAgIH1cbiAgICAgIHZhciByZXF1aXJlID0gW107XG4gICAgICBPYmplY3Qua2V5cyhjKS5mb3JFYWNoKGZ1bmN0aW9uKGtleSkge1xuICAgICAgICBpZiAoa2V5ID09PSAncmVxdWlyZScgfHwga2V5ID09PSAnYWR2YW5jZWQnIHx8IGtleSA9PT0gJ21lZGlhU291cmNlJykge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB2YXIgciA9IGNba2V5XSA9ICh0eXBlb2YgY1trZXldID09PSAnb2JqZWN0JykgP1xuICAgICAgICAgICAgY1trZXldIDoge2lkZWFsOiBjW2tleV19O1xuICAgICAgICBpZiAoci5taW4gIT09IHVuZGVmaW5lZCB8fFxuICAgICAgICAgICAgci5tYXggIT09IHVuZGVmaW5lZCB8fCByLmV4YWN0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICByZXF1aXJlLnB1c2goa2V5KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoci5leGFjdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgaWYgKHR5cGVvZiByLmV4YWN0ID09PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgci4gbWluID0gci5tYXggPSByLmV4YWN0O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjW2tleV0gPSByLmV4YWN0O1xuICAgICAgICAgIH1cbiAgICAgICAgICBkZWxldGUgci5leGFjdDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoci5pZGVhbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgYy5hZHZhbmNlZCA9IGMuYWR2YW5jZWQgfHwgW107XG4gICAgICAgICAgdmFyIG9jID0ge307XG4gICAgICAgICAgaWYgKHR5cGVvZiByLmlkZWFsID09PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgb2Nba2V5XSA9IHttaW46IHIuaWRlYWwsIG1heDogci5pZGVhbH07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG9jW2tleV0gPSByLmlkZWFsO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjLmFkdmFuY2VkLnB1c2gob2MpO1xuICAgICAgICAgIGRlbGV0ZSByLmlkZWFsO1xuICAgICAgICAgIGlmICghT2JqZWN0LmtleXMocikubGVuZ3RoKSB7XG4gICAgICAgICAgICBkZWxldGUgY1trZXldO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICBpZiAocmVxdWlyZS5sZW5ndGgpIHtcbiAgICAgICAgYy5yZXF1aXJlID0gcmVxdWlyZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjO1xuICAgIH07XG4gICAgY29uc3RyYWludHMgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGNvbnN0cmFpbnRzKSk7XG4gICAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCAzOCkge1xuICAgICAgbG9nZ2luZygnc3BlYzogJyArIEpTT04uc3RyaW5naWZ5KGNvbnN0cmFpbnRzKSk7XG4gICAgICBpZiAoY29uc3RyYWludHMuYXVkaW8pIHtcbiAgICAgICAgY29uc3RyYWludHMuYXVkaW8gPSBjb25zdHJhaW50c1RvRkYzN18oY29uc3RyYWludHMuYXVkaW8pO1xuICAgICAgfVxuICAgICAgaWYgKGNvbnN0cmFpbnRzLnZpZGVvKSB7XG4gICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvID0gY29uc3RyYWludHNUb0ZGMzdfKGNvbnN0cmFpbnRzLnZpZGVvKTtcbiAgICAgIH1cbiAgICAgIGxvZ2dpbmcoJ2ZmMzc6ICcgKyBKU09OLnN0cmluZ2lmeShjb25zdHJhaW50cykpO1xuICAgIH1cbiAgICByZXR1cm4gbmF2aWdhdG9yLm1vekdldFVzZXJNZWRpYShjb25zdHJhaW50cywgb25TdWNjZXNzLCBmdW5jdGlvbihlKSB7XG4gICAgICBvbkVycm9yKHNoaW1FcnJvcl8oZSkpO1xuICAgIH0pO1xuICB9O1xuXG4gIC8vIFJldHVybnMgdGhlIHJlc3VsdCBvZiBnZXRVc2VyTWVkaWEgYXMgYSBQcm9taXNlLlxuICB2YXIgZ2V0VXNlck1lZGlhUHJvbWlzZV8gPSBmdW5jdGlvbihjb25zdHJhaW50cykge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgIGdldFVzZXJNZWRpYV8oY29uc3RyYWludHMsIHJlc29sdmUsIHJlamVjdCk7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gU2hpbSBmb3IgbWVkaWFEZXZpY2VzIG9uIG9sZGVyIHZlcnNpb25zLlxuICBpZiAoIW5hdmlnYXRvci5tZWRpYURldmljZXMpIHtcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzID0ge2dldFVzZXJNZWRpYTogZ2V0VXNlck1lZGlhUHJvbWlzZV8sXG4gICAgICBhZGRFdmVudExpc3RlbmVyOiBmdW5jdGlvbigpIHsgfSxcbiAgICAgIHJlbW92ZUV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uKCkgeyB9XG4gICAgfTtcbiAgfVxuICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmVudW1lcmF0ZURldmljZXMgPVxuICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzIHx8IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSkge1xuICAgICAgICAgIHZhciBpbmZvcyA9IFtcbiAgICAgICAgICAgIHtraW5kOiAnYXVkaW9pbnB1dCcsIGRldmljZUlkOiAnZGVmYXVsdCcsIGxhYmVsOiAnJywgZ3JvdXBJZDogJyd9LFxuICAgICAgICAgICAge2tpbmQ6ICd2aWRlb2lucHV0JywgZGV2aWNlSWQ6ICdkZWZhdWx0JywgbGFiZWw6ICcnLCBncm91cElkOiAnJ31cbiAgICAgICAgICBdO1xuICAgICAgICAgIHJlc29sdmUoaW5mb3MpO1xuICAgICAgICB9KTtcbiAgICAgIH07XG5cbiAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCA0MSkge1xuICAgIC8vIFdvcmsgYXJvdW5kIGh0dHA6Ly9idWd6aWwubGEvMTE2OTY2NVxuICAgIHZhciBvcmdFbnVtZXJhdGVEZXZpY2VzID1cbiAgICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzLmJpbmQobmF2aWdhdG9yLm1lZGlhRGV2aWNlcyk7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzID0gZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gb3JnRW51bWVyYXRlRGV2aWNlcygpLnRoZW4odW5kZWZpbmVkLCBmdW5jdGlvbihlKSB7XG4gICAgICAgIGlmIChlLm5hbWUgPT09ICdOb3RGb3VuZEVycm9yJykge1xuICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBlO1xuICAgICAgfSk7XG4gICAgfTtcbiAgfVxuICBpZiAoYnJvd3NlckRldGFpbHMudmVyc2lvbiA8IDQ5KSB7XG4gICAgdmFyIG9yaWdHZXRVc2VyTWVkaWEgPSBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYS5cbiAgICAgICAgYmluZChuYXZpZ2F0b3IubWVkaWFEZXZpY2VzKTtcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYSA9IGZ1bmN0aW9uKGMpIHtcbiAgICAgIHJldHVybiBvcmlnR2V0VXNlck1lZGlhKGMpLnRoZW4oZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgIC8vIFdvcmsgYXJvdW5kIGh0dHBzOi8vYnVnemlsLmxhLzgwMjMyNlxuICAgICAgICBpZiAoYy5hdWRpbyAmJiAhc3RyZWFtLmdldEF1ZGlvVHJhY2tzKCkubGVuZ3RoIHx8XG4gICAgICAgICAgICBjLnZpZGVvICYmICFzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGgpIHtcbiAgICAgICAgICBzdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbih0cmFjaykge1xuICAgICAgICAgICAgdHJhY2suc3RvcCgpO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRocm93IG5ldyBET01FeGNlcHRpb24oJ1RoZSBvYmplY3QgY2FuIG5vdCBiZSBmb3VuZCBoZXJlLicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTm90Rm91bmRFcnJvcicpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzdHJlYW07XG4gICAgICB9LCBmdW5jdGlvbihlKSB7XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChzaGltRXJyb3JfKGUpKTtcbiAgICAgIH0pO1xuICAgIH07XG4gIH1cbiAgaWYgKCEoYnJvd3NlckRldGFpbHMudmVyc2lvbiA+IDU1ICYmXG4gICAgICAnYXV0b0dhaW5Db250cm9sJyBpbiBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFN1cHBvcnRlZENvbnN0cmFpbnRzKCkpKSB7XG4gICAgdmFyIHJlbWFwID0gZnVuY3Rpb24ob2JqLCBhLCBiKSB7XG4gICAgICBpZiAoYSBpbiBvYmogJiYgIShiIGluIG9iaikpIHtcbiAgICAgICAgb2JqW2JdID0gb2JqW2FdO1xuICAgICAgICBkZWxldGUgb2JqW2FdO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgbmF0aXZlR2V0VXNlck1lZGlhID0gbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEuXG4gICAgICAgIGJpbmQobmF2aWdhdG9yLm1lZGlhRGV2aWNlcyk7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEgPSBmdW5jdGlvbihjKSB7XG4gICAgICBpZiAodHlwZW9mIGMgPT09ICdvYmplY3QnICYmIHR5cGVvZiBjLmF1ZGlvID09PSAnb2JqZWN0Jykge1xuICAgICAgICBjID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShjKSk7XG4gICAgICAgIHJlbWFwKGMuYXVkaW8sICdhdXRvR2FpbkNvbnRyb2wnLCAnbW96QXV0b0dhaW5Db250cm9sJyk7XG4gICAgICAgIHJlbWFwKGMuYXVkaW8sICdub2lzZVN1cHByZXNzaW9uJywgJ21vek5vaXNlU3VwcHJlc3Npb24nKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBuYXRpdmVHZXRVc2VyTWVkaWEoYyk7XG4gICAgfTtcblxuICAgIGlmIChNZWRpYVN0cmVhbVRyYWNrICYmIE1lZGlhU3RyZWFtVHJhY2sucHJvdG90eXBlLmdldFNldHRpbmdzKSB7XG4gICAgICB2YXIgbmF0aXZlR2V0U2V0dGluZ3MgPSBNZWRpYVN0cmVhbVRyYWNrLnByb3RvdHlwZS5nZXRTZXR0aW5ncztcbiAgICAgIE1lZGlhU3RyZWFtVHJhY2sucHJvdG90eXBlLmdldFNldHRpbmdzID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBvYmogPSBuYXRpdmVHZXRTZXR0aW5ncy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICByZW1hcChvYmosICdtb3pBdXRvR2FpbkNvbnRyb2wnLCAnYXV0b0dhaW5Db250cm9sJyk7XG4gICAgICAgIHJlbWFwKG9iaiwgJ21vek5vaXNlU3VwcHJlc3Npb24nLCAnbm9pc2VTdXBwcmVzc2lvbicpO1xuICAgICAgICByZXR1cm4gb2JqO1xuICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAoTWVkaWFTdHJlYW1UcmFjayAmJiBNZWRpYVN0cmVhbVRyYWNrLnByb3RvdHlwZS5hcHBseUNvbnN0cmFpbnRzKSB7XG4gICAgICB2YXIgbmF0aXZlQXBwbHlDb25zdHJhaW50cyA9IE1lZGlhU3RyZWFtVHJhY2sucHJvdG90eXBlLmFwcGx5Q29uc3RyYWludHM7XG4gICAgICBNZWRpYVN0cmVhbVRyYWNrLnByb3RvdHlwZS5hcHBseUNvbnN0cmFpbnRzID0gZnVuY3Rpb24oYykge1xuICAgICAgICBpZiAodGhpcy5raW5kID09PSAnYXVkaW8nICYmIHR5cGVvZiBjID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgIGMgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGMpKTtcbiAgICAgICAgICByZW1hcChjLCAnYXV0b0dhaW5Db250cm9sJywgJ21vekF1dG9HYWluQ29udHJvbCcpO1xuICAgICAgICAgIHJlbWFwKGMsICdub2lzZVN1cHByZXNzaW9uJywgJ21vek5vaXNlU3VwcHJlc3Npb24nKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmF0aXZlQXBwbHlDb25zdHJhaW50cy5hcHBseSh0aGlzLCBbY10pO1xuICAgICAgfTtcbiAgICB9XG4gIH1cbiAgbmF2aWdhdG9yLmdldFVzZXJNZWRpYSA9IGZ1bmN0aW9uKGNvbnN0cmFpbnRzLCBvblN1Y2Nlc3MsIG9uRXJyb3IpIHtcbiAgICBpZiAoYnJvd3NlckRldGFpbHMudmVyc2lvbiA8IDQ0KSB7XG4gICAgICByZXR1cm4gZ2V0VXNlck1lZGlhXyhjb25zdHJhaW50cywgb25TdWNjZXNzLCBvbkVycm9yKTtcbiAgICB9XG4gICAgLy8gUmVwbGFjZSBGaXJlZm94IDQ0KydzIGRlcHJlY2F0aW9uIHdhcm5pbmcgd2l0aCB1bnByZWZpeGVkIHZlcnNpb24uXG4gICAgdXRpbHMuZGVwcmVjYXRlZCgnbmF2aWdhdG9yLmdldFVzZXJNZWRpYScsXG4gICAgICAgICduYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYScpO1xuICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKGNvbnN0cmFpbnRzKS50aGVuKG9uU3VjY2Vzcywgb25FcnJvcik7XG4gIH07XG59O1xuIiwiLypcbiAqICBDb3B5cmlnaHQgKGMpIDIwMTYgVGhlIFdlYlJUQyBwcm9qZWN0IGF1dGhvcnMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlIGxpY2Vuc2VcbiAqICB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGluIHRoZSByb290IG9mIHRoZSBzb3VyY2VcbiAqICB0cmVlLlxuICovXG4ndXNlIHN0cmljdCc7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscycpO1xuXG52YXIgc2FmYXJpU2hpbSA9IHtcbiAgLy8gVE9ETzogRHJBbGV4LCBzaG91bGQgYmUgaGVyZSwgZG91YmxlIGNoZWNrIGFnYWluc3QgTGF5b3V0VGVzdHNcblxuICAvLyBUT0RPOiBvbmNlIHRoZSBiYWNrLWVuZCBmb3IgdGhlIG1hYyBwb3J0IGlzIGRvbmUsIGFkZC5cbiAgLy8gVE9ETzogY2hlY2sgZm9yIHdlYmtpdEdUSytcbiAgLy8gc2hpbVBlZXJDb25uZWN0aW9uOiBmdW5jdGlvbigpIHsgfSxcblxuICBzaGltTG9jYWxTdHJlYW1zQVBJOiBmdW5jdGlvbih3aW5kb3cpIHtcbiAgICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ29iamVjdCcgfHwgIXdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoISgnZ2V0TG9jYWxTdHJlYW1zJyBpbiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlKSkge1xuICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRMb2NhbFN0cmVhbXMgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKCF0aGlzLl9sb2NhbFN0cmVhbXMpIHtcbiAgICAgICAgICB0aGlzLl9sb2NhbFN0cmVhbXMgPSBbXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5fbG9jYWxTdHJlYW1zO1xuICAgICAgfTtcbiAgICB9XG4gICAgaWYgKCEoJ2dldFN0cmVhbUJ5SWQnIGluIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUpKSB7XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFN0cmVhbUJ5SWQgPSBmdW5jdGlvbihpZCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0gbnVsbDtcbiAgICAgICAgaWYgKHRoaXMuX2xvY2FsU3RyZWFtcykge1xuICAgICAgICAgIHRoaXMuX2xvY2FsU3RyZWFtcy5mb3JFYWNoKGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICAgICAgaWYgKHN0cmVhbS5pZCA9PT0gaWQpIHtcbiAgICAgICAgICAgICAgcmVzdWx0ID0gc3RyZWFtO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLl9yZW1vdGVTdHJlYW1zKSB7XG4gICAgICAgICAgdGhpcy5fcmVtb3RlU3RyZWFtcy5mb3JFYWNoKGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICAgICAgaWYgKHN0cmVhbS5pZCA9PT0gaWQpIHtcbiAgICAgICAgICAgICAgcmVzdWx0ID0gc3RyZWFtO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9O1xuICAgIH1cbiAgICBpZiAoISgnYWRkU3RyZWFtJyBpbiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlKSkge1xuICAgICAgdmFyIF9hZGRUcmFjayA9IHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkVHJhY2s7XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZFN0cmVhbSA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICBpZiAoIXRoaXMuX2xvY2FsU3RyZWFtcykge1xuICAgICAgICAgIHRoaXMuX2xvY2FsU3RyZWFtcyA9IFtdO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLl9sb2NhbFN0cmVhbXMuaW5kZXhPZihzdHJlYW0pID09PSAtMSkge1xuICAgICAgICAgIHRoaXMuX2xvY2FsU3RyZWFtcy5wdXNoKHN0cmVhbSk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICBzdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbih0cmFjaykge1xuICAgICAgICAgIF9hZGRUcmFjay5jYWxsKHNlbGYsIHRyYWNrLCBzdHJlYW0pO1xuICAgICAgICB9KTtcbiAgICAgIH07XG5cbiAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkVHJhY2sgPSBmdW5jdGlvbih0cmFjaywgc3RyZWFtKSB7XG4gICAgICAgIGlmIChzdHJlYW0pIHtcbiAgICAgICAgICBpZiAoIXRoaXMuX2xvY2FsU3RyZWFtcykge1xuICAgICAgICAgICAgdGhpcy5fbG9jYWxTdHJlYW1zID0gW3N0cmVhbV07XG4gICAgICAgICAgfSBlbHNlIGlmICh0aGlzLl9sb2NhbFN0cmVhbXMuaW5kZXhPZihzdHJlYW0pID09PSAtMSkge1xuICAgICAgICAgICAgdGhpcy5fbG9jYWxTdHJlYW1zLnB1c2goc3RyZWFtKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgX2FkZFRyYWNrLmNhbGwodGhpcywgdHJhY2ssIHN0cmVhbSk7XG4gICAgICB9O1xuICAgIH1cbiAgICBpZiAoISgncmVtb3ZlU3RyZWFtJyBpbiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlKSkge1xuICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5yZW1vdmVTdHJlYW0gPSBmdW5jdGlvbihzdHJlYW0pIHtcbiAgICAgICAgaWYgKCF0aGlzLl9sb2NhbFN0cmVhbXMpIHtcbiAgICAgICAgICB0aGlzLl9sb2NhbFN0cmVhbXMgPSBbXTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgaW5kZXggPSB0aGlzLl9sb2NhbFN0cmVhbXMuaW5kZXhPZihzdHJlYW0pO1xuICAgICAgICBpZiAoaW5kZXggPT09IC0xKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX2xvY2FsU3RyZWFtcy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHZhciB0cmFja3MgPSBzdHJlYW0uZ2V0VHJhY2tzKCk7XG4gICAgICAgIHRoaXMuZ2V0U2VuZGVycygpLmZvckVhY2goZnVuY3Rpb24oc2VuZGVyKSB7XG4gICAgICAgICAgaWYgKHRyYWNrcy5pbmRleE9mKHNlbmRlci50cmFjaykgIT09IC0xKSB7XG4gICAgICAgICAgICBzZWxmLnJlbW92ZVRyYWNrKHNlbmRlcik7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgfVxuICB9LFxuICBzaGltUmVtb3RlU3RyZWFtc0FQSTogZnVuY3Rpb24od2luZG93KSB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgIT09ICdvYmplY3QnIHx8ICF3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCEoJ2dldFJlbW90ZVN0cmVhbXMnIGluIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUpKSB7XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFJlbW90ZVN0cmVhbXMgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3JlbW90ZVN0cmVhbXMgPyB0aGlzLl9yZW1vdGVTdHJlYW1zIDogW107XG4gICAgICB9O1xuICAgIH1cbiAgICBpZiAoISgnb25hZGRzdHJlYW0nIGluIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUpKSB7XG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkod2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZSwgJ29uYWRkc3RyZWFtJywge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHJldHVybiB0aGlzLl9vbmFkZHN0cmVhbTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbihmKSB7XG4gICAgICAgICAgaWYgKHRoaXMuX29uYWRkc3RyZWFtKSB7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2FkZHN0cmVhbScsIHRoaXMuX29uYWRkc3RyZWFtKTtcbiAgICAgICAgICAgIHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcigndHJhY2snLCB0aGlzLl9vbmFkZHN0cmVhbXBvbHkpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXIoJ2FkZHN0cmVhbScsIHRoaXMuX29uYWRkc3RyZWFtID0gZik7XG4gICAgICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVyKCd0cmFjaycsIHRoaXMuX29uYWRkc3RyZWFtcG9seSA9IGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgICAgIHZhciBzdHJlYW0gPSBlLnN0cmVhbXNbMF07XG4gICAgICAgICAgICBpZiAoIXRoaXMuX3JlbW90ZVN0cmVhbXMpIHtcbiAgICAgICAgICAgICAgdGhpcy5fcmVtb3RlU3RyZWFtcyA9IFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRoaXMuX3JlbW90ZVN0cmVhbXMuaW5kZXhPZihzdHJlYW0pID49IDApIHtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5fcmVtb3RlU3RyZWFtcy5wdXNoKHN0cmVhbSk7XG4gICAgICAgICAgICB2YXIgZXZlbnQgPSBuZXcgRXZlbnQoJ2FkZHN0cmVhbScpO1xuICAgICAgICAgICAgZXZlbnQuc3RyZWFtID0gZS5zdHJlYW1zWzBdO1xuICAgICAgICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH0sXG4gIHNoaW1DYWxsYmFja3NBUEk6IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSAnb2JqZWN0JyB8fCAhd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHZhciBwcm90b3R5cGUgPSB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlO1xuICAgIHZhciBjcmVhdGVPZmZlciA9IHByb3RvdHlwZS5jcmVhdGVPZmZlcjtcbiAgICB2YXIgY3JlYXRlQW5zd2VyID0gcHJvdG90eXBlLmNyZWF0ZUFuc3dlcjtcbiAgICB2YXIgc2V0TG9jYWxEZXNjcmlwdGlvbiA9IHByb3RvdHlwZS5zZXRMb2NhbERlc2NyaXB0aW9uO1xuICAgIHZhciBzZXRSZW1vdGVEZXNjcmlwdGlvbiA9IHByb3RvdHlwZS5zZXRSZW1vdGVEZXNjcmlwdGlvbjtcbiAgICB2YXIgYWRkSWNlQ2FuZGlkYXRlID0gcHJvdG90eXBlLmFkZEljZUNhbmRpZGF0ZTtcblxuICAgIHByb3RvdHlwZS5jcmVhdGVPZmZlciA9IGZ1bmN0aW9uKHN1Y2Nlc3NDYWxsYmFjaywgZmFpbHVyZUNhbGxiYWNrKSB7XG4gICAgICB2YXIgb3B0aW9ucyA9IChhcmd1bWVudHMubGVuZ3RoID49IDIpID8gYXJndW1lbnRzWzJdIDogYXJndW1lbnRzWzBdO1xuICAgICAgdmFyIHByb21pc2UgPSBjcmVhdGVPZmZlci5hcHBseSh0aGlzLCBbb3B0aW9uc10pO1xuICAgICAgaWYgKCFmYWlsdXJlQ2FsbGJhY2spIHtcbiAgICAgICAgcmV0dXJuIHByb21pc2U7XG4gICAgICB9XG4gICAgICBwcm9taXNlLnRoZW4oc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2spO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH07XG5cbiAgICBwcm90b3R5cGUuY3JlYXRlQW5zd2VyID0gZnVuY3Rpb24oc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2spIHtcbiAgICAgIHZhciBvcHRpb25zID0gKGFyZ3VtZW50cy5sZW5ndGggPj0gMikgPyBhcmd1bWVudHNbMl0gOiBhcmd1bWVudHNbMF07XG4gICAgICB2YXIgcHJvbWlzZSA9IGNyZWF0ZUFuc3dlci5hcHBseSh0aGlzLCBbb3B0aW9uc10pO1xuICAgICAgaWYgKCFmYWlsdXJlQ2FsbGJhY2spIHtcbiAgICAgICAgcmV0dXJuIHByb21pc2U7XG4gICAgICB9XG4gICAgICBwcm9taXNlLnRoZW4oc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2spO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH07XG5cbiAgICB2YXIgd2l0aENhbGxiYWNrID0gZnVuY3Rpb24oZGVzY3JpcHRpb24sIHN1Y2Nlc3NDYWxsYmFjaywgZmFpbHVyZUNhbGxiYWNrKSB7XG4gICAgICB2YXIgcHJvbWlzZSA9IHNldExvY2FsRGVzY3JpcHRpb24uYXBwbHkodGhpcywgW2Rlc2NyaXB0aW9uXSk7XG4gICAgICBpZiAoIWZhaWx1cmVDYWxsYmFjaykge1xuICAgICAgICByZXR1cm4gcHJvbWlzZTtcbiAgICAgIH1cbiAgICAgIHByb21pc2UudGhlbihzdWNjZXNzQ2FsbGJhY2ssIGZhaWx1cmVDYWxsYmFjayk7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgfTtcbiAgICBwcm90b3R5cGUuc2V0TG9jYWxEZXNjcmlwdGlvbiA9IHdpdGhDYWxsYmFjaztcblxuICAgIHdpdGhDYWxsYmFjayA9IGZ1bmN0aW9uKGRlc2NyaXB0aW9uLCBzdWNjZXNzQ2FsbGJhY2ssIGZhaWx1cmVDYWxsYmFjaykge1xuICAgICAgdmFyIHByb21pc2UgPSBzZXRSZW1vdGVEZXNjcmlwdGlvbi5hcHBseSh0aGlzLCBbZGVzY3JpcHRpb25dKTtcbiAgICAgIGlmICghZmFpbHVyZUNhbGxiYWNrKSB7XG4gICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgICAgfVxuICAgICAgcHJvbWlzZS50aGVuKHN1Y2Nlc3NDYWxsYmFjaywgZmFpbHVyZUNhbGxiYWNrKTtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9O1xuICAgIHByb3RvdHlwZS5zZXRSZW1vdGVEZXNjcmlwdGlvbiA9IHdpdGhDYWxsYmFjaztcblxuICAgIHdpdGhDYWxsYmFjayA9IGZ1bmN0aW9uKGNhbmRpZGF0ZSwgc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2spIHtcbiAgICAgIHZhciBwcm9taXNlID0gYWRkSWNlQ2FuZGlkYXRlLmFwcGx5KHRoaXMsIFtjYW5kaWRhdGVdKTtcbiAgICAgIGlmICghZmFpbHVyZUNhbGxiYWNrKSB7XG4gICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgICAgfVxuICAgICAgcHJvbWlzZS50aGVuKHN1Y2Nlc3NDYWxsYmFjaywgZmFpbHVyZUNhbGxiYWNrKTtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9O1xuICAgIHByb3RvdHlwZS5hZGRJY2VDYW5kaWRhdGUgPSB3aXRoQ2FsbGJhY2s7XG4gIH0sXG4gIHNoaW1HZXRVc2VyTWVkaWE6IGZ1bmN0aW9uKHdpbmRvdykge1xuICAgIHZhciBuYXZpZ2F0b3IgPSB3aW5kb3cgJiYgd2luZG93Lm5hdmlnYXRvcjtcblxuICAgIGlmICghbmF2aWdhdG9yLmdldFVzZXJNZWRpYSkge1xuICAgICAgaWYgKG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEpIHtcbiAgICAgICAgbmF2aWdhdG9yLmdldFVzZXJNZWRpYSA9IG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEuYmluZChuYXZpZ2F0b3IpO1xuICAgICAgfSBlbHNlIGlmIChuYXZpZ2F0b3IubWVkaWFEZXZpY2VzICYmXG4gICAgICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEpIHtcbiAgICAgICAgbmF2aWdhdG9yLmdldFVzZXJNZWRpYSA9IGZ1bmN0aW9uKGNvbnN0cmFpbnRzLCBjYiwgZXJyY2IpIHtcbiAgICAgICAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYShjb25zdHJhaW50cylcbiAgICAgICAgICAudGhlbihjYiwgZXJyY2IpO1xuICAgICAgICB9LmJpbmQobmF2aWdhdG9yKTtcbiAgICAgIH1cbiAgICB9XG4gIH0sXG4gIHNoaW1SVENJY2VTZXJ2ZXJVcmxzOiBmdW5jdGlvbih3aW5kb3cpIHtcbiAgICAvLyBtaWdyYXRlIGZyb20gbm9uLXNwZWMgUlRDSWNlU2VydmVyLnVybCB0byBSVENJY2VTZXJ2ZXIudXJsc1xuICAgIHZhciBPcmlnUGVlckNvbm5lY3Rpb24gPSB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb247XG4gICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uID0gZnVuY3Rpb24ocGNDb25maWcsIHBjQ29uc3RyYWludHMpIHtcbiAgICAgIGlmIChwY0NvbmZpZyAmJiBwY0NvbmZpZy5pY2VTZXJ2ZXJzKSB7XG4gICAgICAgIHZhciBuZXdJY2VTZXJ2ZXJzID0gW107XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcGNDb25maWcuaWNlU2VydmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBzZXJ2ZXIgPSBwY0NvbmZpZy5pY2VTZXJ2ZXJzW2ldO1xuICAgICAgICAgIGlmICghc2VydmVyLmhhc093blByb3BlcnR5KCd1cmxzJykgJiZcbiAgICAgICAgICAgICAgc2VydmVyLmhhc093blByb3BlcnR5KCd1cmwnKSkge1xuICAgICAgICAgICAgdXRpbHMuZGVwcmVjYXRlZCgnUlRDSWNlU2VydmVyLnVybCcsICdSVENJY2VTZXJ2ZXIudXJscycpO1xuICAgICAgICAgICAgc2VydmVyID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShzZXJ2ZXIpKTtcbiAgICAgICAgICAgIHNlcnZlci51cmxzID0gc2VydmVyLnVybDtcbiAgICAgICAgICAgIGRlbGV0ZSBzZXJ2ZXIudXJsO1xuICAgICAgICAgICAgbmV3SWNlU2VydmVycy5wdXNoKHNlcnZlcik7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG5ld0ljZVNlcnZlcnMucHVzaChwY0NvbmZpZy5pY2VTZXJ2ZXJzW2ldKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcGNDb25maWcuaWNlU2VydmVycyA9IG5ld0ljZVNlcnZlcnM7XG4gICAgICB9XG4gICAgICByZXR1cm4gbmV3IE9yaWdQZWVyQ29ubmVjdGlvbihwY0NvbmZpZywgcGNDb25zdHJhaW50cyk7XG4gICAgfTtcbiAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlID0gT3JpZ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZTtcbiAgICAvLyB3cmFwIHN0YXRpYyBtZXRob2RzLiBDdXJyZW50bHkganVzdCBnZW5lcmF0ZUNlcnRpZmljYXRlLlxuICAgIGlmICgnZ2VuZXJhdGVDZXJ0aWZpY2F0ZScgaW4gd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uKSB7XG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkod2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLCAnZ2VuZXJhdGVDZXJ0aWZpY2F0ZScsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gT3JpZ1BlZXJDb25uZWN0aW9uLmdlbmVyYXRlQ2VydGlmaWNhdGU7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfSxcbiAgc2hpbVRyYWNrRXZlbnRUcmFuc2NlaXZlcjogZnVuY3Rpb24od2luZG93KSB7XG4gICAgLy8gQWRkIGV2ZW50LnRyYW5zY2VpdmVyIG1lbWJlciBvdmVyIGRlcHJlY2F0ZWQgZXZlbnQucmVjZWl2ZXJcbiAgICBpZiAodHlwZW9mIHdpbmRvdyA9PT0gJ29iamVjdCcgJiYgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uICYmXG4gICAgICAgICgncmVjZWl2ZXInIGluIHdpbmRvdy5SVENUcmFja0V2ZW50LnByb3RvdHlwZSkgJiZcbiAgICAgICAgLy8gY2FuJ3QgY2hlY2sgJ3RyYW5zY2VpdmVyJyBpbiB3aW5kb3cuUlRDVHJhY2tFdmVudC5wcm90b3R5cGUsIGFzIGl0IGlzXG4gICAgICAgIC8vIGRlZmluZWQgZm9yIHNvbWUgcmVhc29uIGV2ZW4gd2hlbiB3aW5kb3cuUlRDVHJhbnNjZWl2ZXIgaXMgbm90LlxuICAgICAgICAhd2luZG93LlJUQ1RyYW5zY2VpdmVyKSB7XG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkod2luZG93LlJUQ1RyYWNrRXZlbnQucHJvdG90eXBlLCAndHJhbnNjZWl2ZXInLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgcmV0dXJuIHtyZWNlaXZlcjogdGhpcy5yZWNlaXZlcn07XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfVxufTtcblxuLy8gRXhwb3NlIHB1YmxpYyBtZXRob2RzLlxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHNoaW1DYWxsYmFja3NBUEk6IHNhZmFyaVNoaW0uc2hpbUNhbGxiYWNrc0FQSSxcbiAgc2hpbUxvY2FsU3RyZWFtc0FQSTogc2FmYXJpU2hpbS5zaGltTG9jYWxTdHJlYW1zQVBJLFxuICBzaGltUmVtb3RlU3RyZWFtc0FQSTogc2FmYXJpU2hpbS5zaGltUmVtb3RlU3RyZWFtc0FQSSxcbiAgc2hpbUdldFVzZXJNZWRpYTogc2FmYXJpU2hpbS5zaGltR2V0VXNlck1lZGlhLFxuICBzaGltUlRDSWNlU2VydmVyVXJsczogc2FmYXJpU2hpbS5zaGltUlRDSWNlU2VydmVyVXJscyxcbiAgc2hpbVRyYWNrRXZlbnRUcmFuc2NlaXZlcjogc2FmYXJpU2hpbS5zaGltVHJhY2tFdmVudFRyYW5zY2VpdmVyXG4gIC8vIFRPRE9cbiAgLy8gc2hpbVBlZXJDb25uZWN0aW9uOiBzYWZhcmlTaGltLnNoaW1QZWVyQ29ubmVjdGlvblxufTtcbiIsIi8qXG4gKiAgQ29weXJpZ2h0IChjKSAyMDE2IFRoZSBXZWJSVEMgcHJvamVjdCBhdXRob3JzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqICBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhIEJTRC1zdHlsZSBsaWNlbnNlXG4gKiAgdGhhdCBjYW4gYmUgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBvZiB0aGUgc291cmNlXG4gKiAgdHJlZS5cbiAqL1xuIC8qIGVzbGludC1lbnYgbm9kZSAqL1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgbG9nRGlzYWJsZWRfID0gdHJ1ZTtcbnZhciBkZXByZWNhdGlvbldhcm5pbmdzXyA9IHRydWU7XG5cbi8vIFV0aWxpdHkgbWV0aG9kcy5cbnZhciB1dGlscyA9IHtcbiAgZGlzYWJsZUxvZzogZnVuY3Rpb24oYm9vbCkge1xuICAgIGlmICh0eXBlb2YgYm9vbCAhPT0gJ2Jvb2xlYW4nKSB7XG4gICAgICByZXR1cm4gbmV3IEVycm9yKCdBcmd1bWVudCB0eXBlOiAnICsgdHlwZW9mIGJvb2wgK1xuICAgICAgICAgICcuIFBsZWFzZSB1c2UgYSBib29sZWFuLicpO1xuICAgIH1cbiAgICBsb2dEaXNhYmxlZF8gPSBib29sO1xuICAgIHJldHVybiAoYm9vbCkgPyAnYWRhcHRlci5qcyBsb2dnaW5nIGRpc2FibGVkJyA6XG4gICAgICAgICdhZGFwdGVyLmpzIGxvZ2dpbmcgZW5hYmxlZCc7XG4gIH0sXG5cbiAgLyoqXG4gICAqIERpc2FibGUgb3IgZW5hYmxlIGRlcHJlY2F0aW9uIHdhcm5pbmdzXG4gICAqIEBwYXJhbSB7IWJvb2xlYW59IGJvb2wgc2V0IHRvIHRydWUgdG8gZGlzYWJsZSB3YXJuaW5ncy5cbiAgICovXG4gIGRpc2FibGVXYXJuaW5nczogZnVuY3Rpb24oYm9vbCkge1xuICAgIGlmICh0eXBlb2YgYm9vbCAhPT0gJ2Jvb2xlYW4nKSB7XG4gICAgICByZXR1cm4gbmV3IEVycm9yKCdBcmd1bWVudCB0eXBlOiAnICsgdHlwZW9mIGJvb2wgK1xuICAgICAgICAgICcuIFBsZWFzZSB1c2UgYSBib29sZWFuLicpO1xuICAgIH1cbiAgICBkZXByZWNhdGlvbldhcm5pbmdzXyA9ICFib29sO1xuICAgIHJldHVybiAnYWRhcHRlci5qcyBkZXByZWNhdGlvbiB3YXJuaW5ncyAnICsgKGJvb2wgPyAnZGlzYWJsZWQnIDogJ2VuYWJsZWQnKTtcbiAgfSxcblxuICBsb2c6IGZ1bmN0aW9uKCkge1xuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAnb2JqZWN0Jykge1xuICAgICAgaWYgKGxvZ0Rpc2FibGVkXykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBpZiAodHlwZW9mIGNvbnNvbGUgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiBjb25zb2xlLmxvZyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBjb25zb2xlLmxvZy5hcHBseShjb25zb2xlLCBhcmd1bWVudHMpO1xuICAgICAgfVxuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogU2hvd3MgYSBkZXByZWNhdGlvbiB3YXJuaW5nIHN1Z2dlc3RpbmcgdGhlIG1vZGVybiBhbmQgc3BlYy1jb21wYXRpYmxlIEFQSS5cbiAgICovXG4gIGRlcHJlY2F0ZWQ6IGZ1bmN0aW9uKG9sZE1ldGhvZCwgbmV3TWV0aG9kKSB7XG4gICAgaWYgKCFkZXByZWNhdGlvbldhcm5pbmdzXykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zb2xlLndhcm4ob2xkTWV0aG9kICsgJyBpcyBkZXByZWNhdGVkLCBwbGVhc2UgdXNlICcgKyBuZXdNZXRob2QgK1xuICAgICAgICAnIGluc3RlYWQuJyk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEV4dHJhY3QgYnJvd3NlciB2ZXJzaW9uIG91dCBvZiB0aGUgcHJvdmlkZWQgdXNlciBhZ2VudCBzdHJpbmcuXG4gICAqXG4gICAqIEBwYXJhbSB7IXN0cmluZ30gdWFzdHJpbmcgdXNlckFnZW50IHN0cmluZy5cbiAgICogQHBhcmFtIHshc3RyaW5nfSBleHByIFJlZ3VsYXIgZXhwcmVzc2lvbiB1c2VkIGFzIG1hdGNoIGNyaXRlcmlhLlxuICAgKiBAcGFyYW0geyFudW1iZXJ9IHBvcyBwb3NpdGlvbiBpbiB0aGUgdmVyc2lvbiBzdHJpbmcgdG8gYmUgcmV0dXJuZWQuXG4gICAqIEByZXR1cm4geyFudW1iZXJ9IGJyb3dzZXIgdmVyc2lvbi5cbiAgICovXG4gIGV4dHJhY3RWZXJzaW9uOiBmdW5jdGlvbih1YXN0cmluZywgZXhwciwgcG9zKSB7XG4gICAgdmFyIG1hdGNoID0gdWFzdHJpbmcubWF0Y2goZXhwcik7XG4gICAgcmV0dXJuIG1hdGNoICYmIG1hdGNoLmxlbmd0aCA+PSBwb3MgJiYgcGFyc2VJbnQobWF0Y2hbcG9zXSwgMTApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBCcm93c2VyIGRldGVjdG9yLlxuICAgKlxuICAgKiBAcmV0dXJuIHtvYmplY3R9IHJlc3VsdCBjb250YWluaW5nIGJyb3dzZXIgYW5kIHZlcnNpb25cbiAgICogICAgIHByb3BlcnRpZXMuXG4gICAqL1xuICBkZXRlY3RCcm93c2VyOiBmdW5jdGlvbih3aW5kb3cpIHtcbiAgICB2YXIgbmF2aWdhdG9yID0gd2luZG93ICYmIHdpbmRvdy5uYXZpZ2F0b3I7XG5cbiAgICAvLyBSZXR1cm5lZCByZXN1bHQgb2JqZWN0LlxuICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICByZXN1bHQuYnJvd3NlciA9IG51bGw7XG4gICAgcmVzdWx0LnZlcnNpb24gPSBudWxsO1xuXG4gICAgLy8gRmFpbCBlYXJseSBpZiBpdCdzIG5vdCBhIGJyb3dzZXJcbiAgICBpZiAodHlwZW9mIHdpbmRvdyA9PT0gJ3VuZGVmaW5lZCcgfHwgIXdpbmRvdy5uYXZpZ2F0b3IpIHtcbiAgICAgIHJlc3VsdC5icm93c2VyID0gJ05vdCBhIGJyb3dzZXIuJztcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLy8gRmlyZWZveC5cbiAgICBpZiAobmF2aWdhdG9yLm1vekdldFVzZXJNZWRpYSkge1xuICAgICAgcmVzdWx0LmJyb3dzZXIgPSAnZmlyZWZveCc7XG4gICAgICByZXN1bHQudmVyc2lvbiA9IHRoaXMuZXh0cmFjdFZlcnNpb24obmF2aWdhdG9yLnVzZXJBZ2VudCxcbiAgICAgICAgICAvRmlyZWZveFxcLyhcXGQrKVxcLi8sIDEpO1xuICAgIH0gZWxzZSBpZiAobmF2aWdhdG9yLndlYmtpdEdldFVzZXJNZWRpYSkge1xuICAgICAgLy8gQ2hyb21lLCBDaHJvbWl1bSwgV2VidmlldywgT3BlcmEsIGFsbCB1c2UgdGhlIGNocm9tZSBzaGltIGZvciBub3dcbiAgICAgIGlmICh3aW5kb3cud2Via2l0UlRDUGVlckNvbm5lY3Rpb24pIHtcbiAgICAgICAgcmVzdWx0LmJyb3dzZXIgPSAnY2hyb21lJztcbiAgICAgICAgcmVzdWx0LnZlcnNpb24gPSB0aGlzLmV4dHJhY3RWZXJzaW9uKG5hdmlnYXRvci51c2VyQWdlbnQsXG4gICAgICAgICAgL0Nocm9tKGV8aXVtKVxcLyhcXGQrKVxcLi8sIDIpO1xuICAgICAgfSBlbHNlIHsgLy8gU2FmYXJpIChpbiBhbiB1bnB1Ymxpc2hlZCB2ZXJzaW9uKSBvciB1bmtub3duIHdlYmtpdC1iYXNlZC5cbiAgICAgICAgaWYgKG5hdmlnYXRvci51c2VyQWdlbnQubWF0Y2goL1ZlcnNpb25cXC8oXFxkKykuKFxcZCspLykpIHtcbiAgICAgICAgICByZXN1bHQuYnJvd3NlciA9ICdzYWZhcmknO1xuICAgICAgICAgIHJlc3VsdC52ZXJzaW9uID0gdGhpcy5leHRyYWN0VmVyc2lvbihuYXZpZ2F0b3IudXNlckFnZW50LFxuICAgICAgICAgICAgL0FwcGxlV2ViS2l0XFwvKFxcZCspXFwuLywgMSk7XG4gICAgICAgIH0gZWxzZSB7IC8vIHVua25vd24gd2Via2l0LWJhc2VkIGJyb3dzZXIuXG4gICAgICAgICAgcmVzdWx0LmJyb3dzZXIgPSAnVW5zdXBwb3J0ZWQgd2Via2l0LWJhc2VkIGJyb3dzZXIgJyArXG4gICAgICAgICAgICAgICd3aXRoIEdVTSBzdXBwb3J0IGJ1dCBubyBXZWJSVEMgc3VwcG9ydC4nO1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKG5hdmlnYXRvci5tZWRpYURldmljZXMgJiZcbiAgICAgICAgbmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgvRWRnZVxcLyhcXGQrKS4oXFxkKykkLykpIHsgLy8gRWRnZS5cbiAgICAgIHJlc3VsdC5icm93c2VyID0gJ2VkZ2UnO1xuICAgICAgcmVzdWx0LnZlcnNpb24gPSB0aGlzLmV4dHJhY3RWZXJzaW9uKG5hdmlnYXRvci51c2VyQWdlbnQsXG4gICAgICAgICAgL0VkZ2VcXC8oXFxkKykuKFxcZCspJC8sIDIpO1xuICAgIH0gZWxzZSBpZiAobmF2aWdhdG9yLm1lZGlhRGV2aWNlcyAmJlxuICAgICAgICBuYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKC9BcHBsZVdlYktpdFxcLyhcXGQrKVxcLi8pKSB7XG4gICAgICAgIC8vIFNhZmFyaSwgd2l0aCB3ZWJraXRHZXRVc2VyTWVkaWEgcmVtb3ZlZC5cbiAgICAgIHJlc3VsdC5icm93c2VyID0gJ3NhZmFyaSc7XG4gICAgICByZXN1bHQudmVyc2lvbiA9IHRoaXMuZXh0cmFjdFZlcnNpb24obmF2aWdhdG9yLnVzZXJBZ2VudCxcbiAgICAgICAgICAvQXBwbGVXZWJLaXRcXC8oXFxkKylcXC4vLCAxKTtcbiAgICB9IGVsc2UgeyAvLyBEZWZhdWx0IGZhbGx0aHJvdWdoOiBub3Qgc3VwcG9ydGVkLlxuICAgICAgcmVzdWx0LmJyb3dzZXIgPSAnTm90IGEgc3VwcG9ydGVkIGJyb3dzZXIuJztcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSxcblxufTtcblxuLy8gRXhwb3J0LlxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGxvZzogdXRpbHMubG9nLFxuICBkZXByZWNhdGVkOiB1dGlscy5kZXByZWNhdGVkLFxuICBkaXNhYmxlTG9nOiB1dGlscy5kaXNhYmxlTG9nLFxuICBkaXNhYmxlV2FybmluZ3M6IHV0aWxzLmRpc2FibGVXYXJuaW5ncyxcbiAgZXh0cmFjdFZlcnNpb246IHV0aWxzLmV4dHJhY3RWZXJzaW9uLFxuICBzaGltQ3JlYXRlT2JqZWN0VVJMOiB1dGlscy5zaGltQ3JlYXRlT2JqZWN0VVJMLFxuICBkZXRlY3RCcm93c2VyOiB1dGlscy5kZXRlY3RCcm93c2VyLmJpbmQodXRpbHMpXG59O1xuIiwiLypcclxuV2lsZEVtaXR0ZXIuanMgaXMgYSBzbGltIGxpdHRsZSBldmVudCBlbWl0dGVyIGJ5IEBoZW5yaWtqb3JldGVnIGxhcmdlbHkgYmFzZWRcclxub24gQHZpc2lvbm1lZGlhJ3MgRW1pdHRlciBmcm9tIFVJIEtpdC5cclxuXHJcbldoeT8gSSB3YW50ZWQgaXQgc3RhbmRhbG9uZS5cclxuXHJcbkkgYWxzbyB3YW50ZWQgc3VwcG9ydCBmb3Igd2lsZGNhcmQgZW1pdHRlcnMgbGlrZSB0aGlzOlxyXG5cclxuZW1pdHRlci5vbignKicsIGZ1bmN0aW9uIChldmVudE5hbWUsIG90aGVyLCBldmVudCwgcGF5bG9hZHMpIHtcclxuXHJcbn0pO1xyXG5cclxuZW1pdHRlci5vbignc29tZW5hbWVzcGFjZSonLCBmdW5jdGlvbiAoZXZlbnROYW1lLCBwYXlsb2Fkcykge1xyXG5cclxufSk7XHJcblxyXG5QbGVhc2Ugbm90ZSB0aGF0IGNhbGxiYWNrcyB0cmlnZ2VyZWQgYnkgd2lsZGNhcmQgcmVnaXN0ZXJlZCBldmVudHMgYWxzbyBnZXRcclxudGhlIGV2ZW50IG5hbWUgYXMgdGhlIGZpcnN0IGFyZ3VtZW50LlxyXG4qL1xyXG5cclxubW9kdWxlLmV4cG9ydHMgPSBXaWxkRW1pdHRlcjtcclxuXHJcbmZ1bmN0aW9uIFdpbGRFbWl0dGVyKCkgeyB9XHJcblxyXG5XaWxkRW1pdHRlci5taXhpbiA9IGZ1bmN0aW9uIChjb25zdHJ1Y3Rvcikge1xyXG4gICAgdmFyIHByb3RvdHlwZSA9IGNvbnN0cnVjdG9yLnByb3RvdHlwZSB8fCBjb25zdHJ1Y3RvcjtcclxuXHJcbiAgICBwcm90b3R5cGUuaXNXaWxkRW1pdHRlcj0gdHJ1ZTtcclxuXHJcbiAgICAvLyBMaXN0ZW4gb24gdGhlIGdpdmVuIGBldmVudGAgd2l0aCBgZm5gLiBTdG9yZSBhIGdyb3VwIG5hbWUgaWYgcHJlc2VudC5cclxuICAgIHByb3RvdHlwZS5vbiA9IGZ1bmN0aW9uIChldmVudCwgZ3JvdXBOYW1lLCBmbikge1xyXG4gICAgICAgIHRoaXMuY2FsbGJhY2tzID0gdGhpcy5jYWxsYmFja3MgfHwge307XHJcbiAgICAgICAgdmFyIGhhc0dyb3VwID0gKGFyZ3VtZW50cy5sZW5ndGggPT09IDMpLFxyXG4gICAgICAgICAgICBncm91cCA9IGhhc0dyb3VwID8gYXJndW1lbnRzWzFdIDogdW5kZWZpbmVkLFxyXG4gICAgICAgICAgICBmdW5jID0gaGFzR3JvdXAgPyBhcmd1bWVudHNbMl0gOiBhcmd1bWVudHNbMV07XHJcbiAgICAgICAgZnVuYy5fZ3JvdXBOYW1lID0gZ3JvdXA7XHJcbiAgICAgICAgKHRoaXMuY2FsbGJhY2tzW2V2ZW50XSA9IHRoaXMuY2FsbGJhY2tzW2V2ZW50XSB8fCBbXSkucHVzaChmdW5jKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH07XHJcblxyXG4gICAgLy8gQWRkcyBhbiBgZXZlbnRgIGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIGEgc2luZ2xlXHJcbiAgICAvLyB0aW1lIHRoZW4gYXV0b21hdGljYWxseSByZW1vdmVkLlxyXG4gICAgcHJvdG90eXBlLm9uY2UgPSBmdW5jdGlvbiAoZXZlbnQsIGdyb3VwTmFtZSwgZm4pIHtcclxuICAgICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgICAgIGhhc0dyb3VwID0gKGFyZ3VtZW50cy5sZW5ndGggPT09IDMpLFxyXG4gICAgICAgICAgICBncm91cCA9IGhhc0dyb3VwID8gYXJndW1lbnRzWzFdIDogdW5kZWZpbmVkLFxyXG4gICAgICAgICAgICBmdW5jID0gaGFzR3JvdXAgPyBhcmd1bWVudHNbMl0gOiBhcmd1bWVudHNbMV07XHJcbiAgICAgICAgZnVuY3Rpb24gb24oKSB7XHJcbiAgICAgICAgICAgIHNlbGYub2ZmKGV2ZW50LCBvbik7XHJcbiAgICAgICAgICAgIGZ1bmMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5vbihldmVudCwgZ3JvdXAsIG9uKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH07XHJcblxyXG4gICAgLy8gVW5iaW5kcyBhbiBlbnRpcmUgZ3JvdXBcclxuICAgIHByb3RvdHlwZS5yZWxlYXNlR3JvdXAgPSBmdW5jdGlvbiAoZ3JvdXBOYW1lKSB7XHJcbiAgICAgICAgdGhpcy5jYWxsYmFja3MgPSB0aGlzLmNhbGxiYWNrcyB8fCB7fTtcclxuICAgICAgICB2YXIgaXRlbSwgaSwgbGVuLCBoYW5kbGVycztcclxuICAgICAgICBmb3IgKGl0ZW0gaW4gdGhpcy5jYWxsYmFja3MpIHtcclxuICAgICAgICAgICAgaGFuZGxlcnMgPSB0aGlzLmNhbGxiYWNrc1tpdGVtXTtcclxuICAgICAgICAgICAgZm9yIChpID0gMCwgbGVuID0gaGFuZGxlcnMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuICAgICAgICAgICAgICAgIGlmIChoYW5kbGVyc1tpXS5fZ3JvdXBOYW1lID09PSBncm91cE5hbWUpIHtcclxuICAgICAgICAgICAgICAgICAgICAvL2NvbnNvbGUubG9nKCdyZW1vdmluZycpO1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSBpdCBhbmQgc2hvcnRlbiB0aGUgYXJyYXkgd2UncmUgbG9vcGluZyB0aHJvdWdoXHJcbiAgICAgICAgICAgICAgICAgICAgaGFuZGxlcnMuc3BsaWNlKGksIDEpO1xyXG4gICAgICAgICAgICAgICAgICAgIGktLTtcclxuICAgICAgICAgICAgICAgICAgICBsZW4tLTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH07XHJcblxyXG4gICAgLy8gUmVtb3ZlIHRoZSBnaXZlbiBjYWxsYmFjayBmb3IgYGV2ZW50YCBvciBhbGxcclxuICAgIC8vIHJlZ2lzdGVyZWQgY2FsbGJhY2tzLlxyXG4gICAgcHJvdG90eXBlLm9mZiA9IGZ1bmN0aW9uIChldmVudCwgZm4pIHtcclxuICAgICAgICB0aGlzLmNhbGxiYWNrcyA9IHRoaXMuY2FsbGJhY2tzIHx8IHt9O1xyXG4gICAgICAgIHZhciBjYWxsYmFja3MgPSB0aGlzLmNhbGxiYWNrc1tldmVudF0sXHJcbiAgICAgICAgICAgIGk7XHJcblxyXG4gICAgICAgIGlmICghY2FsbGJhY2tzKSByZXR1cm4gdGhpcztcclxuXHJcbiAgICAgICAgLy8gcmVtb3ZlIGFsbCBoYW5kbGVyc1xyXG4gICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAxKSB7XHJcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmNhbGxiYWNrc1tldmVudF07XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gcmVtb3ZlIHNwZWNpZmljIGhhbmRsZXJcclxuICAgICAgICBpID0gY2FsbGJhY2tzLmluZGV4T2YoZm4pO1xyXG4gICAgICAgIGNhbGxiYWNrcy5zcGxpY2UoaSwgMSk7XHJcbiAgICAgICAgaWYgKGNhbGxiYWNrcy5sZW5ndGggPT09IDApIHtcclxuICAgICAgICAgICAgZGVsZXRlIHRoaXMuY2FsbGJhY2tzW2V2ZW50XTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9O1xyXG5cclxuICAgIC8vLyBFbWl0IGBldmVudGAgd2l0aCB0aGUgZ2l2ZW4gYXJncy5cclxuICAgIC8vIGFsc28gY2FsbHMgYW55IGAqYCBoYW5kbGVyc1xyXG4gICAgcHJvdG90eXBlLmVtaXQgPSBmdW5jdGlvbiAoZXZlbnQpIHtcclxuICAgICAgICB0aGlzLmNhbGxiYWNrcyA9IHRoaXMuY2FsbGJhY2tzIHx8IHt9O1xyXG4gICAgICAgIHZhciBhcmdzID0gW10uc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpLFxyXG4gICAgICAgICAgICBjYWxsYmFja3MgPSB0aGlzLmNhbGxiYWNrc1tldmVudF0sXHJcbiAgICAgICAgICAgIHNwZWNpYWxDYWxsYmFja3MgPSB0aGlzLmdldFdpbGRjYXJkQ2FsbGJhY2tzKGV2ZW50KSxcclxuICAgICAgICAgICAgaSxcclxuICAgICAgICAgICAgbGVuLFxyXG4gICAgICAgICAgICBpdGVtLFxyXG4gICAgICAgICAgICBsaXN0ZW5lcnM7XHJcblxyXG4gICAgICAgIGlmIChjYWxsYmFja3MpIHtcclxuICAgICAgICAgICAgbGlzdGVuZXJzID0gY2FsbGJhY2tzLnNsaWNlKCk7XHJcbiAgICAgICAgICAgIGZvciAoaSA9IDAsIGxlbiA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBsZW47ICsraSkge1xyXG4gICAgICAgICAgICAgICAgaWYgKCFsaXN0ZW5lcnNbaV0pIHtcclxuICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGxpc3RlbmVyc1tpXS5hcHBseSh0aGlzLCBhcmdzKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHNwZWNpYWxDYWxsYmFja3MpIHtcclxuICAgICAgICAgICAgbGVuID0gc3BlY2lhbENhbGxiYWNrcy5sZW5ndGg7XHJcbiAgICAgICAgICAgIGxpc3RlbmVycyA9IHNwZWNpYWxDYWxsYmFja3Muc2xpY2UoKTtcclxuICAgICAgICAgICAgZm9yIChpID0gMCwgbGVuID0gbGlzdGVuZXJzLmxlbmd0aDsgaSA8IGxlbjsgKytpKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoIWxpc3RlbmVyc1tpXSkge1xyXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgbGlzdGVuZXJzW2ldLmFwcGx5KHRoaXMsIFtldmVudF0uY29uY2F0KGFyZ3MpKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9O1xyXG5cclxuICAgIC8vIEhlbHBlciBmb3IgZm9yIGZpbmRpbmcgc3BlY2lhbCB3aWxkY2FyZCBldmVudCBoYW5kbGVycyB0aGF0IG1hdGNoIHRoZSBldmVudFxyXG4gICAgcHJvdG90eXBlLmdldFdpbGRjYXJkQ2FsbGJhY2tzID0gZnVuY3Rpb24gKGV2ZW50TmFtZSkge1xyXG4gICAgICAgIHRoaXMuY2FsbGJhY2tzID0gdGhpcy5jYWxsYmFja3MgfHwge307XHJcbiAgICAgICAgdmFyIGl0ZW0sXHJcbiAgICAgICAgICAgIHNwbGl0LFxyXG4gICAgICAgICAgICByZXN1bHQgPSBbXTtcclxuXHJcbiAgICAgICAgZm9yIChpdGVtIGluIHRoaXMuY2FsbGJhY2tzKSB7XHJcbiAgICAgICAgICAgIHNwbGl0ID0gaXRlbS5zcGxpdCgnKicpO1xyXG4gICAgICAgICAgICBpZiAoaXRlbSA9PT0gJyonIHx8IChzcGxpdC5sZW5ndGggPT09IDIgJiYgZXZlbnROYW1lLnNsaWNlKDAsIHNwbGl0WzBdLmxlbmd0aCkgPT09IHNwbGl0WzBdKSkge1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0ID0gcmVzdWx0LmNvbmNhdCh0aGlzLmNhbGxiYWNrc1tpdGVtXSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH07XHJcblxyXG59O1xyXG5cclxuV2lsZEVtaXR0ZXIubWl4aW4oV2lsZEVtaXR0ZXIpO1xyXG4iLCIvKiFcbiAqIEV2ZW50RW1pdHRlciB2NC4yLjkgLSBnaXQuaW8vZWVcbiAqIE9saXZlciBDYWxkd2VsbFxuICogTUlUIGxpY2Vuc2VcbiAqIEBwcmVzZXJ2ZVxuICovXG5cbihmdW5jdGlvbiAoKSB7XG4gICAgJ3VzZSBzdHJpY3QnO1xuXG4gICAgLyoqXG4gICAgICogQ2xhc3MgZm9yIG1hbmFnaW5nIGV2ZW50cy5cbiAgICAgKiBDYW4gYmUgZXh0ZW5kZWQgdG8gcHJvdmlkZSBldmVudCBmdW5jdGlvbmFsaXR5IGluIG90aGVyIGNsYXNzZXMuXG4gICAgICpcbiAgICAgKiBAY2xhc3MgRXZlbnRFbWl0dGVyIE1hbmFnZXMgZXZlbnQgcmVnaXN0ZXJpbmcgYW5kIGVtaXR0aW5nLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIEV2ZW50RW1pdHRlcigpIHt9XG5cbiAgICAvLyBTaG9ydGN1dHMgdG8gaW1wcm92ZSBzcGVlZCBhbmQgc2l6ZVxuICAgIHZhciBwcm90byA9IEV2ZW50RW1pdHRlci5wcm90b3R5cGU7XG4gICAgdmFyIGV4cG9ydHMgPSB0aGlzO1xuICAgIHZhciBvcmlnaW5hbEdsb2JhbFZhbHVlID0gZXhwb3J0cy5FdmVudEVtaXR0ZXI7XG5cbiAgICAvKipcbiAgICAgKiBGaW5kcyB0aGUgaW5kZXggb2YgdGhlIGxpc3RlbmVyIGZvciB0aGUgZXZlbnQgaW4gaXRzIHN0b3JhZ2UgYXJyYXkuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9uW119IGxpc3RlbmVycyBBcnJheSBvZiBsaXN0ZW5lcnMgdG8gc2VhcmNoIHRocm91Z2guXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gbGlzdGVuZXIgTWV0aG9kIHRvIGxvb2sgZm9yLlxuICAgICAqIEByZXR1cm4ge051bWJlcn0gSW5kZXggb2YgdGhlIHNwZWNpZmllZCBsaXN0ZW5lciwgLTEgaWYgbm90IGZvdW5kXG4gICAgICogQGFwaSBwcml2YXRlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaW5kZXhPZkxpc3RlbmVyKGxpc3RlbmVycywgbGlzdGVuZXIpIHtcbiAgICAgICAgdmFyIGkgPSBsaXN0ZW5lcnMubGVuZ3RoO1xuICAgICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgICAgICBpZiAobGlzdGVuZXJzW2ldLmxpc3RlbmVyID09PSBsaXN0ZW5lcikge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFsaWFzIGEgbWV0aG9kIHdoaWxlIGtlZXBpbmcgdGhlIGNvbnRleHQgY29ycmVjdCwgdG8gYWxsb3cgZm9yIG92ZXJ3cml0aW5nIG9mIHRhcmdldCBtZXRob2QuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBUaGUgbmFtZSBvZiB0aGUgdGFyZ2V0IG1ldGhvZC5cbiAgICAgKiBAcmV0dXJuIHtGdW5jdGlvbn0gVGhlIGFsaWFzZWQgbWV0aG9kXG4gICAgICogQGFwaSBwcml2YXRlXG4gICAgICovXG4gICAgZnVuY3Rpb24gYWxpYXMobmFtZSkge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gYWxpYXNDbG9zdXJlKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXNbbmFtZV0uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBsaXN0ZW5lciBhcnJheSBmb3IgdGhlIHNwZWNpZmllZCBldmVudC5cbiAgICAgKiBXaWxsIGluaXRpYWxpc2UgdGhlIGV2ZW50IG9iamVjdCBhbmQgbGlzdGVuZXIgYXJyYXlzIGlmIHJlcXVpcmVkLlxuICAgICAqIFdpbGwgcmV0dXJuIGFuIG9iamVjdCBpZiB5b3UgdXNlIGEgcmVnZXggc2VhcmNoLiBUaGUgb2JqZWN0IGNvbnRhaW5zIGtleXMgZm9yIGVhY2ggbWF0Y2hlZCBldmVudC4gU28gL2JhW3J6XS8gbWlnaHQgcmV0dXJuIGFuIG9iamVjdCBjb250YWluaW5nIGJhciBhbmQgYmF6LiBCdXQgb25seSBpZiB5b3UgaGF2ZSBlaXRoZXIgZGVmaW5lZCB0aGVtIHdpdGggZGVmaW5lRXZlbnQgb3IgYWRkZWQgc29tZSBsaXN0ZW5lcnMgdG8gdGhlbS5cbiAgICAgKiBFYWNoIHByb3BlcnR5IGluIHRoZSBvYmplY3QgcmVzcG9uc2UgaXMgYW4gYXJyYXkgb2YgbGlzdGVuZXIgZnVuY3Rpb25zLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBldnQgTmFtZSBvZiB0aGUgZXZlbnQgdG8gcmV0dXJuIHRoZSBsaXN0ZW5lcnMgZnJvbS5cbiAgICAgKiBAcmV0dXJuIHtGdW5jdGlvbltdfE9iamVjdH0gQWxsIGxpc3RlbmVyIGZ1bmN0aW9ucyBmb3IgdGhlIGV2ZW50LlxuICAgICAqL1xuICAgIHByb3RvLmdldExpc3RlbmVycyA9IGZ1bmN0aW9uIGdldExpc3RlbmVycyhldnQpIHtcbiAgICAgICAgdmFyIGV2ZW50cyA9IHRoaXMuX2dldEV2ZW50cygpO1xuICAgICAgICB2YXIgcmVzcG9uc2U7XG4gICAgICAgIHZhciBrZXk7XG5cbiAgICAgICAgLy8gUmV0dXJuIGEgY29uY2F0ZW5hdGVkIGFycmF5IG9mIGFsbCBtYXRjaGluZyBldmVudHMgaWZcbiAgICAgICAgLy8gdGhlIHNlbGVjdG9yIGlzIGEgcmVndWxhciBleHByZXNzaW9uLlxuICAgICAgICBpZiAoZXZ0IGluc3RhbmNlb2YgUmVnRXhwKSB7XG4gICAgICAgICAgICByZXNwb25zZSA9IHt9O1xuICAgICAgICAgICAgZm9yIChrZXkgaW4gZXZlbnRzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGV2ZW50cy5oYXNPd25Qcm9wZXJ0eShrZXkpICYmIGV2dC50ZXN0KGtleSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2Vba2V5XSA9IGV2ZW50c1trZXldO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJlc3BvbnNlID0gZXZlbnRzW2V2dF0gfHwgKGV2ZW50c1tldnRdID0gW10pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBUYWtlcyBhIGxpc3Qgb2YgbGlzdGVuZXIgb2JqZWN0cyBhbmQgZmxhdHRlbnMgaXQgaW50byBhIGxpc3Qgb2YgbGlzdGVuZXIgZnVuY3Rpb25zLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtPYmplY3RbXX0gbGlzdGVuZXJzIFJhdyBsaXN0ZW5lciBvYmplY3RzLlxuICAgICAqIEByZXR1cm4ge0Z1bmN0aW9uW119IEp1c3QgdGhlIGxpc3RlbmVyIGZ1bmN0aW9ucy5cbiAgICAgKi9cbiAgICBwcm90by5mbGF0dGVuTGlzdGVuZXJzID0gZnVuY3Rpb24gZmxhdHRlbkxpc3RlbmVycyhsaXN0ZW5lcnMpIHtcbiAgICAgICAgdmFyIGZsYXRMaXN0ZW5lcnMgPSBbXTtcbiAgICAgICAgdmFyIGk7XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGxpc3RlbmVycy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICAgICAgZmxhdExpc3RlbmVycy5wdXNoKGxpc3RlbmVyc1tpXS5saXN0ZW5lcik7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmxhdExpc3RlbmVycztcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogRmV0Y2hlcyB0aGUgcmVxdWVzdGVkIGxpc3RlbmVycyB2aWEgZ2V0TGlzdGVuZXJzIGJ1dCB3aWxsIGFsd2F5cyByZXR1cm4gdGhlIHJlc3VsdHMgaW5zaWRlIGFuIG9iamVjdC4gVGhpcyBpcyBtYWlubHkgZm9yIGludGVybmFsIHVzZSBidXQgb3RoZXJzIG1heSBmaW5kIGl0IHVzZWZ1bC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gZXZ0IE5hbWUgb2YgdGhlIGV2ZW50IHRvIHJldHVybiB0aGUgbGlzdGVuZXJzIGZyb20uXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBBbGwgbGlzdGVuZXIgZnVuY3Rpb25zIGZvciBhbiBldmVudCBpbiBhbiBvYmplY3QuXG4gICAgICovXG4gICAgcHJvdG8uZ2V0TGlzdGVuZXJzQXNPYmplY3QgPSBmdW5jdGlvbiBnZXRMaXN0ZW5lcnNBc09iamVjdChldnQpIHtcbiAgICAgICAgdmFyIGxpc3RlbmVycyA9IHRoaXMuZ2V0TGlzdGVuZXJzKGV2dCk7XG4gICAgICAgIHZhciByZXNwb25zZTtcblxuICAgICAgICBpZiAobGlzdGVuZXJzIGluc3RhbmNlb2YgQXJyYXkpIHtcbiAgICAgICAgICAgIHJlc3BvbnNlID0ge307XG4gICAgICAgICAgICByZXNwb25zZVtldnRdID0gbGlzdGVuZXJzO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlIHx8IGxpc3RlbmVycztcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBzcGVjaWZpZWQgZXZlbnQuXG4gICAgICogVGhlIGxpc3RlbmVyIHdpbGwgbm90IGJlIGFkZGVkIGlmIGl0IGlzIGEgZHVwbGljYXRlLlxuICAgICAqIElmIHRoZSBsaXN0ZW5lciByZXR1cm5zIHRydWUgdGhlbiBpdCB3aWxsIGJlIHJlbW92ZWQgYWZ0ZXIgaXQgaXMgY2FsbGVkLlxuICAgICAqIElmIHlvdSBwYXNzIGEgcmVndWxhciBleHByZXNzaW9uIGFzIHRoZSBldmVudCBuYW1lIHRoZW4gdGhlIGxpc3RlbmVyIHdpbGwgYmUgYWRkZWQgdG8gYWxsIGV2ZW50cyB0aGF0IG1hdGNoIGl0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBldnQgTmFtZSBvZiB0aGUgZXZlbnQgdG8gYXR0YWNoIHRoZSBsaXN0ZW5lciB0by5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBsaXN0ZW5lciBNZXRob2QgdG8gYmUgY2FsbGVkIHdoZW4gdGhlIGV2ZW50IGlzIGVtaXR0ZWQuIElmIHRoZSBmdW5jdGlvbiByZXR1cm5zIHRydWUgdGhlbiBpdCB3aWxsIGJlIHJlbW92ZWQgYWZ0ZXIgY2FsbGluZy5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5hZGRMaXN0ZW5lciA9IGZ1bmN0aW9uIGFkZExpc3RlbmVyKGV2dCwgbGlzdGVuZXIpIHtcbiAgICAgICAgdmFyIGxpc3RlbmVycyA9IHRoaXMuZ2V0TGlzdGVuZXJzQXNPYmplY3QoZXZ0KTtcbiAgICAgICAgdmFyIGxpc3RlbmVySXNXcmFwcGVkID0gdHlwZW9mIGxpc3RlbmVyID09PSAnb2JqZWN0JztcbiAgICAgICAgdmFyIGtleTtcblxuICAgICAgICBmb3IgKGtleSBpbiBsaXN0ZW5lcnMpIHtcbiAgICAgICAgICAgIGlmIChsaXN0ZW5lcnMuaGFzT3duUHJvcGVydHkoa2V5KSAmJiBpbmRleE9mTGlzdGVuZXIobGlzdGVuZXJzW2tleV0sIGxpc3RlbmVyKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICBsaXN0ZW5lcnNba2V5XS5wdXNoKGxpc3RlbmVySXNXcmFwcGVkID8gbGlzdGVuZXIgOiB7XG4gICAgICAgICAgICAgICAgICAgIGxpc3RlbmVyOiBsaXN0ZW5lcixcbiAgICAgICAgICAgICAgICAgICAgb25jZTogZmFsc2VcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBbGlhcyBvZiBhZGRMaXN0ZW5lclxuICAgICAqL1xuICAgIHByb3RvLm9uID0gYWxpYXMoJ2FkZExpc3RlbmVyJyk7XG5cbiAgICAvKipcbiAgICAgKiBTZW1pLWFsaWFzIG9mIGFkZExpc3RlbmVyLiBJdCB3aWxsIGFkZCBhIGxpc3RlbmVyIHRoYXQgd2lsbCBiZVxuICAgICAqIGF1dG9tYXRpY2FsbHkgcmVtb3ZlZCBhZnRlciBpdHMgZmlyc3QgZXhlY3V0aW9uLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBldnQgTmFtZSBvZiB0aGUgZXZlbnQgdG8gYXR0YWNoIHRoZSBsaXN0ZW5lciB0by5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBsaXN0ZW5lciBNZXRob2QgdG8gYmUgY2FsbGVkIHdoZW4gdGhlIGV2ZW50IGlzIGVtaXR0ZWQuIElmIHRoZSBmdW5jdGlvbiByZXR1cm5zIHRydWUgdGhlbiBpdCB3aWxsIGJlIHJlbW92ZWQgYWZ0ZXIgY2FsbGluZy5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5hZGRPbmNlTGlzdGVuZXIgPSBmdW5jdGlvbiBhZGRPbmNlTGlzdGVuZXIoZXZ0LCBsaXN0ZW5lcikge1xuICAgICAgICByZXR1cm4gdGhpcy5hZGRMaXN0ZW5lcihldnQsIHtcbiAgICAgICAgICAgIGxpc3RlbmVyOiBsaXN0ZW5lcixcbiAgICAgICAgICAgIG9uY2U6IHRydWVcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEFsaWFzIG9mIGFkZE9uY2VMaXN0ZW5lci5cbiAgICAgKi9cbiAgICBwcm90by5vbmNlID0gYWxpYXMoJ2FkZE9uY2VMaXN0ZW5lcicpO1xuXG4gICAgLyoqXG4gICAgICogRGVmaW5lcyBhbiBldmVudCBuYW1lLiBUaGlzIGlzIHJlcXVpcmVkIGlmIHlvdSB3YW50IHRvIHVzZSBhIHJlZ2V4IHRvIGFkZCBhIGxpc3RlbmVyIHRvIG11bHRpcGxlIGV2ZW50cyBhdCBvbmNlLiBJZiB5b3UgZG9uJ3QgZG8gdGhpcyB0aGVuIGhvdyBkbyB5b3UgZXhwZWN0IGl0IHRvIGtub3cgd2hhdCBldmVudCB0byBhZGQgdG8/IFNob3VsZCBpdCBqdXN0IGFkZCB0byBldmVyeSBwb3NzaWJsZSBtYXRjaCBmb3IgYSByZWdleD8gTm8uIFRoYXQgaXMgc2NhcnkgYW5kIGJhZC5cbiAgICAgKiBZb3UgbmVlZCB0byB0ZWxsIGl0IHdoYXQgZXZlbnQgbmFtZXMgc2hvdWxkIGJlIG1hdGNoZWQgYnkgYSByZWdleC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBldnQgTmFtZSBvZiB0aGUgZXZlbnQgdG8gY3JlYXRlLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLmRlZmluZUV2ZW50ID0gZnVuY3Rpb24gZGVmaW5lRXZlbnQoZXZ0KSB7XG4gICAgICAgIHRoaXMuZ2V0TGlzdGVuZXJzKGV2dCk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVc2VzIGRlZmluZUV2ZW50IHRvIGRlZmluZSBtdWx0aXBsZSBldmVudHMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ1tdfSBldnRzIEFuIGFycmF5IG9mIGV2ZW50IG5hbWVzIHRvIGRlZmluZS5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5kZWZpbmVFdmVudHMgPSBmdW5jdGlvbiBkZWZpbmVFdmVudHMoZXZ0cykge1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGV2dHMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgICAgIHRoaXMuZGVmaW5lRXZlbnQoZXZ0c1tpXSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgYSBsaXN0ZW5lciBmdW5jdGlvbiBmcm9tIHRoZSBzcGVjaWZpZWQgZXZlbnQuXG4gICAgICogV2hlbiBwYXNzZWQgYSByZWd1bGFyIGV4cHJlc3Npb24gYXMgdGhlIGV2ZW50IG5hbWUsIGl0IHdpbGwgcmVtb3ZlIHRoZSBsaXN0ZW5lciBmcm9tIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gZXZ0IE5hbWUgb2YgdGhlIGV2ZW50IHRvIHJlbW92ZSB0aGUgbGlzdGVuZXIgZnJvbS5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBsaXN0ZW5lciBNZXRob2QgdG8gcmVtb3ZlIGZyb20gdGhlIGV2ZW50LlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLnJlbW92ZUxpc3RlbmVyID0gZnVuY3Rpb24gcmVtb3ZlTGlzdGVuZXIoZXZ0LCBsaXN0ZW5lcikge1xuICAgICAgICB2YXIgbGlzdGVuZXJzID0gdGhpcy5nZXRMaXN0ZW5lcnNBc09iamVjdChldnQpO1xuICAgICAgICB2YXIgaW5kZXg7XG4gICAgICAgIHZhciBrZXk7XG5cbiAgICAgICAgZm9yIChrZXkgaW4gbGlzdGVuZXJzKSB7XG4gICAgICAgICAgICBpZiAobGlzdGVuZXJzLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICBpbmRleCA9IGluZGV4T2ZMaXN0ZW5lcihsaXN0ZW5lcnNba2V5XSwgbGlzdGVuZXIpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGluZGV4ICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICBsaXN0ZW5lcnNba2V5XS5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBbGlhcyBvZiByZW1vdmVMaXN0ZW5lclxuICAgICAqL1xuICAgIHByb3RvLm9mZiA9IGFsaWFzKCdyZW1vdmVMaXN0ZW5lcicpO1xuXG4gICAgLyoqXG4gICAgICogQWRkcyBsaXN0ZW5lcnMgaW4gYnVsayB1c2luZyB0aGUgbWFuaXB1bGF0ZUxpc3RlbmVycyBtZXRob2QuXG4gICAgICogSWYgeW91IHBhc3MgYW4gb2JqZWN0IGFzIHRoZSBzZWNvbmQgYXJndW1lbnQgeW91IGNhbiBhZGQgdG8gbXVsdGlwbGUgZXZlbnRzIGF0IG9uY2UuIFRoZSBvYmplY3Qgc2hvdWxkIGNvbnRhaW4ga2V5IHZhbHVlIHBhaXJzIG9mIGV2ZW50cyBhbmQgbGlzdGVuZXJzIG9yIGxpc3RlbmVyIGFycmF5cy4gWW91IGNhbiBhbHNvIHBhc3MgaXQgYW4gZXZlbnQgbmFtZSBhbmQgYW4gYXJyYXkgb2YgbGlzdGVuZXJzIHRvIGJlIGFkZGVkLlxuICAgICAqIFlvdSBjYW4gYWxzbyBwYXNzIGl0IGEgcmVndWxhciBleHByZXNzaW9uIHRvIGFkZCB0aGUgYXJyYXkgb2YgbGlzdGVuZXJzIHRvIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKiBZZWFoLCB0aGlzIGZ1bmN0aW9uIGRvZXMgcXVpdGUgYSBiaXQuIFRoYXQncyBwcm9iYWJseSBhIGJhZCB0aGluZy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdHxSZWdFeHB9IGV2dCBBbiBldmVudCBuYW1lIGlmIHlvdSB3aWxsIHBhc3MgYW4gYXJyYXkgb2YgbGlzdGVuZXJzIG5leHQuIEFuIG9iamVjdCBpZiB5b3Ugd2lzaCB0byBhZGQgdG8gbXVsdGlwbGUgZXZlbnRzIGF0IG9uY2UuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbltdfSBbbGlzdGVuZXJzXSBBbiBvcHRpb25hbCBhcnJheSBvZiBsaXN0ZW5lciBmdW5jdGlvbnMgdG8gYWRkLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLmFkZExpc3RlbmVycyA9IGZ1bmN0aW9uIGFkZExpc3RlbmVycyhldnQsIGxpc3RlbmVycykge1xuICAgICAgICAvLyBQYXNzIHRocm91Z2ggdG8gbWFuaXB1bGF0ZUxpc3RlbmVyc1xuICAgICAgICByZXR1cm4gdGhpcy5tYW5pcHVsYXRlTGlzdGVuZXJzKGZhbHNlLCBldnQsIGxpc3RlbmVycyk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgbGlzdGVuZXJzIGluIGJ1bGsgdXNpbmcgdGhlIG1hbmlwdWxhdGVMaXN0ZW5lcnMgbWV0aG9kLlxuICAgICAqIElmIHlvdSBwYXNzIGFuIG9iamVjdCBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IHlvdSBjYW4gcmVtb3ZlIGZyb20gbXVsdGlwbGUgZXZlbnRzIGF0IG9uY2UuIFRoZSBvYmplY3Qgc2hvdWxkIGNvbnRhaW4ga2V5IHZhbHVlIHBhaXJzIG9mIGV2ZW50cyBhbmQgbGlzdGVuZXJzIG9yIGxpc3RlbmVyIGFycmF5cy5cbiAgICAgKiBZb3UgY2FuIGFsc28gcGFzcyBpdCBhbiBldmVudCBuYW1lIGFuZCBhbiBhcnJheSBvZiBsaXN0ZW5lcnMgdG8gYmUgcmVtb3ZlZC5cbiAgICAgKiBZb3UgY2FuIGFsc28gcGFzcyBpdCBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byByZW1vdmUgdGhlIGxpc3RlbmVycyBmcm9tIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdHxSZWdFeHB9IGV2dCBBbiBldmVudCBuYW1lIGlmIHlvdSB3aWxsIHBhc3MgYW4gYXJyYXkgb2YgbGlzdGVuZXJzIG5leHQuIEFuIG9iamVjdCBpZiB5b3Ugd2lzaCB0byByZW1vdmUgZnJvbSBtdWx0aXBsZSBldmVudHMgYXQgb25jZS5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9uW119IFtsaXN0ZW5lcnNdIEFuIG9wdGlvbmFsIGFycmF5IG9mIGxpc3RlbmVyIGZ1bmN0aW9ucyB0byByZW1vdmUuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBDdXJyZW50IGluc3RhbmNlIG9mIEV2ZW50RW1pdHRlciBmb3IgY2hhaW5pbmcuXG4gICAgICovXG4gICAgcHJvdG8ucmVtb3ZlTGlzdGVuZXJzID0gZnVuY3Rpb24gcmVtb3ZlTGlzdGVuZXJzKGV2dCwgbGlzdGVuZXJzKSB7XG4gICAgICAgIC8vIFBhc3MgdGhyb3VnaCB0byBtYW5pcHVsYXRlTGlzdGVuZXJzXG4gICAgICAgIHJldHVybiB0aGlzLm1hbmlwdWxhdGVMaXN0ZW5lcnModHJ1ZSwgZXZ0LCBsaXN0ZW5lcnMpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBFZGl0cyBsaXN0ZW5lcnMgaW4gYnVsay4gVGhlIGFkZExpc3RlbmVycyBhbmQgcmVtb3ZlTGlzdGVuZXJzIG1ldGhvZHMgYm90aCB1c2UgdGhpcyB0byBkbyB0aGVpciBqb2IuIFlvdSBzaG91bGQgcmVhbGx5IHVzZSB0aG9zZSBpbnN0ZWFkLCB0aGlzIGlzIGEgbGl0dGxlIGxvd2VyIGxldmVsLlxuICAgICAqIFRoZSBmaXJzdCBhcmd1bWVudCB3aWxsIGRldGVybWluZSBpZiB0aGUgbGlzdGVuZXJzIGFyZSByZW1vdmVkICh0cnVlKSBvciBhZGRlZCAoZmFsc2UpLlxuICAgICAqIElmIHlvdSBwYXNzIGFuIG9iamVjdCBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IHlvdSBjYW4gYWRkL3JlbW92ZSBmcm9tIG11bHRpcGxlIGV2ZW50cyBhdCBvbmNlLiBUaGUgb2JqZWN0IHNob3VsZCBjb250YWluIGtleSB2YWx1ZSBwYWlycyBvZiBldmVudHMgYW5kIGxpc3RlbmVycyBvciBsaXN0ZW5lciBhcnJheXMuXG4gICAgICogWW91IGNhbiBhbHNvIHBhc3MgaXQgYW4gZXZlbnQgbmFtZSBhbmQgYW4gYXJyYXkgb2YgbGlzdGVuZXJzIHRvIGJlIGFkZGVkL3JlbW92ZWQuXG4gICAgICogWW91IGNhbiBhbHNvIHBhc3MgaXQgYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gbWFuaXB1bGF0ZSB0aGUgbGlzdGVuZXJzIG9mIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7Qm9vbGVhbn0gcmVtb3ZlIFRydWUgaWYgeW91IHdhbnQgdG8gcmVtb3ZlIGxpc3RlbmVycywgZmFsc2UgaWYgeW91IHdhbnQgdG8gYWRkLlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdHxSZWdFeHB9IGV2dCBBbiBldmVudCBuYW1lIGlmIHlvdSB3aWxsIHBhc3MgYW4gYXJyYXkgb2YgbGlzdGVuZXJzIG5leHQuIEFuIG9iamVjdCBpZiB5b3Ugd2lzaCB0byBhZGQvcmVtb3ZlIGZyb20gbXVsdGlwbGUgZXZlbnRzIGF0IG9uY2UuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbltdfSBbbGlzdGVuZXJzXSBBbiBvcHRpb25hbCBhcnJheSBvZiBsaXN0ZW5lciBmdW5jdGlvbnMgdG8gYWRkL3JlbW92ZS5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5tYW5pcHVsYXRlTGlzdGVuZXJzID0gZnVuY3Rpb24gbWFuaXB1bGF0ZUxpc3RlbmVycyhyZW1vdmUsIGV2dCwgbGlzdGVuZXJzKSB7XG4gICAgICAgIHZhciBpO1xuICAgICAgICB2YXIgdmFsdWU7XG4gICAgICAgIHZhciBzaW5nbGUgPSByZW1vdmUgPyB0aGlzLnJlbW92ZUxpc3RlbmVyIDogdGhpcy5hZGRMaXN0ZW5lcjtcbiAgICAgICAgdmFyIG11bHRpcGxlID0gcmVtb3ZlID8gdGhpcy5yZW1vdmVMaXN0ZW5lcnMgOiB0aGlzLmFkZExpc3RlbmVycztcblxuICAgICAgICAvLyBJZiBldnQgaXMgYW4gb2JqZWN0IHRoZW4gcGFzcyBlYWNoIG9mIGl0cyBwcm9wZXJ0aWVzIHRvIHRoaXMgbWV0aG9kXG4gICAgICAgIGlmICh0eXBlb2YgZXZ0ID09PSAnb2JqZWN0JyAmJiAhKGV2dCBpbnN0YW5jZW9mIFJlZ0V4cCkpIHtcbiAgICAgICAgICAgIGZvciAoaSBpbiBldnQpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXZ0Lmhhc093blByb3BlcnR5KGkpICYmICh2YWx1ZSA9IGV2dFtpXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gUGFzcyB0aGUgc2luZ2xlIGxpc3RlbmVyIHN0cmFpZ2h0IHRocm91Z2ggdG8gdGhlIHNpbmd1bGFyIG1ldGhvZFxuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzaW5nbGUuY2FsbCh0aGlzLCBpLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBPdGhlcndpc2UgcGFzcyBiYWNrIHRvIHRoZSBtdWx0aXBsZSBmdW5jdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgbXVsdGlwbGUuY2FsbCh0aGlzLCBpLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBTbyBldnQgbXVzdCBiZSBhIHN0cmluZ1xuICAgICAgICAgICAgLy8gQW5kIGxpc3RlbmVycyBtdXN0IGJlIGFuIGFycmF5IG9mIGxpc3RlbmVyc1xuICAgICAgICAgICAgLy8gTG9vcCBvdmVyIGl0IGFuZCBwYXNzIGVhY2ggb25lIHRvIHRoZSBtdWx0aXBsZSBtZXRob2RcbiAgICAgICAgICAgIGkgPSBsaXN0ZW5lcnMubGVuZ3RoO1xuICAgICAgICAgICAgd2hpbGUgKGktLSkge1xuICAgICAgICAgICAgICAgIHNpbmdsZS5jYWxsKHRoaXMsIGV2dCwgbGlzdGVuZXJzW2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIGFsbCBsaXN0ZW5lcnMgZnJvbSBhIHNwZWNpZmllZCBldmVudC5cbiAgICAgKiBJZiB5b3UgZG8gbm90IHNwZWNpZnkgYW4gZXZlbnQgdGhlbiBhbGwgbGlzdGVuZXJzIHdpbGwgYmUgcmVtb3ZlZC5cbiAgICAgKiBUaGF0IG1lYW5zIGV2ZXJ5IGV2ZW50IHdpbGwgYmUgZW1wdGllZC5cbiAgICAgKiBZb3UgY2FuIGFsc28gcGFzcyBhIHJlZ2V4IHRvIHJlbW92ZSBhbGwgZXZlbnRzIHRoYXQgbWF0Y2ggaXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ3xSZWdFeHB9IFtldnRdIE9wdGlvbmFsIG5hbWUgb2YgdGhlIGV2ZW50IHRvIHJlbW92ZSBhbGwgbGlzdGVuZXJzIGZvci4gV2lsbCByZW1vdmUgZnJvbSBldmVyeSBldmVudCBpZiBub3QgcGFzc2VkLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLnJlbW92ZUV2ZW50ID0gZnVuY3Rpb24gcmVtb3ZlRXZlbnQoZXZ0KSB7XG4gICAgICAgIHZhciB0eXBlID0gdHlwZW9mIGV2dDtcbiAgICAgICAgdmFyIGV2ZW50cyA9IHRoaXMuX2dldEV2ZW50cygpO1xuICAgICAgICB2YXIga2V5O1xuXG4gICAgICAgIC8vIFJlbW92ZSBkaWZmZXJlbnQgdGhpbmdzIGRlcGVuZGluZyBvbiB0aGUgc3RhdGUgb2YgZXZ0XG4gICAgICAgIGlmICh0eXBlID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgLy8gUmVtb3ZlIGFsbCBsaXN0ZW5lcnMgZm9yIHRoZSBzcGVjaWZpZWQgZXZlbnRcbiAgICAgICAgICAgIGRlbGV0ZSBldmVudHNbZXZ0XTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChldnQgaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAgICAgICAgIC8vIFJlbW92ZSBhbGwgZXZlbnRzIG1hdGNoaW5nIHRoZSByZWdleC5cbiAgICAgICAgICAgIGZvciAoa2V5IGluIGV2ZW50cykge1xuICAgICAgICAgICAgICAgIGlmIChldmVudHMuaGFzT3duUHJvcGVydHkoa2V5KSAmJiBldnQudGVzdChrZXkpKSB7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBldmVudHNba2V5XTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBSZW1vdmUgYWxsIGxpc3RlbmVycyBpbiBhbGwgZXZlbnRzXG4gICAgICAgICAgICBkZWxldGUgdGhpcy5fZXZlbnRzO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEFsaWFzIG9mIHJlbW92ZUV2ZW50LlxuICAgICAqXG4gICAgICogQWRkZWQgdG8gbWlycm9yIHRoZSBub2RlIEFQSS5cbiAgICAgKi9cbiAgICBwcm90by5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBhbGlhcygncmVtb3ZlRXZlbnQnKTtcblxuICAgIC8qKlxuICAgICAqIEVtaXRzIGFuIGV2ZW50IG9mIHlvdXIgY2hvaWNlLlxuICAgICAqIFdoZW4gZW1pdHRlZCwgZXZlcnkgbGlzdGVuZXIgYXR0YWNoZWQgdG8gdGhhdCBldmVudCB3aWxsIGJlIGV4ZWN1dGVkLlxuICAgICAqIElmIHlvdSBwYXNzIHRoZSBvcHRpb25hbCBhcmd1bWVudCBhcnJheSB0aGVuIHRob3NlIGFyZ3VtZW50cyB3aWxsIGJlIHBhc3NlZCB0byBldmVyeSBsaXN0ZW5lciB1cG9uIGV4ZWN1dGlvbi5cbiAgICAgKiBCZWNhdXNlIGl0IHVzZXMgYGFwcGx5YCwgeW91ciBhcnJheSBvZiBhcmd1bWVudHMgd2lsbCBiZSBwYXNzZWQgYXMgaWYgeW91IHdyb3RlIHRoZW0gb3V0IHNlcGFyYXRlbHkuXG4gICAgICogU28gdGhleSB3aWxsIG5vdCBhcnJpdmUgd2l0aGluIHRoZSBhcnJheSBvbiB0aGUgb3RoZXIgc2lkZSwgdGhleSB3aWxsIGJlIHNlcGFyYXRlLlxuICAgICAqIFlvdSBjYW4gYWxzbyBwYXNzIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGVtaXQgdG8gYWxsIGV2ZW50cyB0aGF0IG1hdGNoIGl0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBldnQgTmFtZSBvZiB0aGUgZXZlbnQgdG8gZW1pdCBhbmQgZXhlY3V0ZSBsaXN0ZW5lcnMgZm9yLlxuICAgICAqIEBwYXJhbSB7QXJyYXl9IFthcmdzXSBPcHRpb25hbCBhcnJheSBvZiBhcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIGVhY2ggbGlzdGVuZXIuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBDdXJyZW50IGluc3RhbmNlIG9mIEV2ZW50RW1pdHRlciBmb3IgY2hhaW5pbmcuXG4gICAgICovXG4gICAgcHJvdG8uZW1pdEV2ZW50ID0gZnVuY3Rpb24gZW1pdEV2ZW50KGV2dCwgYXJncykge1xuICAgICAgICB2YXIgbGlzdGVuZXJzID0gdGhpcy5nZXRMaXN0ZW5lcnNBc09iamVjdChldnQpO1xuICAgICAgICB2YXIgbGlzdGVuZXI7XG4gICAgICAgIHZhciBpO1xuICAgICAgICB2YXIga2V5O1xuICAgICAgICB2YXIgcmVzcG9uc2U7XG5cbiAgICAgICAgZm9yIChrZXkgaW4gbGlzdGVuZXJzKSB7XG4gICAgICAgICAgICBpZiAobGlzdGVuZXJzLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICBpID0gbGlzdGVuZXJzW2tleV0ubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgd2hpbGUgKGktLSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGUgbGlzdGVuZXIgcmV0dXJucyB0cnVlIHRoZW4gaXQgc2hhbGwgYmUgcmVtb3ZlZCBmcm9tIHRoZSBldmVudFxuICAgICAgICAgICAgICAgICAgICAvLyBUaGUgZnVuY3Rpb24gaXMgZXhlY3V0ZWQgZWl0aGVyIHdpdGggYSBiYXNpYyBjYWxsIG9yIGFuIGFwcGx5IGlmIHRoZXJlIGlzIGFuIGFyZ3MgYXJyYXlcbiAgICAgICAgICAgICAgICAgICAgbGlzdGVuZXIgPSBsaXN0ZW5lcnNba2V5XVtpXTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAobGlzdGVuZXIub25jZSA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVMaXN0ZW5lcihldnQsIGxpc3RlbmVyLmxpc3RlbmVyKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlID0gbGlzdGVuZXIubGlzdGVuZXIuYXBwbHkodGhpcywgYXJncyB8fCBbXSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3BvbnNlID09PSB0aGlzLl9nZXRPbmNlUmV0dXJuVmFsdWUoKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVMaXN0ZW5lcihldnQsIGxpc3RlbmVyLmxpc3RlbmVyKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBbGlhcyBvZiBlbWl0RXZlbnRcbiAgICAgKi9cbiAgICBwcm90by50cmlnZ2VyID0gYWxpYXMoJ2VtaXRFdmVudCcpO1xuXG4gICAgLyoqXG4gICAgICogU3VidGx5IGRpZmZlcmVudCBmcm9tIGVtaXRFdmVudCBpbiB0aGF0IGl0IHdpbGwgcGFzcyBpdHMgYXJndW1lbnRzIG9uIHRvIHRoZSBsaXN0ZW5lcnMsIGFzIG9wcG9zZWQgdG8gdGFraW5nIGEgc2luZ2xlIGFycmF5IG9mIGFyZ3VtZW50cyB0byBwYXNzIG9uLlxuICAgICAqIEFzIHdpdGggZW1pdEV2ZW50LCB5b3UgY2FuIHBhc3MgYSByZWdleCBpbiBwbGFjZSBvZiB0aGUgZXZlbnQgbmFtZSB0byBlbWl0IHRvIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gZXZ0IE5hbWUgb2YgdGhlIGV2ZW50IHRvIGVtaXQgYW5kIGV4ZWN1dGUgbGlzdGVuZXJzIGZvci5cbiAgICAgKiBAcGFyYW0gey4uLip9IE9wdGlvbmFsIGFkZGl0aW9uYWwgYXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byBlYWNoIGxpc3RlbmVyLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLmVtaXQgPSBmdW5jdGlvbiBlbWl0KGV2dCkge1xuICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgICAgIHJldHVybiB0aGlzLmVtaXRFdmVudChldnQsIGFyZ3MpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBjdXJyZW50IHZhbHVlIHRvIGNoZWNrIGFnYWluc3Qgd2hlbiBleGVjdXRpbmcgbGlzdGVuZXJzLiBJZiBhXG4gICAgICogbGlzdGVuZXJzIHJldHVybiB2YWx1ZSBtYXRjaGVzIHRoZSBvbmUgc2V0IGhlcmUgdGhlbiBpdCB3aWxsIGJlIHJlbW92ZWRcbiAgICAgKiBhZnRlciBleGVjdXRpb24uIFRoaXMgdmFsdWUgZGVmYXVsdHMgdG8gdHJ1ZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIG5ldyB2YWx1ZSB0byBjaGVjayBmb3Igd2hlbiBleGVjdXRpbmcgbGlzdGVuZXJzLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLnNldE9uY2VSZXR1cm5WYWx1ZSA9IGZ1bmN0aW9uIHNldE9uY2VSZXR1cm5WYWx1ZSh2YWx1ZSkge1xuICAgICAgICB0aGlzLl9vbmNlUmV0dXJuVmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEZldGNoZXMgdGhlIGN1cnJlbnQgdmFsdWUgdG8gY2hlY2sgYWdhaW5zdCB3aGVuIGV4ZWN1dGluZyBsaXN0ZW5lcnMuIElmXG4gICAgICogdGhlIGxpc3RlbmVycyByZXR1cm4gdmFsdWUgbWF0Y2hlcyB0aGlzIG9uZSB0aGVuIGl0IHNob3VsZCBiZSByZW1vdmVkXG4gICAgICogYXV0b21hdGljYWxseS4gSXQgd2lsbCByZXR1cm4gdHJ1ZSBieSBkZWZhdWx0LlxuICAgICAqXG4gICAgICogQHJldHVybiB7KnxCb29sZWFufSBUaGUgY3VycmVudCB2YWx1ZSB0byBjaGVjayBmb3Igb3IgdGhlIGRlZmF1bHQsIHRydWUuXG4gICAgICogQGFwaSBwcml2YXRlXG4gICAgICovXG4gICAgcHJvdG8uX2dldE9uY2VSZXR1cm5WYWx1ZSA9IGZ1bmN0aW9uIF9nZXRPbmNlUmV0dXJuVmFsdWUoKSB7XG4gICAgICAgIGlmICh0aGlzLmhhc093blByb3BlcnR5KCdfb25jZVJldHVyblZhbHVlJykpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9vbmNlUmV0dXJuVmFsdWU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBGZXRjaGVzIHRoZSBldmVudHMgb2JqZWN0IGFuZCBjcmVhdGVzIG9uZSBpZiByZXF1aXJlZC5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gVGhlIGV2ZW50cyBzdG9yYWdlIG9iamVjdC5cbiAgICAgKiBAYXBpIHByaXZhdGVcbiAgICAgKi9cbiAgICBwcm90by5fZ2V0RXZlbnRzID0gZnVuY3Rpb24gX2dldEV2ZW50cygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2V2ZW50cyB8fCAodGhpcy5fZXZlbnRzID0ge30pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZXZlcnRzIHRoZSBnbG9iYWwge0BsaW5rIEV2ZW50RW1pdHRlcn0gdG8gaXRzIHByZXZpb3VzIHZhbHVlIGFuZCByZXR1cm5zIGEgcmVmZXJlbmNlIHRvIHRoaXMgdmVyc2lvbi5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge0Z1bmN0aW9ufSBOb24gY29uZmxpY3RpbmcgRXZlbnRFbWl0dGVyIGNsYXNzLlxuICAgICAqL1xuICAgIEV2ZW50RW1pdHRlci5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gbm9Db25mbGljdCgpIHtcbiAgICAgICAgZXhwb3J0cy5FdmVudEVtaXR0ZXIgPSBvcmlnaW5hbEdsb2JhbFZhbHVlO1xuICAgICAgICByZXR1cm4gRXZlbnRFbWl0dGVyO1xuICAgIH07XG5cbiAgICAvLyBFeHBvc2UgdGhlIGNsYXNzIGVpdGhlciB2aWEgQU1ELCBDb21tb25KUyBvciB0aGUgZ2xvYmFsIG9iamVjdFxuICAgIGlmICh0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQpIHtcbiAgICAgICAgZGVmaW5lKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBFdmVudEVtaXR0ZXI7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBlbHNlIGlmICh0eXBlb2YgbW9kdWxlID09PSAnb2JqZWN0JyAmJiBtb2R1bGUuZXhwb3J0cyl7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gRXZlbnRFbWl0dGVyO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgZXhwb3J0cy5FdmVudEVtaXR0ZXIgPSBFdmVudEVtaXR0ZXI7XG4gICAgfVxufS5jYWxsKHRoaXMpKTtcbiIsImZ1bmN0aW9uIE1hcHBlcigpXG57XG4gIHZhciBzb3VyY2VzID0ge307XG5cblxuICB0aGlzLmZvckVhY2ggPSBmdW5jdGlvbihjYWxsYmFjaylcbiAge1xuICAgIGZvcih2YXIga2V5IGluIHNvdXJjZXMpXG4gICAge1xuICAgICAgdmFyIHNvdXJjZSA9IHNvdXJjZXNba2V5XTtcblxuICAgICAgZm9yKHZhciBrZXkyIGluIHNvdXJjZSlcbiAgICAgICAgY2FsbGJhY2soc291cmNlW2tleTJdKTtcbiAgICB9O1xuICB9O1xuXG4gIHRoaXMuZ2V0ID0gZnVuY3Rpb24oaWQsIHNvdXJjZSlcbiAge1xuICAgIHZhciBpZHMgPSBzb3VyY2VzW3NvdXJjZV07XG4gICAgaWYoaWRzID09IHVuZGVmaW5lZClcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgICByZXR1cm4gaWRzW2lkXTtcbiAgfTtcblxuICB0aGlzLnJlbW92ZSA9IGZ1bmN0aW9uKGlkLCBzb3VyY2UpXG4gIHtcbiAgICB2YXIgaWRzID0gc291cmNlc1tzb3VyY2VdO1xuICAgIGlmKGlkcyA9PSB1bmRlZmluZWQpXG4gICAgICByZXR1cm47XG5cbiAgICBkZWxldGUgaWRzW2lkXTtcblxuICAgIC8vIENoZWNrIGl0J3MgZW1wdHlcbiAgICBmb3IodmFyIGkgaW4gaWRzKXtyZXR1cm4gZmFsc2V9XG5cbiAgICBkZWxldGUgc291cmNlc1tzb3VyY2VdO1xuICB9O1xuXG4gIHRoaXMuc2V0ID0gZnVuY3Rpb24odmFsdWUsIGlkLCBzb3VyY2UpXG4gIHtcbiAgICBpZih2YWx1ZSA9PSB1bmRlZmluZWQpXG4gICAgICByZXR1cm4gdGhpcy5yZW1vdmUoaWQsIHNvdXJjZSk7XG5cbiAgICB2YXIgaWRzID0gc291cmNlc1tzb3VyY2VdO1xuICAgIGlmKGlkcyA9PSB1bmRlZmluZWQpXG4gICAgICBzb3VyY2VzW3NvdXJjZV0gPSBpZHMgPSB7fTtcblxuICAgIGlkc1tpZF0gPSB2YWx1ZTtcbiAgfTtcbn07XG5cblxuTWFwcGVyLnByb3RvdHlwZS5wb3AgPSBmdW5jdGlvbihpZCwgc291cmNlKVxue1xuICB2YXIgdmFsdWUgPSB0aGlzLmdldChpZCwgc291cmNlKTtcbiAgaWYodmFsdWUgPT0gdW5kZWZpbmVkKVxuICAgIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgdGhpcy5yZW1vdmUoaWQsIHNvdXJjZSk7XG5cbiAgcmV0dXJuIHZhbHVlO1xufTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IE1hcHBlcjtcbiIsIi8qXG4gKiAoQykgQ29weXJpZ2h0IDIwMTQgS3VyZW50byAoaHR0cDovL2t1cmVudG8ub3JnLylcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICpcbiAqL1xuXG52YXIgSnNvblJwY0NsaWVudCAgPSByZXF1aXJlKCcuL2pzb25ycGNjbGllbnQnKTtcblxuXG5leHBvcnRzLkpzb25ScGNDbGllbnQgID0gSnNvblJwY0NsaWVudDsiLCIvKlxuICogKEMpIENvcHlyaWdodCAyMDE0IEt1cmVudG8gKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKi9cblxudmFyIFJwY0J1aWxkZXIgPSByZXF1aXJlKCcuLi8nKTtcbnZhciBXZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uID0gcmVxdWlyZSgnLi90cmFuc3BvcnRzL3dlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb24nKTtcblxuRGF0ZS5ub3cgPSBEYXRlLm5vdyB8fCBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gK25ldyBEYXRlO1xufTtcblxudmFyIFBJTkdfSU5URVJWQUwgPSA1MDAwO1xuXG52YXIgUkVDT05ORUNUSU5HID0gJ1JFQ09OTkVDVElORyc7XG52YXIgQ09OTkVDVEVEID0gJ0NPTk5FQ1RFRCc7XG52YXIgRElTQ09OTkVDVEVEID0gJ0RJU0NPTk5FQ1RFRCc7XG5cbnZhciBMb2dnZXIgPSBjb25zb2xlO1xuXG4vKipcbiAqXG4gKiBoZWFydGJlYXQ6IGludGVydmFsIGluIG1zIGZvciBlYWNoIGhlYXJ0YmVhdCBtZXNzYWdlLFxuICogc2VuZENsb3NlTWVzc2FnZSA6IHRydWUgLyBmYWxzZSwgYmVmb3JlIGNsb3NpbmcgdGhlIGNvbm5lY3Rpb24sIGl0IHNlbmRzIGEgY2xvc2VTZXNzaW9uIG1lc3NhZ2VcbiAqIDxwcmU+XG4gKiB3cyA6IHtcbiAqIFx0dXJpIDogVVJJIHRvIGNvbm50ZWN0IHRvLFxuICogIHVzZVNvY2tKUyA6IHRydWUgKHVzZSBTb2NrSlMpIC8gZmFsc2UgKHVzZSBXZWJTb2NrZXQpIGJ5IGRlZmF1bHQsXG4gKiBcdG9uY29ubmVjdGVkIDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIGNvbm5lY3Rpb24gaXMgc3VjY2Vzc2Z1bCxcbiAqIFx0b25kaXNjb25uZWN0IDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIHRoZSBjb25uZWN0aW9uIGlzIGxvc3QsXG4gKiBcdG9ucmVjb25uZWN0aW5nIDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIHRoZSBjbGllbnQgaXMgcmVjb25uZWN0aW5nLFxuICogXHRvbnJlY29ubmVjdGVkIDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIHRoZSBjbGllbnQgc3VjY2VzZnVsbHkgcmVjb25uZWN0cyxcbiAqIFx0b25lcnJvciA6IGNhbGxiYWNrIG1ldGhvZCB0byBpbnZva2Ugd2hlbiB0aGVyZSBpcyBhbiBlcnJvclxuICogfSxcbiAqIHJwYyA6IHtcbiAqIFx0cmVxdWVzdFRpbWVvdXQgOiB0aW1lb3V0IGZvciBhIHJlcXVlc3QsXG4gKiBcdHNlc3Npb25TdGF0dXNDaGFuZ2VkOiBjYWxsYmFjayBtZXRob2QgZm9yIGNoYW5nZXMgaW4gc2Vzc2lvbiBzdGF0dXMsXG4gKiBcdG1lZGlhUmVuZWdvdGlhdGlvbjogbWVkaWFSZW5lZ290aWF0aW9uXG4gKiB9XG4gKiA8L3ByZT5cbiAqL1xuZnVuY3Rpb24gSnNvblJwY0NsaWVudChjb25maWd1cmF0aW9uKSB7XG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICB2YXIgd3NDb25maWcgPSBjb25maWd1cmF0aW9uLndzO1xuXG4gICAgdmFyIG5vdFJlY29ubmVjdElmTnVtTGVzc1RoYW4gPSAtMTtcblxuICAgIHZhciBwaW5nTmV4dE51bSA9IDA7XG4gICAgdmFyIGVuYWJsZWRQaW5ncyA9IHRydWU7XG4gICAgdmFyIHBpbmdQb25nU3RhcnRlZCA9IGZhbHNlO1xuICAgIHZhciBwaW5nSW50ZXJ2YWw7XG5cbiAgICB2YXIgc3RhdHVzID0gRElTQ09OTkVDVEVEO1xuXG4gICAgdmFyIG9ucmVjb25uZWN0aW5nID0gd3NDb25maWcub25yZWNvbm5lY3Rpbmc7XG4gICAgdmFyIG9ucmVjb25uZWN0ZWQgPSB3c0NvbmZpZy5vbnJlY29ubmVjdGVkO1xuICAgIHZhciBvbmNvbm5lY3RlZCA9IHdzQ29uZmlnLm9uY29ubmVjdGVkO1xuICAgIHZhciBvbmVycm9yID0gd3NDb25maWcub25lcnJvcjtcblxuICAgIGNvbmZpZ3VyYXRpb24ucnBjLnB1bGwgPSBmdW5jdGlvbihwYXJhbXMsIHJlcXVlc3QpIHtcbiAgICAgICAgcmVxdWVzdC5yZXBseShudWxsLCBcInB1c2hcIik7XG4gICAgfVxuXG4gICAgd3NDb25maWcub25yZWNvbm5lY3RpbmcgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgTG9nZ2VyLmRlYnVnKFwiLS0tLS0tLS0tIE9OUkVDT05ORUNUSU5HIC0tLS0tLS0tLS0tXCIpO1xuICAgICAgICBpZiAoc3RhdHVzID09PSBSRUNPTk5FQ1RJTkcpIHtcbiAgICAgICAgICAgIExvZ2dlci5lcnJvcihcIldlYnNvY2tldCBhbHJlYWR5IGluIFJFQ09OTkVDVElORyBzdGF0ZSB3aGVuIHJlY2VpdmluZyBhIG5ldyBPTlJFQ09OTkVDVElORyBtZXNzYWdlLiBJZ25vcmluZyBpdFwiKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHN0YXR1cyA9IFJFQ09OTkVDVElORztcbiAgICAgICAgaWYgKG9ucmVjb25uZWN0aW5nKSB7XG4gICAgICAgICAgICBvbnJlY29ubmVjdGluZygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgd3NDb25maWcub25yZWNvbm5lY3RlZCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBMb2dnZXIuZGVidWcoXCItLS0tLS0tLS0gT05SRUNPTk5FQ1RFRCAtLS0tLS0tLS0tLVwiKTtcbiAgICAgICAgaWYgKHN0YXR1cyA9PT0gQ09OTkVDVEVEKSB7XG4gICAgICAgICAgICBMb2dnZXIuZXJyb3IoXCJXZWJzb2NrZXQgYWxyZWFkeSBpbiBDT05ORUNURUQgc3RhdGUgd2hlbiByZWNlaXZpbmcgYSBuZXcgT05SRUNPTk5FQ1RFRCBtZXNzYWdlLiBJZ25vcmluZyBpdFwiKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzdGF0dXMgPSBDT05ORUNURUQ7XG5cbiAgICAgICAgZW5hYmxlZFBpbmdzID0gdHJ1ZTtcbiAgICAgICAgdXBkYXRlTm90UmVjb25uZWN0SWZMZXNzVGhhbigpO1xuICAgICAgICB1c2VQaW5nKCk7XG5cbiAgICAgICAgaWYgKG9ucmVjb25uZWN0ZWQpIHtcbiAgICAgICAgICAgIG9ucmVjb25uZWN0ZWQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHdzQ29uZmlnLm9uY29ubmVjdGVkID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIExvZ2dlci5kZWJ1ZyhcIi0tLS0tLS0tLSBPTkNPTk5FQ1RFRCAtLS0tLS0tLS0tLVwiKTtcbiAgICAgICAgaWYgKHN0YXR1cyA9PT0gQ09OTkVDVEVEKSB7XG4gICAgICAgICAgICBMb2dnZXIuZXJyb3IoXCJXZWJzb2NrZXQgYWxyZWFkeSBpbiBDT05ORUNURUQgc3RhdGUgd2hlbiByZWNlaXZpbmcgYSBuZXcgT05DT05ORUNURUQgbWVzc2FnZS4gSWdub3JpbmcgaXRcIik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgc3RhdHVzID0gQ09OTkVDVEVEO1xuXG4gICAgICAgIGVuYWJsZWRQaW5ncyA9IHRydWU7XG4gICAgICAgIHVzZVBpbmcoKTtcblxuICAgICAgICBpZiAob25jb25uZWN0ZWQpIHtcbiAgICAgICAgICAgIG9uY29ubmVjdGVkKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB3c0NvbmZpZy5vbmVycm9yID0gZnVuY3Rpb24oZXJyb3IpIHtcbiAgICAgICAgTG9nZ2VyLmRlYnVnKFwiLS0tLS0tLS0tIE9ORVJST1IgLS0tLS0tLS0tLS1cIik7XG5cbiAgICAgICAgc3RhdHVzID0gRElTQ09OTkVDVEVEO1xuXG4gICAgICAgIGlmIChvbmVycm9yKSB7XG4gICAgICAgICAgICBvbmVycm9yKGVycm9yKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHZhciB3cyA9IG5ldyBXZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uKHdzQ29uZmlnKTtcblxuICAgIExvZ2dlci5kZWJ1ZygnQ29ubmVjdGluZyB3ZWJzb2NrZXQgdG8gVVJJOiAnICsgd3NDb25maWcudXJpKTtcblxuICAgIHZhciBycGNCdWlsZGVyT3B0aW9ucyA9IHtcbiAgICAgICAgcmVxdWVzdF90aW1lb3V0OiBjb25maWd1cmF0aW9uLnJwYy5yZXF1ZXN0VGltZW91dCxcbiAgICAgICAgcGluZ19yZXF1ZXN0X3RpbWVvdXQ6IGNvbmZpZ3VyYXRpb24ucnBjLmhlYXJ0YmVhdFJlcXVlc3RUaW1lb3V0XG4gICAgfTtcblxuICAgIHZhciBycGMgPSBuZXcgUnBjQnVpbGRlcihScGNCdWlsZGVyLnBhY2tlcnMuSnNvblJQQywgcnBjQnVpbGRlck9wdGlvbnMsIHdzLFxuICAgICAgICBmdW5jdGlvbihyZXF1ZXN0KSB7XG5cbiAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnUmVjZWl2ZWQgcmVxdWVzdDogJyArIEpTT04uc3RyaW5naWZ5KHJlcXVlc3QpKTtcblxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICB2YXIgZnVuYyA9IGNvbmZpZ3VyYXRpb24ucnBjW3JlcXVlc3QubWV0aG9kXTtcblxuICAgICAgICAgICAgICAgIGlmIChmdW5jID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLmVycm9yKFwiTWV0aG9kIFwiICsgcmVxdWVzdC5tZXRob2QgKyBcIiBub3QgcmVnaXN0ZXJlZCBpbiBjbGllbnRcIik7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZnVuYyhyZXF1ZXN0LnBhcmFtcywgcmVxdWVzdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgTG9nZ2VyLmVycm9yKCdFeGNlcHRpb24gcHJvY2Vzc2luZyByZXF1ZXN0OiAnICsgSlNPTi5zdHJpbmdpZnkocmVxdWVzdCkpO1xuICAgICAgICAgICAgICAgIExvZ2dlci5lcnJvcihlcnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgIHRoaXMuc2VuZCA9IGZ1bmN0aW9uKG1ldGhvZCwgcGFyYW1zLCBjYWxsYmFjaykge1xuICAgICAgICBpZiAobWV0aG9kICE9PSAncGluZycpIHtcbiAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnUmVxdWVzdDogbWV0aG9kOicgKyBtZXRob2QgKyBcIiBwYXJhbXM6XCIgKyBKU09OLnN0cmluZ2lmeShwYXJhbXMpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciByZXF1ZXN0VGltZSA9IERhdGUubm93KCk7XG5cbiAgICAgICAgcnBjLmVuY29kZShtZXRob2QsIHBhcmFtcywgZnVuY3Rpb24oZXJyb3IsIHJlc3VsdCkge1xuICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLmVycm9yKFwiRVJST1I6XCIgKyBlcnJvci5tZXNzYWdlICsgXCIgaW4gUmVxdWVzdDogbWV0aG9kOlwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCArIFwiIHBhcmFtczpcIiArIEpTT04uc3RyaW5naWZ5KHBhcmFtcykgKyBcIiByZXF1ZXN0OlwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yLnJlcXVlc3QpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyb3IuZGF0YSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLmVycm9yKFwiRVJST1IgREFUQTpcIiArIEpTT04uc3RyaW5naWZ5KGVycm9yLmRhdGEpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHt9XG4gICAgICAgICAgICAgICAgZXJyb3IucmVxdWVzdFRpbWUgPSByZXF1ZXN0VGltZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIGlmIChyZXN1bHQgIT0gdW5kZWZpbmVkICYmIHJlc3VsdC52YWx1ZSAhPT0gJ3BvbmcnKSB7XG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnUmVzcG9uc2U6ICcgKyBKU09OLnN0cmluZ2lmeShyZXN1bHQpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soZXJyb3IsIHJlc3VsdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHVwZGF0ZU5vdFJlY29ubmVjdElmTGVzc1RoYW4oKSB7XG4gICAgICAgIExvZ2dlci5kZWJ1ZyhcIm5vdFJlY29ubmVjdElmTnVtTGVzc1RoYW4gPSBcIiArIHBpbmdOZXh0TnVtICsgJyAob2xkPScgK1xuICAgICAgICAgICAgbm90UmVjb25uZWN0SWZOdW1MZXNzVGhhbiArICcpJyk7XG4gICAgICAgIG5vdFJlY29ubmVjdElmTnVtTGVzc1RoYW4gPSBwaW5nTmV4dE51bTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzZW5kUGluZygpIHtcbiAgICAgICAgaWYgKGVuYWJsZWRQaW5ncykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9IG51bGw7XG4gICAgICAgICAgICBpZiAocGluZ05leHROdW0gPT0gMCB8fCBwaW5nTmV4dE51bSA9PSBub3RSZWNvbm5lY3RJZk51bUxlc3NUaGFuKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0ge1xuICAgICAgICAgICAgICAgICAgICBpbnRlcnZhbDogY29uZmlndXJhdGlvbi5oZWFydGJlYXQgfHwgUElOR19JTlRFUlZBTFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBwaW5nTmV4dE51bSsrO1xuXG4gICAgICAgICAgICBzZWxmLnNlbmQoJ3BpbmcnLCBwYXJhbXMsIChmdW5jdGlvbihwaW5nTnVtKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKGVycm9yLCByZXN1bHQpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBMb2dnZXIuZGVidWcoXCJFcnJvciBpbiBwaW5nIHJlcXVlc3QgI1wiICsgcGluZ051bSArIFwiIChcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3IubWVzc2FnZSArIFwiKVwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChwaW5nTnVtID4gbm90UmVjb25uZWN0SWZOdW1MZXNzVGhhbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZWRQaW5ncyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZU5vdFJlY29ubmVjdElmTGVzc1RoYW4oKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb2dnZXIuZGVidWcoXCJTZXJ2ZXIgZGlkIG5vdCByZXNwb25kIHRvIHBpbmcgbWVzc2FnZSAjXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwaW5nTnVtICsgXCIuIFJlY29ubmVjdGluZy4uLiBcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd3MucmVjb25uZWN0V3MoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pKHBpbmdOZXh0TnVtKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBMb2dnZXIuZGVidWcoXCJUcnlpbmcgdG8gc2VuZCBwaW5nLCBidXQgcGluZyBpcyBub3QgZW5hYmxlZFwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qXG4gICAgKiBJZiBjb25maWd1cmF0aW9uLmhlYXJiZWF0IGhhcyBhbnkgdmFsdWUsIHRoZSBwaW5nLXBvbmcgd2lsbCB3b3JrIHdpdGggdGhlIGludGVydmFsXG4gICAgKiBvZiBjb25maWd1cmF0aW9uLmhlYXJiZWF0XG4gICAgKi9cbiAgICBmdW5jdGlvbiB1c2VQaW5nKCkge1xuICAgICAgICBpZiAoIXBpbmdQb25nU3RhcnRlZCkge1xuICAgICAgICAgICAgTG9nZ2VyLmRlYnVnKFwiU3RhcnRpbmcgcGluZyAoaWYgY29uZmlndXJlZClcIilcbiAgICAgICAgICAgIHBpbmdQb25nU3RhcnRlZCA9IHRydWU7XG5cbiAgICAgICAgICAgIGlmIChjb25maWd1cmF0aW9uLmhlYXJ0YmVhdCAhPSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBwaW5nSW50ZXJ2YWwgPSBzZXRJbnRlcnZhbChzZW5kUGluZywgY29uZmlndXJhdGlvbi5oZWFydGJlYXQpO1xuICAgICAgICAgICAgICAgIHNlbmRQaW5nKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmNsb3NlID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIExvZ2dlci5kZWJ1ZyhcIkNsb3NpbmcganNvblJwY0NsaWVudCBleHBsaWNpdGx5IGJ5IGNsaWVudFwiKTtcblxuICAgICAgICBpZiAocGluZ0ludGVydmFsICE9IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgTG9nZ2VyLmRlYnVnKFwiQ2xlYXJpbmcgcGluZyBpbnRlcnZhbFwiKTtcbiAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwocGluZ0ludGVydmFsKTtcbiAgICAgICAgfVxuICAgICAgICBwaW5nUG9uZ1N0YXJ0ZWQgPSBmYWxzZTtcbiAgICAgICAgZW5hYmxlZFBpbmdzID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKGNvbmZpZ3VyYXRpb24uc2VuZENsb3NlTWVzc2FnZSkge1xuICAgICAgICAgICAgTG9nZ2VyLmRlYnVnKFwiU2VuZGluZyBjbG9zZSBtZXNzYWdlXCIpXG4gICAgICAgICAgICB0aGlzLnNlbmQoJ2Nsb3NlU2Vzc2lvbicsIG51bGwsIGZ1bmN0aW9uKGVycm9yLCByZXN1bHQpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLmVycm9yKFwiRXJyb3Igc2VuZGluZyBjbG9zZSBtZXNzYWdlOiBcIiArIEpTT04uc3RyaW5naWZ5KGVycm9yKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHdzLmNsb3NlKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcblx0XHRcdHdzLmNsb3NlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUaGlzIG1ldGhvZCBpcyBvbmx5IGZvciB0ZXN0aW5nXG4gICAgdGhpcy5mb3JjZUNsb3NlID0gZnVuY3Rpb24obWlsbGlzKSB7XG4gICAgICAgIHdzLmZvcmNlQ2xvc2UobWlsbGlzKTtcbiAgICB9XG5cbiAgICB0aGlzLnJlY29ubmVjdCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB3cy5yZWNvbm5lY3RXcygpO1xuICAgIH1cbn1cblxuXG5tb2R1bGUuZXhwb3J0cyA9IEpzb25ScGNDbGllbnQ7XG4iLCIvKlxuICogKEMpIENvcHlyaWdodCAyMDE0IEt1cmVudG8gKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKi9cblxudmFyIFdlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb24gID0gcmVxdWlyZSgnLi93ZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uJyk7XG5cblxuZXhwb3J0cy5XZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uICA9IFdlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb247IiwiLypcbiAqIChDKSBDb3B5cmlnaHQgMjAxMy0yMDE1IEt1cmVudG8gKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEJyb3dzZXJXZWJTb2NrZXQgPSBnbG9iYWwuV2ViU29ja2V0IHx8IGdsb2JhbC5Nb3pXZWJTb2NrZXQ7XG5cbnZhciBMb2dnZXIgPSBjb25zb2xlO1xuXG4vKipcbiAqIEdldCBlaXRoZXIgdGhlIGBXZWJTb2NrZXRgIG9yIGBNb3pXZWJTb2NrZXRgIGdsb2JhbHNcbiAqIGluIHRoZSBicm93c2VyIG9yIHRyeSB0byByZXNvbHZlIFdlYlNvY2tldC1jb21wYXRpYmxlXG4gKiBpbnRlcmZhY2UgZXhwb3NlZCBieSBgd3NgIGZvciBOb2RlLWxpa2UgZW52aXJvbm1lbnQuXG4gKi9cblxuLyp2YXIgV2ViU29ja2V0ID0gQnJvd3NlcldlYlNvY2tldDtcbmlmICghV2ViU29ja2V0ICYmIHR5cGVvZiB3aW5kb3cgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgV2ViU29ja2V0ID0gcmVxdWlyZSgnd3MnKTtcbiAgICB9IGNhdGNoIChlKSB7IH1cbn0qL1xuXG4vL3ZhciBTb2NrSlMgPSByZXF1aXJlKCdzb2NranMtY2xpZW50Jyk7XG5cbnZhciBNQVhfUkVUUklFUyA9IDIwMDA7IC8vIEZvcmV2ZXIuLi5cbnZhciBSRVRSWV9USU1FX01TID0gMzAwMDsgLy8gRklYTUU6IEltcGxlbWVudCBleHBvbmVudGlhbCB3YWl0IHRpbWVzLi4uXG5cbnZhciBDT05ORUNUSU5HID0gMDtcbnZhciBPUEVOID0gMTtcbnZhciBDTE9TSU5HID0gMjtcbnZhciBDTE9TRUQgPSAzO1xuXG4vKlxuY29uZmlnID0ge1xuXHRcdHVyaSA6IHdzVXJpLFxuXHRcdHVzZVNvY2tKUyA6IHRydWUgKHVzZSBTb2NrSlMpIC8gZmFsc2UgKHVzZSBXZWJTb2NrZXQpIGJ5IGRlZmF1bHQsXG5cdFx0b25jb25uZWN0ZWQgOiBjYWxsYmFjayBtZXRob2QgdG8gaW52b2tlIHdoZW4gY29ubmVjdGlvbiBpcyBzdWNjZXNzZnVsLFxuXHRcdG9uZGlzY29ubmVjdCA6IGNhbGxiYWNrIG1ldGhvZCB0byBpbnZva2Ugd2hlbiB0aGUgY29ubmVjdGlvbiBpcyBsb3N0LFxuXHRcdG9ucmVjb25uZWN0aW5nIDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIHRoZSBjbGllbnQgaXMgcmVjb25uZWN0aW5nLFxuXHRcdG9ucmVjb25uZWN0ZWQgOiBjYWxsYmFjayBtZXRob2QgdG8gaW52b2tlIHdoZW4gdGhlIGNsaWVudCBzdWNjZXNmdWxseSByZWNvbm5lY3RzLFxuXHR9O1xuKi9cbmZ1bmN0aW9uIFdlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb24oY29uZmlnKSB7XG5cbiAgICB2YXIgY2xvc2luZyA9IGZhbHNlO1xuICAgIHZhciByZWdpc3Rlck1lc3NhZ2VIYW5kbGVyO1xuICAgIHZhciB3c1VyaSA9IGNvbmZpZy51cmk7XG4gICAgdmFyIHVzZVNvY2tKUyA9IGNvbmZpZy51c2VTb2NrSlM7XG4gICAgdmFyIHJlY29ubmVjdGluZyA9IGZhbHNlO1xuXG4gICAgdmFyIGZvcmNpbmdEaXNjb25uZWN0aW9uID0gZmFsc2U7XG5cbiAgICB2YXIgd3M7XG5cbiAgICBpZiAodXNlU29ja0pTKSB7XG4gICAgICAgIHdzID0gbmV3IFNvY2tKUyh3c1VyaSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgd3MgPSBuZXcgV2ViU29ja2V0KHdzVXJpKTtcbiAgICB9XG5cbiAgICB3cy5vbm9wZW4gPSBmdW5jdGlvbigpIHtcbiAgICAgICAgbG9nQ29ubmVjdGVkKHdzLCB3c1VyaSk7XG4gICAgICAgIGlmIChjb25maWcub25jb25uZWN0ZWQpIHtcbiAgICAgICAgICAgIGNvbmZpZy5vbmNvbm5lY3RlZCgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHdzLm9uZXJyb3IgPSBmdW5jdGlvbihlcnJvcikge1xuICAgICAgICBMb2dnZXIuZXJyb3IoXCJDb3VsZCBub3QgY29ubmVjdCB0byBcIiArIHdzVXJpICsgXCIgKGludm9raW5nIG9uZXJyb3IgaWYgZGVmaW5lZClcIiwgZXJyb3IpO1xuICAgICAgICBpZiAoY29uZmlnLm9uZXJyb3IpIHtcbiAgICAgICAgICAgIGNvbmZpZy5vbmVycm9yKGVycm9yKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBmdW5jdGlvbiBsb2dDb25uZWN0ZWQod3MsIHdzVXJpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBMb2dnZXIuZGVidWcoXCJXZWJTb2NrZXQgY29ubmVjdGVkIHRvIFwiICsgd3NVcmkpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBMb2dnZXIuZXJyb3IoZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgcmVjb25uZWN0aW9uT25DbG9zZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAod3MucmVhZHlTdGF0ZSA9PT0gQ0xPU0VEKSB7XG4gICAgICAgICAgICBpZiAoY2xvc2luZykge1xuICAgICAgICAgICAgICAgIExvZ2dlci5kZWJ1ZyhcIkNvbm5lY3Rpb24gY2xvc2VkIGJ5IHVzZXJcIik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIExvZ2dlci5kZWJ1ZyhcIkNvbm5lY3Rpb24gY2xvc2VkIHVuZXhwZWN0ZWNseS4gUmVjb25uZWN0aW5nLi4uXCIpO1xuICAgICAgICAgICAgICAgIHJlY29ubmVjdFRvU2FtZVVyaShNQVhfUkVUUklFUywgMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBMb2dnZXIuZGVidWcoXCJDbG9zZSBjYWxsYmFjayBmcm9tIHByZXZpb3VzIHdlYnNvY2tldC4gSWdub3JpbmcgaXRcIik7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgd3Mub25jbG9zZSA9IHJlY29ubmVjdGlvbk9uQ2xvc2U7XG5cbiAgICBmdW5jdGlvbiByZWNvbm5lY3RUb1NhbWVVcmkobWF4UmV0cmllcywgbnVtUmV0cmllcykge1xuICAgICAgICBMb2dnZXIuZGVidWcoXCJyZWNvbm5lY3RUb1NhbWVVcmkgKGF0dGVtcHQgI1wiICsgbnVtUmV0cmllcyArIFwiLCBtYXg9XCIgKyBtYXhSZXRyaWVzICsgXCIpXCIpO1xuXG4gICAgICAgIGlmIChudW1SZXRyaWVzID09PSAxKSB7XG4gICAgICAgICAgICBpZiAocmVjb25uZWN0aW5nKSB7XG4gICAgICAgICAgICAgICAgTG9nZ2VyLndhcm4oXCJUcnlpbmcgdG8gcmVjb25uZWN0VG9OZXdVcmkgd2hlbiByZWNvbm5lY3RpbmcuLi4gSWdub3JpbmcgdGhpcyByZWNvbm5lY3Rpb24uXCIpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZWNvbm5lY3RpbmcgPSB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoY29uZmlnLm9ucmVjb25uZWN0aW5nKSB7XG4gICAgICAgICAgICAgICAgY29uZmlnLm9ucmVjb25uZWN0aW5nKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZm9yY2luZ0Rpc2Nvbm5lY3Rpb24pIHtcbiAgICAgICAgICAgIHJlY29ubmVjdFRvTmV3VXJpKG1heFJldHJpZXMsIG51bVJldHJpZXMsIHdzVXJpKTtcblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKGNvbmZpZy5uZXdXc1VyaU9uUmVjb25uZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgY29uZmlnLm5ld1dzVXJpT25SZWNvbm5lY3Rpb24oZnVuY3Rpb24oZXJyb3IsIG5ld1dzVXJpKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBMb2dnZXIuZGVidWcoZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNvbm5lY3RUb1NhbWVVcmkobWF4UmV0cmllcywgbnVtUmV0cmllcyArIDEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSwgUkVUUllfVElNRV9NUyk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWNvbm5lY3RUb05ld1VyaShtYXhSZXRyaWVzLCBudW1SZXRyaWVzLCBuZXdXc1VyaSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZWNvbm5lY3RUb05ld1VyaShtYXhSZXRyaWVzLCBudW1SZXRyaWVzLCB3c1VyaSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUT0RPIFRlc3QgcmV0cmllcy4gSG93IHRvIGZvcmNlIG5vdCBjb25uZWN0aW9uP1xuICAgIGZ1bmN0aW9uIHJlY29ubmVjdFRvTmV3VXJpKG1heFJldHJpZXMsIG51bVJldHJpZXMsIHJlY29ubmVjdFdzVXJpKSB7XG4gICAgICAgIExvZ2dlci5kZWJ1ZyhcIlJlY29ubmVjdGlvbiBhdHRlbXB0ICNcIiArIG51bVJldHJpZXMpO1xuXG4gICAgICAgIHdzLmNsb3NlKCk7XG5cbiAgICAgICAgd3NVcmkgPSByZWNvbm5lY3RXc1VyaSB8fCB3c1VyaTtcblxuICAgICAgICB2YXIgbmV3V3M7XG4gICAgICAgIGlmICh1c2VTb2NrSlMpIHtcbiAgICAgICAgICAgIG5ld1dzID0gbmV3IFNvY2tKUyh3c1VyaSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBuZXdXcyA9IG5ldyBXZWJTb2NrZXQod3NVcmkpO1xuICAgICAgICB9XG5cbiAgICAgICAgbmV3V3Mub25vcGVuID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBMb2dnZXIuZGVidWcoXCJSZWNvbm5lY3RlZCBhZnRlciBcIiArIG51bVJldHJpZXMgKyBcIiBhdHRlbXB0cy4uLlwiKTtcbiAgICAgICAgICAgIGxvZ0Nvbm5lY3RlZChuZXdXcywgd3NVcmkpO1xuICAgICAgICAgICAgcmVjb25uZWN0aW5nID0gZmFsc2U7XG4gICAgICAgICAgICByZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKCk7XG4gICAgICAgICAgICBpZiAoY29uZmlnLm9ucmVjb25uZWN0ZWQoKSkge1xuICAgICAgICAgICAgICAgIGNvbmZpZy5vbnJlY29ubmVjdGVkKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG5ld1dzLm9uY2xvc2UgPSByZWNvbm5lY3Rpb25PbkNsb3NlO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBvbkVycm9yT3JDbG9zZSA9IGZ1bmN0aW9uKGVycm9yKSB7XG4gICAgICAgICAgICBMb2dnZXIud2FybihcIlJlY29ubmVjdGlvbiBlcnJvcjogXCIsIGVycm9yKTtcblxuICAgICAgICAgICAgaWYgKG51bVJldHJpZXMgPT09IG1heFJldHJpZXMpIHtcbiAgICAgICAgICAgICAgICBpZiAoY29uZmlnLm9uZGlzY29ubmVjdCkge1xuICAgICAgICAgICAgICAgICAgICBjb25maWcub25kaXNjb25uZWN0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICByZWNvbm5lY3RUb1NhbWVVcmkobWF4UmV0cmllcywgbnVtUmV0cmllcyArIDEpO1xuICAgICAgICAgICAgICAgIH0sIFJFVFJZX1RJTUVfTVMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIG5ld1dzLm9uZXJyb3IgPSBvbkVycm9yT3JDbG9zZTtcblxuICAgICAgICB3cyA9IG5ld1dzO1xuICAgIH1cblxuICAgIHRoaXMuY2xvc2UgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgY2xvc2luZyA9IHRydWU7XG4gICAgICAgIHdzLmNsb3NlKCk7XG4gICAgfTtcblxuXG4gICAgLy8gVGhpcyBtZXRob2QgaXMgb25seSBmb3IgdGVzdGluZ1xuICAgIHRoaXMuZm9yY2VDbG9zZSA9IGZ1bmN0aW9uKG1pbGxpcykge1xuICAgICAgICBMb2dnZXIuZGVidWcoXCJUZXN0aW5nOiBGb3JjZSBXZWJTb2NrZXQgY2xvc2VcIik7XG5cbiAgICAgICAgaWYgKG1pbGxpcykge1xuICAgICAgICAgICAgTG9nZ2VyLmRlYnVnKFwiVGVzdGluZzogQ2hhbmdlIHdzVXJpIGZvciBcIiArIG1pbGxpcyArIFwiIG1pbGxpcyB0byBzaW11bGF0ZSBuZXQgZmFpbHVyZVwiKTtcbiAgICAgICAgICAgIHZhciBnb29kV3NVcmkgPSB3c1VyaTtcbiAgICAgICAgICAgIHdzVXJpID0gXCJ3c3M6Ly8yMS4yMzQuMTIuMzQuNDo0NDMvXCI7XG5cbiAgICAgICAgICAgIGZvcmNpbmdEaXNjb25uZWN0aW9uID0gdHJ1ZTtcblxuICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICBMb2dnZXIuZGVidWcoXCJUZXN0aW5nOiBSZWNvdmVyIGdvb2Qgd3NVcmkgXCIgKyBnb29kV3NVcmkpO1xuICAgICAgICAgICAgICAgIHdzVXJpID0gZ29vZFdzVXJpO1xuXG4gICAgICAgICAgICAgICAgZm9yY2luZ0Rpc2Nvbm5lY3Rpb24gPSBmYWxzZTtcblxuICAgICAgICAgICAgfSwgbWlsbGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHdzLmNsb3NlKCk7XG4gICAgfTtcblxuICAgIHRoaXMucmVjb25uZWN0V3MgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgTG9nZ2VyLmRlYnVnKFwicmVjb25uZWN0V3NcIik7XG4gICAgICAgIHJlY29ubmVjdFRvU2FtZVVyaShNQVhfUkVUUklFUywgMSwgd3NVcmkpO1xuICAgIH07XG5cbiAgICB0aGlzLnNlbmQgPSBmdW5jdGlvbihtZXNzYWdlKSB7XG4gICAgICAgIHdzLnNlbmQobWVzc2FnZSk7XG4gICAgfTtcblxuICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGNhbGxiYWNrKSB7XG4gICAgICAgIHJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHdzLmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgY2FsbGJhY2spO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoKTtcbiAgICB9O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFdlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb247XG4iLCIvKlxuICogKEMpIENvcHlyaWdodCAyMDE0IEt1cmVudG8gKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKi9cblxuXG52YXIgZGVmaW5lUHJvcGVydHlfSUU4ID0gZmFsc2VcbmlmKE9iamVjdC5kZWZpbmVQcm9wZXJ0eSlcbntcbiAgdHJ5XG4gIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoe30sIFwieFwiLCB7fSk7XG4gIH1cbiAgY2F0Y2goZSlcbiAge1xuICAgIGRlZmluZVByb3BlcnR5X0lFOCA9IHRydWVcbiAgfVxufVxuXG4vLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9GdW5jdGlvbi9iaW5kXG5pZiAoIUZ1bmN0aW9uLnByb3RvdHlwZS5iaW5kKSB7XG4gIEZ1bmN0aW9uLnByb3RvdHlwZS5iaW5kID0gZnVuY3Rpb24ob1RoaXMpIHtcbiAgICBpZiAodHlwZW9mIHRoaXMgIT09ICdmdW5jdGlvbicpIHtcbiAgICAgIC8vIGNsb3Nlc3QgdGhpbmcgcG9zc2libGUgdG8gdGhlIEVDTUFTY3JpcHQgNVxuICAgICAgLy8gaW50ZXJuYWwgSXNDYWxsYWJsZSBmdW5jdGlvblxuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQgLSB3aGF0IGlzIHRyeWluZyB0byBiZSBib3VuZCBpcyBub3QgY2FsbGFibGUnKTtcbiAgICB9XG5cbiAgICB2YXIgYUFyZ3MgICA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSksXG4gICAgICAgIGZUb0JpbmQgPSB0aGlzLFxuICAgICAgICBmTk9QICAgID0gZnVuY3Rpb24oKSB7fSxcbiAgICAgICAgZkJvdW5kICA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHJldHVybiBmVG9CaW5kLmFwcGx5KHRoaXMgaW5zdGFuY2VvZiBmTk9QICYmIG9UaGlzXG4gICAgICAgICAgICAgICAgID8gdGhpc1xuICAgICAgICAgICAgICAgICA6IG9UaGlzLFxuICAgICAgICAgICAgICAgICBhQXJncy5jb25jYXQoQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9O1xuXG4gICAgZk5PUC5wcm90b3R5cGUgPSB0aGlzLnByb3RvdHlwZTtcbiAgICBmQm91bmQucHJvdG90eXBlID0gbmV3IGZOT1AoKTtcblxuICAgIHJldHVybiBmQm91bmQ7XG4gIH07XG59XG5cblxudmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlcjtcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKTtcblxudmFyIHBhY2tlcnMgPSByZXF1aXJlKCcuL3BhY2tlcnMnKTtcbnZhciBNYXBwZXIgPSByZXF1aXJlKCcuL01hcHBlcicpO1xuXG5cbnZhciBCQVNFX1RJTUVPVVQgPSA1MDAwO1xuXG5cbmZ1bmN0aW9uIHVuaWZ5UmVzcG9uc2VNZXRob2RzKHJlc3BvbnNlTWV0aG9kcylcbntcbiAgaWYoIXJlc3BvbnNlTWV0aG9kcykgcmV0dXJuIHt9O1xuXG4gIGZvcih2YXIga2V5IGluIHJlc3BvbnNlTWV0aG9kcylcbiAge1xuICAgIHZhciB2YWx1ZSA9IHJlc3BvbnNlTWV0aG9kc1trZXldO1xuXG4gICAgaWYodHlwZW9mIHZhbHVlID09ICdzdHJpbmcnKVxuICAgICAgcmVzcG9uc2VNZXRob2RzW2tleV0gPVxuICAgICAge1xuICAgICAgICByZXNwb25zZTogdmFsdWVcbiAgICAgIH1cbiAgfTtcblxuICByZXR1cm4gcmVzcG9uc2VNZXRob2RzO1xufTtcblxuZnVuY3Rpb24gdW5pZnlUcmFuc3BvcnQodHJhbnNwb3J0KVxue1xuICBpZighdHJhbnNwb3J0KSByZXR1cm47XG5cbiAgLy8gVHJhbnNwb3J0IGFzIGEgZnVuY3Rpb25cbiAgaWYodHJhbnNwb3J0IGluc3RhbmNlb2YgRnVuY3Rpb24pXG4gICAgcmV0dXJuIHtzZW5kOiB0cmFuc3BvcnR9O1xuXG4gIC8vIFdlYlNvY2tldCAmIERhdGFDaGFubmVsXG4gIGlmKHRyYW5zcG9ydC5zZW5kIGluc3RhbmNlb2YgRnVuY3Rpb24pXG4gICAgcmV0dXJuIHRyYW5zcG9ydDtcblxuICAvLyBNZXNzYWdlIEFQSSAoSW50ZXItd2luZG93ICYgV2ViV29ya2VyKVxuICBpZih0cmFuc3BvcnQucG9zdE1lc3NhZ2UgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAge1xuICAgIHRyYW5zcG9ydC5zZW5kID0gdHJhbnNwb3J0LnBvc3RNZXNzYWdlO1xuICAgIHJldHVybiB0cmFuc3BvcnQ7XG4gIH1cblxuICAvLyBTdHJlYW0gQVBJXG4gIGlmKHRyYW5zcG9ydC53cml0ZSBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICB7XG4gICAgdHJhbnNwb3J0LnNlbmQgPSB0cmFuc3BvcnQud3JpdGU7XG4gICAgcmV0dXJuIHRyYW5zcG9ydDtcbiAgfVxuXG4gIC8vIFRyYW5zcG9ydHMgdGhhdCBvbmx5IGNhbiByZWNlaXZlIG1lc3NhZ2VzLCBidXQgbm90IHNlbmRcbiAgaWYodHJhbnNwb3J0Lm9ubWVzc2FnZSAhPT0gdW5kZWZpbmVkKSByZXR1cm47XG4gIGlmKHRyYW5zcG9ydC5wYXVzZSBpbnN0YW5jZW9mIEZ1bmN0aW9uKSByZXR1cm47XG5cbiAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVHJhbnNwb3J0IGlzIG5vdCBhIGZ1bmN0aW9uIG5vciBhIHZhbGlkIG9iamVjdFwiKTtcbn07XG5cblxuLyoqXG4gKiBSZXByZXNlbnRhdGlvbiBvZiBhIFJQQyBub3RpZmljYXRpb25cbiAqXG4gKiBAY2xhc3NcbiAqXG4gKiBAY29uc3RydWN0b3JcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbWV0aG9kIC1tZXRob2Qgb2YgdGhlIG5vdGlmaWNhdGlvblxuICogQHBhcmFtIHBhcmFtcyAtIHBhcmFtZXRlcnMgb2YgdGhlIG5vdGlmaWNhdGlvblxuICovXG5mdW5jdGlvbiBScGNOb3RpZmljYXRpb24obWV0aG9kLCBwYXJhbXMpXG57XG4gIGlmKGRlZmluZVByb3BlcnR5X0lFOClcbiAge1xuICAgIHRoaXMubWV0aG9kID0gbWV0aG9kXG4gICAgdGhpcy5wYXJhbXMgPSBwYXJhbXNcbiAgfVxuICBlbHNlXG4gIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ21ldGhvZCcsIHt2YWx1ZTogbWV0aG9kLCBlbnVtZXJhYmxlOiB0cnVlfSk7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICdwYXJhbXMnLCB7dmFsdWU6IHBhcmFtcywgZW51bWVyYWJsZTogdHJ1ZX0pO1xuICB9XG59O1xuXG5cbi8qKlxuICogQGNsYXNzXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IHBhY2tlclxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc11cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gW3RyYW5zcG9ydF1cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBbb25SZXF1ZXN0XVxuICovXG5mdW5jdGlvbiBScGNCdWlsZGVyKHBhY2tlciwgb3B0aW9ucywgdHJhbnNwb3J0LCBvblJlcXVlc3QpXG57XG4gIHZhciBzZWxmID0gdGhpcztcblxuICBpZighcGFja2VyKVxuICAgIHRocm93IG5ldyBTeW50YXhFcnJvcignUGFja2VyIGlzIG5vdCBkZWZpbmVkJyk7XG5cbiAgaWYoIXBhY2tlci5wYWNrIHx8ICFwYWNrZXIudW5wYWNrKVxuICAgIHRocm93IG5ldyBTeW50YXhFcnJvcignUGFja2VyIGlzIGludmFsaWQnKTtcblxuICB2YXIgcmVzcG9uc2VNZXRob2RzID0gdW5pZnlSZXNwb25zZU1ldGhvZHMocGFja2VyLnJlc3BvbnNlTWV0aG9kcyk7XG5cblxuICBpZihvcHRpb25zIGluc3RhbmNlb2YgRnVuY3Rpb24pXG4gIHtcbiAgICBpZih0cmFuc3BvcnQgIT0gdW5kZWZpbmVkKVxuICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlcmUgY2FuJ3QgYmUgcGFyYW1ldGVycyBhZnRlciBvblJlcXVlc3RcIik7XG5cbiAgICBvblJlcXVlc3QgPSBvcHRpb25zO1xuICAgIHRyYW5zcG9ydCA9IHVuZGVmaW5lZDtcbiAgICBvcHRpb25zICAgPSB1bmRlZmluZWQ7XG4gIH07XG5cbiAgaWYob3B0aW9ucyAmJiBvcHRpb25zLnNlbmQgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAge1xuICAgIGlmKHRyYW5zcG9ydCAmJiAhKHRyYW5zcG9ydCBpbnN0YW5jZW9mIEZ1bmN0aW9uKSlcbiAgICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIk9ubHkgYSBmdW5jdGlvbiBjYW4gYmUgYWZ0ZXIgdHJhbnNwb3J0XCIpO1xuXG4gICAgb25SZXF1ZXN0ID0gdHJhbnNwb3J0O1xuICAgIHRyYW5zcG9ydCA9IG9wdGlvbnM7XG4gICAgb3B0aW9ucyAgID0gdW5kZWZpbmVkO1xuICB9O1xuXG4gIGlmKHRyYW5zcG9ydCBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICB7XG4gICAgaWYob25SZXF1ZXN0ICE9IHVuZGVmaW5lZClcbiAgICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIlRoZXJlIGNhbid0IGJlIHBhcmFtZXRlcnMgYWZ0ZXIgb25SZXF1ZXN0XCIpO1xuXG4gICAgb25SZXF1ZXN0ID0gdHJhbnNwb3J0O1xuICAgIHRyYW5zcG9ydCA9IHVuZGVmaW5lZDtcbiAgfTtcblxuICBpZih0cmFuc3BvcnQgJiYgdHJhbnNwb3J0LnNlbmQgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAgICBpZihvblJlcXVlc3QgJiYgIShvblJlcXVlc3QgaW5zdGFuY2VvZiBGdW5jdGlvbikpXG4gICAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJPbmx5IGEgZnVuY3Rpb24gY2FuIGJlIGFmdGVyIHRyYW5zcG9ydFwiKTtcblxuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuXG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuXG4gIGlmKG9uUmVxdWVzdClcbiAgICB0aGlzLm9uKCdyZXF1ZXN0Jywgb25SZXF1ZXN0KTtcblxuXG4gIGlmKGRlZmluZVByb3BlcnR5X0lFOClcbiAgICB0aGlzLnBlZXJJRCA9IG9wdGlvbnMucGVlcklEXG4gIGVsc2VcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ3BlZXJJRCcsIHt2YWx1ZTogb3B0aW9ucy5wZWVySUR9KTtcblxuICB2YXIgbWF4X3JldHJpZXMgPSBvcHRpb25zLm1heF9yZXRyaWVzIHx8IDA7XG5cblxuICBmdW5jdGlvbiB0cmFuc3BvcnRNZXNzYWdlKGV2ZW50KVxuICB7XG4gICAgc2VsZi5kZWNvZGUoZXZlbnQuZGF0YSB8fCBldmVudCk7XG4gIH07XG5cbiAgdGhpcy5nZXRUcmFuc3BvcnQgPSBmdW5jdGlvbigpXG4gIHtcbiAgICByZXR1cm4gdHJhbnNwb3J0O1xuICB9XG4gIHRoaXMuc2V0VHJhbnNwb3J0ID0gZnVuY3Rpb24odmFsdWUpXG4gIHtcbiAgICAvLyBSZW1vdmUgbGlzdGVuZXIgZnJvbSBvbGQgdHJhbnNwb3J0XG4gICAgaWYodHJhbnNwb3J0KVxuICAgIHtcbiAgICAgIC8vIFczQyB0cmFuc3BvcnRzXG4gICAgICBpZih0cmFuc3BvcnQucmVtb3ZlRXZlbnRMaXN0ZW5lcilcbiAgICAgICAgdHJhbnNwb3J0LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCB0cmFuc3BvcnRNZXNzYWdlKTtcblxuICAgICAgLy8gTm9kZS5qcyBTdHJlYW1zIEFQSVxuICAgICAgZWxzZSBpZih0cmFuc3BvcnQucmVtb3ZlTGlzdGVuZXIpXG4gICAgICAgIHRyYW5zcG9ydC5yZW1vdmVMaXN0ZW5lcignZGF0YScsIHRyYW5zcG9ydE1lc3NhZ2UpO1xuICAgIH07XG5cbiAgICAvLyBTZXQgbGlzdGVuZXIgb24gbmV3IHRyYW5zcG9ydFxuICAgIGlmKHZhbHVlKVxuICAgIHtcbiAgICAgIC8vIFczQyB0cmFuc3BvcnRzXG4gICAgICBpZih2YWx1ZS5hZGRFdmVudExpc3RlbmVyKVxuICAgICAgICB2YWx1ZS5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgdHJhbnNwb3J0TWVzc2FnZSk7XG5cbiAgICAgIC8vIE5vZGUuanMgU3RyZWFtcyBBUElcbiAgICAgIGVsc2UgaWYodmFsdWUuYWRkTGlzdGVuZXIpXG4gICAgICAgIHZhbHVlLmFkZExpc3RlbmVyKCdkYXRhJywgdHJhbnNwb3J0TWVzc2FnZSk7XG4gICAgfTtcblxuICAgIHRyYW5zcG9ydCA9IHVuaWZ5VHJhbnNwb3J0KHZhbHVlKTtcbiAgfVxuXG4gIGlmKCFkZWZpbmVQcm9wZXJ0eV9JRTgpXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICd0cmFuc3BvcnQnLFxuICAgIHtcbiAgICAgIGdldDogdGhpcy5nZXRUcmFuc3BvcnQuYmluZCh0aGlzKSxcbiAgICAgIHNldDogdGhpcy5zZXRUcmFuc3BvcnQuYmluZCh0aGlzKVxuICAgIH0pXG5cbiAgdGhpcy5zZXRUcmFuc3BvcnQodHJhbnNwb3J0KTtcblxuXG4gIHZhciByZXF1ZXN0X3RpbWVvdXQgICAgICA9IG9wdGlvbnMucmVxdWVzdF90aW1lb3V0ICAgICAgfHwgQkFTRV9USU1FT1VUO1xuICB2YXIgcGluZ19yZXF1ZXN0X3RpbWVvdXQgPSBvcHRpb25zLnBpbmdfcmVxdWVzdF90aW1lb3V0IHx8IHJlcXVlc3RfdGltZW91dDtcbiAgdmFyIHJlc3BvbnNlX3RpbWVvdXQgICAgID0gb3B0aW9ucy5yZXNwb25zZV90aW1lb3V0ICAgICB8fCBCQVNFX1RJTUVPVVQ7XG4gIHZhciBkdXBsaWNhdGVzX3RpbWVvdXQgICA9IG9wdGlvbnMuZHVwbGljYXRlc190aW1lb3V0ICAgfHwgQkFTRV9USU1FT1VUO1xuXG5cbiAgdmFyIHJlcXVlc3RJRCA9IDA7XG5cbiAgdmFyIHJlcXVlc3RzICA9IG5ldyBNYXBwZXIoKTtcbiAgdmFyIHJlc3BvbnNlcyA9IG5ldyBNYXBwZXIoKTtcbiAgdmFyIHByb2Nlc3NlZFJlc3BvbnNlcyA9IG5ldyBNYXBwZXIoKTtcblxuICB2YXIgbWVzc2FnZTJLZXkgPSB7fTtcblxuXG4gIC8qKlxuICAgKiBTdG9yZSB0aGUgcmVzcG9uc2UgdG8gcHJldmVudCB0byBwcm9jZXNzIGR1cGxpY2F0ZSByZXF1ZXN0IGxhdGVyXG4gICAqL1xuICBmdW5jdGlvbiBzdG9yZVJlc3BvbnNlKG1lc3NhZ2UsIGlkLCBkZXN0KVxuICB7XG4gICAgdmFyIHJlc3BvbnNlID1cbiAgICB7XG4gICAgICBtZXNzYWdlOiBtZXNzYWdlLFxuICAgICAgLyoqIFRpbWVvdXQgdG8gYXV0by1jbGVhbiBvbGQgcmVzcG9uc2VzICovXG4gICAgICB0aW1lb3V0OiBzZXRUaW1lb3V0KGZ1bmN0aW9uKClcbiAgICAgIHtcbiAgICAgICAgcmVzcG9uc2VzLnJlbW92ZShpZCwgZGVzdCk7XG4gICAgICB9LFxuICAgICAgcmVzcG9uc2VfdGltZW91dClcbiAgICB9O1xuXG4gICAgcmVzcG9uc2VzLnNldChyZXNwb25zZSwgaWQsIGRlc3QpO1xuICB9O1xuXG4gIC8qKlxuICAgKiBTdG9yZSB0aGUgcmVzcG9uc2UgdG8gaWdub3JlIGR1cGxpY2F0ZWQgbWVzc2FnZXMgbGF0ZXJcbiAgICovXG4gIGZ1bmN0aW9uIHN0b3JlUHJvY2Vzc2VkUmVzcG9uc2UoYWNrLCBmcm9tKVxuICB7XG4gICAgdmFyIHRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKClcbiAgICB7XG4gICAgICBwcm9jZXNzZWRSZXNwb25zZXMucmVtb3ZlKGFjaywgZnJvbSk7XG4gICAgfSxcbiAgICBkdXBsaWNhdGVzX3RpbWVvdXQpO1xuXG4gICAgcHJvY2Vzc2VkUmVzcG9uc2VzLnNldCh0aW1lb3V0LCBhY2ssIGZyb20pO1xuICB9O1xuXG5cbiAgLyoqXG4gICAqIFJlcHJlc2VudGF0aW9uIG9mIGEgUlBDIHJlcXVlc3RcbiAgICpcbiAgICogQGNsYXNzXG4gICAqIEBleHRlbmRzIFJwY05vdGlmaWNhdGlvblxuICAgKlxuICAgKiBAY29uc3RydWN0b3JcbiAgICpcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1ldGhvZCAtbWV0aG9kIG9mIHRoZSBub3RpZmljYXRpb25cbiAgICogQHBhcmFtIHBhcmFtcyAtIHBhcmFtZXRlcnMgb2YgdGhlIG5vdGlmaWNhdGlvblxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGlkIC0gaWRlbnRpZmllciBvZiB0aGUgcmVxdWVzdFxuICAgKiBAcGFyYW0gW2Zyb21dIC0gc291cmNlIG9mIHRoZSBub3RpZmljYXRpb25cbiAgICovXG4gIGZ1bmN0aW9uIFJwY1JlcXVlc3QobWV0aG9kLCBwYXJhbXMsIGlkLCBmcm9tLCB0cmFuc3BvcnQpXG4gIHtcbiAgICBScGNOb3RpZmljYXRpb24uY2FsbCh0aGlzLCBtZXRob2QsIHBhcmFtcyk7XG5cbiAgICB0aGlzLmdldFRyYW5zcG9ydCA9IGZ1bmN0aW9uKClcbiAgICB7XG4gICAgICByZXR1cm4gdHJhbnNwb3J0O1xuICAgIH1cbiAgICB0aGlzLnNldFRyYW5zcG9ydCA9IGZ1bmN0aW9uKHZhbHVlKVxuICAgIHtcbiAgICAgIHRyYW5zcG9ydCA9IHVuaWZ5VHJhbnNwb3J0KHZhbHVlKTtcbiAgICB9XG5cbiAgICBpZighZGVmaW5lUHJvcGVydHlfSUU4KVxuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICd0cmFuc3BvcnQnLFxuICAgICAge1xuICAgICAgICBnZXQ6IHRoaXMuZ2V0VHJhbnNwb3J0LmJpbmQodGhpcyksXG4gICAgICAgIHNldDogdGhpcy5zZXRUcmFuc3BvcnQuYmluZCh0aGlzKVxuICAgICAgfSlcblxuICAgIHZhciByZXNwb25zZSA9IHJlc3BvbnNlcy5nZXQoaWQsIGZyb20pO1xuXG4gICAgLyoqXG4gICAgICogQGNvbnN0YW50IHtCb29sZWFufSBkdXBsaWNhdGVkXG4gICAgICovXG4gICAgaWYoISh0cmFuc3BvcnQgfHwgc2VsZi5nZXRUcmFuc3BvcnQoKSkpXG4gICAge1xuICAgICAgaWYoZGVmaW5lUHJvcGVydHlfSUU4KVxuICAgICAgICB0aGlzLmR1cGxpY2F0ZWQgPSBCb29sZWFuKHJlc3BvbnNlKVxuICAgICAgZWxzZVxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ2R1cGxpY2F0ZWQnLFxuICAgICAgICB7XG4gICAgICAgICAgdmFsdWU6IEJvb2xlYW4ocmVzcG9uc2UpXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHZhciByZXNwb25zZU1ldGhvZCA9IHJlc3BvbnNlTWV0aG9kc1ttZXRob2RdO1xuXG4gICAgdGhpcy5wYWNrID0gcGFja2VyLnBhY2suYmluZChwYWNrZXIsIHRoaXMsIGlkKVxuXG4gICAgLyoqXG4gICAgICogR2VuZXJhdGUgYSByZXNwb25zZSB0byB0aGlzIHJlcXVlc3RcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7RXJyb3J9IFtlcnJvcl1cbiAgICAgKiBAcGFyYW0geyp9IFtyZXN1bHRdXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgICAqL1xuICAgIHRoaXMucmVwbHkgPSBmdW5jdGlvbihlcnJvciwgcmVzdWx0LCB0cmFuc3BvcnQpXG4gICAge1xuICAgICAgLy8gRml4IG9wdGlvbmFsIHBhcmFtZXRlcnNcbiAgICAgIGlmKGVycm9yIGluc3RhbmNlb2YgRnVuY3Rpb24gfHwgZXJyb3IgJiYgZXJyb3Iuc2VuZCBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICAgICAge1xuICAgICAgICBpZihyZXN1bHQgIT0gdW5kZWZpbmVkKVxuICAgICAgICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIlRoZXJlIGNhbid0IGJlIHBhcmFtZXRlcnMgYWZ0ZXIgY2FsbGJhY2tcIik7XG5cbiAgICAgICAgdHJhbnNwb3J0ID0gZXJyb3I7XG4gICAgICAgIHJlc3VsdCA9IG51bGw7XG4gICAgICAgIGVycm9yID0gdW5kZWZpbmVkO1xuICAgICAgfVxuXG4gICAgICBlbHNlIGlmKHJlc3VsdCBpbnN0YW5jZW9mIEZ1bmN0aW9uXG4gICAgICB8fCByZXN1bHQgJiYgcmVzdWx0LnNlbmQgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAgICAgIHtcbiAgICAgICAgaWYodHJhbnNwb3J0ICE9IHVuZGVmaW5lZClcbiAgICAgICAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJUaGVyZSBjYW4ndCBiZSBwYXJhbWV0ZXJzIGFmdGVyIGNhbGxiYWNrXCIpO1xuXG4gICAgICAgIHRyYW5zcG9ydCA9IHJlc3VsdDtcbiAgICAgICAgcmVzdWx0ID0gbnVsbDtcbiAgICAgIH07XG5cbiAgICAgIHRyYW5zcG9ydCA9IHVuaWZ5VHJhbnNwb3J0KHRyYW5zcG9ydCk7XG5cbiAgICAgIC8vIER1cGxpY2F0ZWQgcmVxdWVzdCwgcmVtb3ZlIG9sZCByZXNwb25zZSB0aW1lb3V0XG4gICAgICBpZihyZXNwb25zZSlcbiAgICAgICAgY2xlYXJUaW1lb3V0KHJlc3BvbnNlLnRpbWVvdXQpO1xuXG4gICAgICBpZihmcm9tICE9IHVuZGVmaW5lZClcbiAgICAgIHtcbiAgICAgICAgaWYoZXJyb3IpXG4gICAgICAgICAgZXJyb3IuZGVzdCA9IGZyb207XG5cbiAgICAgICAgaWYocmVzdWx0KVxuICAgICAgICAgIHJlc3VsdC5kZXN0ID0gZnJvbTtcbiAgICAgIH07XG5cbiAgICAgIHZhciBtZXNzYWdlO1xuXG4gICAgICAvLyBOZXcgcmVxdWVzdCBvciBvdmVycmlkZW4gb25lLCBjcmVhdGUgbmV3IHJlc3BvbnNlIHdpdGggcHJvdmlkZWQgZGF0YVxuICAgICAgaWYoZXJyb3IgfHwgcmVzdWx0ICE9IHVuZGVmaW5lZClcbiAgICAgIHtcbiAgICAgICAgaWYoc2VsZi5wZWVySUQgIT0gdW5kZWZpbmVkKVxuICAgICAgICB7XG4gICAgICAgICAgaWYoZXJyb3IpXG4gICAgICAgICAgICBlcnJvci5mcm9tID0gc2VsZi5wZWVySUQ7XG4gICAgICAgICAgZWxzZVxuICAgICAgICAgICAgcmVzdWx0LmZyb20gPSBzZWxmLnBlZXJJRDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFByb3RvY29sIGluZGljYXRlcyB0aGF0IHJlc3BvbnNlcyBoYXMgb3duIHJlcXVlc3QgbWV0aG9kc1xuICAgICAgICBpZihyZXNwb25zZU1ldGhvZClcbiAgICAgICAge1xuICAgICAgICAgIGlmKHJlc3BvbnNlTWV0aG9kLmVycm9yID09IHVuZGVmaW5lZCAmJiBlcnJvcilcbiAgICAgICAgICAgIG1lc3NhZ2UgPVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBlcnJvcjogZXJyb3JcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICBlbHNlXG4gICAgICAgICAge1xuICAgICAgICAgICAgdmFyIG1ldGhvZCA9IGVycm9yXG4gICAgICAgICAgICAgICAgICAgICAgID8gcmVzcG9uc2VNZXRob2QuZXJyb3JcbiAgICAgICAgICAgICAgICAgICAgICAgOiByZXNwb25zZU1ldGhvZC5yZXNwb25zZTtcblxuICAgICAgICAgICAgbWVzc2FnZSA9XG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIG1ldGhvZDogbWV0aG9kLFxuICAgICAgICAgICAgICBwYXJhbXM6IGVycm9yIHx8IHJlc3VsdFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICAgIG1lc3NhZ2UgPVxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGVycm9yOiAgZXJyb3IsXG4gICAgICAgICAgICByZXN1bHQ6IHJlc3VsdFxuICAgICAgICAgIH07XG5cbiAgICAgICAgbWVzc2FnZSA9IHBhY2tlci5wYWNrKG1lc3NhZ2UsIGlkKTtcbiAgICAgIH1cblxuICAgICAgLy8gRHVwbGljYXRlICYgbm90LW92ZXJyaWRlbiByZXF1ZXN0LCByZS1zZW5kIG9sZCByZXNwb25zZVxuICAgICAgZWxzZSBpZihyZXNwb25zZSlcbiAgICAgICAgbWVzc2FnZSA9IHJlc3BvbnNlLm1lc3NhZ2U7XG5cbiAgICAgIC8vIE5ldyBlbXB0eSByZXBseSwgcmVzcG9uc2UgbnVsbCB2YWx1ZVxuICAgICAgZWxzZVxuICAgICAgICBtZXNzYWdlID0gcGFja2VyLnBhY2soe3Jlc3VsdDogbnVsbH0sIGlkKTtcblxuICAgICAgLy8gU3RvcmUgdGhlIHJlc3BvbnNlIHRvIHByZXZlbnQgdG8gcHJvY2VzcyBhIGR1cGxpY2F0ZWQgcmVxdWVzdCBsYXRlclxuICAgICAgc3RvcmVSZXNwb25zZShtZXNzYWdlLCBpZCwgZnJvbSk7XG5cbiAgICAgIC8vIFJldHVybiB0aGUgc3RvcmVkIHJlc3BvbnNlIHNvIGl0IGNhbiBiZSBkaXJlY3RseSBzZW5kIGJhY2tcbiAgICAgIHRyYW5zcG9ydCA9IHRyYW5zcG9ydCB8fCB0aGlzLmdldFRyYW5zcG9ydCgpIHx8IHNlbGYuZ2V0VHJhbnNwb3J0KCk7XG5cbiAgICAgIGlmKHRyYW5zcG9ydClcbiAgICAgICAgcmV0dXJuIHRyYW5zcG9ydC5zZW5kKG1lc3NhZ2UpO1xuXG4gICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICB9XG4gIH07XG4gIGluaGVyaXRzKFJwY1JlcXVlc3QsIFJwY05vdGlmaWNhdGlvbik7XG5cblxuICBmdW5jdGlvbiBjYW5jZWwobWVzc2FnZSlcbiAge1xuICAgIHZhciBrZXkgPSBtZXNzYWdlMktleVttZXNzYWdlXTtcbiAgICBpZigha2V5KSByZXR1cm47XG5cbiAgICBkZWxldGUgbWVzc2FnZTJLZXlbbWVzc2FnZV07XG5cbiAgICB2YXIgcmVxdWVzdCA9IHJlcXVlc3RzLnBvcChrZXkuaWQsIGtleS5kZXN0KTtcbiAgICBpZighcmVxdWVzdCkgcmV0dXJuO1xuXG4gICAgY2xlYXJUaW1lb3V0KHJlcXVlc3QudGltZW91dCk7XG5cbiAgICAvLyBTdGFydCBkdXBsaWNhdGVkIHJlc3BvbnNlcyB0aW1lb3V0XG4gICAgc3RvcmVQcm9jZXNzZWRSZXNwb25zZShrZXkuaWQsIGtleS5kZXN0KTtcbiAgfTtcblxuICAvKipcbiAgICogQWxsb3cgdG8gY2FuY2VsIGEgcmVxdWVzdCBhbmQgZG9uJ3Qgd2FpdCBmb3IgYSByZXNwb25zZVxuICAgKlxuICAgKiBJZiBgbWVzc2FnZWAgaXMgbm90IGdpdmVuLCBjYW5jZWwgYWxsIHRoZSByZXF1ZXN0XG4gICAqL1xuICB0aGlzLmNhbmNlbCA9IGZ1bmN0aW9uKG1lc3NhZ2UpXG4gIHtcbiAgICBpZihtZXNzYWdlKSByZXR1cm4gY2FuY2VsKG1lc3NhZ2UpO1xuXG4gICAgZm9yKHZhciBtZXNzYWdlIGluIG1lc3NhZ2UyS2V5KVxuICAgICAgY2FuY2VsKG1lc3NhZ2UpO1xuICB9O1xuXG5cbiAgdGhpcy5jbG9zZSA9IGZ1bmN0aW9uKClcbiAge1xuICAgIC8vIFByZXZlbnQgdG8gcmVjZWl2ZSBuZXcgbWVzc2FnZXNcbiAgICB2YXIgdHJhbnNwb3J0ID0gdGhpcy5nZXRUcmFuc3BvcnQoKTtcbiAgICBpZih0cmFuc3BvcnQgJiYgdHJhbnNwb3J0LmNsb3NlKVxuICAgICAgIHRyYW5zcG9ydC5jbG9zZSgpO1xuXG4gICAgLy8gUmVxdWVzdCAmIHByb2Nlc3NlZCByZXNwb25zZXNcbiAgICB0aGlzLmNhbmNlbCgpO1xuXG4gICAgcHJvY2Vzc2VkUmVzcG9uc2VzLmZvckVhY2goY2xlYXJUaW1lb3V0KTtcblxuICAgIC8vIFJlc3BvbnNlc1xuICAgIHJlc3BvbnNlcy5mb3JFYWNoKGZ1bmN0aW9uKHJlc3BvbnNlKVxuICAgIHtcbiAgICAgIGNsZWFyVGltZW91dChyZXNwb25zZS50aW1lb3V0KTtcbiAgICB9KTtcbiAgfTtcblxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZXMgYW5kIGVuY29kZSBhIEpzb25SUEMgMi4wIG1lc3NhZ2VcbiAgICpcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1ldGhvZCAtbWV0aG9kIG9mIHRoZSBub3RpZmljYXRpb25cbiAgICogQHBhcmFtIHBhcmFtcyAtIHBhcmFtZXRlcnMgb2YgdGhlIG5vdGlmaWNhdGlvblxuICAgKiBAcGFyYW0gW2Rlc3RdIC0gZGVzdGluYXRpb24gb2YgdGhlIG5vdGlmaWNhdGlvblxuICAgKiBAcGFyYW0ge29iamVjdH0gW3RyYW5zcG9ydF0gLSB0cmFuc3BvcnQgd2hlcmUgdG8gc2VuZCB0aGUgbWVzc2FnZVxuICAgKiBAcGFyYW0gW2NhbGxiYWNrXSAtIGZ1bmN0aW9uIGNhbGxlZCB3aGVuIGEgcmVzcG9uc2UgdG8gdGhpcyByZXF1ZXN0IGlzXG4gICAqICAgcmVjZWl2ZWQuIElmIG5vdCBkZWZpbmVkLCBhIG5vdGlmaWNhdGlvbiB3aWxsIGJlIHNlbmQgaW5zdGVhZFxuICAgKlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBBIHJhdyBKc29uUlBDIDIuMCByZXF1ZXN0IG9yIG5vdGlmaWNhdGlvbiBzdHJpbmdcbiAgICovXG4gIHRoaXMuZW5jb2RlID0gZnVuY3Rpb24obWV0aG9kLCBwYXJhbXMsIGRlc3QsIHRyYW5zcG9ydCwgY2FsbGJhY2spXG4gIHtcbiAgICAvLyBGaXggb3B0aW9uYWwgcGFyYW1ldGVyc1xuICAgIGlmKHBhcmFtcyBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICAgIHtcbiAgICAgIGlmKGRlc3QgIT0gdW5kZWZpbmVkKVxuICAgICAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJUaGVyZSBjYW4ndCBiZSBwYXJhbWV0ZXJzIGFmdGVyIGNhbGxiYWNrXCIpO1xuXG4gICAgICBjYWxsYmFjayAgPSBwYXJhbXM7XG4gICAgICB0cmFuc3BvcnQgPSB1bmRlZmluZWQ7XG4gICAgICBkZXN0ICAgICAgPSB1bmRlZmluZWQ7XG4gICAgICBwYXJhbXMgICAgPSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgZWxzZSBpZihkZXN0IGluc3RhbmNlb2YgRnVuY3Rpb24pXG4gICAge1xuICAgICAgaWYodHJhbnNwb3J0ICE9IHVuZGVmaW5lZClcbiAgICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlcmUgY2FuJ3QgYmUgcGFyYW1ldGVycyBhZnRlciBjYWxsYmFja1wiKTtcblxuICAgICAgY2FsbGJhY2sgID0gZGVzdDtcbiAgICAgIHRyYW5zcG9ydCA9IHVuZGVmaW5lZDtcbiAgICAgIGRlc3QgICAgICA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBlbHNlIGlmKHRyYW5zcG9ydCBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICAgIHtcbiAgICAgIGlmKGNhbGxiYWNrICE9IHVuZGVmaW5lZClcbiAgICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlcmUgY2FuJ3QgYmUgcGFyYW1ldGVycyBhZnRlciBjYWxsYmFja1wiKTtcblxuICAgICAgY2FsbGJhY2sgID0gdHJhbnNwb3J0O1xuICAgICAgdHJhbnNwb3J0ID0gdW5kZWZpbmVkO1xuICAgIH07XG5cbiAgICBpZihzZWxmLnBlZXJJRCAhPSB1bmRlZmluZWQpXG4gICAge1xuICAgICAgcGFyYW1zID0gcGFyYW1zIHx8IHt9O1xuXG4gICAgICBwYXJhbXMuZnJvbSA9IHNlbGYucGVlcklEO1xuICAgIH07XG5cbiAgICBpZihkZXN0ICE9IHVuZGVmaW5lZClcbiAgICB7XG4gICAgICBwYXJhbXMgPSBwYXJhbXMgfHwge307XG5cbiAgICAgIHBhcmFtcy5kZXN0ID0gZGVzdDtcbiAgICB9O1xuXG4gICAgLy8gRW5jb2RlIG1lc3NhZ2VcbiAgICB2YXIgbWVzc2FnZSA9XG4gICAge1xuICAgICAgbWV0aG9kOiBtZXRob2QsXG4gICAgICBwYXJhbXM6IHBhcmFtc1xuICAgIH07XG5cbiAgICBpZihjYWxsYmFjaylcbiAgICB7XG4gICAgICB2YXIgaWQgPSByZXF1ZXN0SUQrKztcbiAgICAgIHZhciByZXRyaWVkID0gMDtcblxuICAgICAgbWVzc2FnZSA9IHBhY2tlci5wYWNrKG1lc3NhZ2UsIGlkKTtcblxuICAgICAgZnVuY3Rpb24gZGlzcGF0Y2hDYWxsYmFjayhlcnJvciwgcmVzdWx0KVxuICAgICAge1xuICAgICAgICBzZWxmLmNhbmNlbChtZXNzYWdlKTtcblxuICAgICAgICBjYWxsYmFjayhlcnJvciwgcmVzdWx0KTtcbiAgICAgIH07XG5cbiAgICAgIHZhciByZXF1ZXN0ID1cbiAgICAgIHtcbiAgICAgICAgbWVzc2FnZTogICAgICAgICBtZXNzYWdlLFxuICAgICAgICBjYWxsYmFjazogICAgICAgIGRpc3BhdGNoQ2FsbGJhY2ssXG4gICAgICAgIHJlc3BvbnNlTWV0aG9kczogcmVzcG9uc2VNZXRob2RzW21ldGhvZF0gfHwge31cbiAgICAgIH07XG5cbiAgICAgIHZhciBlbmNvZGVfdHJhbnNwb3J0ID0gdW5pZnlUcmFuc3BvcnQodHJhbnNwb3J0KTtcblxuICAgICAgZnVuY3Rpb24gc2VuZFJlcXVlc3QodHJhbnNwb3J0KVxuICAgICAge1xuICAgICAgICB2YXIgcnQgPSAobWV0aG9kID09PSAncGluZycgPyBwaW5nX3JlcXVlc3RfdGltZW91dCA6IHJlcXVlc3RfdGltZW91dCk7XG4gICAgICAgIHJlcXVlc3QudGltZW91dCA9IHNldFRpbWVvdXQodGltZW91dCwgcnQqTWF0aC5wb3coMiwgcmV0cmllZCsrKSk7XG4gICAgICAgIG1lc3NhZ2UyS2V5W21lc3NhZ2VdID0ge2lkOiBpZCwgZGVzdDogZGVzdH07XG4gICAgICAgIHJlcXVlc3RzLnNldChyZXF1ZXN0LCBpZCwgZGVzdCk7XG5cbiAgICAgICAgdHJhbnNwb3J0ID0gdHJhbnNwb3J0IHx8IGVuY29kZV90cmFuc3BvcnQgfHwgc2VsZi5nZXRUcmFuc3BvcnQoKTtcbiAgICAgICAgaWYodHJhbnNwb3J0KVxuICAgICAgICAgIHJldHVybiB0cmFuc3BvcnQuc2VuZChtZXNzYWdlKTtcblxuICAgICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICAgIH07XG5cbiAgICAgIGZ1bmN0aW9uIHJldHJ5KHRyYW5zcG9ydClcbiAgICAgIHtcbiAgICAgICAgdHJhbnNwb3J0ID0gdW5pZnlUcmFuc3BvcnQodHJhbnNwb3J0KTtcblxuICAgICAgICBjb25zb2xlLndhcm4ocmV0cmllZCsnIHJldHJ5IGZvciByZXF1ZXN0IG1lc3NhZ2U6JyxtZXNzYWdlKTtcblxuICAgICAgICB2YXIgdGltZW91dCA9IHByb2Nlc3NlZFJlc3BvbnNlcy5wb3AoaWQsIGRlc3QpO1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG5cbiAgICAgICAgcmV0dXJuIHNlbmRSZXF1ZXN0KHRyYW5zcG9ydCk7XG4gICAgICB9O1xuXG4gICAgICBmdW5jdGlvbiB0aW1lb3V0KClcbiAgICAgIHtcbiAgICAgICAgaWYocmV0cmllZCA8IG1heF9yZXRyaWVzKVxuICAgICAgICAgIHJldHVybiByZXRyeSh0cmFuc3BvcnQpO1xuXG4gICAgICAgIHZhciBlcnJvciA9IG5ldyBFcnJvcignUmVxdWVzdCBoYXMgdGltZWQgb3V0Jyk7XG4gICAgICAgICAgICBlcnJvci5yZXF1ZXN0ID0gbWVzc2FnZTtcblxuICAgICAgICBlcnJvci5yZXRyeSA9IHJldHJ5O1xuXG4gICAgICAgIGRpc3BhdGNoQ2FsbGJhY2soZXJyb3IpXG4gICAgICB9O1xuXG4gICAgICByZXR1cm4gc2VuZFJlcXVlc3QodHJhbnNwb3J0KTtcbiAgICB9O1xuXG4gICAgLy8gUmV0dXJuIHRoZSBwYWNrZWQgbWVzc2FnZVxuICAgIG1lc3NhZ2UgPSBwYWNrZXIucGFjayhtZXNzYWdlKTtcblxuICAgIHRyYW5zcG9ydCA9IHRyYW5zcG9ydCB8fCB0aGlzLmdldFRyYW5zcG9ydCgpO1xuICAgIGlmKHRyYW5zcG9ydClcbiAgICAgIHJldHVybiB0cmFuc3BvcnQuc2VuZChtZXNzYWdlKTtcblxuICAgIHJldHVybiBtZXNzYWdlO1xuICB9O1xuXG4gIC8qKlxuICAgKiBEZWNvZGUgYW5kIHByb2Nlc3MgYSBKc29uUlBDIDIuMCBtZXNzYWdlXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gc3RyaW5nIHdpdGggdGhlIGNvbnRlbnQgb2YgdGhlIG1lc3NhZ2VcbiAgICpcbiAgICogQHJldHVybnMge1JwY05vdGlmaWNhdGlvbnxScGNSZXF1ZXN0fHVuZGVmaW5lZH0gLSB0aGUgcmVwcmVzZW50YXRpb24gb2YgdGhlXG4gICAqICAgbm90aWZpY2F0aW9uIG9yIHRoZSByZXF1ZXN0LiBJZiBhIHJlc3BvbnNlIHdhcyBwcm9jZXNzZWQsIGl0IHdpbGwgcmV0dXJuXG4gICAqICAgYHVuZGVmaW5lZGAgdG8gbm90aWZ5IHRoYXQgaXQgd2FzIHByb2Nlc3NlZFxuICAgKlxuICAgKiBAdGhyb3dzIHtUeXBlRXJyb3J9IC0gTWVzc2FnZSBpcyBub3QgZGVmaW5lZFxuICAgKi9cbiAgdGhpcy5kZWNvZGUgPSBmdW5jdGlvbihtZXNzYWdlLCB0cmFuc3BvcnQpXG4gIHtcbiAgICBpZighbWVzc2FnZSlcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJNZXNzYWdlIGlzIG5vdCBkZWZpbmVkXCIpO1xuXG4gICAgdHJ5XG4gICAge1xuICAgICAgbWVzc2FnZSA9IHBhY2tlci51bnBhY2sobWVzc2FnZSk7XG4gICAgfVxuICAgIGNhdGNoKGUpXG4gICAge1xuICAgICAgLy8gSWdub3JlIGludmFsaWQgbWVzc2FnZXNcbiAgICAgIHJldHVybiBjb25zb2xlLmRlYnVnKGUsIG1lc3NhZ2UpO1xuICAgIH07XG5cbiAgICB2YXIgaWQgICAgID0gbWVzc2FnZS5pZDtcbiAgICB2YXIgYWNrICAgID0gbWVzc2FnZS5hY2s7XG4gICAgdmFyIG1ldGhvZCA9IG1lc3NhZ2UubWV0aG9kO1xuICAgIHZhciBwYXJhbXMgPSBtZXNzYWdlLnBhcmFtcyB8fCB7fTtcblxuICAgIHZhciBmcm9tID0gcGFyYW1zLmZyb207XG4gICAgdmFyIGRlc3QgPSBwYXJhbXMuZGVzdDtcblxuICAgIC8vIElnbm9yZSBtZXNzYWdlcyBzZW5kIGJ5IHVzXG4gICAgaWYoc2VsZi5wZWVySUQgIT0gdW5kZWZpbmVkICYmIGZyb20gPT0gc2VsZi5wZWVySUQpIHJldHVybjtcblxuICAgIC8vIE5vdGlmaWNhdGlvblxuICAgIGlmKGlkID09IHVuZGVmaW5lZCAmJiBhY2sgPT0gdW5kZWZpbmVkKVxuICAgIHtcbiAgICAgIHZhciBub3RpZmljYXRpb24gPSBuZXcgUnBjTm90aWZpY2F0aW9uKG1ldGhvZCwgcGFyYW1zKTtcblxuICAgICAgaWYoc2VsZi5lbWl0KCdyZXF1ZXN0Jywgbm90aWZpY2F0aW9uKSkgcmV0dXJuO1xuICAgICAgcmV0dXJuIG5vdGlmaWNhdGlvbjtcbiAgICB9O1xuXG5cbiAgICBmdW5jdGlvbiBwcm9jZXNzUmVxdWVzdCgpXG4gICAge1xuICAgICAgLy8gSWYgd2UgaGF2ZSBhIHRyYW5zcG9ydCBhbmQgaXQncyBhIGR1cGxpY2F0ZWQgcmVxdWVzdCwgcmVwbHkgaW5tZWRpYXRseVxuICAgICAgdHJhbnNwb3J0ID0gdW5pZnlUcmFuc3BvcnQodHJhbnNwb3J0KSB8fCBzZWxmLmdldFRyYW5zcG9ydCgpO1xuICAgICAgaWYodHJhbnNwb3J0KVxuICAgICAge1xuICAgICAgICB2YXIgcmVzcG9uc2UgPSByZXNwb25zZXMuZ2V0KGlkLCBmcm9tKTtcbiAgICAgICAgaWYocmVzcG9uc2UpXG4gICAgICAgICAgcmV0dXJuIHRyYW5zcG9ydC5zZW5kKHJlc3BvbnNlLm1lc3NhZ2UpO1xuICAgICAgfTtcblxuICAgICAgdmFyIGlkQWNrID0gKGlkICE9IHVuZGVmaW5lZCkgPyBpZCA6IGFjaztcbiAgICAgIHZhciByZXF1ZXN0ID0gbmV3IFJwY1JlcXVlc3QobWV0aG9kLCBwYXJhbXMsIGlkQWNrLCBmcm9tLCB0cmFuc3BvcnQpO1xuXG4gICAgICBpZihzZWxmLmVtaXQoJ3JlcXVlc3QnLCByZXF1ZXN0KSkgcmV0dXJuO1xuICAgICAgcmV0dXJuIHJlcXVlc3Q7XG4gICAgfTtcblxuICAgIGZ1bmN0aW9uIHByb2Nlc3NSZXNwb25zZShyZXF1ZXN0LCBlcnJvciwgcmVzdWx0KVxuICAgIHtcbiAgICAgIHJlcXVlc3QuY2FsbGJhY2soZXJyb3IsIHJlc3VsdCk7XG4gICAgfTtcblxuICAgIGZ1bmN0aW9uIGR1cGxpY2F0ZWRSZXNwb25zZSh0aW1lb3V0KVxuICAgIHtcbiAgICAgIGNvbnNvbGUud2FybihcIlJlc3BvbnNlIGFscmVhZHkgcHJvY2Vzc2VkXCIsIG1lc3NhZ2UpO1xuXG4gICAgICAvLyBVcGRhdGUgZHVwbGljYXRlZCByZXNwb25zZXMgdGltZW91dFxuICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgc3RvcmVQcm9jZXNzZWRSZXNwb25zZShhY2ssIGZyb20pO1xuICAgIH07XG5cblxuICAgIC8vIFJlcXVlc3QsIG9yIHJlc3BvbnNlIHdpdGggb3duIG1ldGhvZFxuICAgIGlmKG1ldGhvZClcbiAgICB7XG4gICAgICAvLyBDaGVjayBpZiBpdCdzIGEgcmVzcG9uc2Ugd2l0aCBvd24gbWV0aG9kXG4gICAgICBpZihkZXN0ID09IHVuZGVmaW5lZCB8fCBkZXN0ID09IHNlbGYucGVlcklEKVxuICAgICAge1xuICAgICAgICB2YXIgcmVxdWVzdCA9IHJlcXVlc3RzLmdldChhY2ssIGZyb20pO1xuICAgICAgICBpZihyZXF1ZXN0KVxuICAgICAgICB7XG4gICAgICAgICAgdmFyIHJlc3BvbnNlTWV0aG9kcyA9IHJlcXVlc3QucmVzcG9uc2VNZXRob2RzO1xuXG4gICAgICAgICAgaWYobWV0aG9kID09IHJlc3BvbnNlTWV0aG9kcy5lcnJvcilcbiAgICAgICAgICAgIHJldHVybiBwcm9jZXNzUmVzcG9uc2UocmVxdWVzdCwgcGFyYW1zKTtcblxuICAgICAgICAgIGlmKG1ldGhvZCA9PSByZXNwb25zZU1ldGhvZHMucmVzcG9uc2UpXG4gICAgICAgICAgICByZXR1cm4gcHJvY2Vzc1Jlc3BvbnNlKHJlcXVlc3QsIG51bGwsIHBhcmFtcyk7XG5cbiAgICAgICAgICByZXR1cm4gcHJvY2Vzc1JlcXVlc3QoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBwcm9jZXNzZWQgPSBwcm9jZXNzZWRSZXNwb25zZXMuZ2V0KGFjaywgZnJvbSk7XG4gICAgICAgIGlmKHByb2Nlc3NlZClcbiAgICAgICAgICByZXR1cm4gZHVwbGljYXRlZFJlc3BvbnNlKHByb2Nlc3NlZCk7XG4gICAgICB9XG5cbiAgICAgIC8vIFJlcXVlc3RcbiAgICAgIHJldHVybiBwcm9jZXNzUmVxdWVzdCgpO1xuICAgIH07XG5cbiAgICB2YXIgZXJyb3IgID0gbWVzc2FnZS5lcnJvcjtcbiAgICB2YXIgcmVzdWx0ID0gbWVzc2FnZS5yZXN1bHQ7XG5cbiAgICAvLyBJZ25vcmUgcmVzcG9uc2VzIG5vdCBzZW5kIHRvIHVzXG4gICAgaWYoZXJyb3IgICYmIGVycm9yLmRlc3QgICYmIGVycm9yLmRlc3QgICE9IHNlbGYucGVlcklEKSByZXR1cm47XG4gICAgaWYocmVzdWx0ICYmIHJlc3VsdC5kZXN0ICYmIHJlc3VsdC5kZXN0ICE9IHNlbGYucGVlcklEKSByZXR1cm47XG5cbiAgICAvLyBSZXNwb25zZVxuICAgIHZhciByZXF1ZXN0ID0gcmVxdWVzdHMuZ2V0KGFjaywgZnJvbSk7XG4gICAgaWYoIXJlcXVlc3QpXG4gICAge1xuICAgICAgdmFyIHByb2Nlc3NlZCA9IHByb2Nlc3NlZFJlc3BvbnNlcy5nZXQoYWNrLCBmcm9tKTtcbiAgICAgIGlmKHByb2Nlc3NlZClcbiAgICAgICAgcmV0dXJuIGR1cGxpY2F0ZWRSZXNwb25zZShwcm9jZXNzZWQpO1xuXG4gICAgICByZXR1cm4gY29uc29sZS53YXJuKFwiTm8gY2FsbGJhY2sgd2FzIGRlZmluZWQgZm9yIHRoaXMgbWVzc2FnZVwiLCBtZXNzYWdlKTtcbiAgICB9O1xuXG4gICAgLy8gUHJvY2VzcyByZXNwb25zZVxuICAgIHByb2Nlc3NSZXNwb25zZShyZXF1ZXN0LCBlcnJvciwgcmVzdWx0KTtcbiAgfTtcbn07XG5pbmhlcml0cyhScGNCdWlsZGVyLCBFdmVudEVtaXR0ZXIpO1xuXG5cblJwY0J1aWxkZXIuUnBjTm90aWZpY2F0aW9uID0gUnBjTm90aWZpY2F0aW9uO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gUnBjQnVpbGRlcjtcblxudmFyIGNsaWVudHMgPSByZXF1aXJlKCcuL2NsaWVudHMnKTtcbnZhciB0cmFuc3BvcnRzID0gcmVxdWlyZSgnLi9jbGllbnRzL3RyYW5zcG9ydHMnKTtcblxuUnBjQnVpbGRlci5jbGllbnRzID0gY2xpZW50cztcblJwY0J1aWxkZXIuY2xpZW50cy50cmFuc3BvcnRzID0gdHJhbnNwb3J0cztcblJwY0J1aWxkZXIucGFja2VycyA9IHBhY2tlcnM7XG4iLCIvKipcbiAqIEpzb25SUEMgMi4wIHBhY2tlclxuICovXG5cbi8qKlxuICogUGFjayBhIEpzb25SUEMgMi4wIG1lc3NhZ2VcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gbWVzc2FnZSAtIG9iamVjdCB0byBiZSBwYWNrYWdlZC4gSXQgcmVxdWlyZXMgdG8gaGF2ZSBhbGwgdGhlXG4gKiAgIGZpZWxkcyBuZWVkZWQgYnkgdGhlIEpzb25SUEMgMi4wIG1lc3NhZ2UgdGhhdCBpdCdzIGdvaW5nIHRvIGJlIGdlbmVyYXRlZFxuICpcbiAqIEByZXR1cm4ge1N0cmluZ30gLSB0aGUgc3RyaW5naWZpZWQgSnNvblJQQyAyLjAgbWVzc2FnZVxuICovXG5mdW5jdGlvbiBwYWNrKG1lc3NhZ2UsIGlkKVxue1xuICB2YXIgcmVzdWx0ID1cbiAge1xuICAgIGpzb25ycGM6IFwiMi4wXCJcbiAgfTtcblxuICAvLyBSZXF1ZXN0XG4gIGlmKG1lc3NhZ2UubWV0aG9kKVxuICB7XG4gICAgcmVzdWx0Lm1ldGhvZCA9IG1lc3NhZ2UubWV0aG9kO1xuXG4gICAgaWYobWVzc2FnZS5wYXJhbXMpXG4gICAgICByZXN1bHQucGFyYW1zID0gbWVzc2FnZS5wYXJhbXM7XG5cbiAgICAvLyBSZXF1ZXN0IGlzIGEgbm90aWZpY2F0aW9uXG4gICAgaWYoaWQgIT0gdW5kZWZpbmVkKVxuICAgICAgcmVzdWx0LmlkID0gaWQ7XG4gIH1cblxuICAvLyBSZXNwb25zZVxuICBlbHNlIGlmKGlkICE9IHVuZGVmaW5lZClcbiAge1xuICAgIGlmKG1lc3NhZ2UuZXJyb3IpXG4gICAge1xuICAgICAgaWYobWVzc2FnZS5yZXN1bHQgIT09IHVuZGVmaW5lZClcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkJvdGggcmVzdWx0IGFuZCBlcnJvciBhcmUgZGVmaW5lZFwiKTtcblxuICAgICAgcmVzdWx0LmVycm9yID0gbWVzc2FnZS5lcnJvcjtcbiAgICB9XG4gICAgZWxzZSBpZihtZXNzYWdlLnJlc3VsdCAhPT0gdW5kZWZpbmVkKVxuICAgICAgcmVzdWx0LnJlc3VsdCA9IG1lc3NhZ2UucmVzdWx0O1xuICAgIGVsc2VcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJObyByZXN1bHQgb3IgZXJyb3IgaXMgZGVmaW5lZFwiKTtcblxuICAgIHJlc3VsdC5pZCA9IGlkO1xuICB9O1xuXG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShyZXN1bHQpO1xufTtcblxuLyoqXG4gKiBVbnBhY2sgYSBKc29uUlBDIDIuMCBtZXNzYWdlXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgLSBzdHJpbmcgd2l0aCB0aGUgY29udGVudCBvZiB0aGUgSnNvblJQQyAyLjAgbWVzc2FnZVxuICpcbiAqIEB0aHJvd3Mge1R5cGVFcnJvcn0gLSBJbnZhbGlkIEpzb25SUEMgdmVyc2lvblxuICpcbiAqIEByZXR1cm4ge09iamVjdH0gLSBvYmplY3QgZmlsbGVkIHdpdGggdGhlIEpzb25SUEMgMi4wIG1lc3NhZ2UgY29udGVudFxuICovXG5mdW5jdGlvbiB1bnBhY2sobWVzc2FnZSlcbntcbiAgdmFyIHJlc3VsdCA9IG1lc3NhZ2U7XG5cbiAgaWYodHlwZW9mIG1lc3NhZ2UgPT09ICdzdHJpbmcnIHx8IG1lc3NhZ2UgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICByZXN1bHQgPSBKU09OLnBhcnNlKG1lc3NhZ2UpO1xuICB9XG5cbiAgLy8gQ2hlY2sgaWYgaXQncyBhIHZhbGlkIG1lc3NhZ2VcblxuICB2YXIgdmVyc2lvbiA9IHJlc3VsdC5qc29ucnBjO1xuICBpZih2ZXJzaW9uICE9PSAnMi4wJylcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiSW52YWxpZCBKc29uUlBDIHZlcnNpb24gJ1wiICsgdmVyc2lvbiArIFwiJzogXCIgKyBtZXNzYWdlKTtcblxuICAvLyBSZXNwb25zZVxuICBpZihyZXN1bHQubWV0aG9kID09IHVuZGVmaW5lZClcbiAge1xuICAgIGlmKHJlc3VsdC5pZCA9PSB1bmRlZmluZWQpXG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiSW52YWxpZCBtZXNzYWdlOiBcIittZXNzYWdlKTtcblxuICAgIHZhciByZXN1bHRfZGVmaW5lZCA9IHJlc3VsdC5yZXN1bHQgIT09IHVuZGVmaW5lZDtcbiAgICB2YXIgZXJyb3JfZGVmaW5lZCAgPSByZXN1bHQuZXJyb3IgICE9PSB1bmRlZmluZWQ7XG5cbiAgICAvLyBDaGVjayBvbmx5IHJlc3VsdCBvciBlcnJvciBpcyBkZWZpbmVkLCBub3QgYm90aCBvciBub25lXG4gICAgaWYocmVzdWx0X2RlZmluZWQgJiYgZXJyb3JfZGVmaW5lZClcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJCb3RoIHJlc3VsdCBhbmQgZXJyb3IgYXJlIGRlZmluZWQ6IFwiK21lc3NhZ2UpO1xuXG4gICAgaWYoIXJlc3VsdF9kZWZpbmVkICYmICFlcnJvcl9kZWZpbmVkKVxuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk5vIHJlc3VsdCBvciBlcnJvciBpcyBkZWZpbmVkOiBcIittZXNzYWdlKTtcblxuICAgIHJlc3VsdC5hY2sgPSByZXN1bHQuaWQ7XG4gICAgZGVsZXRlIHJlc3VsdC5pZDtcbiAgfVxuXG4gIC8vIFJldHVybiB1bnBhY2tlZCBtZXNzYWdlXG4gIHJldHVybiByZXN1bHQ7XG59O1xuXG5cbmV4cG9ydHMucGFjayAgID0gcGFjaztcbmV4cG9ydHMudW5wYWNrID0gdW5wYWNrO1xuIiwiZnVuY3Rpb24gcGFjayhtZXNzYWdlKVxue1xuICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTm90IHlldCBpbXBsZW1lbnRlZFwiKTtcbn07XG5cbmZ1bmN0aW9uIHVucGFjayhtZXNzYWdlKVxue1xuICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTm90IHlldCBpbXBsZW1lbnRlZFwiKTtcbn07XG5cblxuZXhwb3J0cy5wYWNrICAgPSBwYWNrO1xuZXhwb3J0cy51bnBhY2sgPSB1bnBhY2s7XG4iLCJ2YXIgSnNvblJQQyA9IHJlcXVpcmUoJy4vSnNvblJQQycpO1xudmFyIFhtbFJQQyAgPSByZXF1aXJlKCcuL1htbFJQQycpO1xuXG5cbmV4cG9ydHMuSnNvblJQQyA9IEpzb25SUEM7XG5leHBvcnRzLlhtbFJQQyAgPSBYbWxSUEM7XG4iLCIvKlxuICogKEMpIENvcHlyaWdodCAyMDE0LTIwMTUgS3VyZW50byAoaHR0cDovL2t1cmVudG8ub3JnLylcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbnZhciBmcmVlaWNlID0gcmVxdWlyZSgnZnJlZWljZScpXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG52YXIgVUFQYXJzZXIgPSByZXF1aXJlKCd1YS1wYXJzZXItanMnKVxudmFyIHV1aWQgPSByZXF1aXJlKCd1dWlkJylcbnZhciBoYXJrID0gcmVxdWlyZSgnaGFyaycpXG5cbnZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCdldmVudHMnKS5FdmVudEVtaXR0ZXJcbnZhciByZWN1cnNpdmUgPSByZXF1aXJlKCdtZXJnZScpLnJlY3Vyc2l2ZS5iaW5kKHVuZGVmaW5lZCwgdHJ1ZSlcbnZhciBzZHBUcmFuc2xhdG9yID0gcmVxdWlyZSgnc2RwLXRyYW5zbGF0b3InKVxudmFyIGxvZ2dlciA9IHdpbmRvdy5Mb2dnZXIgfHwgY29uc29sZVxuXG4vLyB2YXIgZ1VNID0gbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEgfHwgZnVuY3Rpb24gKGNvbnN0cmFpbnRzKSB7XG4vLyAgIHJldHVybiBuZXcgUHJvbWlzZShuYXZpZ2F0b3IuZ2V0VXNlck1lZGlhKGNvbnN0cmFpbnRzLCBmdW5jdGlvbiAoc3RyZWFtKSB7XG4vLyAgICAgdmlkZW9TdHJlYW0gPSBzdHJlYW1cbi8vICAgICBzdGFydCgpXG4vLyAgIH0pLmVyb3IoY2FsbGJhY2spKTtcbi8vIH1cblxuLyp0cnkge1xuICByZXF1aXJlKCdrdXJlbnRvLWJyb3dzZXItZXh0ZW5zaW9ucycpXG59IGNhdGNoIChlcnJvcikge1xuICBpZiAodHlwZW9mIGdldFNjcmVlbkNvbnN0cmFpbnRzID09PSAndW5kZWZpbmVkJykge1xuICAgIGxvZ2dlci53YXJuKCdzY3JlZW4gc2hhcmluZyBpcyBub3QgYXZhaWxhYmxlJylcblxuICAgIGdldFNjcmVlbkNvbnN0cmFpbnRzID0gZnVuY3Rpb24gZ2V0U2NyZWVuQ29uc3RyYWludHMoc2VuZFNvdXJjZSwgY2FsbGJhY2spIHtcbiAgICAgIGNhbGxiYWNrKG5ldyBFcnJvcihcIlRoaXMgbGlicmFyeSBpcyBub3QgZW5hYmxlZCBmb3Igc2NyZWVuIHNoYXJpbmdcIikpXG4gICAgfVxuICB9XG59Ki9cblxudmFyIE1FRElBX0NPTlNUUkFJTlRTID0ge1xuICBhdWRpbzogdHJ1ZSxcbiAgdmlkZW86IHtcbiAgICB3aWR0aDogNjQwLFxuICAgIGZyYW1lcmF0ZTogMTVcbiAgfVxufVxuXG4vLyBTb21laG93LCB0aGUgVUFQYXJzZXIgY29uc3RydWN0b3IgZ2V0cyBhbiBlbXB0eSB3aW5kb3cgb2JqZWN0LlxuLy8gV2UgbmVlZCB0byBwYXNzIHRoZSB1c2VyIGFnZW50IHN0cmluZyBpbiBvcmRlciB0byBnZXQgaW5mb3JtYXRpb25cbnZhciB1YSA9ICh3aW5kb3cgJiYgd2luZG93Lm5hdmlnYXRvcikgPyB3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudCA6ICcnXG52YXIgcGFyc2VyID0gbmV3IFVBUGFyc2VyKHVhKVxudmFyIGJyb3dzZXIgPSBwYXJzZXIuZ2V0QnJvd3NlcigpXG5cbnZhciB1c2VQbGFuQiA9IGZhbHNlXG5pZiAoYnJvd3Nlci5uYW1lID09PSAnQ2hyb21lJyB8fCBicm93c2VyLm5hbWUgPT09ICdDaHJvbWl1bScpIHtcbiAgbG9nZ2VyLmRlYnVnKGJyb3dzZXIubmFtZSArIFwiOiB1c2luZyBTRFAgUGxhbkJcIilcbiAgdXNlUGxhbkIgPSB0cnVlXG59XG5cbmZ1bmN0aW9uIG5vb3AoZXJyb3IpIHtcbiAgaWYgKGVycm9yKSBsb2dnZXIuZXJyb3IoZXJyb3IpXG59XG5cbmZ1bmN0aW9uIHRyYWNrU3RvcCh0cmFjaykge1xuICB0cmFjay5zdG9wICYmIHRyYWNrLnN0b3AoKVxufVxuXG5mdW5jdGlvbiBzdHJlYW1TdG9wKHN0cmVhbSkge1xuICBzdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaCh0cmFja1N0b3ApXG59XG5cbi8qKlxuICogUmV0dXJucyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBhIFNlc3Npb25EZXNjcmlwdGlvbiBvYmplY3QuXG4gKi9cbnZhciBkdW1wU0RQID0gZnVuY3Rpb24gKGRlc2NyaXB0aW9uKSB7XG4gIGlmICh0eXBlb2YgZGVzY3JpcHRpb24gPT09ICd1bmRlZmluZWQnIHx8IGRlc2NyaXB0aW9uID09PSBudWxsKSB7XG4gICAgcmV0dXJuICcnXG4gIH1cblxuICByZXR1cm4gJ3R5cGU6ICcgKyBkZXNjcmlwdGlvbi50eXBlICsgJ1xcclxcbicgKyBkZXNjcmlwdGlvbi5zZHBcbn1cblxuZnVuY3Rpb24gYnVmZmVyaXplQ2FuZGlkYXRlcyhwYywgb25lcnJvcikge1xuICB2YXIgY2FuZGlkYXRlc1F1ZXVlID0gW11cblxuICBwYy5hZGRFdmVudExpc3RlbmVyKCdzaWduYWxpbmdzdGF0ZWNoYW5nZScsIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5zaWduYWxpbmdTdGF0ZSA9PT0gJ3N0YWJsZScpIHtcbiAgICAgIHdoaWxlIChjYW5kaWRhdGVzUXVldWUubGVuZ3RoKSB7XG4gICAgICAgIHZhciBlbnRyeSA9IGNhbmRpZGF0ZXNRdWV1ZS5zaGlmdCgpXG5cbiAgICAgICAgdGhpcy5hZGRJY2VDYW5kaWRhdGUoZW50cnkuY2FuZGlkYXRlLCBlbnRyeS5jYWxsYmFjaywgZW50cnkuY2FsbGJhY2spXG4gICAgICB9XG4gICAgfVxuICB9KVxuXG4gIHJldHVybiBmdW5jdGlvbiAoY2FuZGlkYXRlLCBjYWxsYmFjaykge1xuICAgIGNhbGxiYWNrID0gY2FsbGJhY2sgfHwgb25lcnJvclxuXG4gICAgc3dpdGNoIChwYy5zaWduYWxpbmdTdGF0ZSkge1xuICAgIGNhc2UgJ2Nsb3NlZCc6XG4gICAgICBjYWxsYmFjayhuZXcgRXJyb3IoJ1BlZXJDb25uZWN0aW9uIG9iamVjdCBpcyBjbG9zZWQnKSk7XG4gICAgICBicmVhaztcbiAgICBjYXNlICdzdGFibGUnOlxuICAgICAgaWYgKHBjLnJlbW90ZURlc2NyaXB0aW9uKSB7XG4gICAgICAgIHBjLmFkZEljZUNhbmRpZGF0ZShjYW5kaWRhdGUsIGNhbGxiYWNrLCBjYWxsYmFjayk7XG4gICAgICB9XG4gICAgICBicmVhaztcbiAgICBkZWZhdWx0OlxuICAgICAgY2FuZGlkYXRlc1F1ZXVlLnB1c2goe1xuICAgICAgICBjYW5kaWRhdGU6IGNhbmRpZGF0ZSxcbiAgICAgICAgY2FsbGJhY2s6IGNhbGxiYWNrXG4gICAgICB9KVxuICAgIH1cbiAgfVxufVxuXG4vKiBTaW11bGNhc3QgdXRpbGl0aWVzICovXG5cbmZ1bmN0aW9uIHJlbW92ZUZJREZyb21PZmZlcihzZHApIHtcbiAgdmFyIG4gPSBzZHAuaW5kZXhPZihcImE9c3NyYy1ncm91cDpGSURcIik7XG5cbiAgaWYgKG4gPiAwKSB7XG4gICAgcmV0dXJuIHNkcC5zbGljZSgwLCBuKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gc2RwO1xuICB9XG59XG5cbmZ1bmN0aW9uIGdldFNpbXVsY2FzdEluZm8odmlkZW9TdHJlYW0pIHtcbiAgdmFyIHZpZGVvVHJhY2tzID0gdmlkZW9TdHJlYW0uZ2V0VmlkZW9UcmFja3MoKTtcbiAgaWYgKCF2aWRlb1RyYWNrcy5sZW5ndGgpIHtcbiAgICBsb2dnZXIud2FybignTm8gdmlkZW8gdHJhY2tzIGF2YWlsYWJsZSBpbiB0aGUgdmlkZW8gc3RyZWFtJylcbiAgICByZXR1cm4gJydcbiAgfVxuICB2YXIgbGluZXMgPSBbXG4gICAgJ2E9eC1nb29nbGUtZmxhZzpjb25mZXJlbmNlJyxcbiAgICAnYT1zc3JjLWdyb3VwOlNJTSAxIDIgMycsXG4gICAgJ2E9c3NyYzoxIGNuYW1lOmxvY2FsVmlkZW8nLFxuICAgICdhPXNzcmM6MSBtc2lkOicgKyB2aWRlb1N0cmVhbS5pZCArICcgJyArIHZpZGVvVHJhY2tzWzBdLmlkLFxuICAgICdhPXNzcmM6MSBtc2xhYmVsOicgKyB2aWRlb1N0cmVhbS5pZCxcbiAgICAnYT1zc3JjOjEgbGFiZWw6JyArIHZpZGVvVHJhY2tzWzBdLmlkLFxuICAgICdhPXNzcmM6MiBjbmFtZTpsb2NhbFZpZGVvJyxcbiAgICAnYT1zc3JjOjIgbXNpZDonICsgdmlkZW9TdHJlYW0uaWQgKyAnICcgKyB2aWRlb1RyYWNrc1swXS5pZCxcbiAgICAnYT1zc3JjOjIgbXNsYWJlbDonICsgdmlkZW9TdHJlYW0uaWQsXG4gICAgJ2E9c3NyYzoyIGxhYmVsOicgKyB2aWRlb1RyYWNrc1swXS5pZCxcbiAgICAnYT1zc3JjOjMgY25hbWU6bG9jYWxWaWRlbycsXG4gICAgJ2E9c3NyYzozIG1zaWQ6JyArIHZpZGVvU3RyZWFtLmlkICsgJyAnICsgdmlkZW9UcmFja3NbMF0uaWQsXG4gICAgJ2E9c3NyYzozIG1zbGFiZWw6JyArIHZpZGVvU3RyZWFtLmlkLFxuICAgICdhPXNzcmM6MyBsYWJlbDonICsgdmlkZW9UcmFja3NbMF0uaWRcbiAgXTtcblxuICBsaW5lcy5wdXNoKCcnKTtcblxuICByZXR1cm4gbGluZXMuam9pbignXFxuJyk7XG59XG5cbi8qKlxuICogV3JhcHBlciBvYmplY3Qgb2YgYW4gUlRDUGVlckNvbm5lY3Rpb24uIFRoaXMgb2JqZWN0IGlzIGFpbWVkIHRvIHNpbXBsaWZ5IHRoZVxuICogZGV2ZWxvcG1lbnQgb2YgV2ViUlRDLWJhc2VkIGFwcGxpY2F0aW9ucy5cbiAqXG4gKiBAY29uc3RydWN0b3IgbW9kdWxlOmt1cmVudG9VdGlscy5XZWJSdGNQZWVyXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1vZGUgTW9kZSBpbiB3aGljaCB0aGUgUGVlckNvbm5lY3Rpb24gd2lsbCBiZSBjb25maWd1cmVkLlxuICogIFZhbGlkIHZhbHVlcyBhcmU6ICdyZWN2JywgJ3NlbmQnLCBhbmQgJ3NlbmRSZWN2J1xuICogQHBhcmFtIGxvY2FsVmlkZW8gVmlkZW8gdGFnIGZvciB0aGUgbG9jYWwgc3RyZWFtXG4gKiBAcGFyYW0gcmVtb3RlVmlkZW8gVmlkZW8gdGFnIGZvciB0aGUgcmVtb3RlIHN0cmVhbVxuICogQHBhcmFtIHtNZWRpYVN0cmVhbX0gdmlkZW9TdHJlYW0gU3RyZWFtIHRvIGJlIHVzZWQgYXMgcHJpbWFyeSBzb3VyY2VcbiAqICAodHlwaWNhbGx5IHZpZGVvIGFuZCBhdWRpbywgb3Igb25seSB2aWRlbyBpZiBjb21iaW5lZCB3aXRoIGF1ZGlvU3RyZWFtKSBmb3JcbiAqICBsb2NhbFZpZGVvIGFuZCB0byBiZSBhZGRlZCBhcyBzdHJlYW0gdG8gdGhlIFJUQ1BlZXJDb25uZWN0aW9uXG4gKiBAcGFyYW0ge01lZGlhU3RyZWFtfSBhdWRpb1N0cmVhbSBTdHJlYW0gdG8gYmUgdXNlZCBhcyBzZWNvbmQgc291cmNlXG4gKiAgKHR5cGljYWxseSBmb3IgYXVkaW8pIGZvciBsb2NhbFZpZGVvIGFuZCB0byBiZSBhZGRlZCBhcyBzdHJlYW0gdG8gdGhlXG4gKiAgUlRDUGVlckNvbm5lY3Rpb25cbiAqL1xuZnVuY3Rpb24gV2ViUnRjUGVlcihtb2RlLCBvcHRpb25zLCBjYWxsYmFjaykge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgV2ViUnRjUGVlcikpIHtcbiAgICByZXR1cm4gbmV3IFdlYlJ0Y1BlZXIobW9kZSwgb3B0aW9ucywgY2FsbGJhY2spXG4gIH1cblxuICBXZWJSdGNQZWVyLnN1cGVyXy5jYWxsKHRoaXMpXG5cbiAgaWYgKG9wdGlvbnMgaW5zdGFuY2VvZiBGdW5jdGlvbikge1xuICAgIGNhbGxiYWNrID0gb3B0aW9uc1xuICAgIG9wdGlvbnMgPSB1bmRlZmluZWRcbiAgfVxuXG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9XG4gIGNhbGxiYWNrID0gKGNhbGxiYWNrIHx8IG5vb3ApLmJpbmQodGhpcylcblxuICB2YXIgc2VsZiA9IHRoaXNcbiAgdmFyIGxvY2FsVmlkZW8gPSBvcHRpb25zLmxvY2FsVmlkZW9cbiAgdmFyIHJlbW90ZVZpZGVvID0gb3B0aW9ucy5yZW1vdGVWaWRlb1xuICB2YXIgdmlkZW9TdHJlYW0gPSBvcHRpb25zLnZpZGVvU3RyZWFtXG4gIHZhciBhdWRpb1N0cmVhbSA9IG9wdGlvbnMuYXVkaW9TdHJlYW1cbiAgdmFyIG1lZGlhQ29uc3RyYWludHMgPSBvcHRpb25zLm1lZGlhQ29uc3RyYWludHNcblxuICB2YXIgY29ubmVjdGlvbkNvbnN0cmFpbnRzID0gb3B0aW9ucy5jb25uZWN0aW9uQ29uc3RyYWludHNcbiAgdmFyIHBjID0gb3B0aW9ucy5wZWVyQ29ubmVjdGlvblxuICB2YXIgc2VuZFNvdXJjZSA9IG9wdGlvbnMuc2VuZFNvdXJjZSB8fCAnd2ViY2FtJ1xuXG4gIHZhciBkYXRhQ2hhbm5lbENvbmZpZyA9IG9wdGlvbnMuZGF0YUNoYW5uZWxDb25maWdcbiAgdmFyIHVzZURhdGFDaGFubmVscyA9IG9wdGlvbnMuZGF0YUNoYW5uZWxzIHx8IGZhbHNlXG4gIHZhciBkYXRhQ2hhbm5lbFxuXG4gIHZhciBndWlkID0gdXVpZC52NCgpXG4gIHZhciBjb25maWd1cmF0aW9uID0gcmVjdXJzaXZlKHtcbiAgICAgIGljZVNlcnZlcnM6IGZyZWVpY2UoKVxuICAgIH0sXG4gICAgb3B0aW9ucy5jb25maWd1cmF0aW9uKVxuXG4gIHZhciBvbmljZWNhbmRpZGF0ZSA9IG9wdGlvbnMub25pY2VjYW5kaWRhdGVcbiAgaWYgKG9uaWNlY2FuZGlkYXRlKSB0aGlzLm9uKCdpY2VjYW5kaWRhdGUnLCBvbmljZWNhbmRpZGF0ZSlcblxuICB2YXIgb25jYW5kaWRhdGVnYXRoZXJpbmdkb25lID0gb3B0aW9ucy5vbmNhbmRpZGF0ZWdhdGhlcmluZ2RvbmVcbiAgaWYgKG9uY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZSkge1xuICAgIHRoaXMub24oJ2NhbmRpZGF0ZWdhdGhlcmluZ2RvbmUnLCBvbmNhbmRpZGF0ZWdhdGhlcmluZ2RvbmUpXG4gIH1cblxuICB2YXIgc2ltdWxjYXN0ID0gb3B0aW9ucy5zaW11bGNhc3RcbiAgdmFyIG11bHRpc3RyZWFtID0gb3B0aW9ucy5tdWx0aXN0cmVhbVxuICB2YXIgaW50ZXJvcCA9IG5ldyBzZHBUcmFuc2xhdG9yLkludGVyb3AoKVxuICB2YXIgY2FuZGlkYXRlc1F1ZXVlT3V0ID0gW11cbiAgdmFyIGNhbmRpZGF0ZWdhdGhlcmluZ2RvbmUgPSBmYWxzZVxuXG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsIHtcbiAgICAncGVlckNvbm5lY3Rpb24nOiB7XG4gICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHBjXG4gICAgICB9XG4gICAgfSxcblxuICAgICdpZCc6IHtcbiAgICAgIHZhbHVlOiBvcHRpb25zLmlkIHx8IGd1aWQsXG4gICAgICB3cml0YWJsZTogZmFsc2VcbiAgICB9LFxuXG4gICAgJ3JlbW90ZVZpZGVvJzoge1xuICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiByZW1vdGVWaWRlb1xuICAgICAgfVxuICAgIH0sXG5cbiAgICAnbG9jYWxWaWRlbyc6IHtcbiAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gbG9jYWxWaWRlb1xuICAgICAgfVxuICAgIH0sXG5cbiAgICAnZGF0YUNoYW5uZWwnOiB7XG4gICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGRhdGFDaGFubmVsXG4gICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIgeyhleHRlcm5hbDpJbWFnZURhdGF8dW5kZWZpbmVkKX0gY3VycmVudEZyYW1lXG4gICAgICovXG4gICAgJ2N1cnJlbnRGcmFtZSc6IHtcbiAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBbVG9Eb10gRmluZCBzb2x1dGlvbiB3aGVuIHdlIGhhdmUgYSByZW1vdGUgc3RyZWFtIGJ1dCB3ZSBkaWRuJ3Qgc2V0XG4gICAgICAgIC8vIGEgcmVtb3RlVmlkZW8gdGFnXG4gICAgICAgIGlmICghcmVtb3RlVmlkZW8pIHJldHVybjtcblxuICAgICAgICBpZiAocmVtb3RlVmlkZW8ucmVhZHlTdGF0ZSA8IHJlbW90ZVZpZGVvLkhBVkVfQ1VSUkVOVF9EQVRBKVxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gdmlkZW8gc3RyZWFtIGRhdGEgYXZhaWxhYmxlJylcblxuICAgICAgICB2YXIgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJylcbiAgICAgICAgY2FudmFzLndpZHRoID0gcmVtb3RlVmlkZW8udmlkZW9XaWR0aFxuICAgICAgICBjYW52YXMuaGVpZ2h0ID0gcmVtb3RlVmlkZW8udmlkZW9IZWlnaHRcblxuICAgICAgICBjYW52YXMuZ2V0Q29udGV4dCgnMmQnKS5kcmF3SW1hZ2UocmVtb3RlVmlkZW8sIDAsIDApXG5cbiAgICAgICAgcmV0dXJuIGNhbnZhc1xuICAgICAgfVxuICAgIH1cbiAgfSlcblxuICAvLyBJbml0IFBlZXJDb25uZWN0aW9uXG4gIGlmICghcGMpIHtcbiAgICBwYyA9IG5ldyBSVENQZWVyQ29ubmVjdGlvbihjb25maWd1cmF0aW9uKTtcbiAgICBpZiAodXNlRGF0YUNoYW5uZWxzICYmICFkYXRhQ2hhbm5lbCkge1xuICAgICAgdmFyIGRjSWQgPSAnV2ViUnRjUGVlci0nICsgc2VsZi5pZFxuICAgICAgdmFyIGRjT3B0aW9ucyA9IHVuZGVmaW5lZFxuICAgICAgaWYgKGRhdGFDaGFubmVsQ29uZmlnKSB7XG4gICAgICAgIGRjSWQgPSBkYXRhQ2hhbm5lbENvbmZpZy5pZCB8fCBkY0lkXG4gICAgICAgIGRjT3B0aW9ucyA9IGRhdGFDaGFubmVsQ29uZmlnLm9wdGlvbnNcbiAgICAgIH1cbiAgICAgIGRhdGFDaGFubmVsID0gcGMuY3JlYXRlRGF0YUNoYW5uZWwoZGNJZCwgZGNPcHRpb25zKTtcbiAgICAgIGlmIChkYXRhQ2hhbm5lbENvbmZpZykge1xuICAgICAgICBkYXRhQ2hhbm5lbC5vbm9wZW4gPSBkYXRhQ2hhbm5lbENvbmZpZy5vbm9wZW47XG4gICAgICAgIGRhdGFDaGFubmVsLm9uY2xvc2UgPSBkYXRhQ2hhbm5lbENvbmZpZy5vbmNsb3NlO1xuICAgICAgICBkYXRhQ2hhbm5lbC5vbm1lc3NhZ2UgPSBkYXRhQ2hhbm5lbENvbmZpZy5vbm1lc3NhZ2U7XG4gICAgICAgIGRhdGFDaGFubmVsLm9uYnVmZmVyZWRhbW91bnRsb3cgPSBkYXRhQ2hhbm5lbENvbmZpZy5vbmJ1ZmZlcmVkYW1vdW50bG93O1xuICAgICAgICBkYXRhQ2hhbm5lbC5vbmVycm9yID0gZGF0YUNoYW5uZWxDb25maWcub25lcnJvciB8fCBub29wO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHBjLmFkZEV2ZW50TGlzdGVuZXIoJ2ljZWNhbmRpZGF0ZScsIGZ1bmN0aW9uIChldmVudCkge1xuICAgIHZhciBjYW5kaWRhdGUgPSBldmVudC5jYW5kaWRhdGVcblxuICAgIGlmIChFdmVudEVtaXR0ZXIubGlzdGVuZXJDb3VudChzZWxmLCAnaWNlY2FuZGlkYXRlJykgfHxcbiAgICAgIEV2ZW50RW1pdHRlci5saXN0ZW5lckNvdW50KFxuICAgICAgICBzZWxmLCAnY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZScpKSB7XG4gICAgICBpZiAoY2FuZGlkYXRlKSB7XG4gICAgICAgIHZhciBjYW5kXG5cbiAgICAgICAgaWYgKG11bHRpc3RyZWFtICYmIHVzZVBsYW5CKSB7XG4gICAgICAgICAgY2FuZCA9IGludGVyb3AuY2FuZGlkYXRlVG9VbmlmaWVkUGxhbihjYW5kaWRhdGUpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY2FuZCA9IGNhbmRpZGF0ZVxuICAgICAgICB9XG5cbiAgICAgICAgc2VsZi5lbWl0KCdpY2VjYW5kaWRhdGUnLCBjYW5kKVxuICAgICAgICBjYW5kaWRhdGVnYXRoZXJpbmdkb25lID0gZmFsc2VcbiAgICAgIH0gZWxzZSBpZiAoIWNhbmRpZGF0ZWdhdGhlcmluZ2RvbmUpIHtcbiAgICAgICAgc2VsZi5lbWl0KCdjYW5kaWRhdGVnYXRoZXJpbmdkb25lJylcbiAgICAgICAgY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZSA9IHRydWVcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKCFjYW5kaWRhdGVnYXRoZXJpbmdkb25lKSB7XG4gICAgICAvLyBOb3QgbGlzdGVuaW5nIHRvICdpY2VjYW5kaWRhdGUnIG9yICdjYW5kaWRhdGVnYXRoZXJpbmdkb25lJyBldmVudHMsIHF1ZXVlXG4gICAgICAvLyB0aGUgY2FuZGlkYXRlIHVudGlsIG9uZSBvZiB0aGVtIGlzIGxpc3RlbmVkXG4gICAgICBjYW5kaWRhdGVzUXVldWVPdXQucHVzaChjYW5kaWRhdGUpXG5cbiAgICAgIGlmICghY2FuZGlkYXRlKSBjYW5kaWRhdGVnYXRoZXJpbmdkb25lID0gdHJ1ZVxuICAgIH1cbiAgfSlcblxuICBwYy5vbnRyYWNrID0gb3B0aW9ucy5vbmFkZHN0cmVhbVxuICBwYy5vbm5lZ290aWF0aW9ubmVlZGVkID0gb3B0aW9ucy5vbm5lZ290aWF0aW9ubmVlZGVkXG4gIHRoaXMub24oJ25ld0xpc3RlbmVyJywgZnVuY3Rpb24gKGV2ZW50LCBsaXN0ZW5lcikge1xuICAgIGlmIChldmVudCA9PT0gJ2ljZWNhbmRpZGF0ZScgfHwgZXZlbnQgPT09ICdjYW5kaWRhdGVnYXRoZXJpbmdkb25lJykge1xuICAgICAgd2hpbGUgKGNhbmRpZGF0ZXNRdWV1ZU91dC5sZW5ndGgpIHtcbiAgICAgICAgdmFyIGNhbmRpZGF0ZSA9IGNhbmRpZGF0ZXNRdWV1ZU91dC5zaGlmdCgpXG5cbiAgICAgICAgaWYgKCFjYW5kaWRhdGUgPT09IChldmVudCA9PT0gJ2NhbmRpZGF0ZWdhdGhlcmluZ2RvbmUnKSkge1xuICAgICAgICAgIGxpc3RlbmVyKGNhbmRpZGF0ZSlcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSlcblxuICB2YXIgYWRkSWNlQ2FuZGlkYXRlID0gYnVmZmVyaXplQ2FuZGlkYXRlcyhwYylcblxuICAvKipcbiAgICogQ2FsbGJhY2sgZnVuY3Rpb24gaW52b2tlZCB3aGVuIGFuIElDRSBjYW5kaWRhdGUgaXMgcmVjZWl2ZWQuIERldmVsb3BlcnMgYXJlXG4gICAqIGV4cGVjdGVkIHRvIGludm9rZSB0aGlzIGZ1bmN0aW9uIGluIG9yZGVyIHRvIGNvbXBsZXRlIHRoZSBTRFAgbmVnb3RpYXRpb24uXG4gICAqXG4gICAqIEBmdW5jdGlvbiBtb2R1bGU6a3VyZW50b1V0aWxzLldlYlJ0Y1BlZXIucHJvdG90eXBlLmFkZEljZUNhbmRpZGF0ZVxuICAgKlxuICAgKiBAcGFyYW0gaWNlQ2FuZGlkYXRlIC0gTGl0ZXJhbCBvYmplY3Qgd2l0aCB0aGUgSUNFIGNhbmRpZGF0ZSBkZXNjcmlwdGlvblxuICAgKiBAcGFyYW0gY2FsbGJhY2sgLSBDYWxsZWQgd2hlbiB0aGUgSUNFIGNhbmRpZGF0ZSBoYXMgYmVlbiBhZGRlZC5cbiAgICovXG4gIHRoaXMuYWRkSWNlQ2FuZGlkYXRlID0gZnVuY3Rpb24gKGljZUNhbmRpZGF0ZSwgY2FsbGJhY2spIHtcbiAgICB2YXIgY2FuZGlkYXRlXG5cbiAgICBpZiAobXVsdGlzdHJlYW0gJiYgdXNlUGxhbkIpIHtcbiAgICAgIGNhbmRpZGF0ZSA9IGludGVyb3AuY2FuZGlkYXRlVG9QbGFuQihpY2VDYW5kaWRhdGUpXG4gICAgfSBlbHNlIHtcbiAgICAgIGNhbmRpZGF0ZSA9IG5ldyBSVENJY2VDYW5kaWRhdGUoaWNlQ2FuZGlkYXRlKVxuICAgIH1cblxuICAgIGxvZ2dlci5kZWJ1ZygnUmVtb3RlIElDRSBjYW5kaWRhdGUgcmVjZWl2ZWQnLCBpY2VDYW5kaWRhdGUpXG4gICAgY2FsbGJhY2sgPSAoY2FsbGJhY2sgfHwgbm9vcCkuYmluZCh0aGlzKVxuICAgIGFkZEljZUNhbmRpZGF0ZShjYW5kaWRhdGUsIGNhbGxiYWNrKVxuICB9XG5cbiAgdGhpcy5nZW5lcmF0ZU9mZmVyID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgY2FsbGJhY2sgPSBjYWxsYmFjay5iaW5kKHRoaXMpXG5cbiAgICB2YXIgb2ZmZXJBdWRpbyA9IHRydWVcbiAgICB2YXIgb2ZmZXJWaWRlbyA9IHRydWVcbiAgICAvLyBDb25zdHJhaW50cyBtdXN0IGhhdmUgYm90aCBibG9ja3NcbiAgICBpZiAobWVkaWFDb25zdHJhaW50cykge1xuICAgICAgb2ZmZXJBdWRpbyA9ICh0eXBlb2YgbWVkaWFDb25zdHJhaW50cy5hdWRpbyA9PT0gJ2Jvb2xlYW4nKSA/XG4gICAgICAgIG1lZGlhQ29uc3RyYWludHMuYXVkaW8gOiB0cnVlXG4gICAgICBvZmZlclZpZGVvID0gKHR5cGVvZiBtZWRpYUNvbnN0cmFpbnRzLnZpZGVvID09PSAnYm9vbGVhbicpID9cbiAgICAgICAgbWVkaWFDb25zdHJhaW50cy52aWRlbyA6IHRydWVcbiAgICB9XG5cbiAgICB2YXIgYnJvd3NlckRlcGVuZGFudENvbnN0cmFpbnRzID0ge1xuICAgICAgb2ZmZXJUb1JlY2VpdmVBdWRpbzogKG1vZGUgIT09ICdzZW5kb25seScgJiYgb2ZmZXJBdWRpbyksXG4gICAgICBvZmZlclRvUmVjZWl2ZVZpZGVvOiAobW9kZSAhPT0gJ3NlbmRvbmx5JyAmJiBvZmZlclZpZGVvKVxuICAgIH1cblxuICAgIC8vRklYTUU6IGNsYXJpZnkgcG9zc2libGUgY29uc3RyYWludHMgcGFzc2VkIHRvIGNyZWF0ZU9mZmVyKClcbiAgICAvKnZhciBjb25zdHJhaW50cyA9IHJlY3Vyc2l2ZShicm93c2VyRGVwZW5kYW50Q29uc3RyYWludHMsXG4gICAgICBjb25uZWN0aW9uQ29uc3RyYWludHMpKi9cblxuICAgIHZhciBjb25zdHJhaW50cyA9IGJyb3dzZXJEZXBlbmRhbnRDb25zdHJhaW50cztcblxuICAgIGxvZ2dlci5kZWJ1ZygnY29uc3RyYWludHM6ICcgKyBKU09OLnN0cmluZ2lmeShjb25zdHJhaW50cykpXG5cbiAgICBwYy5jcmVhdGVPZmZlcihjb25zdHJhaW50cykudGhlbihmdW5jdGlvbiAob2ZmZXIpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZygnQ3JlYXRlZCBTRFAgb2ZmZXInKVxuICAgICAgb2ZmZXIgPSBtYW5nbGVTZHBUb0FkZFNpbXVsY2FzdChvZmZlcilcbiAgICAgIHJldHVybiBwYy5zZXRMb2NhbERlc2NyaXB0aW9uKG9mZmVyKVxuICAgIH0pLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIGxvY2FsRGVzY3JpcHRpb24gPSBwYy5sb2NhbERlc2NyaXB0aW9uXG4gICAgICBsb2dnZXIuZGVidWcoJ0xvY2FsIGRlc2NyaXB0aW9uIHNldCcsIGxvY2FsRGVzY3JpcHRpb24uc2RwKVxuICAgICAgaWYgKG11bHRpc3RyZWFtICYmIHVzZVBsYW5CKSB7XG4gICAgICAgIGxvY2FsRGVzY3JpcHRpb24gPSBpbnRlcm9wLnRvVW5pZmllZFBsYW4obG9jYWxEZXNjcmlwdGlvbilcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdvZmZlcjo6b3JpZ1BsYW5CLT5VbmlmaWVkUGxhbicsIGR1bXBTRFAoXG4gICAgICAgICAgbG9jYWxEZXNjcmlwdGlvbikpXG4gICAgICB9XG4gICAgICBjYWxsYmFjayhudWxsLCBsb2NhbERlc2NyaXB0aW9uLnNkcCwgc2VsZi5wcm9jZXNzQW5zd2VyLmJpbmQoXG4gICAgICAgIHNlbGYpKVxuICAgIH0pLmNhdGNoKGNhbGxiYWNrKVxuICB9XG5cbiAgdGhpcy5nZXRMb2NhbFNlc3Npb25EZXNjcmlwdG9yID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBwYy5sb2NhbERlc2NyaXB0aW9uXG4gIH1cblxuICB0aGlzLmdldFJlbW90ZVNlc3Npb25EZXNjcmlwdG9yID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBwYy5yZW1vdGVEZXNjcmlwdGlvblxuICB9XG5cbiAgZnVuY3Rpb24gc2V0UmVtb3RlVmlkZW8oKSB7XG4gICAgaWYgKHJlbW90ZVZpZGVvKSB7XG4gICAgICB2YXIgc3RyZWFtID0gcGMuZ2V0UmVtb3RlU3RyZWFtcygpWzBdXG4gICAgICB2YXIgdXJsID0gc3RyZWFtID8gVVJMLmNyZWF0ZU9iamVjdFVSTChzdHJlYW0pIDogJydcblxuICAgICAgcmVtb3RlVmlkZW8ucGF1c2UoKVxuICAgICAgcmVtb3RlVmlkZW8uc3JjID0gdXJsXG4gICAgICByZW1vdGVWaWRlby5sb2FkKClcblxuICAgICAgbG9nZ2VyLmRlYnVnKCdSZW1vdGUgVVJMOicsIHVybClcbiAgICB9XG4gIH1cblxuICB0aGlzLnNob3dMb2NhbFZpZGVvID0gZnVuY3Rpb24gKCkge1xuICAgIGxvY2FsVmlkZW8uc3JjID0gVVJMLmNyZWF0ZU9iamVjdFVSTCh2aWRlb1N0cmVhbSlcbiAgICBsb2NhbFZpZGVvLm11dGVkID0gdHJ1ZVxuICB9XG5cbiAgdGhpcy5zZW5kID0gZnVuY3Rpb24gKGRhdGEpIHtcbiAgICBpZiAoZGF0YUNoYW5uZWwgJiYgZGF0YUNoYW5uZWwucmVhZHlTdGF0ZSA9PT0gJ29wZW4nKSB7XG4gICAgICBkYXRhQ2hhbm5lbC5zZW5kKGRhdGEpXG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZ2dlci53YXJuKFxuICAgICAgICAnVHJ5aW5nIHRvIHNlbmQgZGF0YSBvdmVyIGEgbm9uLWV4aXN0aW5nIG9yIGNsb3NlZCBkYXRhIGNoYW5uZWwnKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxsYmFjayBmdW5jdGlvbiBpbnZva2VkIHdoZW4gYSBTRFAgYW5zd2VyIGlzIHJlY2VpdmVkLiBEZXZlbG9wZXJzIGFyZVxuICAgKiBleHBlY3RlZCB0byBpbnZva2UgdGhpcyBmdW5jdGlvbiBpbiBvcmRlciB0byBjb21wbGV0ZSB0aGUgU0RQIG5lZ290aWF0aW9uLlxuICAgKlxuICAgKiBAZnVuY3Rpb24gbW9kdWxlOmt1cmVudG9VdGlscy5XZWJSdGNQZWVyLnByb3RvdHlwZS5wcm9jZXNzQW5zd2VyXG4gICAqXG4gICAqIEBwYXJhbSBzZHBBbnN3ZXIgLSBEZXNjcmlwdGlvbiBvZiBzZHBBbnN3ZXJcbiAgICogQHBhcmFtIGNhbGxiYWNrIC1cbiAgICogICAgICAgICAgICBJbnZva2VkIGFmdGVyIHRoZSBTRFAgYW5zd2VyIGlzIHByb2Nlc3NlZCwgb3IgdGhlcmUgaXMgYW4gZXJyb3IuXG4gICAqL1xuICB0aGlzLnByb2Nlc3NBbnN3ZXIgPSBmdW5jdGlvbiAoc2RwQW5zd2VyLCBjYWxsYmFjaykge1xuICAgIGNhbGxiYWNrID0gKGNhbGxiYWNrIHx8IG5vb3ApLmJpbmQodGhpcylcblxuICAgIHZhciBhbnN3ZXIgPSBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgIHR5cGU6ICdhbnN3ZXInLFxuICAgICAgc2RwOiBzZHBBbnN3ZXJcbiAgICB9KVxuXG4gICAgaWYgKG11bHRpc3RyZWFtICYmIHVzZVBsYW5CKSB7XG4gICAgICB2YXIgcGxhbkJBbnN3ZXIgPSBpbnRlcm9wLnRvUGxhbkIoYW5zd2VyKVxuICAgICAgbG9nZ2VyLmRlYnVnKCdhc253ZXI6OnBsYW5CJywgZHVtcFNEUChwbGFuQkFuc3dlcikpXG4gICAgICBhbnN3ZXIgPSBwbGFuQkFuc3dlclxuICAgIH1cblxuICAgIGxvZ2dlci5kZWJ1ZygnU0RQIGFuc3dlciByZWNlaXZlZCwgc2V0dGluZyByZW1vdGUgZGVzY3JpcHRpb24nKVxuXG4gICAgaWYgKHBjLnNpZ25hbGluZ1N0YXRlID09PSAnY2xvc2VkJykge1xuICAgICAgcmV0dXJuIGNhbGxiYWNrKCdQZWVyQ29ubmVjdGlvbiBpcyBjbG9zZWQnKVxuICAgIH1cblxuICAgIHBjLnNldFJlbW90ZURlc2NyaXB0aW9uKGFuc3dlciwgZnVuY3Rpb24gKCkge1xuICAgICAgICBzZXRSZW1vdGVWaWRlbygpXG5cbiAgICAgICAgY2FsbGJhY2soKVxuICAgICAgfSxcbiAgICAgIGNhbGxiYWNrKVxuICB9XG5cbiAgLyoqXG4gICAqIENhbGxiYWNrIGZ1bmN0aW9uIGludm9rZWQgd2hlbiBhIFNEUCBvZmZlciBpcyByZWNlaXZlZC4gRGV2ZWxvcGVycyBhcmVcbiAgICogZXhwZWN0ZWQgdG8gaW52b2tlIHRoaXMgZnVuY3Rpb24gaW4gb3JkZXIgdG8gY29tcGxldGUgdGhlIFNEUCBuZWdvdGlhdGlvbi5cbiAgICpcbiAgICogQGZ1bmN0aW9uIG1vZHVsZTprdXJlbnRvVXRpbHMuV2ViUnRjUGVlci5wcm90b3R5cGUucHJvY2Vzc09mZmVyXG4gICAqXG4gICAqIEBwYXJhbSBzZHBPZmZlciAtIERlc2NyaXB0aW9uIG9mIHNkcE9mZmVyXG4gICAqIEBwYXJhbSBjYWxsYmFjayAtIENhbGxlZCB3aGVuIHRoZSByZW1vdGUgZGVzY3JpcHRpb24gaGFzIGJlZW4gc2V0XG4gICAqICBzdWNjZXNzZnVsbHkuXG4gICAqL1xuICB0aGlzLnByb2Nlc3NPZmZlciA9IGZ1bmN0aW9uIChzZHBPZmZlciwgY2FsbGJhY2spIHtcbiAgICBjYWxsYmFjayA9IGNhbGxiYWNrLmJpbmQodGhpcylcblxuICAgIHZhciBvZmZlciA9IG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgdHlwZTogJ29mZmVyJyxcbiAgICAgIHNkcDogc2RwT2ZmZXJcbiAgICB9KVxuXG4gICAgaWYgKG11bHRpc3RyZWFtICYmIHVzZVBsYW5CKSB7XG4gICAgICB2YXIgcGxhbkJPZmZlciA9IGludGVyb3AudG9QbGFuQihvZmZlcilcbiAgICAgIGxvZ2dlci5kZWJ1Zygnb2ZmZXI6OnBsYW5CJywgZHVtcFNEUChwbGFuQk9mZmVyKSlcbiAgICAgIG9mZmVyID0gcGxhbkJPZmZlclxuICAgIH1cblxuICAgIGxvZ2dlci5kZWJ1ZygnU0RQIG9mZmVyIHJlY2VpdmVkLCBzZXR0aW5nIHJlbW90ZSBkZXNjcmlwdGlvbicpXG5cbiAgICBpZiAocGMuc2lnbmFsaW5nU3RhdGUgPT09ICdjbG9zZWQnKSB7XG4gICAgICByZXR1cm4gY2FsbGJhY2soJ1BlZXJDb25uZWN0aW9uIGlzIGNsb3NlZCcpXG4gICAgfVxuXG4gICAgcGMuc2V0UmVtb3RlRGVzY3JpcHRpb24ob2ZmZXIpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIHNldFJlbW90ZVZpZGVvKClcbiAgICB9KS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBwYy5jcmVhdGVBbnN3ZXIoKVxuICAgIH0pLnRoZW4oZnVuY3Rpb24gKGFuc3dlcikge1xuICAgICAgYW5zd2VyID0gbWFuZ2xlU2RwVG9BZGRTaW11bGNhc3QoYW5zd2VyKVxuICAgICAgbG9nZ2VyLmRlYnVnKCdDcmVhdGVkIFNEUCBhbnN3ZXInKVxuICAgICAgcmV0dXJuIHBjLnNldExvY2FsRGVzY3JpcHRpb24oYW5zd2VyKVxuICAgIH0pLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIGxvY2FsRGVzY3JpcHRpb24gPSBwYy5sb2NhbERlc2NyaXB0aW9uXG4gICAgICBpZiAobXVsdGlzdHJlYW0gJiYgdXNlUGxhbkIpIHtcbiAgICAgICAgbG9jYWxEZXNjcmlwdGlvbiA9IGludGVyb3AudG9VbmlmaWVkUGxhbihsb2NhbERlc2NyaXB0aW9uKVxuICAgICAgICBsb2dnZXIuZGVidWcoJ2Fuc3dlcjo6b3JpZ1BsYW5CLT5VbmlmaWVkUGxhbicsIGR1bXBTRFAoXG4gICAgICAgICAgbG9jYWxEZXNjcmlwdGlvbikpXG4gICAgICB9XG4gICAgICBsb2dnZXIuZGVidWcoJ0xvY2FsIGRlc2NyaXB0aW9uIHNldCcsIGxvY2FsRGVzY3JpcHRpb24uc2RwKVxuICAgICAgY2FsbGJhY2sobnVsbCwgbG9jYWxEZXNjcmlwdGlvbi5zZHApXG4gICAgfSkuY2F0Y2goY2FsbGJhY2spXG4gIH1cblxuICBmdW5jdGlvbiBtYW5nbGVTZHBUb0FkZFNpbXVsY2FzdChhbnN3ZXIpIHtcbiAgICBpZiAoc2ltdWxjYXN0KSB7XG4gICAgICBpZiAoYnJvd3Nlci5uYW1lID09PSAnQ2hyb21lJyB8fCBicm93c2VyLm5hbWUgPT09ICdDaHJvbWl1bScpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdBZGRpbmcgbXVsdGljYXN0IGluZm8nKVxuICAgICAgICBhbnN3ZXIgPSBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgICAgICAndHlwZSc6IGFuc3dlci50eXBlLFxuICAgICAgICAgICdzZHAnOiByZW1vdmVGSURGcm9tT2ZmZXIoYW5zd2VyLnNkcCkgKyBnZXRTaW11bGNhc3RJbmZvKFxuICAgICAgICAgICAgdmlkZW9TdHJlYW0pXG4gICAgICAgIH0pXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsb2dnZXIud2FybignU2ltdWxjYXN0IGlzIG9ubHkgYXZhaWxhYmxlIGluIENocm9tZSBicm93c2VyLicpXG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGFuc3dlclxuICB9XG5cbiAgLyoqXG4gICAqIFRoaXMgZnVuY3Rpb24gY3JlYXRlcyB0aGUgUlRDUGVlckNvbm5lY3Rpb24gb2JqZWN0IHRha2luZyBpbnRvIGFjY291bnQgdGhlXG4gICAqIHByb3BlcnRpZXMgcmVjZWl2ZWQgaW4gdGhlIGNvbnN0cnVjdG9yLiBJdCBzdGFydHMgdGhlIFNEUCBuZWdvdGlhdGlvblxuICAgKiBwcm9jZXNzOiBnZW5lcmF0ZXMgdGhlIFNEUCBvZmZlciBhbmQgaW52b2tlcyB0aGUgb25zZHBvZmZlciBjYWxsYmFjay4gVGhpc1xuICAgKiBjYWxsYmFjayBpcyBleHBlY3RlZCB0byBzZW5kIHRoZSBTRFAgb2ZmZXIsIGluIG9yZGVyIHRvIG9idGFpbiBhbiBTRFBcbiAgICogYW5zd2VyIGZyb20gYW5vdGhlciBwZWVyLlxuICAgKi9cbiAgZnVuY3Rpb24gc3RhcnQoKSB7XG4gICAgaWYgKHBjLnNpZ25hbGluZ1N0YXRlID09PSAnY2xvc2VkJykge1xuICAgICAgY2FsbGJhY2soXG4gICAgICAgICdUaGUgcGVlciBjb25uZWN0aW9uIG9iamVjdCBpcyBpbiBcImNsb3NlZFwiIHN0YXRlLiBUaGlzIGlzIG1vc3QgbGlrZWx5IGR1ZSB0byBhbiBpbnZvY2F0aW9uIG9mIHRoZSBkaXNwb3NlIG1ldGhvZCBiZWZvcmUgYWNjZXB0aW5nIGluIHRoZSBkaWFsb2d1ZSdcbiAgICAgIClcbiAgICB9XG5cbiAgICBpZiAodmlkZW9TdHJlYW0gJiYgbG9jYWxWaWRlbykge1xuICAgICAgc2VsZi5zaG93TG9jYWxWaWRlbygpXG4gICAgfVxuXG4gICAgaWYgKHZpZGVvU3RyZWFtKSB7XG4gICAgICBwYy5hZGRTdHJlYW0odmlkZW9TdHJlYW0pXG4gICAgfVxuXG4gICAgaWYgKGF1ZGlvU3RyZWFtKSB7XG4gICAgICBwYy5hZGRTdHJlYW0oYXVkaW9TdHJlYW0pXG4gICAgfVxuXG4gICAgLy8gW0hhY2tdIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD00NDM1NThcbiAgICB2YXIgYnJvd3NlciA9IHBhcnNlci5nZXRCcm93c2VyKClcbiAgICBpZiAobW9kZSA9PT0gJ3NlbmRvbmx5JyAmJlxuICAgICAgKGJyb3dzZXIubmFtZSA9PT0gJ0Nocm9tZScgfHwgYnJvd3Nlci5uYW1lID09PSAnQ2hyb21pdW0nKSAmJlxuICAgICAgYnJvd3Nlci5tYWpvciA9PT0gMzkpIHtcbiAgICAgIG1vZGUgPSAnc2VuZHJlY3YnXG4gICAgfVxuXG4gICAgY2FsbGJhY2soKVxuICB9XG5cbiAgaWYgKG1vZGUgIT09ICdyZWN2b25seScgJiYgIXZpZGVvU3RyZWFtICYmICFhdWRpb1N0cmVhbSkge1xuICAgIGZ1bmN0aW9uIGdldE1lZGlhKGNvbnN0cmFpbnRzKSB7XG4gICAgICBpZiAoY29uc3RyYWludHMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb25zdHJhaW50cyA9IE1FRElBX0NPTlNUUkFJTlRTXG4gICAgICB9XG5cbiAgICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKGNvbnN0cmFpbnRzKS50aGVuKGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgdmlkZW9TdHJlYW0gPSBzdHJlYW1cbiAgICAgICAgc3RhcnQoKVxuICAgICAgfSkuY2F0Y2goY2FsbGJhY2spO1xuICAgIH1cbiAgICBpZiAoc2VuZFNvdXJjZSA9PT0gJ3dlYmNhbScpIHtcbiAgICAgIGdldE1lZGlhKG1lZGlhQ29uc3RyYWludHMpXG4gICAgfSBlbHNlIHtcbiAgICAgIGdldFNjcmVlbkNvbnN0cmFpbnRzKHNlbmRTb3VyY2UsIGZ1bmN0aW9uIChlcnJvciwgY29uc3RyYWludHNfKSB7XG4gICAgICAgIGlmIChlcnJvcilcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyb3IpXG5cbiAgICAgICAgY29uc3RyYWludHMgPSBbbWVkaWFDb25zdHJhaW50c11cbiAgICAgICAgY29uc3RyYWludHMudW5zaGlmdChjb25zdHJhaW50c18pXG4gICAgICAgIGdldE1lZGlhKHJlY3Vyc2l2ZS5hcHBseSh1bmRlZmluZWQsIGNvbnN0cmFpbnRzKSlcbiAgICAgIH0sIGd1aWQpXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHNldFRpbWVvdXQoc3RhcnQsIDApXG4gIH1cblxuICB0aGlzLm9uKCdfZGlzcG9zZScsIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAobG9jYWxWaWRlbykge1xuICAgICAgbG9jYWxWaWRlby5wYXVzZSgpXG4gICAgICBsb2NhbFZpZGVvLnNyYyA9ICcnXG4gICAgICBsb2NhbFZpZGVvLmxvYWQoKVxuICAgICAgLy9Vbm11dGUgbG9jYWwgdmlkZW8gaW4gY2FzZSB0aGUgdmlkZW8gdGFnIGlzIGxhdGVyIHVzZWQgZm9yIHJlbW90ZSB2aWRlb1xuICAgICAgbG9jYWxWaWRlby5tdXRlZCA9IGZhbHNlXG4gICAgfVxuICAgIGlmIChyZW1vdGVWaWRlbykge1xuICAgICAgcmVtb3RlVmlkZW8ucGF1c2UoKVxuICAgICAgcmVtb3RlVmlkZW8uc3JjID0gJydcbiAgICAgIHJlbW90ZVZpZGVvLmxvYWQoKVxuICAgIH1cbiAgICBzZWxmLnJlbW92ZUFsbExpc3RlbmVycygpXG5cbiAgICBpZiAod2luZG93LmNhbmNlbENob29zZURlc2t0b3BNZWRpYSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB3aW5kb3cuY2FuY2VsQ2hvb3NlRGVza3RvcE1lZGlhKGd1aWQpXG4gICAgfVxuICB9KVxufVxuaW5oZXJpdHMoV2ViUnRjUGVlciwgRXZlbnRFbWl0dGVyKVxuXG5mdW5jdGlvbiBjcmVhdGVFbmFibGVEZXNjcmlwdG9yKHR5cGUpIHtcbiAgdmFyIG1ldGhvZCA9ICdnZXQnICsgdHlwZSArICdUcmFja3MnXG5cbiAgcmV0dXJuIHtcbiAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgLy8gW1RvRG9dIFNob3VsZCByZXR1cm4gdW5kZWZpbmVkIGlmIG5vdCBhbGwgdHJhY2tzIGhhdmUgdGhlIHNhbWUgdmFsdWU/XG5cbiAgICAgIGlmICghdGhpcy5wZWVyQ29ubmVjdGlvbikgcmV0dXJuXG5cbiAgICAgIHZhciBzdHJlYW1zID0gdGhpcy5wZWVyQ29ubmVjdGlvbi5nZXRMb2NhbFN0cmVhbXMoKVxuICAgICAgaWYgKCFzdHJlYW1zLmxlbmd0aCkgcmV0dXJuXG5cbiAgICAgIGZvciAodmFyIGkgPSAwLCBzdHJlYW07IHN0cmVhbSA9IHN0cmVhbXNbaV07IGkrKykge1xuICAgICAgICB2YXIgdHJhY2tzID0gc3RyZWFtW21ldGhvZF0oKVxuICAgICAgICBmb3IgKHZhciBqID0gMCwgdHJhY2s7IHRyYWNrID0gdHJhY2tzW2pdOyBqKyspXG4gICAgICAgICAgaWYgKCF0cmFjay5lbmFibGVkKSByZXR1cm4gZmFsc2VcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRydWVcbiAgICB9LFxuICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICBmdW5jdGlvbiB0cmFja1NldEVuYWJsZSh0cmFjaykge1xuICAgICAgICB0cmFjay5lbmFibGVkID0gdmFsdWVcbiAgICAgIH1cblxuICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbi5nZXRMb2NhbFN0cmVhbXMoKS5mb3JFYWNoKGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgc3RyZWFtW21ldGhvZF0oKS5mb3JFYWNoKHRyYWNrU2V0RW5hYmxlKVxuICAgICAgfSlcbiAgICB9XG4gIH1cbn1cblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoV2ViUnRjUGVlci5wcm90b3R5cGUsIHtcbiAgJ2VuYWJsZWQnOiB7XG4gICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiB0aGlzLmF1ZGlvRW5hYmxlZCAmJiB0aGlzLnZpZGVvRW5hYmxlZFxuICAgIH0sXG4gICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgIHRoaXMuYXVkaW9FbmFibGVkID0gdGhpcy52aWRlb0VuYWJsZWQgPSB2YWx1ZVxuICAgIH1cbiAgfSxcbiAgJ2F1ZGlvRW5hYmxlZCc6IGNyZWF0ZUVuYWJsZURlc2NyaXB0b3IoJ0F1ZGlvJyksXG4gICd2aWRlb0VuYWJsZWQnOiBjcmVhdGVFbmFibGVEZXNjcmlwdG9yKCdWaWRlbycpXG59KVxuXG5XZWJSdGNQZWVyLnByb3RvdHlwZS5nZXRMb2NhbFN0cmVhbSA9IGZ1bmN0aW9uIChpbmRleCkge1xuICBpZiAodGhpcy5wZWVyQ29ubmVjdGlvbikge1xuICAgIHJldHVybiB0aGlzLnBlZXJDb25uZWN0aW9uLmdldExvY2FsU3RyZWFtcygpW2luZGV4IHx8IDBdXG4gIH1cbn1cblxuV2ViUnRjUGVlci5wcm90b3R5cGUuZ2V0UmVtb3RlU3RyZWFtID0gZnVuY3Rpb24gKGluZGV4KSB7XG4gIGlmICh0aGlzLnBlZXJDb25uZWN0aW9uKSB7XG4gICAgcmV0dXJuIHRoaXMucGVlckNvbm5lY3Rpb24uZ2V0UmVtb3RlU3RyZWFtcygpW2luZGV4IHx8IDBdXG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gVGhpcyBtZXRob2QgZnJlZXMgdGhlIHJlc291cmNlcyB1c2VkIGJ5IFdlYlJ0Y1BlZXIuXG4gKlxuICogQGZ1bmN0aW9uIG1vZHVsZTprdXJlbnRvVXRpbHMuV2ViUnRjUGVlci5wcm90b3R5cGUuZGlzcG9zZVxuICovXG5XZWJSdGNQZWVyLnByb3RvdHlwZS5kaXNwb3NlID0gZnVuY3Rpb24gKCkge1xuICBsb2dnZXIuZGVidWcoJ0Rpc3Bvc2luZyBXZWJSdGNQZWVyJylcblxuICB2YXIgcGMgPSB0aGlzLnBlZXJDb25uZWN0aW9uXG4gIHZhciBkYyA9IHRoaXMuZGF0YUNoYW5uZWxcbiAgdHJ5IHtcbiAgICBpZiAoZGMpIHtcbiAgICAgIGlmIChkYy5zaWduYWxpbmdTdGF0ZSA9PT0gJ2Nsb3NlZCcpIHJldHVyblxuXG4gICAgICBkYy5jbG9zZSgpXG4gICAgfVxuXG4gICAgaWYgKHBjKSB7XG4gICAgICBpZiAocGMuc2lnbmFsaW5nU3RhdGUgPT09ICdjbG9zZWQnKSByZXR1cm5cblxuICAgICAgcGMuZ2V0TG9jYWxTdHJlYW1zKCkuZm9yRWFjaChzdHJlYW1TdG9wKVxuXG4gICAgICAvLyBGSVhNRSBUaGlzIGlzIG5vdCB5ZXQgaW1wbGVtZW50ZWQgaW4gZmlyZWZveFxuICAgICAgLy8gaWYodmlkZW9TdHJlYW0pIHBjLnJlbW92ZVN0cmVhbSh2aWRlb1N0cmVhbSk7XG4gICAgICAvLyBpZihhdWRpb1N0cmVhbSkgcGMucmVtb3ZlU3RyZWFtKGF1ZGlvU3RyZWFtKTtcblxuICAgICAgcGMuY2xvc2UoKVxuICAgIH1cbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLndhcm4oJ0V4Y2VwdGlvbiBkaXNwb3Npbmcgd2VicnRjIHBlZXIgJyArIGVycilcbiAgfVxuXG4gIHRoaXMuZW1pdCgnX2Rpc3Bvc2UnKVxufVxuXG4vL1xuLy8gU3BlY2lhbGl6ZWQgY2hpbGQgY2xhc3Nlc1xuLy9cblxuZnVuY3Rpb24gV2ViUnRjUGVlclJlY3Zvbmx5KG9wdGlvbnMsIGNhbGxiYWNrKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBXZWJSdGNQZWVyUmVjdm9ubHkpKSB7XG4gICAgcmV0dXJuIG5ldyBXZWJSdGNQZWVyUmVjdm9ubHkob3B0aW9ucywgY2FsbGJhY2spXG4gIH1cblxuICBXZWJSdGNQZWVyUmVjdm9ubHkuc3VwZXJfLmNhbGwodGhpcywgJ3JlY3Zvbmx5Jywgb3B0aW9ucywgY2FsbGJhY2spXG59XG5pbmhlcml0cyhXZWJSdGNQZWVyUmVjdm9ubHksIFdlYlJ0Y1BlZXIpXG5cbmZ1bmN0aW9uIFdlYlJ0Y1BlZXJTZW5kb25seShvcHRpb25zLCBjYWxsYmFjaykge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgV2ViUnRjUGVlclNlbmRvbmx5KSkge1xuICAgIHJldHVybiBuZXcgV2ViUnRjUGVlclNlbmRvbmx5KG9wdGlvbnMsIGNhbGxiYWNrKVxuICB9XG5cbiAgV2ViUnRjUGVlclNlbmRvbmx5LnN1cGVyXy5jYWxsKHRoaXMsICdzZW5kb25seScsIG9wdGlvbnMsIGNhbGxiYWNrKVxufVxuaW5oZXJpdHMoV2ViUnRjUGVlclNlbmRvbmx5LCBXZWJSdGNQZWVyKVxuXG5mdW5jdGlvbiBXZWJSdGNQZWVyU2VuZHJlY3Yob3B0aW9ucywgY2FsbGJhY2spIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFdlYlJ0Y1BlZXJTZW5kcmVjdikpIHtcbiAgICByZXR1cm4gbmV3IFdlYlJ0Y1BlZXJTZW5kcmVjdihvcHRpb25zLCBjYWxsYmFjaylcbiAgfVxuXG4gIFdlYlJ0Y1BlZXJTZW5kcmVjdi5zdXBlcl8uY2FsbCh0aGlzLCAnc2VuZHJlY3YnLCBvcHRpb25zLCBjYWxsYmFjaylcbn1cbmluaGVyaXRzKFdlYlJ0Y1BlZXJTZW5kcmVjdiwgV2ViUnRjUGVlcilcblxuZnVuY3Rpb24gaGFya1V0aWxzKHN0cmVhbSwgb3B0aW9ucykge1xuICByZXR1cm4gaGFyayhzdHJlYW0sIG9wdGlvbnMpO1xufVxuXG5leHBvcnRzLmJ1ZmZlcml6ZUNhbmRpZGF0ZXMgPSBidWZmZXJpemVDYW5kaWRhdGVzXG5cbmV4cG9ydHMuV2ViUnRjUGVlclJlY3Zvbmx5ID0gV2ViUnRjUGVlclJlY3Zvbmx5XG5leHBvcnRzLldlYlJ0Y1BlZXJTZW5kb25seSA9IFdlYlJ0Y1BlZXJTZW5kb25seVxuZXhwb3J0cy5XZWJSdGNQZWVyU2VuZHJlY3YgPSBXZWJSdGNQZWVyU2VuZHJlY3ZcbmV4cG9ydHMuaGFyayA9IGhhcmtVdGlsc1xuIiwiLypcbiAqIChDKSBDb3B5cmlnaHQgMjAxNCBLdXJlbnRvIChodHRwOi8va3VyZW50by5vcmcvKVxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICovXG5cbi8qKlxuICogVGhpcyBtb2R1bGUgY29udGFpbnMgYSBzZXQgb2YgcmV1c2FibGUgY29tcG9uZW50cyB0aGF0IGhhdmUgYmVlbiBmb3VuZCB1c2VmdWxcbiAqIGR1cmluZyB0aGUgZGV2ZWxvcG1lbnQgb2YgdGhlIFdlYlJUQyBhcHBsaWNhdGlvbnMgd2l0aCBLdXJlbnRvLlxuICogXG4gKiBAbW9kdWxlIGt1cmVudG9VdGlsc1xuICogXG4gKiBAY29weXJpZ2h0IDIwMTQgS3VyZW50byAoaHR0cDovL2t1cmVudG8ub3JnLylcbiAqIEBsaWNlbnNlIEFMdjJcbiAqL1xuXG52YXIgV2ViUnRjUGVlciA9IHJlcXVpcmUoJy4vV2ViUnRjUGVlcicpO1xuXG5leHBvcnRzLldlYlJ0Y1BlZXIgPSBXZWJSdGNQZWVyO1xuIiwiaW1wb3J0IHsgT3BlblZpZHUgfSBmcm9tICcuL09wZW5WaWR1JztcblxuLy9UaGlzIGV4cG9ydCB3aXRoIC0tc3RhbmRhbG9uZSBvcHRpb24gYWxsb3dzIHVzaW5nIE9wZW5WaWR1IGZyb20gYm93c2VyIHdpdGggbmFtZXNwYWNlXG4vL2V4cG9ydCB7IE9wZW5WaWR1IH0gZnJvbSAnLi9PcGVuVmlkdSc7XG5cbi8vVGhpcyBcImhhY2tcIiBhbGxvd3MgdG8gdXNlIE9wZW5WaWR1IGZyb20gdGhlIGdsb2JhbCBzcGFjZSB3aW5kb3dcbmlmKHdpbmRvdyl7XG4gICAgd2luZG93W1wiT3BlblZpZHVcIl0gPSBPcGVuVmlkdTtcbn1cblxuLy9Db21tYW5kIHRvIGdlbmVyYXRlIGJ1bmRsZS5qcyB3aXRob3V0IG5hbWVzcGFjZVxuLy93YXRjaGlmeSBNYWluLnRzIC1wIFsgdHNpZnkgXSAtLWV4Y2x1ZGUga3VyZW50by1icm93c2VyLWV4dGVuc2lvbnMgLS1kZWJ1ZyAtbyAuLi9zdGF0aWMvanMvT3BlblZpZHUuanMgLXYiLCIvKlxuICogKEMpIENvcHlyaWdodCAyMDE3IE9wZW5WaWR1IChodHRwOi8vb3BlbnZpZHUuaW8vKVxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICovXG5pbXBvcnQgeyBPcGVuVmlkdUludGVybmFsIH0gZnJvbSAnLi4vT3BlblZpZHVJbnRlcm5hbC9PcGVuVmlkdUludGVybmFsJztcblxuaW1wb3J0IHsgU2Vzc2lvbiB9IGZyb20gJy4vU2Vzc2lvbic7XG5pbXBvcnQgeyBQdWJsaXNoZXIgfSBmcm9tICcuL1B1Ymxpc2hlcic7XG5pbXBvcnQgeyBPcGVuVmlkdUVycm9yLCBPcGVuVmlkdUVycm9yTmFtZSB9IGZyb20gJy4uL09wZW5WaWR1SW50ZXJuYWwvT3BlblZpZHVFcnJvcic7XG5cbmltcG9ydCAqIGFzIGFkYXB0ZXIgZnJvbSAnd2VicnRjLWFkYXB0ZXInO1xuaW1wb3J0ICogYXMgc2NyZWVuU2hhcmluZyBmcm9tICcuLi9TY3JlZW5TaGFyaW5nL1NjcmVlbi1DYXB0dXJpbmcuanMnO1xuaW1wb3J0ICogYXMgc2NyZWVuU2hhcmluZ0F1dG8gZnJvbSAnLi4vU2NyZWVuU2hhcmluZy9TY3JlZW4tQ2FwdHVyaW5nLUF1dG8uanMnO1xuXG5pZiAod2luZG93KSB7XG4gICAgd2luZG93W1wiYWRhcHRlclwiXSA9IGFkYXB0ZXI7XG59XG5cbmV4cG9ydCBjbGFzcyBPcGVuVmlkdSB7XG5cbiAgICBvcGVuVmlkdTogT3BlblZpZHVJbnRlcm5hbDtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLm9wZW5WaWR1ID0gbmV3IE9wZW5WaWR1SW50ZXJuYWwoKTtcbiAgICAgICAgY29uc29sZS5pbmZvKFwiJ09wZW5WaWR1JyBpbml0aWFsaXplZFwiKTtcbiAgICB9O1xuXG4gICAgaW5pdFNlc3Npb24oYXBpS2V5OiBzdHJpbmcsIHNlc3Npb25JZDogc3RyaW5nKTogU2Vzc2lvbjtcbiAgICBpbml0U2Vzc2lvbihzZXNzaW9uSWQ6IHN0cmluZyk6IFNlc3Npb247XG5cbiAgICBpbml0U2Vzc2lvbihwYXJhbTEsIHBhcmFtMj8pOiBhbnkge1xuICAgICAgICBpZiAodGhpcy5jaGVja1N5c3RlbVJlcXVpcmVtZW50cygpKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHBhcmFtMiA9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBTZXNzaW9uKHRoaXMub3BlblZpZHUuaW5pdFNlc3Npb24ocGFyYW0yKSwgdGhpcyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgU2Vzc2lvbih0aGlzLm9wZW5WaWR1LmluaXRTZXNzaW9uKHBhcmFtMSksIHRoaXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYWxlcnQoXCJCcm93c2VyIG5vdCBzdXBwb3J0ZWRcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpbml0UHVibGlzaGVyKHBhcmVudElkOiBzdHJpbmcpOiBQdWJsaXNoZXI7XG4gICAgaW5pdFB1Ymxpc2hlcihwYXJlbnRJZDogc3RyaW5nLCBjYW1lcmFPcHRpb25zOiBhbnkpOiBQdWJsaXNoZXI7XG4gICAgaW5pdFB1Ymxpc2hlcihwYXJlbnRJZDogc3RyaW5nLCBjYW1lcmFPcHRpb25zOiBhbnksIGNhbGxiYWNrOiBhbnkpOiBQdWJsaXNoZXI7XG5cbiAgICBpbml0UHVibGlzaGVyKHBhcmVudElkOiBzdHJpbmcsIGNhbWVyYU9wdGlvbnM/OiBhbnksIGNhbGxiYWNrPzogRnVuY3Rpb24pOiBhbnkge1xuICAgICAgICBpZiAodGhpcy5jaGVja1N5c3RlbVJlcXVpcmVtZW50cygpKSB7XG4gICAgICAgICAgICBsZXQgcHVibGlzaGVyOiBQdWJsaXNoZXI7XG4gICAgICAgICAgICBpZiAoY2FtZXJhT3B0aW9ucyAhPSBudWxsKSB7XG5cbiAgICAgICAgICAgICAgICBjYW1lcmFPcHRpb25zLmF1ZGlvID0gY2FtZXJhT3B0aW9ucy5hdWRpbyAhPSBudWxsID8gY2FtZXJhT3B0aW9ucy5hdWRpbyA6IHRydWU7XG4gICAgICAgICAgICAgICAgY2FtZXJhT3B0aW9ucy52aWRlbyA9IGNhbWVyYU9wdGlvbnMudmlkZW8gIT0gbnVsbCA/IGNhbWVyYU9wdGlvbnMudmlkZW8gOiB0cnVlO1xuXG4gICAgICAgICAgICAgICAgaWYgKCFjYW1lcmFPcHRpb25zLnNjcmVlbikge1xuICAgICAgICAgICAgICAgICAgICAvLyBXZWJjYW0gYW5kL29yIG1pY3JvcGhvbmUgaXMgYmVpbmcgcmVxdWVzdGVkXG5cbiAgICAgICAgICAgICAgICAgICAgbGV0IGNhbWVyYU9wdGlvbnNBdXggPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZW5kQXVkaW86IGNhbWVyYU9wdGlvbnMuYXVkaW8gIT0gbnVsbCA/IGNhbWVyYU9wdGlvbnMuYXVkaW8gOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VuZFZpZGVvOiBjYW1lcmFPcHRpb25zLnZpZGVvICE9IG51bGwgPyBjYW1lcmFPcHRpb25zLnZpZGVvIDogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjdGl2ZUF1ZGlvOiBjYW1lcmFPcHRpb25zLmF1ZGlvQWN0aXZlICE9IG51bGwgPyBjYW1lcmFPcHRpb25zLmF1ZGlvQWN0aXZlIDogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjdGl2ZVZpZGVvOiBjYW1lcmFPcHRpb25zLnZpZGVvQWN0aXZlICE9IG51bGwgPyBjYW1lcmFPcHRpb25zLnZpZGVvQWN0aXZlIDogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICBtZWRpYUNvbnN0cmFpbnRzOiB0aGlzLm9wZW5WaWR1LmdlbmVyYXRlTWVkaWFDb25zdHJhaW50cyhjYW1lcmFPcHRpb25zKVxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICBjYW1lcmFPcHRpb25zID0gY2FtZXJhT3B0aW9uc0F1eDtcbiAgICAgICAgICAgICAgICAgICAgcHVibGlzaGVyID0gbmV3IFB1Ymxpc2hlcih0aGlzLm9wZW5WaWR1LmluaXRQdWJsaXNoZXJUYWdnZWQocGFyZW50SWQsIGNhbWVyYU9wdGlvbnMsIGNhbGxiYWNrKSwgcGFyZW50SWQsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiJ1B1Ymxpc2hlcicgaW5pdGlhbGl6ZWRcIik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBwdWJsaXNoZXI7XG5cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpZiAoYWRhcHRlci5icm93c2VyRGV0YWlscy5icm93c2VyID09PSAnZmlyZWZveCcgJiYgYWRhcHRlci5icm93c2VyRGV0YWlscy52ZXJzaW9uID49IDUyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwdWJsaXNoZXIgPSBuZXcgUHVibGlzaGVyKHRoaXMub3BlblZpZHUuaW5pdFB1Ymxpc2hlclNjcmVlbihwYXJlbnRJZCwgY2FsbGJhY2spLCBwYXJlbnRJZCwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzY3JlZW5TaGFyaW5nQXV0by5nZXRTY3JlZW5JZCgoZXJyb3IsIHNvdXJjZUlkLCBzY3JlZW5Db25zdHJhaW50cykgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbWVyYU9wdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbmRBdWRpbzogY2FtZXJhT3B0aW9ucy5hdWRpbyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VuZFZpZGVvOiBjYW1lcmFPcHRpb25zLnZpZGVvLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3RpdmVBdWRpbzogY2FtZXJhT3B0aW9ucy5hdWRpb0FjdGl2ZSAhPSBudWxsID8gY2FtZXJhT3B0aW9ucy5hdWRpb0FjdGl2ZSA6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjdGl2ZVZpZGVvOiBjYW1lcmFPcHRpb25zLnZpZGVvQWN0aXZlICE9IG51bGwgPyBjYW1lcmFPcHRpb25zLnZpZGVvQWN0aXZlIDogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVkaWFDb25zdHJhaW50czoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW86IHNjcmVlbkNvbnN0cmFpbnRzLnZpZGVvLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXVkaW86IGZhbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHVibGlzaGVyLnN0cmVhbS5jb25maWd1cmVTY3JlZW5PcHRpb25zKGNhbWVyYU9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIidQdWJsaXNoZXInIGluaXRpYWxpemVkXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcHVibGlzaGVyO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGFkYXB0ZXIuYnJvd3NlckRldGFpbHMuYnJvd3NlciA9PT0gJ2Nocm9tZScpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNjcmVlbiBpcyBiZWluZyByZXF1ZXN0ZWRcblxuICAgICAgICAgICAgICAgICAgICAgICAgLypzY3JlZW5TaGFyaW5nLmlzQ2hyb21lRXh0ZW5zaW9uQXZhaWxhYmxlKChhdmFpbGFiaWxpdHkpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKGF2YWlsYWJpbGl0eSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdhdmFpbGFibGUnOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdFWFRFTlNJT04gQVZBSUxBQkxFISEhJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY3JlZW5TaGFyaW5nLmdldFNjcmVlbkNvbnN0cmFpbnRzKChlcnJvciwgc2NyZWVuQ29uc3RyYWludHMpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihzY3JlZW5Db25zdHJhaW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAndW5hdmFpbGFibGUnOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdFWFRFTlNJT04gTk9UIEFWQUlMQUJMRSEhIScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ2lzRmlyZWZveCc6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ0lUIElTIEZJUkVGT1ghISEnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjcmVlblNoYXJpbmcuZ2V0U2NyZWVuQ29uc3RyYWludHMoKGVycm9yLCBzY3JlZW5Db25zdHJhaW50cykgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKHNjcmVlbkNvbnN0cmFpbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0pOyovXG4gICAgICAgICAgICAgICAgICAgICAgICBzY3JlZW5TaGFyaW5nQXV0by5nZXRTY3JlZW5JZCgoZXJyb3IsIHNvdXJjZUlkLCBzY3JlZW5Db25zdHJhaW50cykgPT4ge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yID09PSAnbm90LWluc3RhbGxlZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGVycm9yID0gbmV3IE9wZW5WaWR1RXJyb3IoT3BlblZpZHVFcnJvck5hbWUuU0NSRUVOX0VYVEVOU0lPTl9OT1RfSU5TVEFMTEVELCAnaHR0cHM6Ly9jaHJvbWUuZ29vZ2xlLmNvbS93ZWJzdG9yZS9kZXRhaWwvc2NyZWVuLWNhcHR1cmluZy9hamhpZmRkaW1rYXBnY2lmZ2NvZG1tZmRsa25haGZmaycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNhbGxiYWNrKSBjYWxsYmFjayhlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGVycm9yID09PSAncGVybWlzc2lvbi1kZW5pZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldCBlcnJvciA9IG5ldyBPcGVuVmlkdUVycm9yKE9wZW5WaWR1RXJyb3JOYW1lLlNDUkVFTl9DQVBUVVJFX0RFTklFRCwgJ1lvdSBtdXN0IGFsbG93IGFjY2VzcyB0byBvbmUgd2luZG93IG9mIHlvdXIgZGVza3RvcCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNhbGxiYWNrKSBjYWxsYmFjayhlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYW1lcmFPcHRpb25zID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZW5kQXVkaW86IGNhbWVyYU9wdGlvbnMuYXVkaW8gIT0gbnVsbCA/IGNhbWVyYU9wdGlvbnMuYXVkaW8gOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZW5kVmlkZW86IGNhbWVyYU9wdGlvbnMudmlkZW8gIT0gbnVsbCA/IGNhbWVyYU9wdGlvbnMudmlkZW8gOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3RpdmVBdWRpbzogY2FtZXJhT3B0aW9ucy5hdWRpb0FjdGl2ZSAhPSBudWxsID8gY2FtZXJhT3B0aW9ucy5hdWRpb0FjdGl2ZSA6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjdGl2ZVZpZGVvOiBjYW1lcmFPcHRpb25zLnZpZGVvQWN0aXZlICE9IG51bGwgPyBjYW1lcmFPcHRpb25zLnZpZGVvQWN0aXZlIDogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVkaWFDb25zdHJhaW50czoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW86IHNjcmVlbkNvbnN0cmFpbnRzLnZpZGVvLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXVkaW86IGZhbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHVibGlzaGVyLnN0cmVhbS5jb25maWd1cmVTY3JlZW5PcHRpb25zKGNhbWVyYU9wdGlvbnMpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICB9LCAoZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdnZXRTY3JlZW5JZCBlcnJvcicsIGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHB1Ymxpc2hlciA9IG5ldyBQdWJsaXNoZXIodGhpcy5vcGVuVmlkdS5pbml0UHVibGlzaGVyU2NyZWVuKHBhcmVudElkLCBjYWxsYmFjayksIHBhcmVudElkLCB0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIidQdWJsaXNoZXInIGluaXRpYWxpemVkXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHB1Ymxpc2hlcjtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1NjcmVlbiBzaGFyaW5nIG5vdCBzdXBwb3J0ZWQgb24gJyArIGFkYXB0ZXIuYnJvd3NlckRldGFpbHMuYnJvd3Nlcik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNhbWVyYU9wdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgICAgIHNlbmRBdWRpbzogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgc2VuZFZpZGVvOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBhY3RpdmVBdWRpbzogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgYWN0aXZlVmlkZW86IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIGRhdGE6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIG1lZGlhQ29uc3RyYWludHM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGF1ZGlvOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW86IHsgd2lkdGg6IHsgaWRlYWw6IDEyODAgfSB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcHVibGlzaGVyID0gbmV3IFB1Ymxpc2hlcih0aGlzLm9wZW5WaWR1LmluaXRQdWJsaXNoZXJUYWdnZWQocGFyZW50SWQsIGNhbWVyYU9wdGlvbnMsIGNhbGxiYWNrKSwgcGFyZW50SWQsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXCInUHVibGlzaGVyJyBpbml0aWFsaXplZFwiKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcHVibGlzaGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYWxlcnQoXCJCcm93c2VyIG5vdCBzdXBwb3J0ZWRcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjaGVja1N5c3RlbVJlcXVpcmVtZW50cygpOiBudW1iZXIge1xuICAgICAgICBsZXQgYnJvd3NlciA9IGFkYXB0ZXIuYnJvd3NlckRldGFpbHMuYnJvd3NlcjtcbiAgICAgICAgbGV0IHZlcnNpb24gPSBhZGFwdGVyLmJyb3dzZXJEZXRhaWxzLnZlcnNpb247XG5cbiAgICAgICAgLy9CdWcgZml4OiAnbmF2aWdhdG9yLnVzZXJBZ2VudCcgaW4gRmlyZWZveCBmb3IgVWJ1bnR1IDE0LjA0IGRvZXMgbm90IHJldHVybiBcIkZpcmVmb3gvW3ZlcnNpb25dXCIgaW4gdGhlIHN0cmluZywgc28gdmVyc2lvbiByZXR1cm5lZCBpcyBudWxsXG4gICAgICAgIGlmICgoYnJvd3NlciA9PSAnZmlyZWZveCcpICYmICh2ZXJzaW9uID09IG51bGwpKSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoKChicm93c2VyID09ICdjaHJvbWUnKSAmJiAodmVyc2lvbiA+PSAyOCkpIHx8ICgoYnJvd3NlciA9PSAnZWRnZScpICYmICh2ZXJzaW9uID49IDEyKSkgfHwgKChicm93c2VyID09ICdmaXJlZm94JykgJiYgKHZlcnNpb24gPj0gMjIpKSkge1xuICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldERldmljZXMoY2FsbGJhY2spIHtcbiAgICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzKCkudGhlbigoZGV2aWNlSW5mb3MpID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIGRldmljZUluZm9zKTtcbiAgICAgICAgfSkuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgZ2V0dGluZyBkZXZpY2VzXCIsIGVycm9yKTtcbiAgICAgICAgICAgIGNhbGxiYWNrKGVycm9yLCBudWxsKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgZW5hYmxlUHJvZE1vZGUoKSB7XG4gICAgICAgIGNvbnNvbGUubG9nID0gZnVuY3Rpb24gKCkgeyB9O1xuICAgICAgICBjb25zb2xlLmRlYnVnID0gZnVuY3Rpb24gKCkgeyB9O1xuICAgICAgICBjb25zb2xlLmluZm8gPSBmdW5jdGlvbiAoKSB7IH07XG4gICAgICAgIGNvbnNvbGUud2FybiA9IGZ1bmN0aW9uICgpIHsgfTtcbiAgICB9XG5cbn1cbiIsIi8qXG4gKiBvcHRpb25zOiBuYW1lOiBYWFggZGF0YTogdHJ1ZSAoTWF5YmUgdGhpcyBpcyBiYXNlZCBvbiB3ZWJydGMpIGF1ZGlvOiB0cnVlLFxuICogdmlkZW86IHRydWUsIHVybDogXCJmaWxlOi8vLy4uLlwiID4gUGxheWVyIHNjcmVlbjogdHJ1ZSA+IERlc2t0b3AgKGltcGxpY2l0XG4gKiB2aWRlbzp0cnVlLCBhdWRpbzpmYWxzZSkgYXVkaW86IHRydWUsIHZpZGVvOiB0cnVlID4gV2ViY2FtXG4gKlxuICogc3RyZWFtLmhhc0F1ZGlvKCk7IHN0cmVhbS5oYXNWaWRlbygpOyBzdHJlYW0uaGFzRGF0YSgpO1xuICovXG5pbXBvcnQgeyBTdHJlYW0sIFN0cmVhbU9wdGlvbnMsIFZpZGVvT3B0aW9ucyB9IGZyb20gJy4uL09wZW5WaWR1SW50ZXJuYWwvU3RyZWFtJztcbmltcG9ydCB7IFNlc3Npb24gfSBmcm9tICcuL1Nlc3Npb24nO1xuXG5pbXBvcnQgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnd29sZnk4Ny1ldmVudGVtaXR0ZXInKTtcblxuZXhwb3J0IGNsYXNzIFB1Ymxpc2hlciB7XG5cbiAgICBwcml2YXRlIGVlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gICAgYWNjZXNzQWxsb3dlZCA9IGZhbHNlO1xuICAgIGVsZW1lbnQ6IEVsZW1lbnQ7XG4gICAgaWQ6IHN0cmluZztcbiAgICBzdHJlYW06IFN0cmVhbTtcbiAgICBzZXNzaW9uOiBTZXNzaW9uOyAvL0luaXRpYWxpemVkIGJ5IFNlc3Npb24ucHVibGlzaChQdWJsaXNoZXIpXG4gICAgaXNTY3JlZW5SZXF1ZXN0ZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIGNvbnN0cnVjdG9yKHN0cmVhbTogU3RyZWFtLCBwYXJlbnRJZDogc3RyaW5nLCBpc1NjcmVlblJlcXVlc3RlZDogYm9vbGVhbikge1xuICAgICAgICB0aGlzLnN0cmVhbSA9IHN0cmVhbTtcbiAgICAgICAgdGhpcy5pc1NjcmVlblJlcXVlc3RlZCA9IGlzU2NyZWVuUmVxdWVzdGVkO1xuXG4gICAgICAgIHRoaXMuc3RyZWFtLmFkZEV2ZW50TGlzdGVuZXIoJ2NhbWVyYS1hY2Nlc3MtY2hhbmdlZCcsIChldmVudCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5hY2Nlc3NBbGxvd2VkID0gZXZlbnQuYWNjZXNzQWxsb3dlZDtcbiAgICAgICAgICAgIGlmICh0aGlzLmFjY2Vzc0FsbG93ZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnYWNjZXNzQWxsb3dlZCcpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnYWNjZXNzRGVuaWVkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChkb2N1bWVudC5nZXRFbGVtZW50QnlJZChwYXJlbnRJZCkgIT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5lbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQocGFyZW50SWQpISE7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaXNoQXVkaW8odmFsdWU6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5zdHJlYW0uZ2V0V2ViUnRjUGVlcigpLmF1ZGlvRW5hYmxlZCA9IHZhbHVlO1xuICAgIH1cblxuICAgIHB1Ymxpc2hWaWRlbyh2YWx1ZTogYm9vbGVhbikge1xuICAgICAgICB0aGlzLnN0cmVhbS5nZXRXZWJSdGNQZWVyKCkudmlkZW9FbmFibGVkID0gdmFsdWU7XG4gICAgfVxuXG4gICAgZGVzdHJveSgpIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLnVucHVibGlzaCh0aGlzKTtcbiAgICAgICAgdGhpcy5zdHJlYW0uZGlzcG9zZSgpO1xuICAgICAgICB0aGlzLnN0cmVhbS5yZW1vdmVWaWRlbyh0aGlzLmVsZW1lbnQpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBzdWJzY3JpYmVUb1JlbW90ZSgpIHtcbiAgICAgICAgdGhpcy5zdHJlYW0uc3Vic2NyaWJlVG9NeVJlbW90ZSgpO1xuICAgIH1cblxuICAgIG9uKGV2ZW50TmFtZTogc3RyaW5nLCBjYWxsYmFjaykge1xuICAgICAgICB0aGlzLmVlLmFkZExpc3RlbmVyKGV2ZW50TmFtZSwgZXZlbnQgPT4ge1xuICAgICAgICAgICAgaWYgKGV2ZW50KSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiRXZlbnQgJ1wiICsgZXZlbnROYW1lICsgXCInIHRyaWdnZXJlZCBieSAnUHVibGlzaGVyJ1wiLCBldmVudCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkV2ZW50ICdcIiArIGV2ZW50TmFtZSArIFwiJyB0cmlnZ2VyZWQgYnkgJ1B1Ymxpc2hlcidcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYWxsYmFjayhldmVudCk7XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoZXZlbnROYW1lID09ICdzdHJlYW1DcmVhdGVkJykge1xuICAgICAgICAgICAgaWYgKHRoaXMuc3RyZWFtLmlzUHVibGlzaGVyUHVibGlzaGVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3N0cmVhbUNyZWF0ZWQnLCBbeyBzdHJlYW06IHRoaXMuc3RyZWFtIH1dKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdHJlYW0uYWRkRXZlbnRMaXN0ZW5lcignc3RyZWFtLWNyZWF0ZWQtYnktcHVibGlzaGVyJywgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1B1Ymxpc2hlciBlbWl0dGluZyBzdHJlYW1DcmVhdGVkJyk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdzdHJlYW1DcmVhdGVkJywgW3sgc3RyZWFtOiB0aGlzLnN0cmVhbSB9XSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2ZW50TmFtZSA9PSAndmlkZW9FbGVtZW50Q3JlYXRlZCcpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0cmVhbS5pc1ZpZGVvRUxlbWVudENyZWF0ZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgndmlkZW9FbGVtZW50Q3JlYXRlZCcsIFt7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IHRoaXMuc3RyZWFtLmdldFZpZGVvRWxlbWVudCgpXG4gICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbS5hZGRPbmNlRXZlbnRMaXN0ZW5lcigndmlkZW8tZWxlbWVudC1jcmVhdGVkLWJ5LXN0cmVhbScsIChlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaWQgPSBlbGVtZW50LmlkO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgndmlkZW9FbGVtZW50Q3JlYXRlZCcsIFt7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50OiBlbGVtZW50LmVsZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChldmVudE5hbWUgPT0gJ3ZpZGVvUGxheWluZycpIHtcbiAgICAgICAgICAgIHZhciB2aWRlbyA9IHRoaXMuc3RyZWFtLmdldFZpZGVvRWxlbWVudCgpO1xuICAgICAgICAgICAgaWYgKCF0aGlzLnN0cmVhbS5kaXNwbGF5TXlSZW1vdGUoKSAmJiB2aWRlbyAmJlxuICAgICAgICAgICAgICAgIHZpZGVvLmN1cnJlbnRUaW1lID4gMCAmJlxuICAgICAgICAgICAgICAgIHZpZGVvLnBhdXNlZCA9PSBmYWxzZSAmJlxuICAgICAgICAgICAgICAgIHZpZGVvLmVuZGVkID09IGZhbHNlICYmXG4gICAgICAgICAgICAgICAgdmlkZW8ucmVhZHlTdGF0ZSA9PSA0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3ZpZGVvUGxheWluZycsIFt7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IHRoaXMuc3RyZWFtLmdldFZpZGVvRWxlbWVudCgpXG4gICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbS5hZGRPbmNlRXZlbnRMaXN0ZW5lcigndmlkZW8taXMtcGxheWluZycsIChlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCd2aWRlb1BsYXlpbmcnLCBbe1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudDogZWxlbWVudC5lbGVtZW50XG4gICAgICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoZXZlbnROYW1lID09ICdyZW1vdGVWaWRlb1BsYXlpbmcnKSB7XG4gICAgICAgICAgICB2YXIgdmlkZW8gPSB0aGlzLnN0cmVhbS5nZXRWaWRlb0VsZW1lbnQoKTtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0cmVhbS5kaXNwbGF5TXlSZW1vdGUoKSAmJiB2aWRlbyAmJlxuICAgICAgICAgICAgICAgIHZpZGVvLmN1cnJlbnRUaW1lID4gMCAmJlxuICAgICAgICAgICAgICAgIHZpZGVvLnBhdXNlZCA9PSBmYWxzZSAmJlxuICAgICAgICAgICAgICAgIHZpZGVvLmVuZGVkID09IGZhbHNlICYmXG4gICAgICAgICAgICAgICAgdmlkZW8ucmVhZHlTdGF0ZSA9PSA0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3JlbW90ZVZpZGVvUGxheWluZycsIFt7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IHRoaXMuc3RyZWFtLmdldFZpZGVvRWxlbWVudCgpXG4gICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbS5hZGRPbmNlRXZlbnRMaXN0ZW5lcigncmVtb3RlLXZpZGVvLWlzLXBsYXlpbmcnLCAoZWxlbWVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgncmVtb3RlVmlkZW9QbGF5aW5nJywgW3tcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IGVsZW1lbnQuZWxlbWVudFxuICAgICAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2ZW50TmFtZSA9PSAnYWNjZXNzQWxsb3dlZCcpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0cmVhbS5hY2Nlc3NJc0FsbG93ZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnYWNjZXNzQWxsb3dlZCcpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbS5hZGRFdmVudExpc3RlbmVyKCdhY2Nlc3MtYWxsb3dlZC1ieS1wdWJsaXNoZXInLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdhY2Nlc3NBbGxvd2VkJyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2ZW50TmFtZSA9PSAnYWNjZXNzRGVuaWVkJykge1xuICAgICAgICAgICAgaWYgKHRoaXMuc3RyZWFtLmFjY2Vzc0lzRGVuaWVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2FjY2Vzc0RlbmllZCcpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbS5hZGRFdmVudExpc3RlbmVyKCdhY2Nlc3MtZGVuaWVkLWJ5LXB1Ymxpc2hlcicsICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2FjY2Vzc0RlbmllZCcpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufSIsImltcG9ydCB7IFNlc3Npb25JbnRlcm5hbCwgU2Vzc2lvbk9wdGlvbnMsIFNpZ25hbE9wdGlvbnMgfSBmcm9tICcuLi9PcGVuVmlkdUludGVybmFsL1Nlc3Npb25JbnRlcm5hbCc7XG5pbXBvcnQgeyBTdHJlYW0gfSBmcm9tICcuLi9PcGVuVmlkdUludGVybmFsL1N0cmVhbSc7XG5pbXBvcnQgeyBDb25uZWN0aW9uIH0gZnJvbSBcIi4uL09wZW5WaWR1SW50ZXJuYWwvQ29ubmVjdGlvblwiO1xuXG5pbXBvcnQgeyBPcGVuVmlkdSB9IGZyb20gJy4vT3BlblZpZHUnO1xuaW1wb3J0IHsgUHVibGlzaGVyIH0gZnJvbSAnLi9QdWJsaXNoZXInO1xuaW1wb3J0IHsgU3Vic2NyaWJlciB9IGZyb20gJy4vU3Vic2NyaWJlcic7XG5cbmltcG9ydCBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCd3b2xmeTg3LWV2ZW50ZW1pdHRlcicpO1xuXG5leHBvcnQgY2xhc3MgU2Vzc2lvbiB7XG5cbiAgICBzZXNzaW9uSWQ6IFN0cmluZztcbiAgICAvL2NhcGFiaWxpdGllczogQ2FwYWJpbGl0aWVzXG4gICAgY29ubmVjdGlvbjogQ29ubmVjdGlvbjtcblxuICAgIHByaXZhdGUgZWUgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIHNlc3Npb246IFNlc3Npb25JbnRlcm5hbCwgcHJpdmF0ZSBvcGVuVmlkdTogT3BlblZpZHUpIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uSWQgPSBzZXNzaW9uLmdldFNlc3Npb25JZCgpO1xuXG4gICAgICAgIC8vIExpc3RlbnMgdG8gdGhlIGRlYWN0aXZhdGlvbiBvZiB0aGUgZGVmYXVsdCBiZWhhdmlvdXIgdXBvbiB0aGUgZGVsZXRpb24gb2YgYSBTdHJlYW0gb2JqZWN0XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCdzdHJlYW0tZGVzdHJveWVkLWRlZmF1bHQnLCBldmVudCA9PiB7XG4gICAgICAgICAgICBldmVudC5zdHJlYW0ucmVtb3ZlVmlkZW8oKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gTGlzdGVucyB0byB0aGUgZGVhY3RpdmF0aW9uIG9mIHRoZSBkZWZhdWx0IGJlaGF2aW91ciB1cG9uIHRoZSBkaXNjb25uZWN0aW9uIG9mIGEgU2Vzc2lvblxuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcignc2Vzc2lvbi1kaXNjb25uZWN0ZWQtZGVmYXVsdCcsICgpID0+IHtcbiAgICAgICAgICAgIGxldCBzOiBTdHJlYW07XG4gICAgICAgICAgICBmb3IgKHMgb2YgdGhpcy5vcGVuVmlkdS5vcGVuVmlkdS5nZXRSZW1vdGVTdHJlYW1zKCkpIHtcbiAgICAgICAgICAgICAgICBzLnJlbW92ZVZpZGVvKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGhpcy5jb25uZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgc3RyZWFtSWQgaW4gdGhpcy5jb25uZWN0aW9uLmdldFN0cmVhbXMoKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uZ2V0U3RyZWFtcygpW3N0cmVhbUlkXS5yZW1vdmVWaWRlbygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gU2V0cyBvciB1cGRhdGVzIHRoZSB2YWx1ZSBvZiAnY29ubmVjdGlvbicgcHJvcGVydHkuIFRyaWdnZXJlZCBieSBTZXNzaW9uSW50ZXJuYWwgd2hlbiBzdWNjZXNmdWwgY29ubmVjdGlvblxuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcigndXBkYXRlLWNvbm5lY3Rpb24tb2JqZWN0JywgZXZlbnQgPT4ge1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uID0gZXZlbnQuY29ubmVjdGlvbjtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29ubmVjdCh0b2tlbjogc3RyaW5nLCBjYWxsYmFjazogYW55KTtcbiAgICBjb25uZWN0KHRva2VuOiBzdHJpbmcsIG1ldGFkYXRhOiBhbnksIGNhbGxiYWNrOiBhbnkpO1xuXG4gICAgY29ubmVjdChwYXJhbTEsIHBhcmFtMiwgcGFyYW0zPykge1xuICAgICAgICAvLyBFYXJseSBjb25maWd1cmF0aW9uIHRvIGRlYWN0aXZhdGUgYXV0b21hdGljIHN1YnNjcmlwdGlvbiB0byBzdHJlYW1zXG4gICAgICAgIGlmIChwYXJhbTMpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5jb25maWd1cmUoe1xuICAgICAgICAgICAgICAgIHNlc3Npb25JZDogdGhpcy5zZXNzaW9uLmdldFNlc3Npb25JZCgpLFxuICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50SWQ6IHBhcmFtMSxcbiAgICAgICAgICAgICAgICBtZXRhZGF0YTogdGhpcy5zZXNzaW9uLnN0cmluZ0NsaWVudE1ldGFkYXRhKHBhcmFtMiksXG4gICAgICAgICAgICAgICAgc3Vic2NyaWJlVG9TdHJlYW1zOiBmYWxzZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24uY29ubmVjdChwYXJhbTEsIHBhcmFtMyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24uY29uZmlndXJlKHtcbiAgICAgICAgICAgICAgICBzZXNzaW9uSWQ6IHRoaXMuc2Vzc2lvbi5nZXRTZXNzaW9uSWQoKSxcbiAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudElkOiBwYXJhbTEsXG4gICAgICAgICAgICAgICAgbWV0YWRhdGE6ICcnLFxuICAgICAgICAgICAgICAgIHN1YnNjcmliZVRvU3RyZWFtczogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLmNvbm5lY3QocGFyYW0xLCBwYXJhbTIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZGlzY29ubmVjdCgpIHtcbiAgICAgICAgdGhpcy5vcGVuVmlkdS5vcGVuVmlkdS5jbG9zZShmYWxzZSk7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5lbWl0RXZlbnQoJ3Nlc3Npb25EaXNjb25uZWN0ZWQnLCBbe1xuICAgICAgICAgICAgcHJldmVudERlZmF1bHQ6ICgpID0+IHsgdGhpcy5zZXNzaW9uLnJlbW92ZUV2ZW50KCdzZXNzaW9uLWRpc2Nvbm5lY3RlZC1kZWZhdWx0Jyk7IH1cbiAgICAgICAgfV0pO1xuICAgICAgICB0aGlzLnNlc3Npb24uZW1pdEV2ZW50KCdzZXNzaW9uLWRpc2Nvbm5lY3RlZC1kZWZhdWx0JywgW3t9XSk7XG4gICAgfVxuXG4gICAgcHVibGlzaChwdWJsaXNoZXI6IFB1Ymxpc2hlcikge1xuICAgICAgICBpZiAocHVibGlzaGVyLmlzU2NyZWVuUmVxdWVzdGVkICYmICFwdWJsaXNoZXIuc3RyZWFtLmlzU2NyZWVuUmVxdWVzdGVkUmVhZHkpIHtcbiAgICAgICAgICAgIHB1Ymxpc2hlci5zdHJlYW0uYWRkT25jZUV2ZW50TGlzdGVuZXIoJ3NjcmVlbi1yZWFkeScsICgpID0+IHtcbiAgICAgICAgICAgICAgICBwdWJsaXNoZXIuc2Vzc2lvbiA9IHRoaXM7XG4gICAgICAgICAgICAgICAgcHVibGlzaGVyLnN0cmVhbS5wdWJsaXNoKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHB1Ymxpc2hlci5zZXNzaW9uID0gdGhpcztcbiAgICAgICAgICAgIHB1Ymxpc2hlci5zdHJlYW0ucHVibGlzaCgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdW5wdWJsaXNoKHB1Ymxpc2hlcjogUHVibGlzaGVyKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi51bnB1Ymxpc2gocHVibGlzaGVyLnN0cmVhbSk7XG4gICAgfVxuXG4gICAgb24oZXZlbnROYW1lOiBzdHJpbmcsIGNhbGxiYWNrKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgZXZlbnQgPT4ge1xuICAgICAgICAgICAgaWYgKGV2ZW50KSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiRXZlbnQgJ1wiICsgZXZlbnROYW1lICsgXCInIHRyaWdnZXJlZCBieSAnU2Vzc2lvbidcIiwgZXZlbnQpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXCJFdmVudCAnXCIgKyBldmVudE5hbWUgKyBcIicgdHJpZ2dlcmVkIGJ5ICdTZXNzaW9uJ1wiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhbGxiYWNrKGV2ZW50KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgb25jZShldmVudE5hbWU6IHN0cmluZywgY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLmFkZE9uY2VFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgZXZlbnQgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2soZXZlbnQpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBvZmYoZXZlbnROYW1lOiBzdHJpbmcsIGV2ZW50SGFuZGxlcikge1xuICAgICAgICB0aGlzLnNlc3Npb24ucmVtb3ZlTGlzdGVuZXIoZXZlbnROYW1lLCBldmVudEhhbmRsZXIpO1xuICAgIH1cblxuICAgIHN1YnNjcmliZShzdHJlYW06IFN0cmVhbSwgaHRtbElkOiBzdHJpbmcsIHZpZGVvT3B0aW9uczogYW55KTogU3Vic2NyaWJlcjtcbiAgICBzdWJzY3JpYmUoc3RyZWFtOiBTdHJlYW0sIGh0bWxJZDogc3RyaW5nKTogU3Vic2NyaWJlcjtcblxuICAgIHN1YnNjcmliZShwYXJhbTEsIHBhcmFtMiwgcGFyYW0zPyk6IFN1YnNjcmliZXIge1xuICAgICAgICAvLyBTdWJzY3JpcHRpb25cbiAgICAgICAgdGhpcy5zZXNzaW9uLnN1YnNjcmliZShwYXJhbTEpO1xuICAgICAgICBsZXQgc3Vic2NyaWJlciA9IG5ldyBTdWJzY3JpYmVyKHBhcmFtMSwgcGFyYW0yKTtcbiAgICAgICAgcGFyYW0xLnBsYXlPbmx5VmlkZW8ocGFyYW0yLCBudWxsKTtcbiAgICAgICAgcmV0dXJuIHN1YnNjcmliZXI7XG4gICAgfVxuXG4gICAgdW5zdWJzY3JpYmUoc3Vic2NyaWJlcjogU3Vic2NyaWJlcikge1xuICAgICAgICB0aGlzLnNlc3Npb24udW5zdWJzY3JpYmUoc3Vic2NyaWJlci5zdHJlYW0pO1xuICAgICAgICBzdWJzY3JpYmVyLnN0cmVhbS5yZW1vdmVWaWRlbygpO1xuICAgIH1cblxuICAgIHNpZ25hbChzaWduYWw6IFNpZ25hbE9wdGlvbnMsIGNvbXBsZXRpb25IYW5kbGVyPzogRnVuY3Rpb24pIHtcbiAgICAgICAgdmFyIHNpZ25hbE1lc3NhZ2UgPSB7fTtcblxuICAgICAgICBpZiAoc2lnbmFsLnRvICYmIHNpZ25hbC50by5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBsZXQgY29ubmVjdGlvbklkczogc3RyaW5nW10gPSBbXTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2lnbmFsLnRvLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbklkcy5wdXNoKHNpZ25hbC50b1tpXS5jb25uZWN0aW9uSWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2lnbmFsTWVzc2FnZVsndG8nXSA9IGNvbm5lY3Rpb25JZHM7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzaWduYWxNZXNzYWdlWyd0byddID0gW107XG4gICAgICAgIH1cblxuICAgICAgICBzaWduYWxNZXNzYWdlWydkYXRhJ10gPSBzaWduYWwuZGF0YSA/IHNpZ25hbC5kYXRhIDogJyc7XG4gICAgICAgIHNpZ25hbE1lc3NhZ2VbJ3R5cGUnXSA9IHNpZ25hbC50eXBlID8gc2lnbmFsLnR5cGUgOiAnJztcblxuICAgICAgICB0aGlzLm9wZW5WaWR1Lm9wZW5WaWR1LnNlbmRNZXNzYWdlKHRoaXMuc2Vzc2lvbklkLCB0aGlzLmNvbm5lY3Rpb24uY29ubmVjdGlvbklkLCBKU09OLnN0cmluZ2lmeShzaWduYWxNZXNzYWdlKSk7XG4gICAgfVxuXG59XG4iLCJpbXBvcnQgeyBTdHJlYW0sIFN0cmVhbU9wdGlvbnMsIFZpZGVvT3B0aW9ucyB9IGZyb20gJy4uL09wZW5WaWR1SW50ZXJuYWwvU3RyZWFtJztcblxuaW1wb3J0IEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ3dvbGZ5ODctZXZlbnRlbWl0dGVyJyk7XG5cbmV4cG9ydCBjbGFzcyBTdWJzY3JpYmVyIHtcblxuICAgIHByaXZhdGUgZWUgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgICBlbGVtZW50OiBFbGVtZW50O1xuICAgIGlkOiBzdHJpbmc7XG4gICAgc3RyZWFtOiBTdHJlYW07XG5cbiAgICBjb25zdHJ1Y3RvcihzdHJlYW06IFN0cmVhbSwgcGFyZW50SWQ6IHN0cmluZykge1xuICAgICAgICB0aGlzLnN0cmVhbSA9IHN0cmVhbTtcbiAgICAgICAgaWYgKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHBhcmVudElkKSAhPSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLmVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChwYXJlbnRJZCkhITtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uKGV2ZW50TmFtZTogc3RyaW5nLCBjYWxsYmFjaykge1xuICAgICAgICB0aGlzLmVlLmFkZExpc3RlbmVyKGV2ZW50TmFtZSwgZXZlbnQgPT4ge1xuICAgICAgICAgICAgaWYgKGV2ZW50KSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiRXZlbnQgJ1wiICsgZXZlbnROYW1lICsgXCInIHRyaWdnZXJlZCBieSAnU3Vic2NyaWJlcidcIiwgZXZlbnQpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXCJFdmVudCAnXCIgKyBldmVudE5hbWUgKyBcIicgdHJpZ2dlcmVkIGJ5ICdTdWJzY3JpYmVyJ1wiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhbGxiYWNrKGV2ZW50KTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChldmVudE5hbWUgPT0gJ3ZpZGVvRWxlbWVudENyZWF0ZWQnKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5zdHJlYW0uaXNWaWRlb0VMZW1lbnRDcmVhdGVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3ZpZGVvRWxlbWVudENyZWF0ZWQnLCBbe1xuICAgICAgICAgICAgICAgICAgICBlbGVtZW50OiB0aGlzLnN0cmVhbS5nZXRWaWRlb0VsZW1lbnQoKVxuICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdHJlYW0uYWRkT25jZUV2ZW50TGlzdGVuZXIoJ3ZpZGVvLWVsZW1lbnQtY3JlYXRlZC1ieS1zdHJlYW0nLCBlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiU3Vic2NyaWJlciBlbWl0dGluZyB2aWRlb0VsZW1lbnRDcmVhdGVkXCIpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmlkID0gZWxlbWVudC5pZDtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3ZpZGVvRWxlbWVudENyZWF0ZWQnLCBbe1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudDogZWxlbWVudFxuICAgICAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2ZW50TmFtZSA9PSAndmlkZW9QbGF5aW5nJykge1xuICAgICAgICAgICAgdmFyIHZpZGVvID0gdGhpcy5zdHJlYW0uZ2V0VmlkZW9FbGVtZW50KCk7XG4gICAgICAgICAgICBpZiAoIXRoaXMuc3RyZWFtLmRpc3BsYXlNeVJlbW90ZSgpICYmIHZpZGVvICYmXG4gICAgICAgICAgICAgICAgdmlkZW8uY3VycmVudFRpbWUgPiAwICYmIFxuICAgICAgICAgICAgICAgIHZpZGVvLnBhdXNlZCA9PSBmYWxzZSAmJiBcbiAgICAgICAgICAgICAgICB2aWRlby5lbmRlZCA9PSBmYWxzZSAmJlxuICAgICAgICAgICAgICAgIHZpZGVvLnJlYWR5U3RhdGUgPT0gNCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgndmlkZW9QbGF5aW5nJywgW3tcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IHRoaXMuc3RyZWFtLmdldFZpZGVvRWxlbWVudCgpXG4gICAgICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdHJlYW0uYWRkT25jZUV2ZW50TGlzdGVuZXIoJ3ZpZGVvLWlzLXBsYXlpbmcnLCAoZWxlbWVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgndmlkZW9QbGF5aW5nJywgW3tcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IGVsZW1lbnQuZWxlbWVudFxuICAgICAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59IiwiaW1wb3J0IHsgU3RyZWFtLCBTdHJlYW1PcHRpb25zIH0gZnJvbSAnLi9TdHJlYW0nO1xuaW1wb3J0IHsgT3BlblZpZHVJbnRlcm5hbCB9IGZyb20gJy4vT3BlblZpZHVJbnRlcm5hbCc7XG5pbXBvcnQgeyBTZXNzaW9uSW50ZXJuYWwgfSBmcm9tICcuL1Nlc3Npb25JbnRlcm5hbCc7XG5cbnR5cGUgT2JqTWFwPFQ+ID0geyBbczogc3RyaW5nXTogVDsgfVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbm5lY3Rpb25PcHRpb25zIHtcbiAgICBpZDogc3RyaW5nO1xuICAgIG1ldGFkYXRhOiBzdHJpbmc7XG4gICAgc3RyZWFtcz86IFN0cmVhbU9wdGlvbnNbXTtcbiAgICBhdWRpb0FjdGl2ZTogYm9vbGVhbjtcbiAgICB2aWRlb0FjdGl2ZTogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGNsYXNzIENvbm5lY3Rpb24ge1xuXG4gICAgcHVibGljIGNvbm5lY3Rpb25JZDogc3RyaW5nO1xuICAgIHB1YmxpYyBkYXRhOiBzdHJpbmc7XG4gICAgcHVibGljIGNyZWF0aW9uVGltZTogbnVtYmVyO1xuICAgIHByaXZhdGUgc3RyZWFtczogT2JqTWFwPFN0cmVhbT4gPSB7fTtcbiAgICBwcml2YXRlIHN0cmVhbXNPcHRzOiBTdHJlYW1PcHRpb25zW10gPSBbXTtcblxuICAgIGNvbnN0cnVjdG9yKCBwcml2YXRlIG9wZW5WaWR1OiBPcGVuVmlkdUludGVybmFsLCBwcml2YXRlIGxvY2FsOiBib29sZWFuLCBwcml2YXRlIHJvb206IFNlc3Npb25JbnRlcm5hbCwgcHJpdmF0ZSBvcHRpb25zPzogQ29ubmVjdGlvbk9wdGlvbnMgKSB7XG5cbiAgICAgICAgY29uc29sZS5pbmZvKCBcIidDb25uZWN0aW9uJyBjcmVhdGVkIChcIiArICggbG9jYWwgPyBcImxvY2FsXCIgOiBcInJlbW90ZVwiICkgKyBcIilcIiArICggbG9jYWwgPyBcIlwiIDogXCIsIHdpdGggJ2Nvbm5lY3Rpb25JZCcgW1wiICsgKG9wdGlvbnMgPyBvcHRpb25zLmlkIDogJycpICsgXCJdIFwiICkpO1xuXG4gICAgICAgIGlmICggb3B0aW9ucyApIHtcblxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uSWQgPSBvcHRpb25zLmlkO1xuICAgICAgICAgICAgdGhpcy5kYXRhID0gb3B0aW9ucy5tZXRhZGF0YTtcblxuICAgICAgICAgICAgaWYgKCBvcHRpb25zLnN0cmVhbXMgKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5pbml0U3RyZWFtcyhvcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBcbiAgICB9XG5cbiAgICBhZGRTdHJlYW0oIHN0cmVhbTogU3RyZWFtICkge1xuICAgICAgICB0aGlzLnN0cmVhbXNbc3RyZWFtLnN0cmVhbUlkXSA9IHN0cmVhbTtcbiAgICAgICAgdGhpcy5yb29tLmdldFN0cmVhbXMoKVtzdHJlYW0uc3RyZWFtSWRdID0gc3RyZWFtO1xuICAgIH1cblxuICAgIGdldFN0cmVhbXMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmVhbXM7XG4gICAgfVxuXG4gICAgZGlzcG9zZSgpIHtcbiAgICAgICAgZm9yICggbGV0IGtleSBpbiB0aGlzLnN0cmVhbXMgKSB7XG4gICAgICAgICAgICB0aGlzLnN0cmVhbXNba2V5XS5kaXNwb3NlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzZW5kSWNlQ2FuZGlkYXRlKCBjYW5kaWRhdGUgKSB7XG5cbiAgICAgICAgY29uc29sZS5kZWJ1ZygoIHRoaXMubG9jYWwgPyBcIkxvY2FsXCIgOiBcIlJlbW90ZVwiICksIFwiY2FuZGlkYXRlIGZvclwiLFxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uSWQsIEpTT04uc3RyaW5naWZ5KCBjYW5kaWRhdGUgKSApO1xuXG4gICAgICAgIHRoaXMub3BlblZpZHUuc2VuZFJlcXVlc3QoIFwib25JY2VDYW5kaWRhdGVcIiwge1xuICAgICAgICAgICAgZW5kcG9pbnROYW1lOiB0aGlzLmNvbm5lY3Rpb25JZCxcbiAgICAgICAgICAgIGNhbmRpZGF0ZTogY2FuZGlkYXRlLmNhbmRpZGF0ZSxcbiAgICAgICAgICAgIHNkcE1pZDogY2FuZGlkYXRlLnNkcE1pZCxcbiAgICAgICAgICAgIHNkcE1MaW5lSW5kZXg6IGNhbmRpZGF0ZS5zZHBNTGluZUluZGV4XG4gICAgICAgIH0sIGZ1bmN0aW9uKCBlcnJvciwgcmVzcG9uc2UgKSB7XG4gICAgICAgICAgICBpZiAoIGVycm9yICkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoIFwiRXJyb3Igc2VuZGluZyBJQ0UgY2FuZGlkYXRlOiBcIlxuICAgICAgICAgICAgICAgICAgICArIEpTT04uc3RyaW5naWZ5KCBlcnJvciApICk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGluaXRTdHJlYW1zKG9wdGlvbnMpIHtcbiAgICAgICAgZm9yICggbGV0IHN0cmVhbU9wdGlvbnMgb2Ygb3B0aW9ucy5zdHJlYW1zICkge1xuICAgICAgICAgICAgXG4gICAgICAgICAgICBsZXQgc3RyZWFtT3B0cyA9IHtcbiAgICAgICAgICAgICAgICBpZDogc3RyZWFtT3B0aW9ucy5pZCxcbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uOiB0aGlzLFxuICAgICAgICAgICAgICAgIHNlbmRBdWRpbzogc3RyZWFtT3B0aW9ucy5zZW5kQXVkaW8sXG4gICAgICAgICAgICAgICAgc2VuZFZpZGVvOiBzdHJlYW1PcHRpb25zLnNlbmRWaWRlbyxcbiAgICAgICAgICAgICAgICByZWN2QXVkaW86ICggc3RyZWFtT3B0aW9ucy5hdWRpb0FjdGl2ZSA9PSB1bmRlZmluZWQgPyB0cnVlIDogc3RyZWFtT3B0aW9ucy5hdWRpb0FjdGl2ZSApLFxuICAgICAgICAgICAgICAgIHJlY3ZWaWRlbzogKCBzdHJlYW1PcHRpb25zLnZpZGVvQWN0aXZlID09IHVuZGVmaW5lZCA/IHRydWUgOiBzdHJlYW1PcHRpb25zLnZpZGVvQWN0aXZlICksXG4gICAgICAgICAgICAgICAgdHlwZU9mVmlkZW86IHN0cmVhbU9wdGlvbnMudHlwZU9mVmlkZW8sXG4gICAgICAgICAgICAgICAgYWN0aXZlQXVkaW86IHN0cmVhbU9wdGlvbnMuYWN0aXZlQXVkaW8sXG4gICAgICAgICAgICAgICAgYWN0aXZlVmlkZW86IHN0cmVhbU9wdGlvbnMuYWN0aXZlVmlkZW8sXG4gICAgICAgICAgICAgICAgZGF0YTogc3RyZWFtT3B0aW9ucy5kYXRhLFxuICAgICAgICAgICAgICAgIG1lZGlhQ29uc3RyYWludHM6IHN0cmVhbU9wdGlvbnMubWVkaWFDb25zdHJhaW50c1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IHN0cmVhbSA9IG5ldyBTdHJlYW0odGhpcy5vcGVuVmlkdSwgZmFsc2UsIHRoaXMucm9vbSwgc3RyZWFtT3B0cyApO1xuXG4gICAgICAgICAgICB0aGlzLmFkZFN0cmVhbSggc3RyZWFtICk7XG4gICAgICAgICAgICB0aGlzLnN0cmVhbXNPcHRzLnB1c2goIHN0cmVhbU9wdHMgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIlJlbW90ZSAnQ29ubmVjdGlvbicgd2l0aCAnY29ubmVjdGlvbklkJyBbXCIgKyB0aGlzLmNvbm5lY3Rpb25JZCArIFwiXSBpcyBub3cgY29uZmlndXJlZCBmb3IgcmVjZWl2aW5nIFN0cmVhbXMgd2l0aCBvcHRpb25zOiBcIiwgdGhpcy5zdHJlYW1zT3B0cyApO1xuICAgIH1cbn0iLCJleHBvcnQgZW51bSBPcGVuVmlkdUVycm9yTmFtZSB7XG4gICAgQ0FNRVJBX0FDQ0VTU19ERU5JRUQgPSAnQ0FNRVJBX0FDQ0VTU19ERU5JRUQnLFxuICAgIE1JQ1JPUEhPTkVfQUNDRVNTX0RFTklFRCA9ICdNSUNST1BIT05FX0FDQ0VTU19ERU5JRUQnLFxuICAgIFNDUkVFTl9DQVBUVVJFX0RFTklFRCA9ICdTQ1JFRU5fQ0FQVFVSRV9ERU5JRUQnLFxuICAgIE5PX1ZJREVPX0RFVklDRSA9ICdOT19WSURFT19ERVZJQ0UnLFxuICAgIE5PX0lOUFVUX0RFVklDRSA9ICdOT19JTlBVVF9ERVZJQ0UnLFxuICAgIFNDUkVFTl9FWFRFTlNJT05fTk9UX0lOU1RBTExFRCA9ICdTQ1JFRU5fRVhURU5TSU9OX05PVF9JTlNUQUxMRUQnLFxuICAgIEdFTkVSSUNfRVJST1IgPSAnR0VORVJJQ19FUlJPUidcbn1cblxuZXhwb3J0IGNsYXNzIE9wZW5WaWR1RXJyb3Ige1xuXG4gICAgbmFtZTogT3BlblZpZHVFcnJvck5hbWU7XG4gICAgbWVzc2FnZTogc3RyaW5nO1xuXG4gICAgY29uc3RydWN0b3IobmFtZTogT3BlblZpZHVFcnJvck5hbWUsIG1lc3NhZ2U6IHN0cmluZykge1xuICAgICAgICB0aGlzLm5hbWUgPSBuYW1lO1xuICAgICAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xuICAgIH1cblxufSIsIi8qXG4gKiAoQykgQ29weXJpZ2h0IDIwMTcgT3BlblZpZHUgKGh0dHA6Ly9vcGVudmlkdS5pby8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKi9cbmltcG9ydCB7IFNlc3Npb25JbnRlcm5hbCwgU2Vzc2lvbk9wdGlvbnMgfSBmcm9tICcuL1Nlc3Npb25JbnRlcm5hbCc7XG5pbXBvcnQgeyBPcGVuVmlkdUVycm9yLCBPcGVuVmlkdUVycm9yTmFtZSB9IGZyb20gJy4vT3BlblZpZHVFcnJvcic7XG5pbXBvcnQgeyBTdHJlYW0gfSBmcm9tICcuL1N0cmVhbSc7XG5pbXBvcnQgKiBhcyBScGNCdWlsZGVyIGZyb20gJy4uL0t1cmVudG9VdGlscy9rdXJlbnRvLWpzb25ycGMnO1xuXG5leHBvcnQgdHlwZSBDYWxsYmFjazxUPiA9IChlcnJvcj86IGFueSwgb3BlblZpZHU/OiBUKSA9PiB2b2lkO1xuXG5leHBvcnQgY2xhc3MgT3BlblZpZHVJbnRlcm5hbCB7XG5cbiAgICBwcml2YXRlIHdzVXJpO1xuICAgIHByaXZhdGUgc2Vzc2lvbjogU2Vzc2lvbkludGVybmFsO1xuICAgIHByaXZhdGUganNvblJwY0NsaWVudDogYW55O1xuICAgIHByaXZhdGUgcnBjUGFyYW1zOiBhbnk7XG4gICAgcHJpdmF0ZSBjYWxsYmFjazogQ2FsbGJhY2s8T3BlblZpZHVJbnRlcm5hbD47XG4gICAgcHJpdmF0ZSBjYW1lcmE6IFN0cmVhbTtcbiAgICBwcml2YXRlIHJlbW90ZVN0cmVhbXM6IFN0cmVhbVtdID0gW107XG5cbiAgICBwcml2YXRlIHNlY3JldDogc3RyaW5nO1xuXG4gICAgY29uc3RydWN0b3IoKSB7IH07XG5cblxuICAgIC8qIE5FVyBNRVRIT0RTICovXG4gICAgaW5pdFNlc3Npb24oc2Vzc2lvbklkKSB7XG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIidTZXNzaW9uJyBpbml0aWFsaXplZCB3aXRoICdzZXNzaW9uSWQnIFtcIiArIHNlc3Npb25JZCArIFwiXVwiKTtcbiAgICAgICAgdGhpcy5zZXNzaW9uID0gbmV3IFNlc3Npb25JbnRlcm5hbCh0aGlzLCBzZXNzaW9uSWQpO1xuICAgICAgICByZXR1cm4gdGhpcy5zZXNzaW9uO1xuICAgIH1cblxuICAgIGluaXRQdWJsaXNoZXJUYWdnZWQocGFyZW50SWQ6IHN0cmluZywgY2FtZXJhT3B0aW9uczogYW55LCBjYWxsYmFjaz86IEZ1bmN0aW9uKTogU3RyZWFtIHtcblxuICAgICAgICB0aGlzLmdldENhbWVyYShjYW1lcmFPcHRpb25zKTtcblxuICAgICAgICB0aGlzLmNhbWVyYS5yZXF1ZXN0Q2FtZXJhQWNjZXNzKChlcnJvciwgY2FtZXJhKSA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAvLyBOZWl0aGVyIGNhbWVyYSBvciBtaWNyb3Bob25lIGRldmljZSBpcyBhbGxvd2VkL2FibGUgdG8gY2FwdHVyZSBtZWRpYVxuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgICAgICBjYWxsYmFjayhlcnJvcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMuY2FtZXJhLmVlLmVtaXRFdmVudCgnYWNjZXNzLWRlbmllZC1ieS1wdWJsaXNoZXInKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jYW1lcmEuc2V0VmlkZW9FbGVtZW50KHRoaXMuY2FtZXJhUmVhZHkoY2FtZXJhISwgcGFyZW50SWQpKTtcbiAgICAgICAgICAgICAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2sodW5kZWZpbmVkKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdGhpcy5jYW1lcmE7XG4gICAgfVxuXG4gICAgaW5pdFB1Ymxpc2hlclNjcmVlbihwYXJlbnRJZDogc3RyaW5nLCBjYWxsYmFjaz8pOiBTdHJlYW0ge1xuICAgICAgICB0aGlzLmNhbWVyYSA9IG5ldyBTdHJlYW0odGhpcywgdHJ1ZSwgdGhpcy5zZXNzaW9uLCAnc2NyZWVuLW9wdGlvbnMnKTtcbiAgICAgICAgdGhpcy5jYW1lcmEuYWRkT25jZUV2ZW50TGlzdGVuZXIoJ2Nhbi1yZXF1ZXN0LXNjcmVlbicsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuY2FtZXJhLnJlcXVlc3RDYW1lcmFBY2Nlc3MoKGVycm9yLCBjYW1lcmEpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYW1lcmEuZWUuZW1pdEV2ZW50KCdhY2Nlc3MtZGVuaWVkLWJ5LXB1Ymxpc2hlcicpO1xuICAgICAgICAgICAgICAgICAgICBsZXQgZXJyb3JOYW1lOiBPcGVuVmlkdUVycm9yTmFtZSA9IE9wZW5WaWR1RXJyb3JOYW1lLlNDUkVFTl9DQVBUVVJFX0RFTklFRDtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGVycm9yTWVzc2FnZSA9ICdZb3UgbXVzdCBhbGxvdyBhY2Nlc3MgdG8gb25lIHdpbmRvdyBvZiB5b3VyIGRlc2t0b3AnO1xuICAgICAgICAgICAgICAgICAgICBsZXQgZSA9IG5ldyBPcGVuVmlkdUVycm9yKGVycm9yTmFtZSwgZXJyb3JNZXNzYWdlKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjayhlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYW1lcmEuc2V0VmlkZW9FbGVtZW50KHRoaXMuY2FtZXJhUmVhZHkoY2FtZXJhISwgcGFyZW50SWQpKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuY2FtZXJhLmdldFNlbmRBdWRpbygpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGUgdXNlciB3YW50cyB0byBzZW5kIGF1ZGlvIHdpdGggdGhlIHNjcmVlbiBjYXB0dXJpbmdcbiAgICAgICAgICAgICAgICAgICAgICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKHsgYXVkaW86IHRydWUsIHZpZGVvOiBmYWxzZSB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKHVzZXJTdHJlYW0gPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNhbWVyYS5nZXRXclN0cmVhbSgpLmFkZFRyYWNrKHVzZXJTdHJlYW0uZ2V0QXVkaW9UcmFja3MoKVswXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2FtZXJhLmlzU2NyZWVuUmVxdWVzdGVkUmVhZHkgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNhbWVyYS5lZS5lbWl0RXZlbnQoJ3NjcmVlbi1yZWFkeScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKHVuZGVmaW5lZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2FtZXJhLmVlLmVtaXRFdmVudCgnYWNjZXNzLWRlbmllZC1ieS1wdWJsaXNoZXInKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGFjY2Vzc2luZyB0aGUgbWljcm9waG9uZVwiLCBlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGVycm9yTmFtZTogT3BlblZpZHVFcnJvck5hbWUgPSBPcGVuVmlkdUVycm9yTmFtZS5NSUNST1BIT05FX0FDQ0VTU19ERU5JRUQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXQgZXJyb3JNZXNzYWdlID0gZXJyb3IudG9TdHJpbmcoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKG5ldyBPcGVuVmlkdUVycm9yKGVycm9yTmFtZSwgZXJyb3JNZXNzYWdlKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2FtZXJhLmlzU2NyZWVuUmVxdWVzdGVkUmVhZHkgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jYW1lcmEuZWUuZW1pdEV2ZW50KCdzY3JlZW4tcmVhZHknKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKHVuZGVmaW5lZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0aGlzLmNhbWVyYTtcbiAgICB9XG5cbiAgICBjYW1lcmFSZWFkeShjYW1lcmE6IFN0cmVhbSwgcGFyZW50SWQ6IHN0cmluZykge1xuICAgICAgICB0aGlzLmNhbWVyYSA9IGNhbWVyYTtcbiAgICAgICAgbGV0IHZpZGVvRWxlbWVudCA9IHRoaXMuY2FtZXJhLnBsYXlPbmx5VmlkZW8ocGFyZW50SWQsIG51bGwpO1xuICAgICAgICB0aGlzLmNhbWVyYS5lbWl0U3RyZWFtUmVhZHlFdmVudCgpO1xuICAgICAgICByZXR1cm4gdmlkZW9FbGVtZW50O1xuICAgIH1cblxuICAgIGluaXRQdWJsaXNoZXIoY2FtZXJhT3B0aW9uczogYW55LCBjYWxsYmFjaykge1xuICAgICAgICB0aGlzLmdldENhbWVyYShjYW1lcmFPcHRpb25zKTtcbiAgICAgICAgdGhpcy5jYW1lcmEucmVxdWVzdENhbWVyYUFjY2VzcygoZXJyb3IsIGNhbWVyYSkgPT4ge1xuICAgICAgICAgICAgaWYgKGVycm9yKSBjYWxsYmFjayhlcnJvcik7XG4gICAgICAgICAgICBlbHNlIGNhbGxiYWNrKHVuZGVmaW5lZCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGdldExvY2FsU3RyZWFtKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jYW1lcmE7XG4gICAgfVxuXG4gICAgZ2V0UmVtb3RlU3RyZWFtcygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVtb3RlU3RyZWFtcztcbiAgICB9XG4gICAgLyogTkVXIE1FVEhPRFMgKi9cblxuICAgIGdldFdzVXJpKCkge1xuICAgICAgICByZXR1cm4gdGhpcy53c1VyaTtcbiAgICB9XG5cbiAgICBzZXRXc1VyaSh3c1VyaTogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMud3NVcmkgPSB3c1VyaTtcbiAgICB9XG5cbiAgICBnZXRTZWNyZXQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlY3JldDtcbiAgICB9XG5cbiAgICBzZXRTZWNyZXQoc2VjcmV0OiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5zZWNyZXQgPSBzZWNyZXQ7XG4gICAgfVxuXG4gICAgZ2V0T3BlblZpZHVTZXJ2ZXJVUkwoKSB7XG4gICAgICAgIHJldHVybiAnaHR0cHM6Ly8nICsgdGhpcy53c1VyaS5zcGxpdChcIndzczovL1wiKVsxXS5zcGxpdChcIi9yb29tXCIpWzBdO1xuICAgIH1cblxuICAgIGdldFJvb20oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlc3Npb247XG4gICAgfVxuXG4gICAgY29ubmVjdChjYWxsYmFjazogQ2FsbGJhY2s8T3BlblZpZHVJbnRlcm5hbD4pOiB2b2lkIHtcblxuICAgICAgICB0aGlzLmNhbGxiYWNrID0gY2FsbGJhY2s7XG5cbiAgICAgICAgdGhpcy5pbml0SnNvblJwY0NsaWVudCh0aGlzLndzVXJpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGluaXRKc29uUnBjQ2xpZW50KHdzVXJpOiBzdHJpbmcpOiB2b2lkIHtcblxuICAgICAgICBsZXQgY29uZmlnID0ge1xuICAgICAgICAgICAgaGVhcnRiZWF0OiAzMDAwLFxuICAgICAgICAgICAgc2VuZENsb3NlTWVzc2FnZTogZmFsc2UsXG4gICAgICAgICAgICB3czoge1xuICAgICAgICAgICAgICAgIHVyaTogd3NVcmksXG4gICAgICAgICAgICAgICAgdXNlU29ja0pTOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBvbmNvbm5lY3RlZDogdGhpcy5jb25uZWN0Q2FsbGJhY2suYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBvbmRpc2Nvbm5lY3Q6IHRoaXMuZGlzY29ubmVjdENhbGxiYWNrLmJpbmQodGhpcyksXG4gICAgICAgICAgICAgICAgb25yZWNvbm5lY3Rpbmc6IHRoaXMucmVjb25uZWN0aW5nQ2FsbGJhY2suYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBvbnJlY29ubmVjdGVkOiB0aGlzLnJlY29ubmVjdGVkQ2FsbGJhY2suYmluZCh0aGlzKVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHJwYzoge1xuICAgICAgICAgICAgICAgIHJlcXVlc3RUaW1lb3V0OiAxNTAwMCxcbiAgICAgICAgICAgICAgICAvL25vdGlmaWNhdGlvbnNcbiAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudEpvaW5lZDogdGhpcy5vblBhcnRpY2lwYW50Sm9pbmVkLmJpbmQodGhpcyksXG4gICAgICAgICAgICAgICAgcGFydGljaXBhbnRQdWJsaXNoZWQ6IHRoaXMub25QYXJ0aWNpcGFudFB1Ymxpc2hlZC5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50VW5wdWJsaXNoZWQ6IHRoaXMub25QYXJ0aWNpcGFudExlZnQuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudExlZnQ6IHRoaXMub25QYXJ0aWNpcGFudExlZnQuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudEV2aWN0ZWQ6IHRoaXMub25QYXJ0aWNpcGFudEV2aWN0ZWQuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBzZW5kTWVzc2FnZTogdGhpcy5vbk5ld01lc3NhZ2UuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBpY2VDYW5kaWRhdGU6IHRoaXMuaWNlQ2FuZGlkYXRlRXZlbnQuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBtZWRpYUVycm9yOiB0aGlzLm9uTWVkaWFFcnJvci5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgIGN1c3Rvbk5vdGlmaWNhdGlvbjogdGhpcy5jdXN0b21Ob3RpZmljYXRpb24uYmluZCh0aGlzKVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuanNvblJwY0NsaWVudCA9IG5ldyBScGNCdWlsZGVyLmNsaWVudHMuSnNvblJwY0NsaWVudChjb25maWcpO1xuICAgIH1cblxuXG4gICAgcHJpdmF0ZSBjdXN0b21Ob3RpZmljYXRpb24ocGFyYW1zKSB7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24uZW1pdEV2ZW50KFwiY3VzdG9tLW1lc3NhZ2UtcmVjZWl2ZWRcIiwgW3sgcGFyYW1zOiBwYXJhbXMgfV0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjb25uZWN0Q2FsbGJhY2soZXJyb3IpIHtcbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICB0aGlzLmNhbGxiYWNrKGVycm9yKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuY2FsbGJhY2sobnVsbCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGlzUm9vbUF2YWlsYWJsZSgpIHtcbiAgICAgICAgaWYgKHRoaXMuc2Vzc2lvbiAhPT0gdW5kZWZpbmVkICYmIHRoaXMuc2Vzc2lvbiBpbnN0YW5jZW9mIFNlc3Npb25JbnRlcm5hbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oJ1Jvb20gaW5zdGFuY2Ugbm90IGZvdW5kJyk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGRpc2Nvbm5lY3RDYWxsYmFjaygpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdXZWJzb2NrZXQgY29ubmVjdGlvbiBsb3N0Jyk7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24ub25Mb3N0Q29ubmVjdGlvbigpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYWxlcnQoJ0Nvbm5lY3Rpb24gZXJyb3IuIFBsZWFzZSByZWxvYWQgcGFnZS4nKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgcmVjb25uZWN0aW5nQ2FsbGJhY2soKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignV2Vic29ja2V0IGNvbm5lY3Rpb24gbG9zdCAocmVjb25uZWN0aW5nKScpO1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uTG9zdENvbm5lY3Rpb24oKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGFsZXJ0KCdDb25uZWN0aW9uIGVycm9yLiBQbGVhc2UgcmVsb2FkIHBhZ2UuJyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHJlY29ubmVjdGVkQ2FsbGJhY2soKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignV2Vic29ja2V0IHJlY29ubmVjdGVkJyk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblBhcnRpY2lwYW50Sm9pbmVkKHBhcmFtcykge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uUGFydGljaXBhbnRKb2luZWQocGFyYW1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgb25QYXJ0aWNpcGFudFB1Ymxpc2hlZChwYXJhbXMpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5vblBhcnRpY2lwYW50UHVibGlzaGVkKHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIG9uUGFydGljaXBhbnRMZWZ0KHBhcmFtcykge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uUGFydGljaXBhbnRMZWZ0KHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIG9uUGFydGljaXBhbnRFdmljdGVkKHBhcmFtcykge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uUGFydGljaXBhbnRFdmljdGVkKHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIG9uTmV3TWVzc2FnZShwYXJhbXMpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5vbk5ld01lc3NhZ2UocGFyYW1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgaWNlQ2FuZGlkYXRlRXZlbnQocGFyYW1zKSB7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24ucmVjdkljZUNhbmRpZGF0ZShwYXJhbXMpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblJvb21DbG9zZWQocGFyYW1zKSB7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24ub25Sb29tQ2xvc2VkKHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIG9uTWVkaWFFcnJvcihwYXJhbXMpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5vbk1lZGlhRXJyb3IocGFyYW1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgc2V0UnBjUGFyYW1zKHBhcmFtczogYW55KSB7XG4gICAgICAgIHRoaXMucnBjUGFyYW1zID0gcGFyYW1zO1xuICAgIH1cblxuICAgIHNlbmRSZXF1ZXN0KG1ldGhvZCwgcGFyYW1zLCBjYWxsYmFjaz8pIHtcblxuICAgICAgICBpZiAocGFyYW1zICYmIHBhcmFtcyBpbnN0YW5jZW9mIEZ1bmN0aW9uKSB7XG4gICAgICAgICAgICBjYWxsYmFjayA9IHBhcmFtcztcbiAgICAgICAgICAgIHBhcmFtcyA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHBhcmFtcyA9IHBhcmFtcyB8fCB7fTtcblxuICAgICAgICBpZiAodGhpcy5ycGNQYXJhbXMgJiYgdGhpcy5ycGNQYXJhbXMgIT09IG51bGwgJiYgdGhpcy5ycGNQYXJhbXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZm9yIChsZXQgaW5kZXggaW4gdGhpcy5ycGNQYXJhbXMpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5ycGNQYXJhbXMuaGFzT3duUHJvcGVydHkoaW5kZXgpKSB7XG4gICAgICAgICAgICAgICAgICAgIHBhcmFtc1tpbmRleF0gPSB0aGlzLnJwY1BhcmFtc1tpbmRleF07XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZGVidWcoJ1JQQyBwYXJhbSBhZGRlZCB0byByZXF1ZXN0IHsnICsgaW5kZXggKyAnOiAnICsgdGhpcy5ycGNQYXJhbXNbaW5kZXhdICsgJ30nKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmRlYnVnKCdTZW5kaW5nIHJlcXVlc3Q6IHttZXRob2Q6XCInICsgbWV0aG9kICsgJ1wiLCBwYXJhbXM6ICcgKyBKU09OLnN0cmluZ2lmeShwYXJhbXMpICsgJ30nKTtcblxuICAgICAgICB0aGlzLmpzb25ScGNDbGllbnQuc2VuZChtZXRob2QsIHBhcmFtcywgY2FsbGJhY2spO1xuICAgIH1cblxuICAgIGNsb3NlKGZvcmNlZCkge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLmxlYXZlKGZvcmNlZCwgdGhpcy5qc29uUnBjQ2xpZW50KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBkaXNjb25uZWN0UGFydGljaXBhbnQoc3RyZWFtKSB7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24uZGlzY29ubmVjdChzdHJlYW0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZ2V0Q2FtZXJhKG9wdGlvbnM/KSB7XG5cbiAgICAgICAgaWYgKHRoaXMuY2FtZXJhKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jYW1lcmE7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7XG4gICAgICAgICAgICBzZW5kQXVkaW86IHRydWUsXG4gICAgICAgICAgICBzZW5kVmlkZW86IHRydWUsXG4gICAgICAgICAgICBhY3RpdmVBdWRpbzogdHJ1ZSxcbiAgICAgICAgICAgIGFjdGl2ZVZpZGVvOiB0cnVlLFxuICAgICAgICAgICAgZGF0YTogdHJ1ZSxcbiAgICAgICAgICAgIG1lZGlhQ29uc3RyYWludHM6IHtcbiAgICAgICAgICAgICAgICBhdWRpbzogdHJ1ZSxcbiAgICAgICAgICAgICAgICB2aWRlbzogeyB3aWR0aDogeyBpZGVhbDogMTI4MCB9IH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBvcHRpb25zLmNvbm5lY3Rpb24gPSB0aGlzLnNlc3Npb24uZ2V0TG9jYWxQYXJ0aWNpcGFudCgpO1xuXG4gICAgICAgIHRoaXMuY2FtZXJhID0gbmV3IFN0cmVhbSh0aGlzLCB0cnVlLCB0aGlzLnNlc3Npb24sIG9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gdGhpcy5jYW1lcmE7XG4gICAgfTtcblxuICAgIC8vQ0hBVFxuICAgIHNlbmRNZXNzYWdlKHJvb20sIHVzZXIsIG1lc3NhZ2UpIHtcbiAgICAgICAgdGhpcy5zZW5kUmVxdWVzdCgnc2VuZE1lc3NhZ2UnLCB7XG4gICAgICAgICAgICBtZXNzYWdlOiBtZXNzYWdlLFxuICAgICAgICAgICAgdXNlck1lc3NhZ2U6IHVzZXIsXG4gICAgICAgICAgICByb29tTWVzc2FnZTogcm9vbVxuICAgICAgICB9LCBmdW5jdGlvbiAoZXJyb3IsIHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIHNlbmRDdXN0b21SZXF1ZXN0KHBhcmFtcywgY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5zZW5kUmVxdWVzdCgnY3VzdG9tUmVxdWVzdCcsIHBhcmFtcywgY2FsbGJhY2spO1xuICAgIH07XG5cblxuXG5cbiAgICB0b2dnbGVMb2NhbFZpZGVvVHJhY2soYWN0aXZhdGU6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5nZXRDYW1lcmEoKS5nZXRXZWJSdGNQZWVyKCkudmlkZW9FbmFibGVkID0gYWN0aXZhdGU7XG4gICAgfVxuXG4gICAgdG9nZ2xlTG9jYWxBdWRpb1RyYWNrKGFjdGl2YXRlOiBib29sZWFuKSB7XG4gICAgICAgIHRoaXMuZ2V0Q2FtZXJhKCkuZ2V0V2ViUnRjUGVlcigpLmF1ZGlvRW5hYmxlZCA9IGFjdGl2YXRlO1xuICAgIH1cblxuICAgIHB1Ymxpc2hMb2NhbFZpZGVvQXVkaW8oKSB7XG4gICAgICAgIHRoaXMudG9nZ2xlTG9jYWxWaWRlb1RyYWNrKHRydWUpO1xuICAgICAgICB0aGlzLnRvZ2dsZUxvY2FsQXVkaW9UcmFjayh0cnVlKTtcbiAgICB9XG5cbiAgICB1bnB1Ymxpc2hMb2NhbFZpZGVvQXVkaW8oKSB7XG4gICAgICAgIHRoaXMudG9nZ2xlTG9jYWxWaWRlb1RyYWNrKGZhbHNlKTtcbiAgICAgICAgdGhpcy50b2dnbGVMb2NhbEF1ZGlvVHJhY2soZmFsc2UpO1xuICAgIH1cblxuICAgIGdlbmVyYXRlTWVkaWFDb25zdHJhaW50cyhjYW1lcmFPcHRpb25zOiBhbnkpIHtcbiAgICAgICAgbGV0IG1lZGlhQ29uc3RyYWludHMgPSB7XG4gICAgICAgICAgICBhdWRpbzogY2FtZXJhT3B0aW9ucy5hdWRpbyxcbiAgICAgICAgICAgIHZpZGVvOiB7fVxuICAgICAgICB9XG4gICAgICAgIGlmICghY2FtZXJhT3B0aW9ucy52aWRlbykge1xuICAgICAgICAgICAgbWVkaWFDb25zdHJhaW50cy52aWRlbyA9IGZhbHNlXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsZXQgdywgaDtcbiAgICAgICAgICAgIHN3aXRjaCAoY2FtZXJhT3B0aW9ucy5xdWFsaXR5KSB7XG4gICAgICAgICAgICAgICAgY2FzZSAnTE9XJzpcbiAgICAgICAgICAgICAgICAgICAgdyA9IDMyMDtcbiAgICAgICAgICAgICAgICAgICAgaCA9IDI0MDtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAnTUVESVVNJzpcbiAgICAgICAgICAgICAgICAgICAgdyA9IDY0MDtcbiAgICAgICAgICAgICAgICAgICAgaCA9IDQ4MDtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAnSElHSCc6XG4gICAgICAgICAgICAgICAgICAgIHcgPSAxMjgwO1xuICAgICAgICAgICAgICAgICAgICBoID0gNzIwO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICB3ID0gNjQwO1xuICAgICAgICAgICAgICAgICAgICBoID0gNDgwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbWVkaWFDb25zdHJhaW50cy52aWRlb1snd2lkdGgnXSA9IHsgZXhhY3Q6IHcgfTtcbiAgICAgICAgICAgIG1lZGlhQ29uc3RyYWludHMudmlkZW9bJ2hlaWdodCddID0geyBleGFjdDogaCB9O1xuICAgICAgICAgICAgLy9tZWRpYUNvbnN0cmFpbnRzLnZpZGVvWydmcmFtZVJhdGUnXSA9IHsgaWRlYWw6IE51bWJlcigoPEhUTUxJbnB1dEVsZW1lbnQ+ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2ZyYW1lUmF0ZScpKS52YWx1ZSkgfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbWVkaWFDb25zdHJhaW50cztcbiAgICB9XG5cbn1cbiIsImltcG9ydCB7IFN0cmVhbSB9IGZyb20gJy4vU3RyZWFtJztcbmltcG9ydCB7IE9wZW5WaWR1SW50ZXJuYWwgfSBmcm9tICcuL09wZW5WaWR1SW50ZXJuYWwnO1xuaW1wb3J0IHsgQ29ubmVjdGlvbiwgQ29ubmVjdGlvbk9wdGlvbnMgfSBmcm9tICcuL0Nvbm5lY3Rpb24nO1xuaW1wb3J0IEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ3dvbGZ5ODctZXZlbnRlbWl0dGVyJyk7XG5cbmNvbnN0IFNFQ1JFVF9QQVJBTSA9ICc/c2VjcmV0PSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2Vzc2lvbk9wdGlvbnMge1xuICAgIHNlc3Npb25JZDogc3RyaW5nO1xuICAgIHBhcnRpY2lwYW50SWQ6IHN0cmluZztcbiAgICBtZXRhZGF0YTogc3RyaW5nO1xuICAgIHN1YnNjcmliZVRvU3RyZWFtcz86IGJvb2xlYW47XG4gICAgdXBkYXRlU3BlYWtlckludGVydmFsPzogbnVtYmVyO1xuICAgIHRocmVzaG9sZFNwZWFrZXI/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2lnbmFsT3B0aW9ucyB7XG4gICAgdHlwZT86IHN0cmluZztcbiAgICB0bz86IENvbm5lY3Rpb25bXTtcbiAgICBkYXRhPzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgU2Vzc2lvbkludGVybmFsIHtcblxuICAgIHByaXZhdGUgaWQ6IHN0cmluZztcbiAgICBwcml2YXRlIHNlc3Npb25JZDogc3RyaW5nO1xuICAgIHByaXZhdGUgZWUgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gICAgcHJpdmF0ZSBzdHJlYW1zID0ge307XG4gICAgcHJpdmF0ZSBwYXJ0aWNpcGFudHMgPSB7fTtcbiAgICBwcml2YXRlIHB1Ymxpc2hlcnNTcGVha2luZzogQ29ubmVjdGlvbltdID0gW107XG4gICAgcHJpdmF0ZSBjb25uZWN0ZWQgPSBmYWxzZTtcbiAgICBwdWJsaWMgbG9jYWxQYXJ0aWNpcGFudDogQ29ubmVjdGlvbjtcbiAgICBwcml2YXRlIHN1YnNjcmliZVRvU3RyZWFtczogYm9vbGVhbjtcbiAgICBwcml2YXRlIHVwZGF0ZVNwZWFrZXJJbnRlcnZhbDogbnVtYmVyO1xuICAgIHB1YmxpYyB0aHJlc2hvbGRTcGVha2VyOiBudW1iZXI7XG4gICAgcHJpdmF0ZSBvcHRpb25zOiBTZXNzaW9uT3B0aW9ucztcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgb3BlblZpZHU6IE9wZW5WaWR1SW50ZXJuYWwsIHNlc3Npb25JZDogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbklkID0gdGhpcy5nZXRVcmxXaXRob3V0U2VjcmV0KHNlc3Npb25JZCk7XG4gICAgICAgIHRoaXMubG9jYWxQYXJ0aWNpcGFudCA9IG5ldyBDb25uZWN0aW9uKHRoaXMub3BlblZpZHUsIHRydWUsIHRoaXMpO1xuICAgICAgICBpZiAoIXRoaXMub3BlblZpZHUuZ2V0V3NVcmkoKSkge1xuICAgICAgICAgICAgdGhpcy5wcm9jZXNzT3BlblZpZHVVcmwoc2Vzc2lvbklkKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgcHJvY2Vzc09wZW5WaWR1VXJsKHVybDogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMub3BlblZpZHUuc2V0U2VjcmV0KHRoaXMuZ2V0U2VjcmV0RnJvbVVybCh1cmwpKTtcbiAgICAgICAgdGhpcy5vcGVuVmlkdS5zZXRXc1VyaSh0aGlzLmdldEZpbmFsVXJsKHVybCkpO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0U2VjcmV0RnJvbVVybCh1cmw6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgICAgIGxldCBzZWNyZXQgPSAnJztcbiAgICAgICAgaWYgKHVybC5pbmRleE9mKFNFQ1JFVF9QQVJBTSkgIT09IC0xKSB7XG4gICAgICAgICAgICBzZWNyZXQgPSB1cmwuc3Vic3RyaW5nKHVybC5sYXN0SW5kZXhPZihTRUNSRVRfUEFSQU0pICsgU0VDUkVUX1BBUkFNLmxlbmd0aCwgdXJsLmxlbmd0aCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlY3JldDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldFVybFdpdGhvdXRTZWNyZXQodXJsOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICBpZiAoIXVybCkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignc2Vzc2lvbklkIGlzIG5vdCBkZWZpbmVkJyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHVybC5pbmRleE9mKFNFQ1JFVF9QQVJBTSkgIT09IC0xKSB7XG4gICAgICAgICAgICB1cmwgPSB1cmwuc3Vic3RyaW5nKDAsIHVybC5sYXN0SW5kZXhPZihTRUNSRVRfUEFSQU0pKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0RmluYWxVcmwodXJsOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICB1cmwgPSB0aGlzLmdldFVybFdpdGhvdXRTZWNyZXQodXJsKS5zdWJzdHJpbmcoMCwgdXJsLmxhc3RJbmRleE9mKCcvJykpICsgJy9yb29tJztcbiAgICAgICAgaWYgKHVybC5pbmRleE9mKFwiLm5ncm9rLmlvXCIpICE9PSAtMSkge1xuICAgICAgICAgICAgLy8gT3BlblZpZHUgc2VydmVyIFVSTCByZWZlcmVzIHRvIGEgbmdyb2sgSVA6IHNlY3VyZSB3c3MgcHJvdG9jb2wgYW5kIGRlbGV0ZSBwb3J0IG9mIFVSTFxuICAgICAgICAgICAgdXJsID0gdXJsLnJlcGxhY2UoXCJ3czovL1wiLCBcIndzczovL1wiKTtcbiAgICAgICAgICAgIGxldCByZWdleCA9IC9cXC5uZ3Jva1xcLmlvOlxcZCsvO1xuICAgICAgICAgICAgdXJsID0gdXJsLnJlcGxhY2UocmVnZXgsIFwiLm5ncm9rLmlvXCIpO1xuICAgICAgICB9IGVsc2UgaWYgKCh1cmwuaW5kZXhPZihcImxvY2FsaG9zdFwiKSAhPT0gLTEpIHx8ICh1cmwuaW5kZXhPZihcIjEyNy4wLjAuMVwiKSAhPSAtMSkpIHtcbiAgICAgICAgICAgIC8vIE9wZW5WaWR1IHNlcnZlciBVUkwgcmVmZXJlcyB0byBsb2NhbGhvc3QgSVBcblxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1cmw7XG4gICAgfVxuXG5cblxuICAgIC8qIE5FVyBNRVRIT0RTICovXG4gICAgY29ubmVjdCh0b2tlbiwgY2FsbGJhY2spIHtcblxuICAgICAgICB0aGlzLm9wZW5WaWR1LmNvbm5lY3QoKGVycm9yKSA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjaygnRVJST1IgQ09OTkVDVElORyBUTyBPUEVOVklEVScpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG5cbiAgICAgICAgICAgICAgICBpZiAoIXRva2VuKSB7XG4gICAgICAgICAgICAgICAgICAgIHRva2VuID0gdGhpcy5yYW5kb21Ub2tlbigpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGxldCBqb2luUGFyYW1zID0ge1xuICAgICAgICAgICAgICAgICAgICB0b2tlbjogdG9rZW4sXG4gICAgICAgICAgICAgICAgICAgIHNlc3Npb246IHRoaXMuc2Vzc2lvbklkLFxuICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YTogdGhpcy5vcHRpb25zLm1ldGFkYXRhLFxuICAgICAgICAgICAgICAgICAgICBzZWNyZXQ6IHRoaXMub3BlblZpZHUuZ2V0U2VjcmV0KCksXG4gICAgICAgICAgICAgICAgICAgIGRhdGFDaGFubmVsczogZmFsc2VcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAodGhpcy5sb2NhbFBhcnRpY2lwYW50KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChPYmplY3Qua2V5cyh0aGlzLmxvY2FsUGFydGljaXBhbnQuZ2V0U3RyZWFtcygpKS5zb21lKHN0cmVhbUlkID0+XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbXNbc3RyZWFtSWRdLmlzRGF0YUNoYW5uZWxFbmFibGVkKCkpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBqb2luUGFyYW1zLmRhdGFDaGFubmVscyA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLm9wZW5WaWR1LnNlbmRSZXF1ZXN0KCdqb2luUm9vbScsIGpvaW5QYXJhbXMsIChlcnJvciwgcmVzcG9uc2UpID0+IHtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0ZWQgPSB0cnVlO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgZXhQYXJ0aWNpcGFudHMgPSByZXNwb25zZS52YWx1ZTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSU1QT1JUQU5UOiBVcGRhdGUgY29ubmVjdGlvbklkIHdpdGggdmFsdWUgc2VuZCBieSBzZXJ2ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubG9jYWxQYXJ0aWNpcGFudC5jb25uZWN0aW9uSWQgPSByZXNwb25zZS5pZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGFydGljaXBhbnRzW3Jlc3BvbnNlLmlkXSA9IHRoaXMubG9jYWxQYXJ0aWNpcGFudDtcblxuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHJvb21FdmVudCA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudHM6IG5ldyBBcnJheTxDb25uZWN0aW9uPigpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmVhbXM6IG5ldyBBcnJheTxTdHJlYW0+KClcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGxlbmd0aCA9IGV4UGFydGljaXBhbnRzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldCBjb25uZWN0aW9uID0gbmV3IENvbm5lY3Rpb24odGhpcy5vcGVuVmlkdSwgZmFsc2UsIHRoaXMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4UGFydGljaXBhbnRzW2ldKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmNyZWF0aW9uVGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wYXJ0aWNpcGFudHNbY29ubmVjdGlvbi5jb25uZWN0aW9uSWRdID0gY29ubmVjdGlvbjtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvb21FdmVudC5wYXJ0aWNpcGFudHMucHVzaChjb25uZWN0aW9uKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldCBzdHJlYW1zID0gY29ubmVjdGlvbi5nZXRTdHJlYW1zKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQga2V5IGluIHN0cmVhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm9vbUV2ZW50LnN0cmVhbXMucHVzaChzdHJlYW1zW2tleV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5zdWJzY3JpYmVUb1N0cmVhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmVhbXNba2V5XS5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVXBkYXRlIGxvY2FsIENvbm5lY3Rpb24gb2JqZWN0IHByb3BlcnRpZXMgd2l0aCB2YWx1ZXMgcmV0dXJuZWQgYnkgc2VydmVyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvY2FsUGFydGljaXBhbnQuZGF0YSA9IHJlc3BvbnNlLm1ldGFkYXRhO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2NhbFBhcnRpY2lwYW50LmNyZWF0aW9uVGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVcGRhdGVzIHRoZSB2YWx1ZSBvZiBwcm9wZXJ0eSAnY29ubmVjdGlvbicgaW4gU2Vzc2lvbiBvYmplY3RcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCd1cGRhdGUtY29ubmVjdGlvbi1vYmplY3QnLCBbeyBjb25uZWN0aW9uOiB0aGlzLmxvY2FsUGFydGljaXBhbnQgfV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3duIGNvbm5lY3Rpb24gY3JlYXRlZCBldmVudFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2Nvbm5lY3Rpb25DcmVhdGVkJywgW3sgY29ubmVjdGlvbjogdGhpcy5sb2NhbFBhcnRpY2lwYW50IH1dKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gT25lIGNvbm5lY3Rpb24gY3JlYXRlZCBldmVudCBmb3IgZWFjaCBleGlzdGluZyBjb25uZWN0aW9uIGluIHRoZSBzZXNzaW9uXG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBwYXJ0IG9mIHJvb21FdmVudC5wYXJ0aWNpcGFudHMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnY29ubmVjdGlvbkNyZWF0ZWQnLCBbeyBjb25uZWN0aW9uOiBwYXJ0IH1dKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgLy9pZiAodGhpcy5zdWJzY3JpYmVUb1N0cmVhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAobGV0IHN0cmVhbSBvZiByb29tRXZlbnQuc3RyZWFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdzdHJlYW1DcmVhdGVkJywgW3sgc3RyZWFtIH1dKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFkZGluZyB0aGUgcmVtb3RlIHN0cmVhbSB0byB0aGUgT3BlblZpZHUgb2JqZWN0XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5vcGVuVmlkdS5nZXRSZW1vdGVTdHJlYW1zKCkucHVzaChzdHJlYW0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjayh1bmRlZmluZWQpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1Ymxpc2goKSB7XG4gICAgICAgIHRoaXMub3BlblZpZHUuZ2V0Q2FtZXJhKCkucHVibGlzaCgpO1xuICAgIH1cbiAgICAvKiBORVcgTUVUSE9EUyAqL1xuXG5cblxuXG5cbiAgICBjb25maWd1cmUob3B0aW9uczogU2Vzc2lvbk9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgICAgICAgdGhpcy5pZCA9IG9wdGlvbnMuc2Vzc2lvbklkO1xuICAgICAgICB0aGlzLnN1YnNjcmliZVRvU3RyZWFtcyA9IG9wdGlvbnMuc3Vic2NyaWJlVG9TdHJlYW1zID09IG51bGwgPyB0cnVlIDogb3B0aW9ucy5zdWJzY3JpYmVUb1N0cmVhbXM7XG4gICAgICAgIHRoaXMudXBkYXRlU3BlYWtlckludGVydmFsID0gb3B0aW9ucy51cGRhdGVTcGVha2VySW50ZXJ2YWwgfHwgMTUwMDtcbiAgICAgICAgdGhpcy50aHJlc2hvbGRTcGVha2VyID0gb3B0aW9ucy50aHJlc2hvbGRTcGVha2VyIHx8IC01MDtcbiAgICAgICAgdGhpcy5hY3RpdmF0ZVVwZGF0ZU1haW5TcGVha2VyKCk7XG4gICAgfVxuXG4gICAgZ2V0SWQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmlkO1xuICAgIH1cblxuICAgIGdldFNlc3Npb25JZCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2Vzc2lvbklkO1xuICAgIH1cblxuICAgIHByaXZhdGUgYWN0aXZhdGVVcGRhdGVNYWluU3BlYWtlcigpIHtcblxuICAgICAgICAvKnNldEludGVydmFsKCgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLnB1Ymxpc2hlcnNTcGVha2luZy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3B1Ymxpc2hlclN0YXJ0U3BlYWtpbmcnLCBbe1xuICAgICAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudElkOiB0aGlzLnB1Ymxpc2hlcnNTcGVha2luZ1t0aGlzLnB1Ymxpc2hlcnNTcGVha2luZy5sZW5ndGggLSAxXVxuICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSwgdGhpcy51cGRhdGVTcGVha2VySW50ZXJ2YWwpOyovXG4gICAgfVxuXG4gICAgZ2V0TG9jYWxQYXJ0aWNpcGFudCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxQYXJ0aWNpcGFudDtcbiAgICB9XG5cbiAgICBhZGRFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgbGlzdGVuZXIpIHtcbiAgICAgICAgdGhpcy5lZS5vbihldmVudE5hbWUsIGxpc3RlbmVyKTtcbiAgICB9XG5cbiAgICBhZGRPbmNlRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsIGxpc3RlbmVyKSB7XG4gICAgICAgIHRoaXMuZWUub25jZShldmVudE5hbWUsIGxpc3RlbmVyKTtcbiAgICB9XG5cbiAgICByZW1vdmVMaXN0ZW5lcihldmVudE5hbWUsIGxpc3RlbmVyKSB7XG4gICAgICAgIHRoaXMuZWUub2ZmKGV2ZW50TmFtZSwgbGlzdGVuZXIpO1xuICAgIH1cblxuICAgIHJlbW92ZUV2ZW50KGV2ZW50TmFtZSkge1xuICAgICAgICB0aGlzLmVlLnJlbW92ZUV2ZW50KGV2ZW50TmFtZSk7XG4gICAgfVxuXG4gICAgZW1pdEV2ZW50KGV2ZW50TmFtZSwgZXZlbnRzQXJyYXkpIHtcbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoZXZlbnROYW1lLCBldmVudHNBcnJheSk7XG4gICAgfVxuXG5cbiAgICBzdWJzY3JpYmUoc3RyZWFtOiBTdHJlYW0pIHtcbiAgICAgICAgc3RyZWFtLnN1YnNjcmliZSgpO1xuICAgIH1cblxuICAgIHVuc3Vic2NyaWJlKHN0cmVhbSkge1xuICAgICAgICBjb25zb2xlLmluZm8oXCJVbnN1YnNjcmliaW5nIGZyb20gXCIgKyBzdHJlYW0uc3RyZWFtSWQpO1xuICAgICAgICB0aGlzLm9wZW5WaWR1LnNlbmRSZXF1ZXN0KCd1bnN1YnNjcmliZUZyb21WaWRlbycsIHtcbiAgICAgICAgICAgIHNlbmRlcjogc3RyZWFtLnN0cmVhbUlkXG4gICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IsIHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciB1bnN1YnNjcmliaW5nIGZyb20gU3Vic2NyaWJlclwiLCBlcnJvcik7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiVW5zdWJzY3JpYmVkIGNvcnJlY3RseSBmcm9tIFwiICsgc3RyZWFtLnN0cmVhbUlkKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBvblBhcnRpY2lwYW50UHVibGlzaGVkKG9wdGlvbnMpIHtcblxuICAgICAgICAvLyBHZXQgdGhlIGV4aXN0aW5nIENvbm5lY3Rpb24gY3JlYXRlZCBvbiAnb25QYXJ0aWNpcGFudEpvaW5lZCcgZm9yXG4gICAgICAgIC8vIGV4aXN0aW5nIHBhcnRpY2lwYW50cyBvciBjcmVhdGUgYSBuZXcgb25lIGZvciBuZXcgcGFydGljaXBhbnRzXG4gICAgICAgIGxldCBjb25uZWN0aW9uID0gdGhpcy5wYXJ0aWNpcGFudHNbb3B0aW9ucy5pZF07XG4gICAgICAgIGlmIChjb25uZWN0aW9uKSB7XG4gICAgICAgICAgICAvLyBVcGRhdGUgZXhpc3RpbmcgQ29ubmVjdGlvblxuICAgICAgICAgICAgb3B0aW9ucy5tZXRhZGF0YSA9IGNvbm5lY3Rpb24uZGF0YTtcbiAgICAgICAgICAgIGNvbm5lY3Rpb24ub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgICAgICAgICBjb25uZWN0aW9uLmluaXRTdHJlYW1zKG9wdGlvbnMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gQ3JlYXRlIG5ldyBDb25uZWN0aW9uXG4gICAgICAgICAgICBjb25uZWN0aW9uID0gbmV3IENvbm5lY3Rpb24odGhpcy5vcGVuVmlkdSwgZmFsc2UsIHRoaXMsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHBpZCA9IGNvbm5lY3Rpb24uY29ubmVjdGlvbklkO1xuICAgICAgICBpZiAoIShwaWQgaW4gdGhpcy5wYXJ0aWNpcGFudHMpKSB7XG4gICAgICAgICAgICBjb25zb2xlLmRlYnVnKFwiUmVtb3RlIENvbm5lY3Rpb24gbm90IGZvdW5kIGluIGNvbm5lY3Rpb25zIGxpc3QgYnkgaXRzIGlkIFtcIiArIHBpZCArIFwiXVwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZGVidWcoXCJSZW1vdGUgQ29ubmVjdGlvbiBmb3VuZCBpbiBjb25uZWN0aW9ucyBsaXN0IGJ5IGl0cyBpZCBbXCIgKyBwaWQgKyBcIl1cIik7XG4gICAgICAgIH1cblxuXG4gICAgICAgIHRoaXMucGFydGljaXBhbnRzW3BpZF0gPSBjb25uZWN0aW9uO1xuXG4gICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdwYXJ0aWNpcGFudC1wdWJsaXNoZWQnLCBbeyBjb25uZWN0aW9uIH1dKTtcblxuICAgICAgICBsZXQgc3RyZWFtcyA9IGNvbm5lY3Rpb24uZ2V0U3RyZWFtcygpO1xuICAgICAgICBmb3IgKGxldCBrZXkgaW4gc3RyZWFtcykge1xuICAgICAgICAgICAgbGV0IHN0cmVhbSA9IHN0cmVhbXNba2V5XTtcblxuICAgICAgICAgICAgaWYgKHRoaXMuc3Vic2NyaWJlVG9TdHJlYW1zKSB7XG4gICAgICAgICAgICAgICAgc3RyZWFtLnN1YnNjcmliZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3N0cmVhbUNyZWF0ZWQnLCBbeyBzdHJlYW0gfV0pO1xuICAgICAgICAgICAgLy8gQWRkaW5nIHRoZSByZW1vdGUgc3RyZWFtIHRvIHRoZSBPcGVuVmlkdSBvYmplY3RcbiAgICAgICAgICAgIHRoaXMub3BlblZpZHUuZ2V0UmVtb3RlU3RyZWFtcygpLnB1c2goc3RyZWFtKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uUGFydGljaXBhbnRKb2luZWQobXNnKSB7XG5cbiAgICAgICAgbGV0IGNvbm5lY3Rpb24gPSBuZXcgQ29ubmVjdGlvbih0aGlzLm9wZW5WaWR1LCBmYWxzZSwgdGhpcywgbXNnKTtcbiAgICAgICAgY29ubmVjdGlvbi5jcmVhdGlvblRpbWUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcblxuICAgICAgICBsZXQgcGlkID0gY29ubmVjdGlvbi5jb25uZWN0aW9uSWQ7XG4gICAgICAgIGlmICghKHBpZCBpbiB0aGlzLnBhcnRpY2lwYW50cykpIHtcbiAgICAgICAgICAgIHRoaXMucGFydGljaXBhbnRzW3BpZF0gPSBjb25uZWN0aW9uO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy91c2UgZXhpc3Rpbmcgc28gdGhhdCB3ZSBkb24ndCBsb3NlIHN0cmVhbXMgaW5mb1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFwiQ29ubmVjdGlvbiBhbHJlYWR5IGV4aXN0cyBpbiBjb25uZWN0aW9ucyBsaXN0IHdpdGggXCIgK1xuICAgICAgICAgICAgICAgIFwidGhlIHNhbWUgY29ubmVjdGlvbklkLCBvbGQ6XCIsIHRoaXMucGFydGljaXBhbnRzW3BpZF0sIFwiLCBqb2luZWQgbm93OlwiLCBjb25uZWN0aW9uKTtcbiAgICAgICAgICAgIGNvbm5lY3Rpb24gPSB0aGlzLnBhcnRpY2lwYW50c1twaWRdO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3BhcnRpY2lwYW50LWpvaW5lZCcsIFt7XG4gICAgICAgICAgICBjb25uZWN0aW9uOiBjb25uZWN0aW9uXG4gICAgICAgIH1dKTtcblxuICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnY29ubmVjdGlvbkNyZWF0ZWQnLCBbe1xuICAgICAgICAgICAgY29ubmVjdGlvbjogY29ubmVjdGlvblxuICAgICAgICB9XSk7XG5cbiAgICB9XG5cbiAgICBvblBhcnRpY2lwYW50TGVmdChtc2cpIHtcblxuICAgICAgICBsZXQgY29ubmVjdGlvbiA9IHRoaXMucGFydGljaXBhbnRzW21zZy5uYW1lXTtcblxuICAgICAgICBpZiAoY29ubmVjdGlvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBkZWxldGUgdGhpcy5wYXJ0aWNpcGFudHNbbXNnLm5hbWVdO1xuXG4gICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgncGFydGljaXBhbnQtbGVmdCcsIFt7XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbjogY29ubmVjdGlvblxuICAgICAgICAgICAgfV0pO1xuXG4gICAgICAgICAgICBsZXQgc3RyZWFtcyA9IGNvbm5lY3Rpb24uZ2V0U3RyZWFtcygpO1xuICAgICAgICAgICAgZm9yIChsZXQga2V5IGluIHN0cmVhbXMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnc3RyZWFtRGVzdHJveWVkJywgW3tcbiAgICAgICAgICAgICAgICAgICAgc3RyZWFtOiBzdHJlYW1zW2tleV0sXG4gICAgICAgICAgICAgICAgICAgIHByZXZlbnREZWZhdWx0OiAoKSA9PiB7IHRoaXMuZWUucmVtb3ZlRXZlbnQoJ3N0cmVhbS1kZXN0cm95ZWQtZGVmYXVsdCcpOyB9XG4gICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdzdHJlYW0tZGVzdHJveWVkLWRlZmF1bHQnLCBbe1xuICAgICAgICAgICAgICAgICAgICBzdHJlYW06IHN0cmVhbXNba2V5XVxuICAgICAgICAgICAgICAgIH1dKTtcblxuICAgICAgICAgICAgICAgIC8vIERlbGV0aW5nIHRoZSByZW1vdmVkIHN0cmVhbSBmcm9tIHRoZSBPcGVuVmlkdSBvYmplY3RcbiAgICAgICAgICAgICAgICBsZXQgaW5kZXggPSB0aGlzLm9wZW5WaWR1LmdldFJlbW90ZVN0cmVhbXMoKS5pbmRleE9mKHN0cmVhbXNba2V5XSk7XG4gICAgICAgICAgICAgICAgdGhpcy5vcGVuVmlkdS5nZXRSZW1vdGVTdHJlYW1zKCkuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29ubmVjdGlvbi5kaXNwb3NlKCk7XG5cbiAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdjb25uZWN0aW9uRGVzdHJveWVkJywgW3tcbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uOiBjb25uZWN0aW9uXG4gICAgICAgICAgICB9XSk7XG5cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcIlBhcnRpY2lwYW50IFwiICsgbXNnLm5hbWVcbiAgICAgICAgICAgICAgICArIFwiIHVua25vd24uIFBhcnRpY2lwYW50czogXCJcbiAgICAgICAgICAgICAgICArIEpTT04uc3RyaW5naWZ5KHRoaXMucGFydGljaXBhbnRzKSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgb25QYXJ0aWNpcGFudEV2aWN0ZWQobXNnKSB7XG4gICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdwYXJ0aWNpcGFudC1ldmljdGVkJywgW3tcbiAgICAgICAgICAgIGxvY2FsUGFydGljaXBhbnQ6IHRoaXMubG9jYWxQYXJ0aWNpcGFudFxuICAgICAgICB9XSk7XG4gICAgfTtcblxuICAgIG9uTmV3TWVzc2FnZShtc2cpIHtcblxuICAgICAgICBjb25zb2xlLmluZm8oXCJOZXcgc2lnbmFsOiBcIiArIEpTT04uc3RyaW5naWZ5KG1zZykpO1xuXG4gICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdzaWduYWwnLCBbe1xuICAgICAgICAgICAgZGF0YTogbXNnLmRhdGEsXG4gICAgICAgICAgICBmcm9tOiB0aGlzLnBhcnRpY2lwYW50c1ttc2cuZnJvbV0sXG4gICAgICAgICAgICB0eXBlOiBtc2cudHlwZVxuICAgICAgICB9XSk7XG5cbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3NpZ25hbDonICsgbXNnLnR5cGUsIFt7XG4gICAgICAgICAgICBkYXRhOiBtc2cuZGF0YSxcbiAgICAgICAgICAgIGZyb206IHRoaXMucGFydGljaXBhbnRzW21zZy5mcm9tXSxcbiAgICAgICAgICAgIHR5cGU6IG1zZy50eXBlXG4gICAgICAgIH1dKTtcblxuICAgIH1cblxuICAgIHJlY3ZJY2VDYW5kaWRhdGUobXNnKSB7XG5cbiAgICAgICAgbGV0IGNhbmRpZGF0ZSA9IHtcbiAgICAgICAgICAgIGNhbmRpZGF0ZTogbXNnLmNhbmRpZGF0ZSxcbiAgICAgICAgICAgIHNkcE1pZDogbXNnLnNkcE1pZCxcbiAgICAgICAgICAgIHNkcE1MaW5lSW5kZXg6IG1zZy5zZHBNTGluZUluZGV4XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgY29ubmVjdGlvbiA9IHRoaXMucGFydGljaXBhbnRzW21zZy5lbmRwb2ludE5hbWVdO1xuICAgICAgICBpZiAoIWNvbm5lY3Rpb24pIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJQYXJ0aWNpcGFudCBub3QgZm91bmQgZm9yIGVuZHBvaW50IFwiICtcbiAgICAgICAgICAgICAgICBtc2cuZW5kcG9pbnROYW1lICsgXCIuIEljZSBjYW5kaWRhdGUgd2lsbCBiZSBpZ25vcmVkLlwiLFxuICAgICAgICAgICAgICAgIGNhbmRpZGF0ZSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgc3RyZWFtcyA9IGNvbm5lY3Rpb24uZ2V0U3RyZWFtcygpO1xuICAgICAgICBmb3IgKGxldCBrZXkgaW4gc3RyZWFtcykge1xuICAgICAgICAgICAgbGV0IHN0cmVhbSA9IHN0cmVhbXNba2V5XTtcbiAgICAgICAgICAgIHN0cmVhbS5nZXRXZWJSdGNQZWVyKCkuYWRkSWNlQ2FuZGlkYXRlKGNhbmRpZGF0ZSwgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBhZGRpbmcgY2FuZGlkYXRlIGZvciBcIiArIGtleVxuICAgICAgICAgICAgICAgICAgICAgICAgKyBcIiBzdHJlYW0gb2YgZW5kcG9pbnQgXCIgKyBtc2cuZW5kcG9pbnROYW1lXG4gICAgICAgICAgICAgICAgICAgICAgICArIFwiOiBcIiArIGVycm9yKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uUm9vbUNsb3NlZChtc2cpIHtcblxuICAgICAgICBjb25zb2xlLmluZm8oXCJSb29tIGNsb3NlZDogXCIgKyBKU09OLnN0cmluZ2lmeShtc2cpKTtcbiAgICAgICAgbGV0IHJvb20gPSBtc2cucm9vbTtcbiAgICAgICAgaWYgKHJvb20gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3Jvb20tY2xvc2VkJywgW3tcbiAgICAgICAgICAgICAgICByb29tOiByb29tXG4gICAgICAgICAgICB9XSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJSb29tIHVuZGVmaW5lZCBpbiBvbiByb29tIGNsb3NlZFwiLCBtc2cpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb25Mb3N0Q29ubmVjdGlvbigpIHtcblxuICAgICAgICBpZiAoIXRoaXMuY29ubmVjdGVkKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oJ05vdCBjb25uZWN0ZWQgdG8gcm9vbTogaWYgeW91IGFyZSBub3QgZGVidWdnaW5nLCB0aGlzIGlzIHByb2JhYmx5IGEgY2VydGlmaWNhdGUgZXJyb3InKTtcbiAgICAgICAgICAgIGlmICh3aW5kb3cuY29uZmlybSgnSWYgeW91IGFyZSBub3QgZGVidWdnaW5nLCB0aGlzIGlzIHByb2JhYmx5IGEgY2VydGlmaWNhdGUgZXJyb3IgYXQgXFxcIicgKyB0aGlzLm9wZW5WaWR1LmdldE9wZW5WaWR1U2VydmVyVVJMKCkgKyAnXFxcIlxcblxcbkNsaWNrIE9LIHRvIG5hdmlnYXRlIGFuZCBhY2NlcHQgaXQnKSkge1xuICAgICAgICAgICAgICAgIGxvY2F0aW9uLmFzc2lnbih0aGlzLm9wZW5WaWR1LmdldE9wZW5WaWR1U2VydmVyVVJMKCkgKyAnL2FjY2VwdC1jZXJ0aWZpY2F0ZScpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnNvbGUud2FybignTG9zdCBjb25uZWN0aW9uIGluIFNlc3Npb24gJyArIHRoaXMuaWQpO1xuICAgICAgICBsZXQgcm9vbSA9IHRoaXMuaWQ7XG4gICAgICAgIGlmIChyb29tICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdsb3N0LWNvbm5lY3Rpb24nLCBbeyByb29tIH1dKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybignUm9vbSB1bmRlZmluZWQgd2hlbiBsb3N0IGNvbm5lY3Rpb24nKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uTWVkaWFFcnJvcihwYXJhbXMpIHtcblxuICAgICAgICBjb25zb2xlLmVycm9yKFwiTWVkaWEgZXJyb3I6IFwiICsgSlNPTi5zdHJpbmdpZnkocGFyYW1zKSk7XG4gICAgICAgIGxldCBlcnJvciA9IHBhcmFtcy5lcnJvcjtcbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnZXJyb3ItbWVkaWEnLCBbe1xuICAgICAgICAgICAgICAgIGVycm9yOiBlcnJvclxuICAgICAgICAgICAgfV0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFwiUmVjZWl2ZWQgdW5kZWZpbmVkIG1lZGlhIGVycm9yLiBQYXJhbXM6XCIsIHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKlxuICAgICAqIGZvcmNlZCBtZWFucyB0aGUgdXNlciB3YXMgZXZpY3RlZCwgbm8gbmVlZCB0byBzZW5kIHRoZSAnbGVhdmVSb29tJyByZXF1ZXN0XG4gICAgICovXG4gICAgbGVhdmUoZm9yY2VkLCBqc29uUnBjQ2xpZW50KSB7XG5cbiAgICAgICAgZm9yY2VkID0gISFmb3JjZWQ7XG5cbiAgICAgICAgY29uc29sZS5pbmZvKFwiTGVhdmluZyBTZXNzaW9uIChmb3JjZWQ9XCIgKyBmb3JjZWQgKyBcIilcIik7XG5cbiAgICAgICAgaWYgKHRoaXMuY29ubmVjdGVkICYmICFmb3JjZWQpIHtcbiAgICAgICAgICAgIHRoaXMub3BlblZpZHUuc2VuZFJlcXVlc3QoJ2xlYXZlUm9vbScsIGZ1bmN0aW9uIChlcnJvciwgcmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGpzb25ScGNDbGllbnQuY2xvc2UoKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAganNvblJwY0NsaWVudC5jbG9zZSgpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY29ubmVjdGVkID0gZmFsc2U7XG4gICAgICAgIGlmICh0aGlzLnBhcnRpY2lwYW50cykge1xuICAgICAgICAgICAgZm9yIChsZXQgcGlkIGluIHRoaXMucGFydGljaXBhbnRzKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5wYXJ0aWNpcGFudHNbcGlkXS5kaXNwb3NlKCk7XG4gICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMucGFydGljaXBhbnRzW3BpZF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBkaXNjb25uZWN0KHN0cmVhbTogU3RyZWFtKSB7XG5cbiAgICAgICAgbGV0IGNvbm5lY3Rpb24gPSBzdHJlYW0uZ2V0UGFydGljaXBhbnQoKTtcbiAgICAgICAgaWYgKCFjb25uZWN0aW9uKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiU3RyZWFtIHRvIGRpc2Nvbm5lY3QgaGFzIG5vIHBhcnRpY2lwYW50XCIsIHN0cmVhbSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBkZWxldGUgdGhpcy5wYXJ0aWNpcGFudHNbY29ubmVjdGlvbi5jb25uZWN0aW9uSWRdO1xuICAgICAgICBjb25uZWN0aW9uLmRpc3Bvc2UoKTtcblxuICAgICAgICBpZiAoY29ubmVjdGlvbiA9PT0gdGhpcy5sb2NhbFBhcnRpY2lwYW50KSB7XG5cbiAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIlVucHVibGlzaGluZyBteSBtZWRpYSAoSSdtIFwiICsgY29ubmVjdGlvbi5jb25uZWN0aW9uSWQgKyBcIilcIik7XG4gICAgICAgICAgICBkZWxldGUgdGhpcy5sb2NhbFBhcnRpY2lwYW50O1xuICAgICAgICAgICAgdGhpcy5vcGVuVmlkdS5zZW5kUmVxdWVzdCgndW5wdWJsaXNoVmlkZW8nLCBmdW5jdGlvbiAoZXJyb3IsIHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIk1lZGlhIHVucHVibGlzaGVkIGNvcnJlY3RseVwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy51bnN1YnNjcmliZShzdHJlYW0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdW5wdWJsaXNoKHN0cmVhbTogU3RyZWFtKSB7XG5cbiAgICAgICAgbGV0IGNvbm5lY3Rpb24gPSBzdHJlYW0uZ2V0UGFydGljaXBhbnQoKTtcbiAgICAgICAgaWYgKCFjb25uZWN0aW9uKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiU3RyZWFtIHRvIGRpc2Nvbm5lY3QgaGFzIG5vIHBhcnRpY2lwYW50XCIsIHN0cmVhbSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY29ubmVjdGlvbiA9PT0gdGhpcy5sb2NhbFBhcnRpY2lwYW50KSB7XG5cbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnBhcnRpY2lwYW50c1tjb25uZWN0aW9uLmNvbm5lY3Rpb25JZF07XG4gICAgICAgICAgICBjb25uZWN0aW9uLmRpc3Bvc2UoKTtcblxuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiVW5wdWJsaXNoaW5nIG15IG1lZGlhIChJJ20gXCIgKyBjb25uZWN0aW9uLmNvbm5lY3Rpb25JZCArIFwiKVwiKTtcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmxvY2FsUGFydGljaXBhbnQ7XG4gICAgICAgICAgICB0aGlzLm9wZW5WaWR1LnNlbmRSZXF1ZXN0KCd1bnB1Ymxpc2hWaWRlbycsIGZ1bmN0aW9uIChlcnJvciwgcmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiTWVkaWEgdW5wdWJsaXNoZWQgY29ycmVjdGx5XCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZ2V0U3RyZWFtcygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RyZWFtcztcbiAgICB9XG5cbiAgICBhZGRQYXJ0aWNpcGFudFNwZWFraW5nKHBhcnRpY2lwYW50SWQpIHtcbiAgICAgICAgdGhpcy5wdWJsaXNoZXJzU3BlYWtpbmcucHVzaChwYXJ0aWNpcGFudElkKTtcbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3B1Ymxpc2hlclN0YXJ0U3BlYWtpbmcnLCBbe1xuICAgICAgICAgICAgcGFydGljaXBhbnRJZDogcGFydGljaXBhbnRJZFxuICAgICAgICB9XSk7XG4gICAgfVxuXG4gICAgcmVtb3ZlUGFydGljaXBhbnRTcGVha2luZyhwYXJ0aWNpcGFudElkKSB7XG4gICAgICAgIGxldCBwb3MgPSAtMTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnB1Ymxpc2hlcnNTcGVha2luZy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKHRoaXMucHVibGlzaGVyc1NwZWFraW5nW2ldID09IHBhcnRpY2lwYW50SWQpIHtcbiAgICAgICAgICAgICAgICBwb3MgPSBpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChwb3MgIT0gLTEpIHtcbiAgICAgICAgICAgIHRoaXMucHVibGlzaGVyc1NwZWFraW5nLnNwbGljZShwb3MsIDEpO1xuICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3B1Ymxpc2hlclN0b3BTcGVha2luZycsIFt7XG4gICAgICAgICAgICAgICAgcGFydGljaXBhbnRJZDogcGFydGljaXBhbnRJZFxuICAgICAgICAgICAgfV0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgc3RyaW5nQ2xpZW50TWV0YWRhdGEobWV0YWRhdGEpOiBzdHJpbmcge1xuICAgICAgICBpZiAoISh0eXBlb2YgbWV0YWRhdGEgPT09ICdzdHJpbmcnKSkge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG1ldGFkYXRhKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBtZXRhZGF0YTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgcmFuZG9tVG9rZW4oKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnNsaWNlKDIpICsgTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc2xpY2UoMik7XG4gICAgfVxuXG59XG4iLCIvKlxuICogb3B0aW9uczogbmFtZTogWFhYIGRhdGE6IHRydWUgKE1heWJlIHRoaXMgaXMgYmFzZWQgb24gd2VicnRjKSBhdWRpbzogdHJ1ZSxcbiAqIHZpZGVvOiB0cnVlLCB1cmw6IFwiZmlsZTovLy8uLi5cIiA+IFBsYXllciBzY3JlZW46IHRydWUgPiBEZXNrdG9wIChpbXBsaWNpdFxuICogdmlkZW86dHJ1ZSwgYXVkaW86ZmFsc2UpIGF1ZGlvOiB0cnVlLCB2aWRlbzogdHJ1ZSA+IFdlYmNhbVxuICpcbiAqIHN0cmVhbS5oYXNBdWRpbygpOyBzdHJlYW0uaGFzVmlkZW8oKTsgc3RyZWFtLmhhc0RhdGEoKTtcbiAqL1xuaW1wb3J0IHsgQ29ubmVjdGlvbiB9IGZyb20gJy4vQ29ubmVjdGlvbic7XG5pbXBvcnQgeyBTZXNzaW9uSW50ZXJuYWwgfSBmcm9tICcuL1Nlc3Npb25JbnRlcm5hbCc7XG5pbXBvcnQgeyBPcGVuVmlkdUludGVybmFsLCBDYWxsYmFjayB9IGZyb20gJy4vT3BlblZpZHVJbnRlcm5hbCc7XG5pbXBvcnQgeyBPcGVuVmlkdUVycm9yLCBPcGVuVmlkdUVycm9yTmFtZSB9IGZyb20gJy4vT3BlblZpZHVFcnJvcic7XG5pbXBvcnQgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnd29sZnk4Ny1ldmVudGVtaXR0ZXInKTtcbmltcG9ydCAqIGFzIGt1cmVudG9VdGlscyBmcm9tICcuLi9LdXJlbnRvVXRpbHMva3VyZW50by11dGlscy1qcyc7XG5cbmltcG9ydCAqIGFzIGFkYXB0ZXIgZnJvbSAnd2VicnRjLWFkYXB0ZXInO1xuZGVjbGFyZSB2YXIgbmF2aWdhdG9yOiBhbnk7XG5kZWNsYXJlIHZhciBSVENTZXNzaW9uRGVzY3JpcHRpb246IGFueTtcblxuaWYgKHdpbmRvdykge1xuICAgIHdpbmRvd1tcImFkYXB0ZXJcIl0gPSBhZGFwdGVyO1xufVxuXG5mdW5jdGlvbiBqcShpZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gaWQucmVwbGFjZSgvKEB8OnxcXC58XFxbfFxcXXwsKS9nLCBcIlxcXFwkMVwiKTtcbn1cblxuZnVuY3Rpb24gc2hvdyhpZDogc3RyaW5nKSB7XG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoanEoaWQpKSEuc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XG59XG5cbmZ1bmN0aW9uIGhpZGUoaWQ6IHN0cmluZykge1xuICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGpxKGlkKSkhLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3RyZWFtT3B0aW9ucyB7XG4gICAgaWQ6IHN0cmluZztcbiAgICBjb25uZWN0aW9uOiBDb25uZWN0aW9uO1xuICAgIHJlY3ZWaWRlbzogYm9vbGVhbjtcbiAgICByZWN2QXVkaW86IGJvb2xlYW47XG4gICAgc2VuZFZpZGVvOiBib29sZWFuO1xuICAgIHNlbmRBdWRpbzogYm9vbGVhbjtcbiAgICBhY3RpdmVBdWRpbzogYm9vbGVhbjtcbiAgICBhY3RpdmVWaWRlbzogYm9vbGVhbjtcbiAgICBkYXRhOiBib29sZWFuO1xuICAgIG1lZGlhQ29uc3RyYWludHM6IGFueTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBWaWRlb09wdGlvbnMge1xuICAgIHRodW1iOiBzdHJpbmc7XG4gICAgdmlkZW86IEhUTUxWaWRlb0VsZW1lbnQ7XG59XG5cbmV4cG9ydCBjbGFzcyBTdHJlYW0ge1xuXG4gICAgcHVibGljIGNvbm5lY3Rpb246IENvbm5lY3Rpb247XG4gICAgcHVibGljIHN0cmVhbUlkOiBzdHJpbmc7XG4gICAgcHVibGljIGhhc1ZpZGVvOiBib29sZWFuO1xuICAgIHB1YmxpYyBoYXNBdWRpbzogYm9vbGVhbjtcbiAgICBwdWJsaWMgdHlwZU9mVmlkZW86IHN0cmluZzsgLy8gJ0NBTUVSQScgb3IgJ1NDUkVFTidcblxuICAgIGVlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICAgIHByaXZhdGUgd3JTdHJlYW06IE1lZGlhU3RyZWFtO1xuICAgIHByaXZhdGUgd3A6IGFueTtcbiAgICBwcml2YXRlIHZpZGVvOiBIVE1MVmlkZW9FbGVtZW50O1xuICAgIHByaXZhdGUgdmlkZW9FbGVtZW50czogVmlkZW9PcHRpb25zW10gPSBbXTtcbiAgICBwcml2YXRlIGVsZW1lbnRzOiBIVE1MRGl2RWxlbWVudFtdID0gW107XG4gICAgcHJpdmF0ZSBzcGVlY2hFdmVudDogYW55O1xuICAgIHByaXZhdGUgcmVjdlZpZGVvOiBib29sZWFuO1xuICAgIHByaXZhdGUgcmVjdkF1ZGlvOiBib29sZWFuO1xuICAgIHByaXZhdGUgc2VuZFZpZGVvOiBib29sZWFuO1xuICAgIHByaXZhdGUgc2VuZEF1ZGlvOiBib29sZWFuO1xuICAgIHByaXZhdGUgbWVkaWFDb25zdHJhaW50czogYW55O1xuICAgIHByaXZhdGUgc2hvd015UmVtb3RlID0gZmFsc2U7XG4gICAgcHJpdmF0ZSBsb2NhbE1pcnJvcmVkID0gZmFsc2U7XG4gICAgcHJpdmF0ZSBjaGFuSWQgPSAwO1xuICAgIHByaXZhdGUgZGF0YUNoYW5uZWw6IGJvb2xlYW47XG4gICAgcHJpdmF0ZSBkYXRhQ2hhbm5lbE9wZW5lZCA9IGZhbHNlO1xuXG4gICAgcHJpdmF0ZSBhY3RpdmVBdWRpbyA9IHRydWU7XG4gICAgcHJpdmF0ZSBhY3RpdmVWaWRlbyA9IHRydWU7XG5cbiAgICBwcml2YXRlIHZpZGVvU3JjT2JqZWN0OiBNZWRpYVN0cmVhbSB8IG51bGw7XG4gICAgcHJpdmF0ZSBwYXJlbnRJZDogc3RyaW5nO1xuICAgIHB1YmxpYyBpc1JlYWR5VG9QdWJsaXNoOiBib29sZWFuID0gZmFsc2U7XG4gICAgcHVibGljIGlzUHVibGlzaGVyUHVibGlzaGVkOiBib29sZWFuID0gZmFsc2U7XG4gICAgcHVibGljIGlzVmlkZW9FTGVtZW50Q3JlYXRlZDogYm9vbGVhbiA9IGZhbHNlO1xuICAgIHB1YmxpYyBhY2Nlc3NJc0FsbG93ZWQ6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBwdWJsaWMgYWNjZXNzSXNEZW5pZWQ6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBwdWJsaWMgaXNTY3JlZW5SZXF1ZXN0ZWRSZWFkeTogYm9vbGVhbiA9IGZhbHNlO1xuICAgIHByaXZhdGUgaXNTY3JlZW5SZXF1ZXN0ZWQgPSBmYWxzZTtcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgb3BlblZpZHU6IE9wZW5WaWR1SW50ZXJuYWwsIHByaXZhdGUgbG9jYWw6IGJvb2xlYW4sIHByaXZhdGUgcm9vbTogU2Vzc2lvbkludGVybmFsLCBvcHRpb25zOiBhbnkpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMgIT09ICdzY3JlZW4tb3B0aW9ucycpIHtcbiAgICAgICAgICAgIHRoaXMuY29uZmlndXJlT3B0aW9ucyhvcHRpb25zKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuaXNTY3JlZW5SZXF1ZXN0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uID0gdGhpcy5yb29tLmdldExvY2FsUGFydGljaXBhbnQoKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXIoJ3NyYy1hZGRlZCcsIChzcmNFdmVudCkgPT4ge1xuICAgICAgICAgICAgdGhpcy52aWRlb1NyY09iamVjdCA9IHNyY0V2ZW50LnNyY09iamVjdDtcbiAgICAgICAgICAgIGlmICh0aGlzLnZpZGVvKSB0aGlzLnZpZGVvLnNyY09iamVjdCA9IHNyY0V2ZW50LnNyY09iamVjdDtcbiAgICAgICAgICAgIGNvbnNvbGUuZGVidWcoXCJWaWRlbyBzcmNPYmplY3QgW1wiICsgc3JjRXZlbnQuc3JjT2JqZWN0ICsgXCJdIGFkZGVkIHRvIHN0cmVhbSBbXCIgKyB0aGlzLnN0cmVhbUlkICsgXCJdXCIpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBlbWl0U3JjRXZlbnQod3JzdHJlYW0pIHtcbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3NyYy1hZGRlZCcsIFt7XG4gICAgICAgICAgICBzcmNPYmplY3Q6IHdyc3RyZWFtXG4gICAgICAgIH1dKTtcbiAgICB9XG5cbiAgICBlbWl0U3RyZWFtUmVhZHlFdmVudCgpIHtcbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3N0cmVhbS1yZWFkeScpLCBbe31dO1xuICAgIH1cblxuICAgIGdldFZpZGVvU3JjT2JqZWN0KCkge1xuICAgICAgICByZXR1cm4gdGhpcy52aWRlb1NyY09iamVjdDtcbiAgICB9XG5cbiAgICByZW1vdmVWaWRlbyhwYXJlbnRFbGVtZW50OiBzdHJpbmcpO1xuICAgIHJlbW92ZVZpZGVvKHBhcmVudEVsZW1lbnQ6IEVsZW1lbnQpO1xuICAgIHJlbW92ZVZpZGVvKCk7XG5cbiAgICByZW1vdmVWaWRlbyhwYXJlbnRFbGVtZW50Pykge1xuICAgICAgICBpZiAodHlwZW9mIHBhcmVudEVsZW1lbnQgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHBhcmVudEVsZW1lbnQpIS5yZW1vdmVDaGlsZCh0aGlzLnZpZGVvKTtcbiAgICAgICAgfSBlbHNlIGlmIChwYXJlbnRFbGVtZW50IGluc3RhbmNlb2YgRWxlbWVudCkge1xuICAgICAgICAgICAgcGFyZW50RWxlbWVudC5yZW1vdmVDaGlsZCh0aGlzLnZpZGVvKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICghcGFyZW50RWxlbWVudCkge1xuICAgICAgICAgICAgaWYgKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMucGFyZW50SWQpKSB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wYXJlbnRJZCkhLnJlbW92ZUNoaWxkKHRoaXMudmlkZW8pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgZ2V0VmlkZW9FbGVtZW50KCk6IEhUTUxWaWRlb0VsZW1lbnQge1xuICAgICAgICByZXR1cm4gdGhpcy52aWRlbztcbiAgICB9XG5cbiAgICBzZXRWaWRlb0VsZW1lbnQodmlkZW86IEhUTUxWaWRlb0VsZW1lbnQpIHtcbiAgICAgICAgdGhpcy52aWRlbyA9IHZpZGVvO1xuICAgIH1cblxuICAgIGdldFJlY3ZWaWRlbygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVjdlZpZGVvO1xuICAgIH1cblxuICAgIGdldFJlY3ZBdWRpbygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVjdkF1ZGlvO1xuICAgIH1cblxuICAgIGdldFNlbmRWaWRlbygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2VuZFZpZGVvO1xuICAgIH1cblxuICAgIGdldFNlbmRBdWRpbygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2VuZEF1ZGlvO1xuICAgIH1cblxuXG4gICAgc3Vic2NyaWJlVG9NeVJlbW90ZSgpIHtcbiAgICAgICAgdGhpcy5zaG93TXlSZW1vdGUgPSB0cnVlO1xuICAgIH1cblxuICAgIGRpc3BsYXlNeVJlbW90ZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2hvd015UmVtb3RlO1xuICAgIH1cblxuICAgIG1pcnJvckxvY2FsU3RyZWFtKHdyKSB7XG4gICAgICAgIHRoaXMuc2hvd015UmVtb3RlID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5sb2NhbE1pcnJvcmVkID0gdHJ1ZTtcbiAgICAgICAgaWYgKHdyKSB7XG4gICAgICAgICAgICB0aGlzLndyU3RyZWFtID0gd3I7XG4gICAgICAgICAgICB0aGlzLmVtaXRTcmNFdmVudCh0aGlzLndyU3RyZWFtKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlzTG9jYWxNaXJyb3JlZCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxNaXJyb3JlZDtcbiAgICB9XG5cbiAgICBnZXRDaGFubmVsTmFtZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RyZWFtSWQgKyAnXycgKyB0aGlzLmNoYW5JZCsrO1xuICAgIH1cblxuXG4gICAgaXNEYXRhQ2hhbm5lbEVuYWJsZWQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRhdGFDaGFubmVsO1xuICAgIH1cblxuXG4gICAgaXNEYXRhQ2hhbm5lbE9wZW5lZCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0YUNoYW5uZWxPcGVuZWQ7XG4gICAgfVxuXG4gICAgb25EYXRhQ2hhbm5lbE9wZW4oZXZlbnQpIHtcbiAgICAgICAgY29uc29sZS5kZWJ1ZygnRGF0YSBjaGFubmVsIGlzIG9wZW5lZCcpO1xuICAgICAgICB0aGlzLmRhdGFDaGFubmVsT3BlbmVkID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBvbkRhdGFDaGFubmVsQ2xvc2VkKGV2ZW50KSB7XG4gICAgICAgIGNvbnNvbGUuZGVidWcoJ0RhdGEgY2hhbm5lbCBpcyBjbG9zZWQnKTtcbiAgICAgICAgdGhpcy5kYXRhQ2hhbm5lbE9wZW5lZCA9IGZhbHNlO1xuICAgIH1cblxuICAgIHNlbmREYXRhKGRhdGEpIHtcbiAgICAgICAgaWYgKHRoaXMud3AgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdXZWJSVEMgcGVlciBoYXMgbm90IGJlZW4gY3JlYXRlZCB5ZXQnKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMuZGF0YUNoYW5uZWxPcGVuZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRGF0YSBjaGFubmVsIGlzIG5vdCBvcGVuZWQnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmluZm8oXCJTZW5kaW5nIHRocm91Z2ggZGF0YSBjaGFubmVsOiBcIiArIGRhdGEpO1xuICAgICAgICB0aGlzLndwLnNlbmQoZGF0YSk7XG4gICAgfVxuXG4gICAgZ2V0V3JTdHJlYW0oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLndyU3RyZWFtO1xuICAgIH1cblxuICAgIGdldFdlYlJ0Y1BlZXIoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLndwO1xuICAgIH1cblxuICAgIGFkZEV2ZW50TGlzdGVuZXIoZXZlbnROYW1lOiBzdHJpbmcsIGxpc3RlbmVyOiBhbnkpIHtcbiAgICAgICAgdGhpcy5lZS5hZGRMaXN0ZW5lcihldmVudE5hbWUsIGxpc3RlbmVyKTtcbiAgICB9XG5cbiAgICBhZGRPbmNlRXZlbnRMaXN0ZW5lcihldmVudE5hbWU6IHN0cmluZywgbGlzdGVuZXI6IGFueSkge1xuICAgICAgICB0aGlzLmVlLmFkZE9uY2VMaXN0ZW5lcihldmVudE5hbWUsIGxpc3RlbmVyKTtcbiAgICB9XG5cbiAgICByZW1vdmVMaXN0ZW5lcihldmVudE5hbWUpIHtcbiAgICAgICAgdGhpcy5lZS5yZW1vdmVBbGxMaXN0ZW5lcnMoZXZlbnROYW1lKTtcbiAgICB9XG5cbiAgICBzaG93U3Bpbm5lcihzcGlubmVyUGFyZW50SWQ6IHN0cmluZykge1xuICAgICAgICBsZXQgcHJvZ3Jlc3MgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICAgcHJvZ3Jlc3MuaWQgPSAncHJvZ3Jlc3MtJyArIHRoaXMuc3RyZWFtSWQ7XG4gICAgICAgIHByb2dyZXNzLnN0eWxlLmJhY2tncm91bmQgPSBcImNlbnRlciB0cmFuc3BhcmVudCB1cmwoJ2ltZy9zcGlubmVyLmdpZicpIG5vLXJlcGVhdFwiO1xuICAgICAgICBsZXQgc3Bpbm5lclBhcmVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHNwaW5uZXJQYXJlbnRJZCk7XG4gICAgICAgIGlmIChzcGlubmVyUGFyZW50KSB7XG4gICAgICAgICAgICBzcGlubmVyUGFyZW50LmFwcGVuZENoaWxkKHByb2dyZXNzKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGhpZGVTcGlubmVyKHNwaW5uZXJJZD86IHN0cmluZykge1xuICAgICAgICBzcGlubmVySWQgPSAoc3Bpbm5lcklkID09PSB1bmRlZmluZWQpID8gdGhpcy5zdHJlYW1JZCA6IHNwaW5uZXJJZDtcbiAgICAgICAgaGlkZSgncHJvZ3Jlc3MtJyArIHNwaW5uZXJJZCk7XG4gICAgfVxuXG4gICAgcGxheU9ubHlWaWRlbyhwYXJlbnRFbGVtZW50LCB0aHVtYm5haWxJZCkge1xuXG4gICAgICAgIHRoaXMudmlkZW8gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd2aWRlbycpO1xuXG4gICAgICAgIHRoaXMudmlkZW8uaWQgPSAodGhpcy5sb2NhbCA/ICdsb2NhbC0nIDogJ3JlbW90ZS0nKSArICd2aWRlby0nICsgdGhpcy5zdHJlYW1JZDtcbiAgICAgICAgdGhpcy52aWRlby5hdXRvcGxheSA9IHRydWU7XG4gICAgICAgIHRoaXMudmlkZW8uY29udHJvbHMgPSBmYWxzZTtcbiAgICAgICAgdGhpcy52aWRlby5zcmNPYmplY3QgPSB0aGlzLnZpZGVvU3JjT2JqZWN0O1xuXG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50cy5wdXNoKHtcbiAgICAgICAgICAgIHRodW1iOiB0aHVtYm5haWxJZCxcbiAgICAgICAgICAgIHZpZGVvOiB0aGlzLnZpZGVvXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICh0aGlzLmxvY2FsICYmICF0aGlzLmRpc3BsYXlNeVJlbW90ZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnZpZGVvLm11dGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMudmlkZW8ub25jYW5wbGF5ID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkxvY2FsICdTdHJlYW0nIHdpdGggaWQgW1wiICsgdGhpcy5zdHJlYW1JZCArIFwiXSB2aWRlbyBpcyBub3cgcGxheWluZ1wiKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgndmlkZW8taXMtcGxheWluZycsIFt7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IHRoaXMudmlkZW9cbiAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy52aWRlby50aXRsZSA9IHRoaXMuc3RyZWFtSWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHBhcmVudEVsZW1lbnQgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIHRoaXMucGFyZW50SWQgPSBwYXJlbnRFbGVtZW50O1xuXG4gICAgICAgICAgICBsZXQgcGFyZW50RWxlbWVudERvbSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHBhcmVudEVsZW1lbnQpO1xuICAgICAgICAgICAgaWYgKHBhcmVudEVsZW1lbnREb20pIHtcbiAgICAgICAgICAgICAgICB0aGlzLnZpZGVvID0gcGFyZW50RWxlbWVudERvbS5hcHBlbmRDaGlsZCh0aGlzLnZpZGVvKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgndmlkZW8tZWxlbWVudC1jcmVhdGVkLWJ5LXN0cmVhbScsIFt7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IHRoaXMudmlkZW9cbiAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICAgICAgdGhpcy5pc1ZpZGVvRUxlbWVudENyZWF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5wYXJlbnRJZCA9IHBhcmVudEVsZW1lbnQuaWQ7XG4gICAgICAgICAgICB0aGlzLnZpZGVvID0gcGFyZW50RWxlbWVudC5hcHBlbmRDaGlsZCh0aGlzLnZpZGVvKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuaXNSZWFkeVRvUHVibGlzaCA9IHRydWU7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudmlkZW87XG4gICAgfVxuXG4gICAgcGxheVRodW1ibmFpbCh0aHVtYm5haWxJZCkge1xuXG4gICAgICAgIGxldCBjb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICAgY29udGFpbmVyLmNsYXNzTmFtZSA9IFwicGFydGljaXBhbnRcIjtcbiAgICAgICAgY29udGFpbmVyLmlkID0gdGhpcy5zdHJlYW1JZDtcbiAgICAgICAgbGV0IHRodW1ibmFpbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRodW1ibmFpbElkKTtcbiAgICAgICAgaWYgKHRodW1ibmFpbCkge1xuICAgICAgICAgICAgdGh1bWJuYWlsLmFwcGVuZENoaWxkKGNvbnRhaW5lcik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmVsZW1lbnRzLnB1c2goY29udGFpbmVyKTtcblxuICAgICAgICBsZXQgbmFtZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQobmFtZSk7XG4gICAgICAgIGxldCB1c2VyTmFtZSA9IHRoaXMuc3RyZWFtSWQucmVwbGFjZSgnX3dlYmNhbScsICcnKTtcbiAgICAgICAgaWYgKHVzZXJOYW1lLmxlbmd0aCA+PSAxNikge1xuICAgICAgICAgICAgdXNlck5hbWUgPSB1c2VyTmFtZS5zdWJzdHJpbmcoMCwgMTYpICsgXCIuLi5cIjtcbiAgICAgICAgfVxuICAgICAgICBuYW1lLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHVzZXJOYW1lKSk7XG4gICAgICAgIG5hbWUuaWQgPSBcIm5hbWUtXCIgKyB0aGlzLnN0cmVhbUlkO1xuICAgICAgICBuYW1lLmNsYXNzTmFtZSA9IFwibmFtZVwiO1xuICAgICAgICBuYW1lLnRpdGxlID0gdGhpcy5zdHJlYW1JZDtcblxuICAgICAgICB0aGlzLnNob3dTcGlubmVyKHRodW1ibmFpbElkKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5wbGF5T25seVZpZGVvKGNvbnRhaW5lciwgdGh1bWJuYWlsSWQpO1xuICAgIH1cblxuICAgIGdldFBhcnRpY2lwYW50KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25uZWN0aW9uO1xuICAgIH1cblxuICAgIGdldFJUQ1BlZXJDb25uZWN0aW9uKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRXZWJSdGNQZWVyKCkucGVlckNvbm5lY3Rpb247XG4gICAgfVxuXG4gICAgcmVxdWVzdENhbWVyYUFjY2VzcyhjYWxsYmFjazogQ2FsbGJhY2s8U3RyZWFtPikge1xuXG4gICAgICAgIHRoaXMuY29ubmVjdGlvbi5hZGRTdHJlYW0odGhpcyk7XG5cbiAgICAgICAgbGV0IGNvbnN0cmFpbnRzID0gdGhpcy5tZWRpYUNvbnN0cmFpbnRzO1xuXG4gICAgICAgIC8qbGV0IGNvbnN0cmFpbnRzMiA9IHtcbiAgICAgICAgICAgIGF1ZGlvOiB0cnVlLFxuICAgICAgICAgICAgdmlkZW86IHtcbiAgICAgICAgICAgICAgICB3aWR0aDoge1xuICAgICAgICAgICAgICAgICAgICBpZGVhbDogMTI4MFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZnJhbWVSYXRlOiB7XG4gICAgICAgICAgICAgICAgICAgIGlkZWFsOiAxNVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTsqL1xuXG4gICAgICAgIHRoaXMudXNlck1lZGlhSGFzVmlkZW8oKGhhc1ZpZGVvKSA9PiB7XG4gICAgICAgICAgICBpZiAoIWhhc1ZpZGVvKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc2VuZFZpZGVvKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKG5ldyBPcGVuVmlkdUVycm9yKE9wZW5WaWR1RXJyb3JOYW1lLk5PX1ZJREVPX0RFVklDRSwgJ1lvdSBoYXZlIHJlcXVlc3RlZCBjYW1lcmEgYWNjZXNzIGJ1dCB0aGVyZSBpcyBubyB2aWRlbyBpbnB1dCBkZXZpY2UgYXZhaWxhYmxlLiBUcnlpbmcgdG8gY29ubmVjdCB3aXRoIGFuIGF1ZGlvIGlucHV0IGRldmljZSBvbmx5JyksIHRoaXMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuc2VuZEF1ZGlvKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKG5ldyBPcGVuVmlkdUVycm9yKE9wZW5WaWR1RXJyb3JOYW1lLk5PX0lOUFVUX0RFVklDRSwgJ1lvdSBtdXN0IGluaXQgUHVibGlzaGVyIG9iamVjdCB3aXRoIGF1ZGlvIG9yIHZpZGVvIHN0cmVhbXMgZW5hYmxlZCcpLCB1bmRlZmluZWQpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2VuZFZpZGVvID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVxdWVzdENhbWVyYUFjY2VzQXV4KGNvbnN0cmFpbnRzLCBjYWxsYmFjayk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlcXVlc3RDYW1lcmFBY2Nlc0F1eChjb25zdHJhaW50cywgY2FsbGJhY2spO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlcXVlc3RDYW1lcmFBY2Nlc0F1eChjb25zdHJhaW50cywgY2FsbGJhY2spIHtcbiAgICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEoY29uc3RyYWludHMpXG4gICAgICAgICAgICAudGhlbih1c2VyU3RyZWFtID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbWVyYUFjY2Vzc1N1Y2Nlc3ModXNlclN0cmVhbSwgY2FsbGJhY2spO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5hY2Nlc3NJc0RlbmllZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgdGhpcy5hY2Nlc3NJc0FsbG93ZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBsZXQgZXJyb3JOYW1lOiBPcGVuVmlkdUVycm9yTmFtZTtcbiAgICAgICAgICAgICAgICBsZXQgZXJyb3JNZXNzYWdlID0gZXJyb3IudG9TdHJpbmcoKTs7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmlzU2NyZWVuUmVxdWVzdGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGVycm9yTmFtZSA9IHRoaXMuc2VuZFZpZGVvID8gT3BlblZpZHVFcnJvck5hbWUuQ0FNRVJBX0FDQ0VTU19ERU5JRUQgOiBPcGVuVmlkdUVycm9yTmFtZS5NSUNST1BIT05FX0FDQ0VTU19ERU5JRUQ7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JOYW1lID0gT3BlblZpZHVFcnJvck5hbWUuU0NSRUVOX0NBUFRVUkVfREVOSUVEOyAvLyBUaGlzIGNvZGUgaXMgb25seSByZWFjaGFibGUgZm9yIEZpcmVmb3hcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY2FsbGJhY2sobmV3IE9wZW5WaWR1RXJyb3IoZXJyb3JOYW1lLCBlcnJvck1lc3NhZ2UpLCB1bmRlZmluZWQpO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjYW1lcmFBY2Nlc3NTdWNjZXNzKHVzZXJTdHJlYW06IE1lZGlhU3RyZWFtLCBjYWxsYmFjazogRnVuY3Rpb24pIHtcbiAgICAgICAgdGhpcy5hY2Nlc3NJc0FsbG93ZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLmFjY2Vzc0lzRGVuaWVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdhY2Nlc3MtYWxsb3dlZC1ieS1wdWJsaXNoZXInKTtcblxuICAgICAgICBpZiAodXNlclN0cmVhbS5nZXRBdWRpb1RyYWNrcygpWzBdICE9IG51bGwpIHtcbiAgICAgICAgICAgIHVzZXJTdHJlYW0uZ2V0QXVkaW9UcmFja3MoKVswXS5lbmFibGVkID0gdGhpcy5hY3RpdmVBdWRpbztcbiAgICAgICAgfVxuICAgICAgICBpZiAodXNlclN0cmVhbS5nZXRWaWRlb1RyYWNrcygpWzBdICE9IG51bGwpIHtcbiAgICAgICAgICAgIHVzZXJTdHJlYW0uZ2V0VmlkZW9UcmFja3MoKVswXS5lbmFibGVkID0gdGhpcy5hY3RpdmVWaWRlbztcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMud3JTdHJlYW0gPSB1c2VyU3RyZWFtO1xuICAgICAgICB0aGlzLmVtaXRTcmNFdmVudCh0aGlzLndyU3RyZWFtKTtcblxuICAgICAgICBjYWxsYmFjayh1bmRlZmluZWQsIHRoaXMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgdXNlck1lZGlhSGFzVmlkZW8oY2FsbGJhY2spIHtcbiAgICAgICAgLy8gSWYgdGhlIHVzZXIgaXMgZ29pbmcgdG8gcHVibGlzaCBpdHMgc2NyZWVuIHRoZXJlJ3MgYSB2aWRlbyBzb3VyY2VcbiAgICAgICAgaWYgKHRoaXMuaXNTY3JlZW5SZXF1ZXN0ZWQpIHtcbiAgICAgICAgICAgIGNhbGxiYWNrKHRydWUpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gTGlzdCBhbGwgaW5wdXQgZGV2aWNlcyBhbmQgc2VyYWNoIGZvciBhIHZpZGVvIGtpbmRcbiAgICAgICAgICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZW51bWVyYXRlRGV2aWNlcygpLnRoZW4oZnVuY3Rpb24gKG1lZGlhRGV2aWNlcykge1xuICAgICAgICAgICAgICAgIHZhciB2aWRlb0lucHV0ID0gbWVkaWFEZXZpY2VzLmZpbHRlcihmdW5jdGlvbiAoZGV2aWNlSW5mbykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGV2aWNlSW5mby5raW5kID09PSAndmlkZW9pbnB1dCc7XG4gICAgICAgICAgICAgICAgfSlbMF07XG4gICAgICAgICAgICAgICAgY2FsbGJhY2sodmlkZW9JbnB1dCAhPSBudWxsKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGlzaFZpZGVvQ2FsbGJhY2soZXJyb3IsIHNkcE9mZmVyUGFyYW0sIHdwKSB7XG5cbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm4gY29uc29sZS5lcnJvcihcIihwdWJsaXNoKSBTRFAgb2ZmZXIgZXJyb3I6IFwiXG4gICAgICAgICAgICAgICAgKyBKU09OLnN0cmluZ2lmeShlcnJvcikpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc29sZS5kZWJ1ZyhcIlNlbmRpbmcgU0RQIG9mZmVyIHRvIHB1Ymxpc2ggYXMgXCJcbiAgICAgICAgICAgICsgdGhpcy5zdHJlYW1JZCwgc2RwT2ZmZXJQYXJhbSk7XG5cbiAgICAgICAgdGhpcy5vcGVuVmlkdS5zZW5kUmVxdWVzdChcInB1Ymxpc2hWaWRlb1wiLCB7XG4gICAgICAgICAgICBzZHBPZmZlcjogc2RwT2ZmZXJQYXJhbSxcbiAgICAgICAgICAgIGRvTG9vcGJhY2s6IHRoaXMuZGlzcGxheU15UmVtb3RlKCkgfHwgZmFsc2UsXG4gICAgICAgICAgICBhdWRpb0FjdGl2ZTogdGhpcy5zZW5kQXVkaW8sXG4gICAgICAgICAgICB2aWRlb0FjdGl2ZTogdGhpcy5zZW5kVmlkZW8sXG4gICAgICAgICAgICB0eXBlT2ZWaWRlbzogKCh0aGlzLnNlbmRWaWRlbykgPyAoKHRoaXMuaXNTY3JlZW5SZXF1ZXN0ZWQpID8gJ1NDUkVFTicgOidDQU1FUkEnKSA6ICcnKVxuICAgICAgICB9LCAoZXJyb3IsIHJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3Igb24gcHVibGlzaFZpZGVvOiBcIiArIEpTT04uc3RyaW5naWZ5KGVycm9yKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMucHJvY2Vzc1NkcEFuc3dlcihyZXNwb25zZS5zZHBBbnN3ZXIpO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIidQdWJsaXNoZXInIHN1Y2Nlc2Z1bGx5IHB1Ymxpc2hlZCB0byBzZXNzaW9uXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzdGFydFZpZGVvQ2FsbGJhY2soZXJyb3IsIHNkcE9mZmVyUGFyYW0sIHdwKSB7XG4gICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgcmV0dXJuIGNvbnNvbGUuZXJyb3IoXCIoc3Vic2NyaWJlKSBTRFAgb2ZmZXIgZXJyb3I6IFwiXG4gICAgICAgICAgICAgICAgKyBKU09OLnN0cmluZ2lmeShlcnJvcikpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUuZGVidWcoXCJTZW5kaW5nIFNEUCBvZmZlciB0byBzdWJzY3JpYmUgdG8gXCJcbiAgICAgICAgICAgICsgdGhpcy5zdHJlYW1JZCwgc2RwT2ZmZXJQYXJhbSk7XG4gICAgICAgIHRoaXMub3BlblZpZHUuc2VuZFJlcXVlc3QoXCJyZWNlaXZlVmlkZW9Gcm9tXCIsIHtcbiAgICAgICAgICAgIHNlbmRlcjogdGhpcy5zdHJlYW1JZCxcbiAgICAgICAgICAgIHNkcE9mZmVyOiBzZHBPZmZlclBhcmFtXG4gICAgICAgIH0sIChlcnJvciwgcmVzcG9uc2UpID0+IHtcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBvbiByZWN2VmlkZW9Gcm9tOiBcIiArIEpTT04uc3RyaW5naWZ5KGVycm9yKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMucHJvY2Vzc1NkcEFuc3dlcihyZXNwb25zZS5zZHBBbnN3ZXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGluaXRXZWJSdGNQZWVyKHNkcE9mZmVyQ2FsbGJhY2spIHtcbiAgICAgICAgaWYgKHRoaXMubG9jYWwpIHtcblxuICAgICAgICAgICAgbGV0IHVzZXJNZWRpYUNvbnN0cmFpbnRzID0ge1xuICAgICAgICAgICAgICAgIGF1ZGlvOiB0aGlzLnNlbmRBdWRpbyxcbiAgICAgICAgICAgICAgICB2aWRlbzogdGhpcy5zZW5kVmlkZW9cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IG9wdGlvbnM6IGFueSA9IHtcbiAgICAgICAgICAgICAgICB2aWRlb1N0cmVhbTogdGhpcy53clN0cmVhbSxcbiAgICAgICAgICAgICAgICBtZWRpYUNvbnN0cmFpbnRzOiB1c2VyTWVkaWFDb25zdHJhaW50cyxcbiAgICAgICAgICAgICAgICBvbmljZWNhbmRpZGF0ZTogdGhpcy5jb25uZWN0aW9uLnNlbmRJY2VDYW5kaWRhdGUuYmluZCh0aGlzLmNvbm5lY3Rpb24pLFxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5kYXRhQ2hhbm5lbCkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZGF0YUNoYW5uZWxDb25maWcgPSB7XG4gICAgICAgICAgICAgICAgICAgIGlkOiB0aGlzLmdldENoYW5uZWxOYW1lKCksXG4gICAgICAgICAgICAgICAgICAgIG9ub3BlbjogdGhpcy5vbkRhdGFDaGFubmVsT3BlbixcbiAgICAgICAgICAgICAgICAgICAgb25jbG9zZTogdGhpcy5vbkRhdGFDaGFubmVsQ2xvc2VkXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmRhdGFDaGFubmVscyA9IHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLmRpc3BsYXlNeVJlbW90ZSgpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy53cCA9IGt1cmVudG9VdGlscy5XZWJSdGNQZWVyLldlYlJ0Y1BlZXJTZW5kcmVjdihvcHRpb25zLCBlcnJvciA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRoaXMud3AuZ2VuZXJhdGVPZmZlcihzZHBPZmZlckNhbGxiYWNrLmJpbmQodGhpcykpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLndwID0ga3VyZW50b1V0aWxzLldlYlJ0Y1BlZXIuV2ViUnRjUGVlclNlbmRvbmx5KG9wdGlvbnMsIGVycm9yID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdGhpcy53cC5nZW5lcmF0ZU9mZmVyKHNkcE9mZmVyQ2FsbGJhY2suYmluZCh0aGlzKSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmlzUHVibGlzaGVyUHVibGlzaGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdzdHJlYW0tY3JlYXRlZC1ieS1wdWJsaXNoZXInKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGxldCBvZmZlckNvbnN0cmFpbnRzID0ge1xuICAgICAgICAgICAgICAgIGF1ZGlvOiB0aGlzLnJlY3ZBdWRpbyxcbiAgICAgICAgICAgICAgICB2aWRlbzogdGhpcy5yZWN2VmlkZW9cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zb2xlLmRlYnVnKFwiJ1Nlc3Npb24uc3Vic2NyaWJlKFN0cmVhbSknIGNhbGxlZC4gQ29uc3RyYWludHMgb2YgZ2VuZXJhdGUgU0RQIG9mZmVyXCIsXG4gICAgICAgICAgICAgICAgb2ZmZXJDb25zdHJhaW50cyk7XG4gICAgICAgICAgICBsZXQgb3B0aW9ucyA9IHtcbiAgICAgICAgICAgICAgICBvbmljZWNhbmRpZGF0ZTogdGhpcy5jb25uZWN0aW9uLnNlbmRJY2VDYW5kaWRhdGUuYmluZCh0aGlzLmNvbm5lY3Rpb24pLFxuICAgICAgICAgICAgICAgIG1lZGlhQ29uc3RyYWludHM6IG9mZmVyQ29uc3RyYWludHNcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMud3AgPSBrdXJlbnRvVXRpbHMuV2ViUnRjUGVlci5XZWJSdGNQZWVyUmVjdm9ubHkob3B0aW9ucywgZXJyb3IgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMud3AuZ2VuZXJhdGVPZmZlcihzZHBPZmZlckNhbGxiYWNrLmJpbmQodGhpcykpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc29sZS5kZWJ1ZyhcIldhaXRpbmcgZm9yIFNEUCBvZmZlciB0byBiZSBnZW5lcmF0ZWQgKFwiXG4gICAgICAgICAgICArICh0aGlzLmxvY2FsID8gXCJsb2NhbFwiIDogXCJyZW1vdGVcIikgKyBcIiAnU3RyZWFtJzogXCIgKyB0aGlzLnN0cmVhbUlkICsgXCIpXCIpO1xuICAgIH1cblxuICAgIHB1Ymxpc2goKSB7XG5cbiAgICAgICAgLy8gRklYTUU6IFRocm93IGVycm9yIHdoZW4gc3RyZWFtIGlzIG5vdCBsb2NhbFxuICAgICAgICBpZiAodGhpcy5pc1JlYWR5VG9QdWJsaXNoKSB7XG4gICAgICAgICAgICB0aGlzLmluaXRXZWJSdGNQZWVyKHRoaXMucHVibGlzaFZpZGVvQ2FsbGJhY2spO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5lZS5vbmNlKCdzdHJlYW0tcmVhZHknLCBzdHJlYW1FdmVudCA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5wdWJsaXNoKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEZJWE1FOiBOb3cgd2UgaGF2ZSBjb3VwbGVkIGNvbm5lY3RpbmcgdG8gYSByb29tIGFuZCBhZGRpbmcgYVxuICAgICAgICAvLyBzdHJlYW0gdG8gdGhpcyByb29tLiBCdXQgaW4gdGhlIG5ldyBBUEksIHRoZXJlIGFyZSB0d28gc3RlcHMuXG4gICAgICAgIC8vIFRoaXMgaXMgdGhlIHNlY29uZCBzdGVwLiBGb3Igbm93LCBpdCBkbyBub3RoaW5nLlxuXG4gICAgfVxuXG4gICAgc3Vic2NyaWJlKCkge1xuXG4gICAgICAgIC8vIEZJWE1FOiBJbiB0aGUgY3VycmVudCBpbXBsZW1lbnRhdGlvbiBhbGwgcGFydGljaXBhbnRzIGFyZSBzdWJzY3JpYmVkXG4gICAgICAgIC8vIGF1dG9tYXRpY2FsbHkgdG8gYWxsIG90aGVyIHBhcnRpY2lwYW50cy4gV2UgdXNlIHRoaXMgbWV0aG9kIG9ubHkgdG9cbiAgICAgICAgLy8gbmVnb3RpYXRlIFNEUFxuXG4gICAgICAgIHRoaXMuaW5pdFdlYlJ0Y1BlZXIodGhpcy5zdGFydFZpZGVvQ2FsbGJhY2spO1xuICAgIH1cblxuICAgIHByb2Nlc3NTZHBBbnN3ZXIoc2RwQW5zd2VyKSB7XG5cbiAgICAgICAgbGV0IGFuc3dlciA9IG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgICAgICAgdHlwZTogJ2Fuc3dlcicsXG4gICAgICAgICAgICBzZHA6IHNkcEFuc3dlcixcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnNvbGUuZGVidWcodGhpcy5zdHJlYW1JZCArIFwiOiBzZXQgcGVlciBjb25uZWN0aW9uIHdpdGggcmVjdmQgU0RQIGFuc3dlclwiLFxuICAgICAgICAgICAgc2RwQW5zd2VyKTtcbiAgICAgICAgbGV0IHBhcnRpY2lwYW50SWQgPSB0aGlzLnN0cmVhbUlkO1xuICAgICAgICBsZXQgcGMgPSB0aGlzLndwLnBlZXJDb25uZWN0aW9uO1xuICAgICAgICBwYy5zZXRSZW1vdGVEZXNjcmlwdGlvbihhbnN3ZXIsICgpID0+IHtcbiAgICAgICAgICAgIC8vIEF2b2lkcyB0byBzdWJzY3JpYmUgdG8geW91ciBvd24gc3RyZWFtIHJlbW90ZWx5IFxuICAgICAgICAgICAgLy8gZXhjZXB0IHdoZW4gc2hvd015UmVtb3RlIGlzIHRydWVcbiAgICAgICAgICAgIGlmICghdGhpcy5sb2NhbCB8fCB0aGlzLmRpc3BsYXlNeVJlbW90ZSgpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy53clN0cmVhbSA9IHBjLmdldFJlbW90ZVN0cmVhbXMoKVswXTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmRlYnVnKFwiUGVlciByZW1vdGUgc3RyZWFtXCIsIHRoaXMud3JTdHJlYW0pO1xuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMud3JTdHJlYW0gIT0gdW5kZWZpbmVkKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lbWl0U3JjRXZlbnQodGhpcy53clN0cmVhbSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMud3JTdHJlYW0uZ2V0QXVkaW9UcmFja3MoKVswXSAhPSBudWxsKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3BlZWNoRXZlbnQgPSBrdXJlbnRvVXRpbHMuV2ViUnRjUGVlci5oYXJrKHRoaXMud3JTdHJlYW0sIHsgdGhyZXNob2xkOiB0aGlzLnJvb20udGhyZXNob2xkU3BlYWtlciB9KTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zcGVlY2hFdmVudC5vbignc3BlYWtpbmcnLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy90aGlzLnJvb20uYWRkUGFydGljaXBhbnRTcGVha2luZyhwYXJ0aWNpcGFudElkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJvb20uZW1pdEV2ZW50KCdwdWJsaXNoZXJTdGFydFNwZWFraW5nJywgW3tcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGlvbjogdGhpcy5jb25uZWN0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJlYW1JZDogdGhpcy5zdHJlYW1JZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNwZWVjaEV2ZW50Lm9uKCdzdG9wcGVkX3NwZWFraW5nJywgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcy5yb29tLnJlbW92ZVBhcnRpY2lwYW50U3BlYWtpbmcocGFydGljaXBhbnRJZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yb29tLmVtaXRFdmVudCgncHVibGlzaGVyU3RvcFNwZWFraW5nJywgW3tcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGlvbjogdGhpcy5jb25uZWN0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJlYW1JZDogdGhpcy5zdHJlYW1JZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgdmlkZW9FbGVtZW50IG9mIHRoaXMudmlkZW9FbGVtZW50cykge1xuICAgICAgICAgICAgICAgICAgICBsZXQgdGh1bWJuYWlsSWQgPSB2aWRlb0VsZW1lbnQudGh1bWI7XG4gICAgICAgICAgICAgICAgICAgIGxldCB2aWRlbyA9IHZpZGVvRWxlbWVudC52aWRlbztcbiAgICAgICAgICAgICAgICAgICAgdmlkZW8uc3JjT2JqZWN0ID0gdGhpcy53clN0cmVhbTtcbiAgICAgICAgICAgICAgICAgICAgdmlkZW8ub25jYW5wbGF5ID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMubG9jYWwgJiYgdGhpcy5kaXNwbGF5TXlSZW1vdGUoKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIllvdXIgb3duIHJlbW90ZSAnU3RyZWFtJyB3aXRoIGlkIFtcIiArIHRoaXMuc3RyZWFtSWQgKyBcIl0gdmlkZW8gaXMgbm93IHBsYXlpbmdcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3JlbW90ZS12aWRlby1pcy1wbGF5aW5nJywgW3tcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudDogdmlkZW9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCF0aGlzLmxvY2FsICYmICF0aGlzLmRpc3BsYXlNeVJlbW90ZSgpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiUmVtb3RlICdTdHJlYW0nIHdpdGggaWQgW1wiICsgdGhpcy5zdHJlYW1JZCArIFwiXSB2aWRlbyBpcyBub3cgcGxheWluZ1wiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgndmlkZW8taXMtcGxheWluZycsIFt7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IHZpZGVvXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgLy9zaG93KHRodW1ibmFpbElkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcy5oaWRlU3Bpbm5lcih0aGlzLnN0cmVhbUlkKTtcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5yb29tLmVtaXRFdmVudCgnc3RyZWFtLXN1YnNjcmliZWQnLCBbe1xuICAgICAgICAgICAgICAgICAgICBzdHJlYW06IHRoaXNcbiAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIGVycm9yID0+IHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IodGhpcy5zdHJlYW1JZCArIFwiOiBFcnJvciBzZXR0aW5nIFNEUCB0byB0aGUgcGVlciBjb25uZWN0aW9uOiBcIlxuICAgICAgICAgICAgICAgICsgSlNPTi5zdHJpbmdpZnkoZXJyb3IpKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgdW5wdWJsaXNoKCkge1xuICAgICAgICBpZiAodGhpcy53cCkge1xuICAgICAgICAgICAgdGhpcy53cC5kaXNwb3NlKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAodGhpcy53clN0cmVhbSkge1xuICAgICAgICAgICAgICAgIHRoaXMud3JTdHJlYW0uZ2V0QXVkaW9UcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uICh0cmFjaykge1xuICAgICAgICAgICAgICAgICAgICB0cmFjay5zdG9wICYmIHRyYWNrLnN0b3AoKVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgdGhpcy53clN0cmVhbS5nZXRWaWRlb1RyYWNrcygpLmZvckVhY2goZnVuY3Rpb24gKHRyYWNrKSB7XG4gICAgICAgICAgICAgICAgICAgIHRyYWNrLnN0b3AgJiYgdHJhY2suc3RvcCgpXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLnNwZWVjaEV2ZW50KSB7XG4gICAgICAgICAgICB0aGlzLnNwZWVjaEV2ZW50LnN0b3AoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnNvbGUuaW5mbyh0aGlzLnN0cmVhbUlkICsgXCI6IFN0cmVhbSAnXCIgKyB0aGlzLnN0cmVhbUlkICsgXCInIHVucHVibGlzaGVkXCIpO1xuICAgIH1cblxuICAgIGRpc3Bvc2UoKSB7XG5cbiAgICAgICAgZnVuY3Rpb24gZGlzcG9zZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICAgICAgaWYgKGVsZW1lbnQgJiYgZWxlbWVudC5wYXJlbnROb2RlKSB7XG4gICAgICAgICAgICAgICAgZWxlbWVudC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGVsZW1lbnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5lbGVtZW50cy5mb3JFYWNoKGUgPT4gZGlzcG9zZUVsZW1lbnQoZSkpO1xuXG4gICAgICAgIC8vdGhpcy52aWRlb0VsZW1lbnRzLmZvckVhY2godmUgPT4gZGlzcG9zZUVsZW1lbnQodmUudmlkZW8pKTtcblxuICAgICAgICBkaXNwb3NlRWxlbWVudChcInByb2dyZXNzLVwiICsgdGhpcy5zdHJlYW1JZCk7XG5cbiAgICAgICAgaWYgKHRoaXMud3ApIHtcbiAgICAgICAgICAgIHRoaXMud3AuZGlzcG9zZSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKHRoaXMud3JTdHJlYW0pIHtcbiAgICAgICAgICAgICAgICB0aGlzLndyU3RyZWFtLmdldEF1ZGlvVHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbiAodHJhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgdHJhY2suc3RvcCAmJiB0cmFjay5zdG9wKClcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIHRoaXMud3JTdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uICh0cmFjaykge1xuICAgICAgICAgICAgICAgICAgICB0cmFjay5zdG9wICYmIHRyYWNrLnN0b3AoKVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5zcGVlY2hFdmVudCkge1xuICAgICAgICAgICAgdGhpcy5zcGVlY2hFdmVudC5zdG9wKCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmluZm8oKHRoaXMubG9jYWwgPyBcIkxvY2FsIFwiIDogXCJSZW1vdGUgXCIpICsgXCInU3RyZWFtJyB3aXRoIGlkIFtcIiArIHRoaXMuc3RyZWFtSWQgKyBcIl0nIGhhcyBiZWVuIHN1Y2Nlc2Z1bGx5IGRpc3Bvc2VkXCIpO1xuICAgIH1cblxuICAgIHByaXZhdGUgY29uZmlndXJlT3B0aW9ucyhvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICB0aGlzLnN0cmVhbUlkID0gb3B0aW9ucy5pZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuc3RyZWFtSWQgPSBcIldFQkNBTVwiO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY29ubmVjdGlvbiA9IG9wdGlvbnMuY29ubmVjdGlvbjtcbiAgICAgICAgdGhpcy5yZWN2VmlkZW8gPSBvcHRpb25zLnJlY3ZWaWRlbyB8fCBmYWxzZTtcbiAgICAgICAgdGhpcy5yZWN2QXVkaW8gPSBvcHRpb25zLnJlY3ZBdWRpbyB8fCBmYWxzZTtcbiAgICAgICAgdGhpcy5zZW5kVmlkZW8gPSBvcHRpb25zLnNlbmRWaWRlbztcbiAgICAgICAgdGhpcy5zZW5kQXVkaW8gPSBvcHRpb25zLnNlbmRBdWRpbztcbiAgICAgICAgdGhpcy5hY3RpdmVBdWRpbyA9IG9wdGlvbnMuYWN0aXZlQXVkaW87XG4gICAgICAgIHRoaXMuYWN0aXZlVmlkZW8gPSBvcHRpb25zLmFjdGl2ZVZpZGVvO1xuICAgICAgICB0aGlzLmRhdGFDaGFubmVsID0gb3B0aW9ucy5kYXRhIHx8IGZhbHNlO1xuICAgICAgICB0aGlzLm1lZGlhQ29uc3RyYWludHMgPSBvcHRpb25zLm1lZGlhQ29uc3RyYWludHM7XG5cbiAgICAgICAgdGhpcy5oYXNBdWRpbyA9ICgodGhpcy5yZWN2QXVkaW8gfHwgdGhpcy5zZW5kQXVkaW8pICE9IHVuZGVmaW5lZCkgPyAodGhpcy5yZWN2QXVkaW8gfHwgdGhpcy5zZW5kQXVkaW8pIDogZmFsc2U7XG4gICAgICAgIHRoaXMuaGFzVmlkZW8gPSAoKHRoaXMucmVjdlZpZGVvIHx8IHRoaXMuc2VuZFZpZGVvKSAhPSB1bmRlZmluZWQpID8gKHRoaXMucmVjdlZpZGVvIHx8IHRoaXMuc2VuZFZpZGVvKSA6IGZhbHNlO1xuICAgICAgICB0aGlzLnR5cGVPZlZpZGVvID0gb3B0aW9ucy50eXBlT2ZWaWRlbztcbiAgICB9XG5cbiAgICBjb25maWd1cmVTY3JlZW5PcHRpb25zKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHRoaXMuc3RyZWFtSWQgPSBvcHRpb25zLmlkO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zdHJlYW1JZCA9IFwiU0NSRUVOXCI7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5yZWN2VmlkZW8gPSBvcHRpb25zLnJlY3ZWaWRlbyB8fCBmYWxzZTtcbiAgICAgICAgdGhpcy5yZWN2QXVkaW8gPSBvcHRpb25zLnJlY3ZBdWRpbyB8fCBmYWxzZTtcbiAgICAgICAgdGhpcy5zZW5kVmlkZW8gPSBvcHRpb25zLnNlbmRWaWRlbztcbiAgICAgICAgdGhpcy5zZW5kQXVkaW8gPSBvcHRpb25zLnNlbmRBdWRpbztcbiAgICAgICAgdGhpcy5hY3RpdmVBdWRpbyA9IG9wdGlvbnMuYWN0aXZlQXVkaW87XG4gICAgICAgIHRoaXMuYWN0aXZlVmlkZW8gPSBvcHRpb25zLmFjdGl2ZVZpZGVvO1xuICAgICAgICB0aGlzLmRhdGFDaGFubmVsID0gb3B0aW9ucy5kYXRhIHx8IGZhbHNlO1xuICAgICAgICB0aGlzLm1lZGlhQ29uc3RyYWludHMgPSBvcHRpb25zLm1lZGlhQ29uc3RyYWludHM7XG5cbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2Nhbi1yZXF1ZXN0LXNjcmVlbicpO1xuICAgIH1cbn1cbiIsIi8vIExhc3QgdGltZSB1cGRhdGVkIGF0IEZlYiAxNiwgMjAxNywgMDg6MzI6MjNcblxuLy8gTGF0ZXN0IGZpbGUgY2FuIGJlIGZvdW5kIGhlcmU6IGh0dHBzOi8vY2RuLndlYnJ0Yy1leHBlcmltZW50LmNvbS9nZXRTY3JlZW5JZC5qc1xuXG4vLyBNdWF6IEtoYW4gICAgICAgICAtIHd3dy5NdWF6S2hhbi5jb21cbi8vIE1JVCBMaWNlbnNlICAgICAgIC0gd3d3LldlYlJUQy1FeHBlcmltZW50LmNvbS9saWNlbmNlXG4vLyBEb2N1bWVudGF0aW9uICAgICAtIGh0dHBzOi8vZ2l0aHViLmNvbS9tdWF6LWtoYW4vZ2V0U2NyZWVuSWQuXG5cbi8vIF9fX19fX19fX19fX19fXG4vLyBnZXRTY3JlZW5JZC5qc1xuXG4vKlxuZ2V0U2NyZWVuSWQoZnVuY3Rpb24gKGVycm9yLCBzb3VyY2VJZCwgc2NyZWVuX2NvbnN0cmFpbnRzKSB7XG4gICAgLy8gZXJyb3IgICAgPT0gbnVsbCB8fCAncGVybWlzc2lvbi1kZW5pZWQnIHx8ICdub3QtaW5zdGFsbGVkJyB8fCAnaW5zdGFsbGVkLWRpc2FibGVkJyB8fCAnbm90LWNocm9tZSdcbiAgICAvLyBzb3VyY2VJZCA9PSBudWxsIHx8ICdzdHJpbmcnIHx8ICdmaXJlZm94J1xuICAgIFxuICAgIGlmKHNvdXJjZUlkID09ICdmaXJlZm94Jykge1xuICAgICAgICBuYXZpZ2F0b3IubW96R2V0VXNlck1lZGlhKHNjcmVlbl9jb25zdHJhaW50cywgb25TdWNjZXNzLCBvbkZhaWx1cmUpO1xuICAgIH1cbiAgICBlbHNlIG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEoc2NyZWVuX2NvbnN0cmFpbnRzLCBvblN1Y2Nlc3MsIG9uRmFpbHVyZSk7XG59KTtcbiovXG5cbndpbmRvdy5nZXRTY3JlZW5JZCA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgIC8vIGZvciBGaXJlZm94OlxuICAgIC8vIHNvdXJjZUlkID09ICdmaXJlZm94J1xuICAgIC8vIHNjcmVlbl9jb25zdHJhaW50cyA9IHsuLi59XG4gICAgaWYgKCEhbmF2aWdhdG9yLm1vekdldFVzZXJNZWRpYSkge1xuICAgICAgICBjYWxsYmFjayhudWxsLCAnZmlyZWZveCcsIHtcbiAgICAgICAgICAgIHZpZGVvOiB7XG4gICAgICAgICAgICAgICAgbW96TWVkaWFTb3VyY2U6ICd3aW5kb3cnLFxuICAgICAgICAgICAgICAgIG1lZGlhU291cmNlOiAnd2luZG93J1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgb25JRnJhbWVDYWxsYmFjayk7XG5cbiAgICBmdW5jdGlvbiBvbklGcmFtZUNhbGxiYWNrKGV2ZW50KSB7XG4gICAgICAgIGlmICghZXZlbnQuZGF0YSkgcmV0dXJuO1xuXG4gICAgICAgIGlmIChldmVudC5kYXRhLmNocm9tZU1lZGlhU291cmNlSWQpIHtcbiAgICAgICAgICAgIGlmIChldmVudC5kYXRhLmNocm9tZU1lZGlhU291cmNlSWQgPT09ICdQZXJtaXNzaW9uRGVuaWVkRXJyb3InKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soJ3Blcm1pc3Npb24tZGVuaWVkJyk7XG4gICAgICAgICAgICB9IGVsc2UgY2FsbGJhY2sobnVsbCwgZXZlbnQuZGF0YS5jaHJvbWVNZWRpYVNvdXJjZUlkLCBnZXRTY3JlZW5Db25zdHJhaW50cyhudWxsLCBldmVudC5kYXRhLmNocm9tZU1lZGlhU291cmNlSWQpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChldmVudC5kYXRhLmNocm9tZUV4dGVuc2lvblN0YXR1cykge1xuICAgICAgICAgICAgY2FsbGJhY2soZXZlbnQuZGF0YS5jaHJvbWVFeHRlbnNpb25TdGF0dXMsIG51bGwsIGdldFNjcmVlbkNvbnN0cmFpbnRzKGV2ZW50LmRhdGEuY2hyb21lRXh0ZW5zaW9uU3RhdHVzKSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB0aGlzIGV2ZW50IGxpc3RlbmVyIGlzIG5vIG1vcmUgbmVlZGVkXG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgb25JRnJhbWVDYWxsYmFjayk7XG4gICAgfVxuXG4gICAgc2V0VGltZW91dChwb3N0R2V0U291cmNlSWRNZXNzYWdlLCAxMDApO1xufTtcblxuZnVuY3Rpb24gZ2V0U2NyZWVuQ29uc3RyYWludHMoZXJyb3IsIHNvdXJjZUlkKSB7XG4gICAgdmFyIHNjcmVlbl9jb25zdHJhaW50cyA9IHtcbiAgICAgICAgYXVkaW86IGZhbHNlLFxuICAgICAgICB2aWRlbzoge1xuICAgICAgICAgICAgbWFuZGF0b3J5OiB7XG4gICAgICAgICAgICAgICAgY2hyb21lTWVkaWFTb3VyY2U6IGVycm9yID8gJ3NjcmVlbicgOiAnZGVza3RvcCcsXG4gICAgICAgICAgICAgICAgbWF4V2lkdGg6IHdpbmRvdy5zY3JlZW4ud2lkdGggPiAxOTIwID8gd2luZG93LnNjcmVlbi53aWR0aCA6IDE5MjAsXG4gICAgICAgICAgICAgICAgbWF4SGVpZ2h0OiB3aW5kb3cuc2NyZWVuLmhlaWdodCA+IDEwODAgPyB3aW5kb3cuc2NyZWVuLmhlaWdodCA6IDEwODBcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvcHRpb25hbDogW11cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBpZiAoc291cmNlSWQpIHtcbiAgICAgICAgc2NyZWVuX2NvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5jaHJvbWVNZWRpYVNvdXJjZUlkID0gc291cmNlSWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNjcmVlbl9jb25zdHJhaW50cztcbn1cblxuZnVuY3Rpb24gcG9zdEdldFNvdXJjZUlkTWVzc2FnZSgpIHtcbiAgICBpZiAoIWlmcmFtZSkge1xuICAgICAgICBsb2FkSUZyYW1lKHBvc3RHZXRTb3VyY2VJZE1lc3NhZ2UpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFpZnJhbWUuaXNMb2FkZWQpIHtcbiAgICAgICAgc2V0VGltZW91dChwb3N0R2V0U291cmNlSWRNZXNzYWdlLCAxMDApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cucG9zdE1lc3NhZ2Uoe1xuICAgICAgICBjYXB0dXJlU291cmNlSWQ6IHRydWVcbiAgICB9LCAnKicpO1xufVxuXG52YXIgaWZyYW1lO1xuXG4vLyB0aGlzIGZ1bmN0aW9uIGlzIHVzZWQgaW4gUlRDTXVsdGlDb25uZWN0aW9uIHYzXG53aW5kb3cuZ2V0U2NyZWVuQ29uc3RyYWludHMgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICBsb2FkSUZyYW1lKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgZ2V0U2NyZWVuSWQoZnVuY3Rpb24gKGVycm9yLCBzb3VyY2VJZCwgc2NyZWVuX2NvbnN0cmFpbnRzKSB7XG4gICAgICAgICAgICBjYWxsYmFjayhlcnJvciwgc2NyZWVuX2NvbnN0cmFpbnRzLnZpZGVvKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59O1xuXG5mdW5jdGlvbiBsb2FkSUZyYW1lKGxvYWRDYWxsYmFjaykge1xuICAgIGlmIChpZnJhbWUpIHtcbiAgICAgICAgbG9hZENhbGxiYWNrKCk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZnJhbWUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpZnJhbWUnKTtcbiAgICBpZnJhbWUub25sb2FkID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZnJhbWUuaXNMb2FkZWQgPSB0cnVlO1xuXG4gICAgICAgIGxvYWRDYWxsYmFjaygpO1xuICAgIH07XG4gICAgaWZyYW1lLnNyYyA9ICdodHRwczovL3d3dy53ZWJydGMtZXhwZXJpbWVudC5jb20vZ2V0U291cmNlSWQvJzsgLy8gaHR0cHM6Ly93d3d3LnlvdXJkb21haW4uY29tL2dldFNjcmVlbklkLmh0bWxcbiAgICBpZnJhbWUuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAoZG9jdW1lbnQuYm9keSB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQpLmFwcGVuZENoaWxkKGlmcmFtZSk7XG59XG5cbndpbmRvdy5nZXRDaHJvbWVFeHRlbnNpb25TdGF0dXMgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICAvLyBmb3IgRmlyZWZveDpcbiAgICBpZiAoISFuYXZpZ2F0b3IubW96R2V0VXNlck1lZGlhKSB7XG4gICAgICAgIGNhbGxiYWNrKCdpbnN0YWxsZWQtZW5hYmxlZCcpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBvbklGcmFtZUNhbGxiYWNrKTtcblxuICAgIGZ1bmN0aW9uIG9uSUZyYW1lQ2FsbGJhY2soZXZlbnQpIHtcbiAgICAgICAgaWYgKCFldmVudC5kYXRhKSByZXR1cm47XG5cbiAgICAgICAgaWYgKGV2ZW50LmRhdGEuY2hyb21lRXh0ZW5zaW9uU3RhdHVzKSB7XG4gICAgICAgICAgICBjYWxsYmFjayhldmVudC5kYXRhLmNocm9tZUV4dGVuc2lvblN0YXR1cyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB0aGlzIGV2ZW50IGxpc3RlbmVyIGlzIG5vIG1vcmUgbmVlZGVkXG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgb25JRnJhbWVDYWxsYmFjayk7XG4gICAgfVxuXG4gICAgc2V0VGltZW91dChwb3N0R2V0Q2hyb21lRXh0ZW5zaW9uU3RhdHVzTWVzc2FnZSwgMTAwKTtcbn07XG5cbmZ1bmN0aW9uIHBvc3RHZXRDaHJvbWVFeHRlbnNpb25TdGF0dXNNZXNzYWdlKCkge1xuICAgIGlmICghaWZyYW1lKSB7XG4gICAgICAgIGxvYWRJRnJhbWUocG9zdEdldENocm9tZUV4dGVuc2lvblN0YXR1c01lc3NhZ2UpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFpZnJhbWUuaXNMb2FkZWQpIHtcbiAgICAgICAgc2V0VGltZW91dChwb3N0R2V0Q2hyb21lRXh0ZW5zaW9uU3RhdHVzTWVzc2FnZSwgMTAwKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmcmFtZS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKHtcbiAgICAgICAgZ2V0Q2hyb21lRXh0ZW5zaW9uU3RhdHVzOiB0cnVlXG4gICAgfSwgJyonKTtcbn1cblxuZXhwb3J0cy5nZXRTY3JlZW5JZCA9IGdldFNjcmVlbklkO1xuZXhwb3J0cy5nZXRDaHJvbWVFeHRlbnNpb25TdGF0dXMgPSBnZXRDaHJvbWVFeHRlbnNpb25TdGF0dXM7XG4iXX0=