@opentok/client 2.23.4 → 2.23.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/js/opentok.d.ts +14 -10
- package/dist/js/opentok.js +589 -271
- package/dist/js/opentok.js.map +1 -1
- package/dist/js/opentok.min.js +5 -5
- package/dist/js/opentok.min.js.map +1 -1
- package/package.json +1 -1
package/dist/js/opentok.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license OpenTok.js 2.23.
|
|
2
|
+
* @license OpenTok.js 2.23.6 388a3eb5a
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) 2010-2022 TokBox, Inc.
|
|
5
5
|
* Subject to the applicable Software Development Kit (SDK) License Agreement:
|
|
6
6
|
* https://www.vonage.com/legal/communications-apis/terms-of-use/
|
|
7
7
|
*
|
|
8
|
-
* Date:
|
|
8
|
+
* Date: Tue, 27 Sep 2022 19:18:37 GMT
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
@@ -1499,6 +1499,8 @@ module.exports = {
|
|
|
1499
1499
|
SCREEN_SHARING_NOT_SUPPORTED: 'OT_SCREEN_SHARING_NOT_SUPPORTED',
|
|
1500
1500
|
// The WebRTC connection failed during setDescription.
|
|
1501
1501
|
SET_REMOTE_DESCRIPTION_FAILED: 'OT_SET_REMOTE_DESCRIPTION_FAILED',
|
|
1502
|
+
// Setting the ICE configuration failed.
|
|
1503
|
+
FAILED_SET_CONFIGURATION: 'OT_FAILED_SET_CONFIGURATION',
|
|
1502
1504
|
// Rumor.Socket cannot connect when it is already connecting or connected.
|
|
1503
1505
|
SOCKET_ALREADY_CONNECTED_CONNECTING: 'OT_SOCKET_ALREADY_CONNECTED_CONNECTING',
|
|
1504
1506
|
// A connection was closed abnormally (that is, with no close frame being sent) when a status code
|
|
@@ -4794,7 +4796,7 @@ module.exports = function EventsFactory(deps) {
|
|
|
4794
4796
|
});
|
|
4795
4797
|
};
|
|
4796
4798
|
|
|
4797
|
-
Events.
|
|
4799
|
+
Events.CaptionReceivedEvent = function CaptionReceivedEvent(caption, streamId) {
|
|
4798
4800
|
return new Event('caption', false, {
|
|
4799
4801
|
caption,
|
|
4800
4802
|
streamId
|
|
@@ -5534,7 +5536,7 @@ module.exports = {
|
|
|
5534
5536
|
SUBSCRIBER_DESTROYED: 'destroyed',
|
|
5535
5537
|
SUBSCRIBER_CONNECTED: 'connected',
|
|
5536
5538
|
SUBSCRIBER_DISCONNECTED: 'disconnected',
|
|
5537
|
-
|
|
5539
|
+
SUBSCRIBER_CAPTION_RECEIVED: 'captionReceived',
|
|
5538
5540
|
// DeviceManager Events
|
|
5539
5541
|
DEVICES_DETECTED: 'devicesDetected',
|
|
5540
5542
|
// DevicePanel Events
|
|
@@ -6451,7 +6453,7 @@ const _require = __webpack_require__(138),
|
|
|
6451
6453
|
/** @type builtInConfig */
|
|
6452
6454
|
|
|
6453
6455
|
|
|
6454
|
-
const builtInConfig = cloneDeep({"version":"v2.23.
|
|
6456
|
+
const builtInConfig = cloneDeep({"version":"v2.23.6","buildHash":"388a3eb5a","minimumVersion":{"firefox":52,"chrome":49},"debug":"false","websiteURL":"http://www.tokbox.com","configURL":"https://config.opentok.com","ipWhitelistConfigURL":"","cdnURL":"https://static.opentok.com","loggingURL":"https://hlg.tokbox.com/prod","apiURL":"https://anvil.opentok.com"});
|
|
6455
6457
|
const whitelistAllowedRuntimeProperties = pick(['apiURL', 'assetURL', 'cdnURL', 'sessionInfoOverrides', 'loggingURL']);
|
|
6456
6458
|
const liveConfigMap = {
|
|
6457
6459
|
apiUrl: 'apiURL',
|
|
@@ -9860,6 +9862,27 @@ module.exports = function PeerConnectionFactory(deps) {
|
|
|
9860
9862
|
function FakeRTCRtpSender(track) {
|
|
9861
9863
|
this.track = track;
|
|
9862
9864
|
}
|
|
9865
|
+
|
|
9866
|
+
api.setIceConfig = newIceConfig => {
|
|
9867
|
+
try {
|
|
9868
|
+
// Firefox does not follow the spec laid out in MDN for attempts to change the certs
|
|
9869
|
+
// after they've already been set. The documentation states the following about certificates:
|
|
9870
|
+
// once the certificates have been set, this property is ignored in future calls to
|
|
9871
|
+
// RTCPeerConnection.setConfiguration().
|
|
9872
|
+
if (env.isFirefox) {
|
|
9873
|
+
newIceConfig.certificates = _peerConnection.getConfiguration().certificates;
|
|
9874
|
+
}
|
|
9875
|
+
|
|
9876
|
+
_peerConnection.setConfiguration(newIceConfig);
|
|
9877
|
+
} catch (err) {
|
|
9878
|
+
throw new OTHelpersError(`A peer connection failed to set configuration with ${err.message}`, Errors.FAILED_SET_CONFIGURATION);
|
|
9879
|
+
}
|
|
9880
|
+
|
|
9881
|
+
_iceRestartNeeded.set(true);
|
|
9882
|
+
|
|
9883
|
+
api.generateOffer();
|
|
9884
|
+
return _peerConnection;
|
|
9885
|
+
};
|
|
9863
9886
|
/**
|
|
9864
9887
|
* Remove a track from the underlying PeerConnection
|
|
9865
9888
|
*
|
|
@@ -17208,6 +17231,10 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
17208
17231
|
this._getMediaProcessor = () => mediaProcessor;
|
|
17209
17232
|
|
|
17210
17233
|
this._removePeerConnection = peerConnection => {
|
|
17234
|
+
if (!peerConnection) {
|
|
17235
|
+
return;
|
|
17236
|
+
}
|
|
17237
|
+
|
|
17211
17238
|
const _getPeerConnectionMet = getPeerConnectionMeta(peerConnection),
|
|
17212
17239
|
peerConnectionId = _getPeerConnectionMet.peerConnectionId;
|
|
17213
17240
|
|
|
@@ -18526,7 +18553,7 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
18526
18553
|
var _ref28 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee17(shouldHaveVideo) {
|
|
18527
18554
|
var _vidDevices$find;
|
|
18528
18555
|
|
|
18529
|
-
var vidDevices, oldTrack, oldTrackDeviceId, newTrack,
|
|
18556
|
+
var _properties$videoDime, videoDimensions, vidDevices, oldTrack, oldTrackDeviceId, newTrack, videoFilter;
|
|
18530
18557
|
|
|
18531
18558
|
return _regenerator.default.wrap(function _callee17$(_context17) {
|
|
18532
18559
|
while (1) switch (_context17.prev = _context17.next) {
|
|
@@ -18539,41 +18566,42 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
18539
18566
|
return _context17.abrupt("return");
|
|
18540
18567
|
|
|
18541
18568
|
case 2:
|
|
18542
|
-
|
|
18569
|
+
_properties$videoDime = properties.videoDimensions, videoDimensions = _properties$videoDime === void 0 ? getVideoDimensions() : _properties$videoDime;
|
|
18570
|
+
_context17.next = 5;
|
|
18543
18571
|
return getVideoDevices();
|
|
18544
18572
|
|
|
18545
|
-
case
|
|
18573
|
+
case 5:
|
|
18546
18574
|
vidDevices = _context17.sent;
|
|
18547
18575
|
oldTrack = getCurrentTrack();
|
|
18548
18576
|
|
|
18549
18577
|
if (oldTrack) {
|
|
18550
|
-
_context17.next =
|
|
18578
|
+
_context17.next = 9;
|
|
18551
18579
|
break;
|
|
18552
18580
|
}
|
|
18553
18581
|
|
|
18554
18582
|
throw otError(Errors.NOT_SUPPORTED, new Error('Publisher._toggleVideo cannot toggleVideo when you have no video source.'));
|
|
18555
18583
|
|
|
18556
|
-
case
|
|
18584
|
+
case 9:
|
|
18557
18585
|
// oldTrackDeviceId is undefined when it comes from a canvasTracks, i.e.: it is currently muted
|
|
18558
18586
|
oldTrackDeviceId = (_vidDevices$find = vidDevices.find(device => device.label === oldTrack.label)) == null ? void 0 : _vidDevices$find.deviceId;
|
|
18559
18587
|
|
|
18560
18588
|
if (isNewTrackNeeded(shouldHaveVideo, oldTrackDeviceId)) {
|
|
18561
|
-
_context17.next =
|
|
18589
|
+
_context17.next = 12;
|
|
18562
18590
|
break;
|
|
18563
18591
|
}
|
|
18564
18592
|
|
|
18565
18593
|
return _context17.abrupt("return");
|
|
18566
18594
|
|
|
18567
|
-
case
|
|
18595
|
+
case 12:
|
|
18568
18596
|
if (!(oldTrack.readyState === 'ended')) {
|
|
18569
|
-
_context17.next =
|
|
18597
|
+
_context17.next = 15;
|
|
18570
18598
|
break;
|
|
18571
18599
|
}
|
|
18572
18600
|
|
|
18573
18601
|
isTrackManuallyStopped = true;
|
|
18574
18602
|
return _context17.abrupt("return");
|
|
18575
18603
|
|
|
18576
|
-
case
|
|
18604
|
+
case 15:
|
|
18577
18605
|
if (shouldHaveVideo && OTHelpers.env.isAndroid && OTHelpers.env.isChrome) {
|
|
18578
18606
|
// On Chrome on Android you need to stop the previous video track OPENTOK-37206
|
|
18579
18607
|
if (oldTrack && oldTrack.stop) {
|
|
@@ -18586,9 +18614,6 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
18586
18614
|
break;
|
|
18587
18615
|
}
|
|
18588
18616
|
|
|
18589
|
-
// create a canvas and grab the track from it to pass into video
|
|
18590
|
-
// resize the canvas so that we don't emit a 'streamPropertyChanged' event
|
|
18591
|
-
_properties$videoDime = properties.videoDimensions, videoDimensions = _properties$videoDime === void 0 ? getVideoDimensions() : _properties$videoDime;
|
|
18592
18617
|
_context17.prev = 17;
|
|
18593
18618
|
newTrack = createCanvasVideoTrack(videoDimensions);
|
|
18594
18619
|
_context17.next = 24;
|
|
@@ -18732,9 +18757,37 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
18732
18757
|
};
|
|
18733
18758
|
}());
|
|
18734
18759
|
/**
|
|
18735
|
-
*
|
|
18736
|
-
*
|
|
18737
|
-
*
|
|
18760
|
+
* Toggles video on or off for the publisher. It causes the video to be published
|
|
18761
|
+
* (if it is currently not being published, the client is connected,
|
|
18762
|
+
* and the publisher is publishing) when the <code>value</code> is <code>true</code>;
|
|
18763
|
+
* it stops publishing video (if it is currently being published) when the <code>value</code>
|
|
18764
|
+
* is <code>false</code>.
|
|
18765
|
+
*
|
|
18766
|
+
* <p>
|
|
18767
|
+
* <i>Note:</i> The behavior of <code>publishVideo</code> varies depending on whether
|
|
18768
|
+
* the publisher is currently connected and publishing:
|
|
18769
|
+
* </p>
|
|
18770
|
+
*
|
|
18771
|
+
* <ul>
|
|
18772
|
+
* <li>Calling <code>publishVideo(true)</code> when the publisher is not connected to a session
|
|
18773
|
+
* causes the publisher to capture and render video locally, but it does not stream video.</li>
|
|
18774
|
+
*
|
|
18775
|
+
* <li>Calling <code>publishVideo(false)</code> when the publisher is not connected to a session
|
|
18776
|
+
* causes the publisher to stop capturing video locally. No video is streamed.</li>
|
|
18777
|
+
*
|
|
18778
|
+
* <li>Calling <code>publishVideo(true)</code> when the publisher is connected to a session
|
|
18779
|
+
* but not currently publishing causes it to capture and render video locally, but it does not stream video.</li>
|
|
18780
|
+
*
|
|
18781
|
+
* <li>Calling <code>publishVideo(false)</code> when the publisher is connected to a session
|
|
18782
|
+
* but not currently publishing causes the publisher to stop capturing video locally. No video is streamed.</li>
|
|
18783
|
+
*
|
|
18784
|
+
* <li>Calling <code>publishVideo(true)</code> when the publisher is both connected to a session
|
|
18785
|
+
* and currently publishing causes the publisher to capture and render video locally and to
|
|
18786
|
+
* stream video.</li>
|
|
18787
|
+
*
|
|
18788
|
+
* <li>Calling <code>publishVideo(false)</code> when the publisher is both connected to a session
|
|
18789
|
+
* and currently publishing causes the publisher to stop capturing video and to stream empty video frames.</li>
|
|
18790
|
+
* </ul>
|
|
18738
18791
|
*
|
|
18739
18792
|
* @param {Boolean} value Whether to start publishing video (<code>true</code>)
|
|
18740
18793
|
* or not (<code>false</code>).
|
|
@@ -20107,6 +20160,27 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
20107
20160
|
|
|
20108
20161
|
|
|
20109
20162
|
this._ = {
|
|
20163
|
+
setIceConfig(newIceConfig) {
|
|
20164
|
+
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee30() {
|
|
20165
|
+
var pcs;
|
|
20166
|
+
return _regenerator.default.wrap(function _callee30$(_context30) {
|
|
20167
|
+
while (1) switch (_context30.prev = _context30.next) {
|
|
20168
|
+
case 0:
|
|
20169
|
+
_context30.next = 2;
|
|
20170
|
+
return getAllPeerConnections();
|
|
20171
|
+
|
|
20172
|
+
case 2:
|
|
20173
|
+
pcs = _context30.sent;
|
|
20174
|
+
pcs.forEach(pc => pc.setIceConfig(newIceConfig));
|
|
20175
|
+
|
|
20176
|
+
case 4:
|
|
20177
|
+
case "end":
|
|
20178
|
+
return _context30.stop();
|
|
20179
|
+
}
|
|
20180
|
+
}, _callee30);
|
|
20181
|
+
}))();
|
|
20182
|
+
},
|
|
20183
|
+
|
|
20110
20184
|
publishToSession: (session, analyticsReplacement) => {
|
|
20111
20185
|
if (analyticsReplacement) {
|
|
20112
20186
|
analytics = analyticsReplacement;
|
|
@@ -20380,65 +20454,65 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
20380
20454
|
},
|
|
20381
20455
|
|
|
20382
20456
|
switchTracks() {
|
|
20383
|
-
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
20457
|
+
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee31() {
|
|
20384
20458
|
var stream;
|
|
20385
|
-
return _regenerator.default.wrap(function
|
|
20386
|
-
while (1) switch (
|
|
20459
|
+
return _regenerator.default.wrap(function _callee31$(_context31) {
|
|
20460
|
+
while (1) switch (_context31.prev = _context31.next) {
|
|
20387
20461
|
case 0:
|
|
20388
|
-
|
|
20389
|
-
|
|
20462
|
+
_context31.prev = 0;
|
|
20463
|
+
_context31.next = 3;
|
|
20390
20464
|
return getUserMedia().catch(userMediaError);
|
|
20391
20465
|
|
|
20392
20466
|
case 3:
|
|
20393
|
-
stream =
|
|
20394
|
-
|
|
20467
|
+
stream = _context31.sent;
|
|
20468
|
+
_context31.next = 10;
|
|
20395
20469
|
break;
|
|
20396
20470
|
|
|
20397
20471
|
case 6:
|
|
20398
|
-
|
|
20399
|
-
|
|
20400
|
-
logging.error(`OT.Publisher.switchTracks failed to getUserMedia: ${
|
|
20401
|
-
throw
|
|
20472
|
+
_context31.prev = 6;
|
|
20473
|
+
_context31.t0 = _context31["catch"](0);
|
|
20474
|
+
logging.error(`OT.Publisher.switchTracks failed to getUserMedia: ${_context31.t0}`);
|
|
20475
|
+
throw _context31.t0;
|
|
20402
20476
|
|
|
20403
20477
|
case 10:
|
|
20404
20478
|
setNewStream(stream);
|
|
20405
|
-
|
|
20479
|
+
_context31.prev = 11;
|
|
20406
20480
|
bindVideo();
|
|
20407
|
-
|
|
20481
|
+
_context31.next = 21;
|
|
20408
20482
|
break;
|
|
20409
20483
|
|
|
20410
20484
|
case 15:
|
|
20411
|
-
|
|
20412
|
-
|
|
20485
|
+
_context31.prev = 15;
|
|
20486
|
+
_context31.t1 = _context31["catch"](11);
|
|
20413
20487
|
|
|
20414
|
-
if (!(
|
|
20415
|
-
|
|
20488
|
+
if (!(_context31.t1 instanceof CancellationError)) {
|
|
20489
|
+
_context31.next = 19;
|
|
20416
20490
|
break;
|
|
20417
20491
|
}
|
|
20418
20492
|
|
|
20419
|
-
return
|
|
20493
|
+
return _context31.abrupt("return");
|
|
20420
20494
|
|
|
20421
20495
|
case 19:
|
|
20422
|
-
logging.error('Error while binding video',
|
|
20423
|
-
throw
|
|
20496
|
+
logging.error('Error while binding video', _context31.t1);
|
|
20497
|
+
throw _context31.t1;
|
|
20424
20498
|
|
|
20425
20499
|
case 21:
|
|
20426
|
-
|
|
20500
|
+
_context31.prev = 21;
|
|
20427
20501
|
replaceTracks();
|
|
20428
|
-
|
|
20502
|
+
_context31.next = 29;
|
|
20429
20503
|
break;
|
|
20430
20504
|
|
|
20431
20505
|
case 25:
|
|
20432
|
-
|
|
20433
|
-
|
|
20434
|
-
logging.error('Error replacing tracks',
|
|
20435
|
-
throw
|
|
20506
|
+
_context31.prev = 25;
|
|
20507
|
+
_context31.t2 = _context31["catch"](21);
|
|
20508
|
+
logging.error('Error replacing tracks', _context31.t2);
|
|
20509
|
+
throw _context31.t2;
|
|
20436
20510
|
|
|
20437
20511
|
case 29:
|
|
20438
20512
|
case "end":
|
|
20439
|
-
return
|
|
20513
|
+
return _context31.stop();
|
|
20440
20514
|
}
|
|
20441
|
-
},
|
|
20515
|
+
}, _callee31, null, [[0, 6], [11, 15], [21, 25]]);
|
|
20442
20516
|
}))();
|
|
20443
20517
|
},
|
|
20444
20518
|
|
|
@@ -20478,32 +20552,32 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
20478
20552
|
demoOnlyCycleVideo: this.cycleVideo,
|
|
20479
20553
|
|
|
20480
20554
|
testOnlyGetFramesEncoded() {
|
|
20481
|
-
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
20555
|
+
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee32() {
|
|
20482
20556
|
var peerConnections;
|
|
20483
|
-
return _regenerator.default.wrap(function
|
|
20484
|
-
while (1) switch (
|
|
20557
|
+
return _regenerator.default.wrap(function _callee32$(_context32) {
|
|
20558
|
+
while (1) switch (_context32.prev = _context32.next) {
|
|
20485
20559
|
case 0:
|
|
20486
|
-
|
|
20560
|
+
_context32.next = 2;
|
|
20487
20561
|
return getAllPeerConnections();
|
|
20488
20562
|
|
|
20489
20563
|
case 2:
|
|
20490
|
-
peerConnections =
|
|
20564
|
+
peerConnections = _context32.sent;
|
|
20491
20565
|
|
|
20492
20566
|
if (peerConnections.length) {
|
|
20493
|
-
|
|
20567
|
+
_context32.next = 5;
|
|
20494
20568
|
break;
|
|
20495
20569
|
}
|
|
20496
20570
|
|
|
20497
20571
|
throw new Error('No established PeerConnections yet');
|
|
20498
20572
|
|
|
20499
20573
|
case 5:
|
|
20500
|
-
return
|
|
20574
|
+
return _context32.abrupt("return", peerConnections[0]._testOnlyGetFramesEncoded());
|
|
20501
20575
|
|
|
20502
20576
|
case 6:
|
|
20503
20577
|
case "end":
|
|
20504
|
-
return
|
|
20578
|
+
return _context32.stop();
|
|
20505
20579
|
}
|
|
20506
|
-
},
|
|
20580
|
+
}, _callee32);
|
|
20507
20581
|
}))();
|
|
20508
20582
|
},
|
|
20509
20583
|
|
|
@@ -20545,70 +20619,66 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
20545
20619
|
});
|
|
20546
20620
|
},
|
|
20547
20621
|
startRelayedToRoutedTransition: function () {
|
|
20548
|
-
var _startRelayedToRoutedTransition = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
20549
|
-
return _regenerator.default.wrap(function
|
|
20550
|
-
while (1) switch (
|
|
20622
|
+
var _startRelayedToRoutedTransition = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee33() {
|
|
20623
|
+
return _regenerator.default.wrap(function _callee33$(_context33) {
|
|
20624
|
+
while (1) switch (_context33.prev = _context33.next) {
|
|
20551
20625
|
case 0:
|
|
20626
|
+
if (!(activeSourceStreamId === 'MANTIS')) {
|
|
20627
|
+
_context33.next = 2;
|
|
20628
|
+
break;
|
|
20629
|
+
}
|
|
20630
|
+
|
|
20631
|
+
return _context33.abrupt("return");
|
|
20632
|
+
|
|
20633
|
+
case 2:
|
|
20552
20634
|
logRelayedToRoutedTransition('Attempt');
|
|
20553
20635
|
|
|
20554
20636
|
if (_this.session) {
|
|
20555
|
-
|
|
20637
|
+
_context33.next = 6;
|
|
20556
20638
|
break;
|
|
20557
20639
|
}
|
|
20558
20640
|
|
|
20559
20641
|
logRelayedToRoutedTransition('Failure', {
|
|
20560
20642
|
reason: 'Not connected to the session.'
|
|
20561
20643
|
});
|
|
20562
|
-
return
|
|
20644
|
+
return _context33.abrupt("return");
|
|
20563
20645
|
|
|
20564
|
-
case
|
|
20646
|
+
case 6:
|
|
20565
20647
|
if (_this.streamId) {
|
|
20566
|
-
|
|
20648
|
+
_context33.next = 9;
|
|
20567
20649
|
break;
|
|
20568
20650
|
}
|
|
20569
20651
|
|
|
20570
20652
|
logRelayedToRoutedTransition('Failure', {
|
|
20571
20653
|
reason: 'No streamId available'
|
|
20572
20654
|
});
|
|
20573
|
-
return
|
|
20574
|
-
|
|
20575
|
-
case 7:
|
|
20576
|
-
if (getP2pPeerConnection()) {
|
|
20577
|
-
_context32.next = 10;
|
|
20578
|
-
break;
|
|
20579
|
-
}
|
|
20580
|
-
|
|
20581
|
-
// If the P2P leg doesn't exist, it means there's no need to transition to routed.
|
|
20582
|
-
logRelayedToRoutedTransition('Failure', {
|
|
20583
|
-
reason: 'There is no Relayed Peer connection created.'
|
|
20584
|
-
});
|
|
20585
|
-
return _context32.abrupt("return");
|
|
20655
|
+
return _context33.abrupt("return");
|
|
20586
20656
|
|
|
20587
|
-
case
|
|
20657
|
+
case 9:
|
|
20588
20658
|
_this.session._.streamDestroy(_this.streamId, 'P2P');
|
|
20589
20659
|
|
|
20590
|
-
|
|
20591
|
-
|
|
20660
|
+
_context33.t0 = _this;
|
|
20661
|
+
_context33.next = 13;
|
|
20592
20662
|
return getP2pPeerConnection();
|
|
20593
20663
|
|
|
20594
|
-
case
|
|
20595
|
-
|
|
20664
|
+
case 13:
|
|
20665
|
+
_context33.t1 = _context33.sent;
|
|
20596
20666
|
|
|
20597
|
-
|
|
20667
|
+
_context33.t0._removePeerConnection.call(_context33.t0, _context33.t1);
|
|
20598
20668
|
|
|
20599
|
-
|
|
20669
|
+
_context33.next = 17;
|
|
20600
20670
|
return _restartSendingRtpToMantis();
|
|
20601
20671
|
|
|
20602
|
-
case
|
|
20672
|
+
case 17:
|
|
20603
20673
|
logRelayedToRoutedTransition('Success');
|
|
20604
20674
|
|
|
20605
20675
|
_this.trigger('streamDestroyForP2PComplete');
|
|
20606
20676
|
|
|
20607
|
-
case
|
|
20677
|
+
case 19:
|
|
20608
20678
|
case "end":
|
|
20609
|
-
return
|
|
20679
|
+
return _context33.stop();
|
|
20610
20680
|
}
|
|
20611
|
-
},
|
|
20681
|
+
}, _callee33);
|
|
20612
20682
|
}));
|
|
20613
20683
|
|
|
20614
20684
|
function startRelayedToRoutedTransition() {
|
|
@@ -20888,7 +20958,10 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
20888
20958
|
* <p>
|
|
20889
20959
|
* This method is incompatible with the
|
|
20890
20960
|
* <a href="Publisher.html#setVideoMediaProcessorConnector">Publisher.setVideoMediaProcessorConnector()</a>
|
|
20891
|
-
* method.
|
|
20961
|
+
* method. Calling this method after <code>Publisher.setVideoMediaProcessorConnector(connector)</code>
|
|
20962
|
+
* returns a promise that is rejected with an error, with the <code>name</code> property of the error
|
|
20963
|
+
* set to <code>'OT_NOT_SUPPORTED'</code>. You can remove the connector by calling
|
|
20964
|
+
* <code>Publisher.setVideoMediaProcessorConnector(null)</code>.
|
|
20892
20965
|
* </p>
|
|
20893
20966
|
*
|
|
20894
20967
|
* <p>
|
|
@@ -20905,12 +20978,15 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
20905
20978
|
* The browser does not support this method.
|
|
20906
20979
|
* </li>
|
|
20907
20980
|
* <li>
|
|
20908
|
-
* The publisher is not using a
|
|
20981
|
+
* The publisher is not using a supported video source. (The <code>videoSource</code>
|
|
20909
20982
|
* option of the <a href="OT.html#initPublisher">OT.initPublisher()</a> method was
|
|
20910
|
-
* set to <code>null</code>, <code>false</code>,
|
|
20983
|
+
* set to <code>null</code>, <code>false</code>, or
|
|
20911
20984
|
* <code>"screen"</code>).
|
|
20912
20985
|
* </li>
|
|
20913
20986
|
* <li>
|
|
20987
|
+
* A custom filter is already being used via the <code>Publisher.setVideoMediaProcessorConnector()</code> method.
|
|
20988
|
+
* </li>
|
|
20989
|
+
* <li>
|
|
20914
20990
|
* There are no video input devices (cameras) available.
|
|
20915
20991
|
* </li>
|
|
20916
20992
|
* <li>
|
|
@@ -20964,19 +21040,19 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
20964
21040
|
*/
|
|
20965
21041
|
|
|
20966
21042
|
this.applyVideoFilter = /*#__PURE__*/function () {
|
|
20967
|
-
var _ref41 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
21043
|
+
var _ref41 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee34(videoFilter) {
|
|
20968
21044
|
var isSupported, message, _webRTCStream$getVide2, originalVideoTrack, filteredVideoTrack;
|
|
20969
21045
|
|
|
20970
|
-
return _regenerator.default.wrap(function
|
|
20971
|
-
while (1) switch (
|
|
21046
|
+
return _regenerator.default.wrap(function _callee34$(_context34) {
|
|
21047
|
+
while (1) switch (_context34.prev = _context34.next) {
|
|
20972
21048
|
case 0:
|
|
20973
21049
|
logAnalyticsEvent('applyVideoFilter', 'Attempt', {
|
|
20974
21050
|
videoFilter
|
|
20975
21051
|
});
|
|
20976
|
-
|
|
21052
|
+
_context34.prev = 1;
|
|
20977
21053
|
|
|
20978
21054
|
if (!_videoMediaProcessorConnector) {
|
|
20979
|
-
|
|
21055
|
+
_context34.next = 4;
|
|
20980
21056
|
break;
|
|
20981
21057
|
}
|
|
20982
21058
|
|
|
@@ -20986,7 +21062,7 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
20986
21062
|
isSupported = MediaProcessor.isSupported();
|
|
20987
21063
|
|
|
20988
21064
|
if (isSupported) {
|
|
20989
|
-
|
|
21065
|
+
_context34.next = 7;
|
|
20990
21066
|
break;
|
|
20991
21067
|
}
|
|
20992
21068
|
|
|
@@ -20994,7 +21070,7 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
20994
21070
|
|
|
20995
21071
|
case 7:
|
|
20996
21072
|
if (mediaProcessor.isValidVideoFilter(videoFilter)) {
|
|
20997
|
-
|
|
21073
|
+
_context34.next = 9;
|
|
20998
21074
|
break;
|
|
20999
21075
|
}
|
|
21000
21076
|
|
|
@@ -21002,7 +21078,7 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21002
21078
|
|
|
21003
21079
|
case 9:
|
|
21004
21080
|
if (webRTCStream) {
|
|
21005
|
-
|
|
21081
|
+
_context34.next = 14;
|
|
21006
21082
|
break;
|
|
21007
21083
|
}
|
|
21008
21084
|
|
|
@@ -21011,11 +21087,11 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21011
21087
|
message
|
|
21012
21088
|
});
|
|
21013
21089
|
logging.warn(message);
|
|
21014
|
-
return
|
|
21090
|
+
return _context34.abrupt("return");
|
|
21015
21091
|
|
|
21016
21092
|
case 14:
|
|
21017
21093
|
if (!isScreenSharing) {
|
|
21018
|
-
|
|
21094
|
+
_context34.next = 16;
|
|
21019
21095
|
break;
|
|
21020
21096
|
}
|
|
21021
21097
|
|
|
@@ -21023,36 +21099,36 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21023
21099
|
|
|
21024
21100
|
case 16:
|
|
21025
21101
|
if (!_this.getVideoFilter()) {
|
|
21026
|
-
|
|
21102
|
+
_context34.next = 29;
|
|
21027
21103
|
break;
|
|
21028
21104
|
}
|
|
21029
21105
|
|
|
21030
21106
|
if (!mediaProcessor.canUpdateVideoFilter(videoFilter.type)) {
|
|
21031
|
-
|
|
21107
|
+
_context34.next = 27;
|
|
21032
21108
|
break;
|
|
21033
21109
|
}
|
|
21034
21110
|
|
|
21035
|
-
|
|
21036
|
-
|
|
21111
|
+
_context34.prev = 18;
|
|
21112
|
+
_context34.next = 21;
|
|
21037
21113
|
return mediaProcessor.updateVideoFilter(videoFilter);
|
|
21038
21114
|
|
|
21039
21115
|
case 21:
|
|
21040
|
-
return
|
|
21116
|
+
return _context34.abrupt("return");
|
|
21041
21117
|
|
|
21042
21118
|
case 24:
|
|
21043
|
-
|
|
21044
|
-
|
|
21045
|
-
logging.warn(`Error updating video filter: ${
|
|
21119
|
+
_context34.prev = 24;
|
|
21120
|
+
_context34.t0 = _context34["catch"](18);
|
|
21121
|
+
logging.warn(`Error updating video filter: ${_context34.t0}`);
|
|
21046
21122
|
|
|
21047
21123
|
case 27:
|
|
21048
|
-
|
|
21124
|
+
_context34.next = 29;
|
|
21049
21125
|
return _this.clearVideoFilter();
|
|
21050
21126
|
|
|
21051
21127
|
case 29:
|
|
21052
21128
|
_webRTCStream$getVide2 = webRTCStream.getVideoTracks(), originalVideoTrack = _webRTCStream$getVide2[0];
|
|
21053
21129
|
|
|
21054
21130
|
if (originalVideoTrack) {
|
|
21055
|
-
|
|
21131
|
+
_context34.next = 35;
|
|
21056
21132
|
break;
|
|
21057
21133
|
}
|
|
21058
21134
|
|
|
@@ -21061,40 +21137,40 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21061
21137
|
message
|
|
21062
21138
|
});
|
|
21063
21139
|
logging.warn(message);
|
|
21064
|
-
return
|
|
21140
|
+
return _context34.abrupt("return");
|
|
21065
21141
|
|
|
21066
21142
|
case 35:
|
|
21067
21143
|
enableMediaProcessorLogging();
|
|
21068
|
-
|
|
21144
|
+
_context34.next = 38;
|
|
21069
21145
|
return mediaProcessor.setVideoFilter(videoFilter);
|
|
21070
21146
|
|
|
21071
21147
|
case 38:
|
|
21072
|
-
|
|
21148
|
+
_context34.next = 40;
|
|
21073
21149
|
return mediaProcessor.setMediaStream(webRTCStream);
|
|
21074
21150
|
|
|
21075
21151
|
case 40:
|
|
21076
|
-
filteredVideoTrack =
|
|
21152
|
+
filteredVideoTrack = _context34.sent;
|
|
21077
21153
|
|
|
21078
21154
|
if (!filteredVideoTrack) {
|
|
21079
|
-
|
|
21155
|
+
_context34.next = 44;
|
|
21080
21156
|
break;
|
|
21081
21157
|
}
|
|
21082
21158
|
|
|
21083
|
-
|
|
21159
|
+
_context34.next = 44;
|
|
21084
21160
|
return replaceTrackAndUpdate(originalVideoTrack, filteredVideoTrack);
|
|
21085
21161
|
|
|
21086
21162
|
case 44:
|
|
21087
|
-
|
|
21163
|
+
_context34.next = 51;
|
|
21088
21164
|
break;
|
|
21089
21165
|
|
|
21090
21166
|
case 46:
|
|
21091
|
-
|
|
21092
|
-
|
|
21093
|
-
logging.error(`Error applying video filter: ${
|
|
21167
|
+
_context34.prev = 46;
|
|
21168
|
+
_context34.t1 = _context34["catch"](1);
|
|
21169
|
+
logging.error(`Error applying video filter: ${_context34.t1}`);
|
|
21094
21170
|
logAnalyticsEvent('applyVideoFilter', 'Failure', {
|
|
21095
|
-
message:
|
|
21171
|
+
message: _context34.t1.message
|
|
21096
21172
|
});
|
|
21097
|
-
throw
|
|
21173
|
+
throw _context34.t1;
|
|
21098
21174
|
|
|
21099
21175
|
case 51:
|
|
21100
21176
|
currentVideoFilter = videoFilter;
|
|
@@ -21104,9 +21180,9 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21104
21180
|
|
|
21105
21181
|
case 53:
|
|
21106
21182
|
case "end":
|
|
21107
|
-
return
|
|
21183
|
+
return _context34.stop();
|
|
21108
21184
|
}
|
|
21109
|
-
},
|
|
21185
|
+
}, _callee34, null, [[1, 46], [18, 24]]);
|
|
21110
21186
|
}));
|
|
21111
21187
|
|
|
21112
21188
|
return function (_x24) {
|
|
@@ -21152,8 +21228,8 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21152
21228
|
* Sets a
|
|
21153
21229
|
* <a href="https://vonage.github.io/media-processor-docs/classes/MediaProcessorConnector.html">MediaProcessorConnector</a>
|
|
21154
21230
|
* for the publisher video track.
|
|
21155
|
-
* A publisher can have only one MediaProcessorConnector applied at one time. When you set a new
|
|
21156
|
-
* connector, the previously set connector is removed.
|
|
21231
|
+
* A publisher can have only one video MediaProcessorConnector applied at one time. When you set a new
|
|
21232
|
+
* connector, the previously set video connector is removed.
|
|
21157
21233
|
*
|
|
21158
21234
|
* <p>
|
|
21159
21235
|
* This is a <em>beta</em> feature.
|
|
@@ -21161,8 +21237,11 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21161
21237
|
*
|
|
21162
21238
|
* <p>
|
|
21163
21239
|
* This method is incompatible with the
|
|
21164
|
-
<a href="Publisher.html#applyVideoFilter">Publisher.applyVideoFilter()</a>
|
|
21165
|
-
method.
|
|
21240
|
+
* <a href="Publisher.html#applyVideoFilter">Publisher.applyVideoFilter()</a>
|
|
21241
|
+
* method. Calling this method after <code>Publisher.applyVideoFilter(filter)</code> returns
|
|
21242
|
+
* a promise rejected with an error, with the <code>name</code> property of the error set to
|
|
21243
|
+
* <code>'OT_NOT_SUPPORTED'</code>. You can clear the video filter by calling
|
|
21244
|
+
* <code>Publisher.clearVideoFilter()</code>.
|
|
21166
21245
|
* </p>
|
|
21167
21246
|
*
|
|
21168
21247
|
* <p>
|
|
@@ -21180,6 +21259,9 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21180
21259
|
* There are no video input devices (cameras) available.
|
|
21181
21260
|
* </li>
|
|
21182
21261
|
* <li>
|
|
21262
|
+
* A video filter has already been applied via the <code>Publisher.applyVideoFilter()</code> method.
|
|
21263
|
+
* </li>
|
|
21264
|
+
* <li>
|
|
21183
21265
|
* There was an error acquiring video from the video input device.
|
|
21184
21266
|
* </li>
|
|
21185
21267
|
* <li>
|
|
@@ -21210,18 +21292,18 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21210
21292
|
|
|
21211
21293
|
|
|
21212
21294
|
this.setVideoMediaProcessorConnector = /*#__PURE__*/function () {
|
|
21213
|
-
var _ref42 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
21295
|
+
var _ref42 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee35(mediaProcessorConnector) {
|
|
21214
21296
|
var _webRTCStream$getVide3, filteredVideoTrack, videoTrack, _webRTCStream$getVide4, originalVideoTrack, message;
|
|
21215
21297
|
|
|
21216
|
-
return _regenerator.default.wrap(function
|
|
21217
|
-
while (1) switch (
|
|
21298
|
+
return _regenerator.default.wrap(function _callee35$(_context35) {
|
|
21299
|
+
while (1) switch (_context35.prev = _context35.next) {
|
|
21218
21300
|
case 0:
|
|
21219
21301
|
logAnalyticsEvent('setVideoMediaProcessorConnector', 'Attempt', {
|
|
21220
21302
|
message: mediaProcessorConnector ? 'setting the connector' : 'clearing the connector'
|
|
21221
21303
|
});
|
|
21222
21304
|
|
|
21223
21305
|
if (!_this.getVideoFilter()) {
|
|
21224
|
-
|
|
21306
|
+
_context35.next = 4;
|
|
21225
21307
|
break;
|
|
21226
21308
|
}
|
|
21227
21309
|
|
|
@@ -21232,17 +21314,17 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21232
21314
|
|
|
21233
21315
|
case 4:
|
|
21234
21316
|
if (!_videoMediaProcessorConnector) {
|
|
21235
|
-
|
|
21317
|
+
_context35.next = 14;
|
|
21236
21318
|
break;
|
|
21237
21319
|
}
|
|
21238
21320
|
|
|
21239
21321
|
_webRTCStream$getVide3 = webRTCStream.getVideoTracks(), filteredVideoTrack = _webRTCStream$getVide3[0];
|
|
21240
|
-
|
|
21322
|
+
_context35.next = 8;
|
|
21241
21323
|
return getTrackFromDeviceId(currentDeviceId);
|
|
21242
21324
|
|
|
21243
21325
|
case 8:
|
|
21244
|
-
videoTrack =
|
|
21245
|
-
|
|
21326
|
+
videoTrack = _context35.sent;
|
|
21327
|
+
_context35.next = 11;
|
|
21246
21328
|
return replaceTrackAndUpdate(filteredVideoTrack, videoTrack);
|
|
21247
21329
|
|
|
21248
21330
|
case 11:
|
|
@@ -21254,18 +21336,18 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21254
21336
|
|
|
21255
21337
|
case 14:
|
|
21256
21338
|
if (mediaProcessorConnector) {
|
|
21257
|
-
|
|
21339
|
+
_context35.next = 17;
|
|
21258
21340
|
break;
|
|
21259
21341
|
}
|
|
21260
21342
|
|
|
21261
21343
|
logAnalyticsEvent('setVideoMediaProcessorConnector', 'Success', {
|
|
21262
21344
|
message: 'clearing the connector'
|
|
21263
21345
|
});
|
|
21264
|
-
return
|
|
21346
|
+
return _context35.abrupt("return");
|
|
21265
21347
|
|
|
21266
21348
|
case 17:
|
|
21267
21349
|
if (MediaProcessorConnector.isValidConnector(mediaProcessorConnector)) {
|
|
21268
|
-
|
|
21350
|
+
_context35.next = 20;
|
|
21269
21351
|
break;
|
|
21270
21352
|
}
|
|
21271
21353
|
|
|
@@ -21279,7 +21361,7 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21279
21361
|
_webRTCStream$getVide4 = webRTCStream.getVideoTracks(), originalVideoTrack = _webRTCStream$getVide4[0];
|
|
21280
21362
|
|
|
21281
21363
|
if (originalVideoTrack) {
|
|
21282
|
-
|
|
21364
|
+
_context35.next = 28;
|
|
21283
21365
|
break;
|
|
21284
21366
|
}
|
|
21285
21367
|
|
|
@@ -21289,65 +21371,119 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21289
21371
|
});
|
|
21290
21372
|
logging.warn(`setVideoMediaProcessorConnector: ${message}`);
|
|
21291
21373
|
_videoMediaProcessorConnector = null;
|
|
21292
|
-
return
|
|
21374
|
+
return _context35.abrupt("return");
|
|
21293
21375
|
|
|
21294
21376
|
case 28:
|
|
21295
|
-
|
|
21296
|
-
|
|
21377
|
+
_context35.prev = 28;
|
|
21378
|
+
_context35.next = 31;
|
|
21297
21379
|
return _videoMediaProcessorConnector.setTrack(originalVideoTrack);
|
|
21298
21380
|
|
|
21299
21381
|
case 31:
|
|
21300
|
-
filteredVideoTrack =
|
|
21301
|
-
|
|
21382
|
+
filteredVideoTrack = _context35.sent;
|
|
21383
|
+
_context35.next = 34;
|
|
21302
21384
|
return replaceTrackAndUpdate(originalVideoTrack, filteredVideoTrack);
|
|
21303
21385
|
|
|
21304
21386
|
case 34:
|
|
21305
|
-
|
|
21387
|
+
_context35.next = 42;
|
|
21306
21388
|
break;
|
|
21307
21389
|
|
|
21308
21390
|
case 36:
|
|
21309
|
-
|
|
21310
|
-
|
|
21391
|
+
_context35.prev = 36;
|
|
21392
|
+
_context35.t0 = _context35["catch"](28);
|
|
21311
21393
|
_videoMediaProcessorConnector = null;
|
|
21312
|
-
logging.error(`setVideoMediaProcessorConnector: Error getting track from MediaProcessorConnector: ${
|
|
21394
|
+
logging.error(`setVideoMediaProcessorConnector: Error getting track from MediaProcessorConnector: ${_context35.t0}`);
|
|
21313
21395
|
logAnalyticsEvent('setVideoMediaProcessorConnector', 'Failure', {
|
|
21314
|
-
message:
|
|
21396
|
+
message: _context35.t0.message
|
|
21315
21397
|
});
|
|
21316
|
-
throw
|
|
21398
|
+
throw _context35.t0;
|
|
21317
21399
|
|
|
21318
21400
|
case 42:
|
|
21319
21401
|
logAnalyticsEvent('setVideoMediaProcessorConnector', 'Success');
|
|
21320
21402
|
|
|
21321
21403
|
case 43:
|
|
21322
21404
|
case "end":
|
|
21323
|
-
return
|
|
21405
|
+
return _context35.stop();
|
|
21324
21406
|
}
|
|
21325
|
-
},
|
|
21407
|
+
}, _callee35, null, [[28, 36]]);
|
|
21326
21408
|
}));
|
|
21327
21409
|
|
|
21328
21410
|
return function (_x25) {
|
|
21329
21411
|
return _ref42.apply(this, arguments);
|
|
21330
21412
|
};
|
|
21331
21413
|
}();
|
|
21414
|
+
/**
|
|
21415
|
+
* Sets a
|
|
21416
|
+
* <a href="https://vonage.github.io/media-processor-docs/classes/MediaProcessorConnector.html">MediaProcessorConnector</a>
|
|
21417
|
+
* for the publisher audio track.
|
|
21418
|
+
* A publisher can have only one audio MediaProcessorConnector applied at one time. When you set a new
|
|
21419
|
+
* connector, the previously set audio connector is removed.
|
|
21420
|
+
*
|
|
21421
|
+
* <p>
|
|
21422
|
+
* This is a <em>beta</em> feature.
|
|
21423
|
+
* </p>
|
|
21424
|
+
*
|
|
21425
|
+
* <p>
|
|
21426
|
+
* <em>Note:</em> MediaProcessors are only supported in recent versions of Chrome, Electron, Opera, and Edge.
|
|
21427
|
+
* They are not supported in other (non-Chromium-based) browsers or on iOS. You can check if the client
|
|
21428
|
+
* supports this feature by calling the
|
|
21429
|
+
* <a href="OT.html#hasMediaProcessorSupport">OT.hasMediaProcessorSupport()</a> method.
|
|
21430
|
+
* </p>
|
|
21431
|
+
*
|
|
21432
|
+
* <p>
|
|
21433
|
+
* Calling this method results in an error (the Promise returned by the method is rejected)
|
|
21434
|
+
* in the following conditions:
|
|
21435
|
+
* <ul>
|
|
21436
|
+
* <li>
|
|
21437
|
+
* There are no audio input devices (microphones) available.
|
|
21438
|
+
* </li>
|
|
21439
|
+
* <li>
|
|
21440
|
+
* There was an error acquiring audio from the audio input device.
|
|
21441
|
+
* </li>
|
|
21442
|
+
* <li>
|
|
21443
|
+
* There was an error acquiring the processed track from the MediaProcessorConnector.
|
|
21444
|
+
* </li>
|
|
21445
|
+
* </ul>
|
|
21446
|
+
* </p>
|
|
21447
|
+
*
|
|
21448
|
+
* <p>
|
|
21449
|
+
* You can clear the current connector by calling this method with <code>null</code>.
|
|
21450
|
+
*
|
|
21451
|
+
* <p>
|
|
21452
|
+
* For more information, see the
|
|
21453
|
+
* <a href="https://tokbox.com/developer/guides/vonage-media-processor/js/">Media Processor</a>
|
|
21454
|
+
* developer guide.
|
|
21455
|
+
*
|
|
21456
|
+
* @param {MediaProcessorConnector} mediaProcessorConnector A MediaProcessorConnector instance.
|
|
21457
|
+
* See the <a href="https://vonage.github.io/media-processor-docs/classes/MediaProcessorConnector.html">Vonage Media Processor library docs</a>.
|
|
21458
|
+
*
|
|
21459
|
+
* @method #setAudioMediaProcessorConnector
|
|
21460
|
+
* @memberOf Publisher
|
|
21461
|
+
*
|
|
21462
|
+
* @see <a href="OT.html#hasMediaProcessorSupport">OT.hasMediaProcessorSupport()</a>
|
|
21463
|
+
*
|
|
21464
|
+
* @return {Promise} A promise that resolves when the operation completes successfully.
|
|
21465
|
+
* If there is an error, the promise is rejected and no connector is set.
|
|
21466
|
+
*/
|
|
21467
|
+
|
|
21332
21468
|
|
|
21333
21469
|
this.setAudioMediaProcessorConnector = /*#__PURE__*/function () {
|
|
21334
|
-
var _ref43 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
21470
|
+
var _ref43 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee36(mediaProcessorConnector) {
|
|
21335
21471
|
var _webRTCStream$getAudi, filteredAudioTrack, _webRTCStream$getAudi2, originalAudioTrack, message;
|
|
21336
21472
|
|
|
21337
|
-
return _regenerator.default.wrap(function
|
|
21338
|
-
while (1) switch (
|
|
21473
|
+
return _regenerator.default.wrap(function _callee36$(_context36) {
|
|
21474
|
+
while (1) switch (_context36.prev = _context36.next) {
|
|
21339
21475
|
case 0:
|
|
21340
21476
|
logAnalyticsEvent('setAudioMediaProcessorConnector', 'Attempt', {
|
|
21341
21477
|
message: mediaProcessorConnector ? 'setting the connector' : 'clearing the connector'
|
|
21342
21478
|
});
|
|
21343
21479
|
|
|
21344
21480
|
if (!_audioMediaProcessorConnector) {
|
|
21345
|
-
|
|
21481
|
+
_context36.next = 7;
|
|
21346
21482
|
break;
|
|
21347
21483
|
}
|
|
21348
21484
|
|
|
21349
21485
|
_webRTCStream$getAudi = webRTCStream.getAudioTracks(), filteredAudioTrack = _webRTCStream$getAudi[0];
|
|
21350
|
-
|
|
21486
|
+
_context36.next = 5;
|
|
21351
21487
|
return replaceAudioTrack(filteredAudioTrack, _audioMediaProcessorConnector.originalTrack);
|
|
21352
21488
|
|
|
21353
21489
|
case 5:
|
|
@@ -21357,18 +21493,18 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21357
21493
|
|
|
21358
21494
|
case 7:
|
|
21359
21495
|
if (mediaProcessorConnector) {
|
|
21360
|
-
|
|
21496
|
+
_context36.next = 10;
|
|
21361
21497
|
break;
|
|
21362
21498
|
}
|
|
21363
21499
|
|
|
21364
21500
|
logAnalyticsEvent('setAudioMediaProcessorConnector', 'Success', {
|
|
21365
21501
|
message: 'clearing the connector'
|
|
21366
21502
|
});
|
|
21367
|
-
return
|
|
21503
|
+
return _context36.abrupt("return");
|
|
21368
21504
|
|
|
21369
21505
|
case 10:
|
|
21370
21506
|
if (MediaProcessorConnector.isValidConnector(mediaProcessorConnector)) {
|
|
21371
|
-
|
|
21507
|
+
_context36.next = 13;
|
|
21372
21508
|
break;
|
|
21373
21509
|
}
|
|
21374
21510
|
|
|
@@ -21381,7 +21517,7 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21381
21517
|
_webRTCStream$getAudi2 = webRTCStream.getAudioTracks(), originalAudioTrack = _webRTCStream$getAudi2[0];
|
|
21382
21518
|
|
|
21383
21519
|
if (originalAudioTrack) {
|
|
21384
|
-
|
|
21520
|
+
_context36.next = 20;
|
|
21385
21521
|
break;
|
|
21386
21522
|
}
|
|
21387
21523
|
|
|
@@ -21391,41 +21527,41 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21391
21527
|
});
|
|
21392
21528
|
logging.warn(`setAudioMediaProcessorConnector: ${message}`);
|
|
21393
21529
|
_audioMediaProcessorConnector = null;
|
|
21394
|
-
return
|
|
21530
|
+
return _context36.abrupt("return");
|
|
21395
21531
|
|
|
21396
21532
|
case 20:
|
|
21397
21533
|
_audioMediaProcessorConnector = new MediaProcessorConnector(mediaProcessorConnector);
|
|
21398
|
-
|
|
21399
|
-
|
|
21534
|
+
_context36.prev = 21;
|
|
21535
|
+
_context36.next = 24;
|
|
21400
21536
|
return _audioMediaProcessorConnector.setTrack(originalAudioTrack);
|
|
21401
21537
|
|
|
21402
21538
|
case 24:
|
|
21403
|
-
filteredAudioTrack =
|
|
21404
|
-
|
|
21539
|
+
filteredAudioTrack = _context36.sent;
|
|
21540
|
+
_context36.next = 27;
|
|
21405
21541
|
return replaceAudioTrack(_this.getAudioSource(), filteredAudioTrack);
|
|
21406
21542
|
|
|
21407
21543
|
case 27:
|
|
21408
|
-
|
|
21544
|
+
_context36.next = 35;
|
|
21409
21545
|
break;
|
|
21410
21546
|
|
|
21411
21547
|
case 29:
|
|
21412
|
-
|
|
21413
|
-
|
|
21548
|
+
_context36.prev = 29;
|
|
21549
|
+
_context36.t0 = _context36["catch"](21);
|
|
21414
21550
|
_audioMediaProcessorConnector = null;
|
|
21415
|
-
logging.error(`setAudioMediaProcessorConnector: Error getting track from MediaProcessorConnector: ${
|
|
21551
|
+
logging.error(`setAudioMediaProcessorConnector: Error getting track from MediaProcessorConnector: ${_context36.t0}`);
|
|
21416
21552
|
logAnalyticsEvent('setAudioMediaProcessorConnector', 'Failure', {
|
|
21417
|
-
message:
|
|
21553
|
+
message: _context36.t0.message
|
|
21418
21554
|
});
|
|
21419
|
-
throw
|
|
21555
|
+
throw _context36.t0;
|
|
21420
21556
|
|
|
21421
21557
|
case 35:
|
|
21422
21558
|
logAnalyticsEvent('setAudioMediaProcessorConnector', 'Success');
|
|
21423
21559
|
|
|
21424
21560
|
case 36:
|
|
21425
21561
|
case "end":
|
|
21426
|
-
return
|
|
21562
|
+
return _context36.stop();
|
|
21427
21563
|
}
|
|
21428
|
-
},
|
|
21564
|
+
}, _callee36, null, [[21, 29]]);
|
|
21429
21565
|
}));
|
|
21430
21566
|
|
|
21431
21567
|
return function (_x26) {
|
|
@@ -21451,16 +21587,16 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21451
21587
|
*/
|
|
21452
21588
|
|
|
21453
21589
|
|
|
21454
|
-
this.clearVideoFilter = /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
21590
|
+
this.clearVideoFilter = /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee37() {
|
|
21455
21591
|
var message, oldVideoFilter, _webRTCStream$getVide5, filteredVideoTrack, videoTrack;
|
|
21456
21592
|
|
|
21457
|
-
return _regenerator.default.wrap(function
|
|
21458
|
-
while (1) switch (
|
|
21593
|
+
return _regenerator.default.wrap(function _callee37$(_context37) {
|
|
21594
|
+
while (1) switch (_context37.prev = _context37.next) {
|
|
21459
21595
|
case 0:
|
|
21460
21596
|
logAnalyticsEvent('clearVideoFilter', 'Attempt');
|
|
21461
21597
|
|
|
21462
21598
|
if (_this.getVideoFilter()) {
|
|
21463
|
-
|
|
21599
|
+
_context37.next = 6;
|
|
21464
21600
|
break;
|
|
21465
21601
|
}
|
|
21466
21602
|
|
|
@@ -21469,11 +21605,11 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21469
21605
|
message
|
|
21470
21606
|
});
|
|
21471
21607
|
logging.debug(message);
|
|
21472
|
-
return
|
|
21608
|
+
return _context37.abrupt("return");
|
|
21473
21609
|
|
|
21474
21610
|
case 6:
|
|
21475
21611
|
if (MediaProcessor.isSupported()) {
|
|
21476
|
-
|
|
21612
|
+
_context37.next = 11;
|
|
21477
21613
|
break;
|
|
21478
21614
|
}
|
|
21479
21615
|
|
|
@@ -21482,11 +21618,11 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21482
21618
|
message
|
|
21483
21619
|
});
|
|
21484
21620
|
logging.warn(message);
|
|
21485
|
-
return
|
|
21621
|
+
return _context37.abrupt("return");
|
|
21486
21622
|
|
|
21487
21623
|
case 11:
|
|
21488
21624
|
if (webRTCStream) {
|
|
21489
|
-
|
|
21625
|
+
_context37.next = 16;
|
|
21490
21626
|
break;
|
|
21491
21627
|
}
|
|
21492
21628
|
|
|
@@ -21495,66 +21631,66 @@ module.exports = function PublisherFactory(_ref) {
|
|
|
21495
21631
|
message
|
|
21496
21632
|
});
|
|
21497
21633
|
logging.warn(message);
|
|
21498
|
-
return
|
|
21634
|
+
return _context37.abrupt("return");
|
|
21499
21635
|
|
|
21500
21636
|
case 16:
|
|
21501
21637
|
if (!currentVideoFilter) {
|
|
21502
|
-
|
|
21638
|
+
_context37.next = 43;
|
|
21503
21639
|
break;
|
|
21504
21640
|
}
|
|
21505
21641
|
|
|
21506
21642
|
oldVideoFilter = currentVideoFilter;
|
|
21507
21643
|
currentVideoFilter = null;
|
|
21508
21644
|
_webRTCStream$getVide5 = webRTCStream.getVideoTracks(), filteredVideoTrack = _webRTCStream$getVide5[0];
|
|
21509
|
-
|
|
21510
|
-
|
|
21645
|
+
_context37.prev = 20;
|
|
21646
|
+
_context37.next = 23;
|
|
21511
21647
|
return getTrackFromDeviceId(currentDeviceId);
|
|
21512
21648
|
|
|
21513
21649
|
case 23:
|
|
21514
|
-
videoTrack =
|
|
21515
|
-
|
|
21650
|
+
videoTrack = _context37.sent;
|
|
21651
|
+
_context37.next = 30;
|
|
21516
21652
|
break;
|
|
21517
21653
|
|
|
21518
21654
|
case 26:
|
|
21519
|
-
|
|
21520
|
-
|
|
21521
|
-
logging.error(
|
|
21522
|
-
return
|
|
21655
|
+
_context37.prev = 26;
|
|
21656
|
+
_context37.t0 = _context37["catch"](20);
|
|
21657
|
+
logging.error(_context37.t0);
|
|
21658
|
+
return _context37.abrupt("return");
|
|
21523
21659
|
|
|
21524
21660
|
case 30:
|
|
21525
21661
|
if (videoTrack) {
|
|
21526
|
-
|
|
21662
|
+
_context37.next = 33;
|
|
21527
21663
|
break;
|
|
21528
21664
|
}
|
|
21529
21665
|
|
|
21530
21666
|
logging.warn('Failed to clear filter because there is no video track.');
|
|
21531
|
-
return
|
|
21667
|
+
return _context37.abrupt("return");
|
|
21532
21668
|
|
|
21533
21669
|
case 33:
|
|
21534
|
-
|
|
21535
|
-
|
|
21670
|
+
_context37.prev = 33;
|
|
21671
|
+
_context37.next = 36;
|
|
21536
21672
|
return replaceTrackAndUpdate(filteredVideoTrack, videoTrack);
|
|
21537
21673
|
|
|
21538
21674
|
case 36:
|
|
21539
|
-
|
|
21675
|
+
_context37.next = 38;
|
|
21540
21676
|
return destroyMediaProcessor();
|
|
21541
21677
|
|
|
21542
21678
|
case 38:
|
|
21543
|
-
|
|
21679
|
+
_context37.next = 43;
|
|
21544
21680
|
break;
|
|
21545
21681
|
|
|
21546
21682
|
case 40:
|
|
21547
|
-
|
|
21548
|
-
|
|
21683
|
+
_context37.prev = 40;
|
|
21684
|
+
_context37.t1 = _context37["catch"](33);
|
|
21549
21685
|
// Restore the previous filter since this call has failed. This way, this function can be
|
|
21550
21686
|
// called again if needed.
|
|
21551
21687
|
currentVideoFilter = oldVideoFilter;
|
|
21552
21688
|
|
|
21553
21689
|
case 43:
|
|
21554
21690
|
case "end":
|
|
21555
|
-
return
|
|
21691
|
+
return _context37.stop();
|
|
21556
21692
|
}
|
|
21557
|
-
},
|
|
21693
|
+
}, _callee37, null, [[20, 26], [33, 40]]);
|
|
21558
21694
|
}));
|
|
21559
21695
|
};
|
|
21560
21696
|
/**
|
|
@@ -31683,6 +31819,10 @@ module.exports = function PublisherPeerConnectionFactory(deps) {
|
|
|
31683
31819
|
});
|
|
31684
31820
|
};
|
|
31685
31821
|
|
|
31822
|
+
this.setIceConfig = newIceConfig => {
|
|
31823
|
+
_peerConnection.setIceConfig(newIceConfig);
|
|
31824
|
+
};
|
|
31825
|
+
|
|
31686
31826
|
this.getSenders = function () {
|
|
31687
31827
|
return _peerConnection.getSenders();
|
|
31688
31828
|
};
|
|
@@ -32122,6 +32262,10 @@ module.exports = function SubscriberPeerConnectionFactory(deps) {
|
|
|
32122
32262
|
}
|
|
32123
32263
|
};
|
|
32124
32264
|
|
|
32265
|
+
this.setIceConfig = iceConfig => {
|
|
32266
|
+
_peerConnection.setIceConfig(iceConfig);
|
|
32267
|
+
};
|
|
32268
|
+
|
|
32125
32269
|
this.startAudioStatsWatcher = function (disableAudioLevelStuckAt0) {
|
|
32126
32270
|
if (!_subscriberAudioWatcher) {
|
|
32127
32271
|
_subscriberAudioWatcher = watchSubscriberAudio(_peerConnection.getStats.bind(_peerConnection), reason => {
|
|
@@ -33108,10 +33252,10 @@ module.exports = function SubscriberFactory(_temp) {
|
|
|
33108
33252
|
}
|
|
33109
33253
|
});
|
|
33110
33254
|
|
|
33111
|
-
_session.on('
|
|
33255
|
+
_session.on('captionReceived', event => {
|
|
33112
33256
|
if (event.streamId === _subscriber.streamId) {
|
|
33113
33257
|
this.dispatchEvent(event);
|
|
33114
|
-
this.trigger(eventNames.
|
|
33258
|
+
this.trigger(eventNames.SUBSCRIBER_CAPTION_RECEIVED, event);
|
|
33115
33259
|
}
|
|
33116
33260
|
});
|
|
33117
33261
|
|
|
@@ -33635,13 +33779,16 @@ module.exports = function SubscriberFactory(_temp) {
|
|
|
33635
33779
|
// Also https://jira.vonage.com/browse/OPENTOK-27112
|
|
33636
33780
|
|
|
33637
33781
|
|
|
33638
|
-
peerConnection
|
|
33639
|
-
|
|
33640
|
-
|
|
33641
|
-
|
|
33642
|
-
|
|
33643
|
-
|
|
33644
|
-
|
|
33782
|
+
if (peerConnection) {
|
|
33783
|
+
// No peer connection if subscribingToSelf
|
|
33784
|
+
peerConnection._getVideoTracks().forEach(track => {
|
|
33785
|
+
if ((typeof window !== undefined ? window : global).webkitMediaStream) {
|
|
33786
|
+
track.enabled = false;
|
|
33787
|
+
} else {
|
|
33788
|
+
track.enabled = _stream.hasVideo && _properties.subscribeToVideo;
|
|
33789
|
+
}
|
|
33790
|
+
});
|
|
33791
|
+
} // Binding the new stream with only its respective tracks
|
|
33645
33792
|
|
|
33646
33793
|
|
|
33647
33794
|
_context7.next = 16;
|
|
@@ -33658,7 +33805,7 @@ module.exports = function SubscriberFactory(_temp) {
|
|
|
33658
33805
|
throw new Error('Subscriber destroyed');
|
|
33659
33806
|
|
|
33660
33807
|
case 19:
|
|
33661
|
-
if ((typeof window !== undefined ? window : global).webkitMediaStream) {
|
|
33808
|
+
if (peerConnection && (typeof window !== undefined ? window : global).webkitMediaStream) {
|
|
33662
33809
|
// Enable any video streams that we previously disabled for OPENTOK-27112
|
|
33663
33810
|
peerConnection._getVideoTracks().forEach(track => {
|
|
33664
33811
|
track.enabled = _stream.hasVideo && _properties.subscribeToVideo;
|
|
@@ -35477,31 +35624,72 @@ module.exports = function SubscriberFactory(_temp) {
|
|
|
35477
35624
|
|
|
35478
35625
|
unblockAudio: () => _widgetView && _widgetView.unblockAudio(),
|
|
35479
35626
|
webRtcStream: () => _webRTCStream,
|
|
35627
|
+
setIceConfig: function () {
|
|
35628
|
+
var _setIceConfig = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee21(iceConfig) {
|
|
35629
|
+
return _regenerator.default.wrap(function _callee21$(_context21) {
|
|
35630
|
+
while (1) switch (_context21.prev = _context21.next) {
|
|
35631
|
+
case 0:
|
|
35632
|
+
getAllPeerConnections().forEach( /*#__PURE__*/function () {
|
|
35633
|
+
var _ref29 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee20(pc) {
|
|
35634
|
+
return _regenerator.default.wrap(function _callee20$(_context20) {
|
|
35635
|
+
while (1) switch (_context20.prev = _context20.next) {
|
|
35636
|
+
case 0:
|
|
35637
|
+
_context20.next = 2;
|
|
35638
|
+
return pc;
|
|
35639
|
+
|
|
35640
|
+
case 2:
|
|
35641
|
+
return _context20.abrupt("return", _context20.sent.setIceConfig(iceConfig));
|
|
35642
|
+
|
|
35643
|
+
case 3:
|
|
35644
|
+
case "end":
|
|
35645
|
+
return _context20.stop();
|
|
35646
|
+
}
|
|
35647
|
+
}, _callee20);
|
|
35648
|
+
}));
|
|
35649
|
+
|
|
35650
|
+
return function (_x20) {
|
|
35651
|
+
return _ref29.apply(this, arguments);
|
|
35652
|
+
};
|
|
35653
|
+
}());
|
|
35654
|
+
|
|
35655
|
+
case 1:
|
|
35656
|
+
case "end":
|
|
35657
|
+
return _context21.stop();
|
|
35658
|
+
}
|
|
35659
|
+
}, _callee21);
|
|
35660
|
+
}));
|
|
35661
|
+
|
|
35662
|
+
function setIceConfig(_x19) {
|
|
35663
|
+
return _setIceConfig.apply(this, arguments);
|
|
35664
|
+
}
|
|
35665
|
+
|
|
35666
|
+
return setIceConfig;
|
|
35667
|
+
}(),
|
|
35480
35668
|
privateEvents: new EventEmitter(),
|
|
35481
35669
|
|
|
35482
35670
|
startRoutedToRelayedTransition() {
|
|
35483
|
-
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
35671
|
+
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee22() {
|
|
35484
35672
|
var mantisPeerConnection;
|
|
35485
|
-
return _regenerator.default.wrap(function
|
|
35486
|
-
while (1) switch (
|
|
35673
|
+
return _regenerator.default.wrap(function _callee22$(_context22) {
|
|
35674
|
+
while (1) switch (_context22.prev = _context22.next) {
|
|
35487
35675
|
case 0:
|
|
35488
35676
|
if (!(_properties.testNetwork || isLocalStream(_stream, _session))) {
|
|
35489
|
-
|
|
35677
|
+
_context22.next = 2;
|
|
35490
35678
|
break;
|
|
35491
35679
|
}
|
|
35492
35680
|
|
|
35493
|
-
return
|
|
35681
|
+
return _context22.abrupt("return");
|
|
35494
35682
|
|
|
35495
35683
|
case 2:
|
|
35496
35684
|
logRoutedToRelayedTransition('Attempt');
|
|
35497
|
-
|
|
35685
|
+
_context22.next = 5;
|
|
35498
35686
|
return getPeerConnectionBySourceStreamId('MANTIS');
|
|
35499
35687
|
|
|
35500
35688
|
case 5:
|
|
35501
|
-
mantisPeerConnection =
|
|
35689
|
+
mantisPeerConnection = _context22.sent;
|
|
35502
35690
|
|
|
35503
35691
|
if (mantisPeerConnection == null ? void 0 : mantisPeerConnection.iceConnectionStateIsConnected()) {
|
|
35504
|
-
|
|
35692
|
+
_context22.next = 9;
|
|
35505
35693
|
break;
|
|
35506
35694
|
}
|
|
35507
35695
|
|
|
@@ -35516,7 +35704,7 @@ module.exports = function SubscriberFactory(_temp) {
|
|
|
35516
35704
|
logRoutedToRelayedTransition('Failure', {
|
|
35517
35705
|
reason: 'Attempted to transition to Relayed without being connected in Routed mode.'
|
|
35518
35706
|
});
|
|
35519
|
-
return
|
|
35707
|
+
return _context22.abrupt("return");
|
|
35520
35708
|
|
|
35521
35709
|
case 9:
|
|
35522
35710
|
socket.subscriberCreate(_stream.id, _widgetId, // subscriberId
|
|
@@ -35530,24 +35718,24 @@ module.exports = function SubscriberFactory(_temp) {
|
|
|
35530
35718
|
|
|
35531
35719
|
case 10:
|
|
35532
35720
|
case "end":
|
|
35533
|
-
return
|
|
35721
|
+
return _context22.stop();
|
|
35534
35722
|
}
|
|
35535
|
-
},
|
|
35723
|
+
}, _callee22);
|
|
35536
35724
|
}))();
|
|
35537
35725
|
},
|
|
35538
35726
|
|
|
35539
35727
|
startRelayedToRoutedTransition() {
|
|
35540
|
-
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
35728
|
+
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee23() {
|
|
35541
35729
|
var webRTCStream, mantisPc, peerConnection;
|
|
35542
|
-
return _regenerator.default.wrap(function
|
|
35543
|
-
while (1) switch (
|
|
35730
|
+
return _regenerator.default.wrap(function _callee23$(_context23) {
|
|
35731
|
+
while (1) switch (_context23.prev = _context23.next) {
|
|
35544
35732
|
case 0:
|
|
35545
35733
|
if (!(_properties.testNetwork || isLocalStream(_stream, _session))) {
|
|
35546
|
-
|
|
35734
|
+
_context23.next = 2;
|
|
35547
35735
|
break;
|
|
35548
35736
|
}
|
|
35549
35737
|
|
|
35550
|
-
return
|
|
35738
|
+
return _context23.abrupt("return");
|
|
35551
35739
|
|
|
35552
35740
|
case 2:
|
|
35553
35741
|
logRelayedToRoutedTransition('Attempt');
|
|
@@ -35556,19 +35744,19 @@ module.exports = function SubscriberFactory(_temp) {
|
|
|
35556
35744
|
_mediaStream = _webRTCStream;
|
|
35557
35745
|
|
|
35558
35746
|
if (!_shouldUseSpc) {
|
|
35559
|
-
|
|
35747
|
+
_context23.next = 11;
|
|
35560
35748
|
break;
|
|
35561
35749
|
}
|
|
35562
35750
|
|
|
35563
|
-
|
|
35751
|
+
_context23.next = 9;
|
|
35564
35752
|
return getPeerConnectionBySourceStreamId('MANTIS');
|
|
35565
35753
|
|
|
35566
35754
|
case 9:
|
|
35567
|
-
mantisPc =
|
|
35755
|
+
mantisPc = _context23.sent;
|
|
35568
35756
|
_mediaStream = new MediaStream(mantisPc._getTracks());
|
|
35569
35757
|
|
|
35570
35758
|
case 11:
|
|
35571
|
-
|
|
35759
|
+
_context23.next = 13;
|
|
35572
35760
|
return bindWebRTCStream(_mediaStream);
|
|
35573
35761
|
|
|
35574
35762
|
case 13:
|
|
@@ -35580,12 +35768,12 @@ module.exports = function SubscriberFactory(_temp) {
|
|
|
35580
35768
|
_activeSourceStreamId = 'MANTIS'; // remove webRTCStream
|
|
35581
35769
|
|
|
35582
35770
|
removeWebRTCStream('P2P');
|
|
35583
|
-
|
|
35771
|
+
_context23.next = 19;
|
|
35584
35772
|
return getCurrentPeerConnection();
|
|
35585
35773
|
|
|
35586
35774
|
case 19:
|
|
35587
|
-
peerConnection =
|
|
35588
|
-
|
|
35775
|
+
peerConnection = _context23.sent;
|
|
35776
|
+
_context23.next = 22;
|
|
35589
35777
|
return createAudioLevelSampler(peerConnection);
|
|
35590
35778
|
|
|
35591
35779
|
case 22:
|
|
@@ -35593,9 +35781,9 @@ module.exports = function SubscriberFactory(_temp) {
|
|
|
35593
35781
|
|
|
35594
35782
|
case 23:
|
|
35595
35783
|
case "end":
|
|
35596
|
-
return
|
|
35784
|
+
return _context23.stop();
|
|
35597
35785
|
}
|
|
35598
|
-
},
|
|
35786
|
+
}, _callee23);
|
|
35599
35787
|
}))();
|
|
35600
35788
|
},
|
|
35601
35789
|
|
|
@@ -35713,10 +35901,10 @@ module.exports = function SubscriberFactory(_temp) {
|
|
|
35713
35901
|
|
|
35714
35902
|
|
|
35715
35903
|
this.subscribeToCaptions = /*#__PURE__*/function () {
|
|
35716
|
-
var
|
|
35904
|
+
var _ref30 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee24(value) {
|
|
35717
35905
|
var active, attributes;
|
|
35718
|
-
return _regenerator.default.wrap(function
|
|
35719
|
-
while (1) switch (
|
|
35906
|
+
return _regenerator.default.wrap(function _callee24$(_context24) {
|
|
35907
|
+
while (1) switch (_context24.prev = _context24.next) {
|
|
35720
35908
|
case 0:
|
|
35721
35909
|
active = castToBoolean(value, true);
|
|
35722
35910
|
attributes = {
|
|
@@ -35733,13 +35921,13 @@ module.exports = function SubscriberFactory(_temp) {
|
|
|
35733
35921
|
|
|
35734
35922
|
case 6:
|
|
35735
35923
|
case "end":
|
|
35736
|
-
return
|
|
35924
|
+
return _context24.stop();
|
|
35737
35925
|
}
|
|
35738
|
-
},
|
|
35926
|
+
}, _callee24);
|
|
35739
35927
|
}));
|
|
35740
35928
|
|
|
35741
|
-
return function (
|
|
35742
|
-
return
|
|
35929
|
+
return function (_x21) {
|
|
35930
|
+
return _ref30.apply(this, arguments);
|
|
35743
35931
|
};
|
|
35744
35932
|
}();
|
|
35745
35933
|
/*
|
|
@@ -38555,7 +38743,7 @@ class MediaProcessorConnector {
|
|
|
38555
38743
|
});
|
|
38556
38744
|
}
|
|
38557
38745
|
}
|
|
38558
|
-
const encodedJs = "KGZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2NsYXNzIFR7fVQudXBkYXRlcz17dHJhbnNmb3JtZXJfbmV3OiJOZXcgdHJhbnNmb3JtZXIiLHRyYW5zZm9ybWVyX251bGw6Ik51bGwgdHJhbnNmb3JtZXIifSxULmVycm9ycz17dHJhbnNmb3JtZXJfbm9uZToiTm8gdHJhbnNmb3JtZXJzIHByb3ZpZGVkIix0cmFuc2Zvcm1lcl9zdGFydDoiQ2Fubm90IHN0YXJ0IHRyYW5zZm9ybWVyIix0cmFuc2Zvcm1lcl90cmFuc2Zvcm06IkNhbm5vdCB0cmFuc2Zvcm0gZnJhbWUiLHRyYW5zZm9ybWVyX2ZsdXNoOiJDYW5ub3QgZmx1c2ggdHJhbnNmb3JtZXIiLHJlYWRhYmxlX251bGw6IlJlYWRhYmxlIGlzIG51bGwiLHdyaXRhYmxlX251bGw6IldyaXRhYmxlIGlzIG51bGwifTt2YXIgdGU9e2V4cG9ydHM6e319LEVlPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKCl7Zm9yKHZhciBuPW5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoKSxvPTA7bzxuLmxlbmd0aDtvKyspbltvXT1hcmd1bWVudHNbb107cmV0dXJuIGUuYXBwbHkodCxuKX19LHJ0PUVlLFI9T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztmdW5jdGlvbiByZShyKXtyZXR1cm4gQXJyYXkuaXNBcnJheShyKX1mdW5jdGlvbiBzZShyKXtyZXR1cm4gdHlwZW9mIHI9PSJ1bmRlZmluZWQifWZ1bmN0aW9uIHN0KHIpe3JldHVybiByIT09bnVsbCYmIXNlKHIpJiZyLmNvbnN0cnVjdG9yIT09bnVsbCYmIXNlKHIuY29uc3RydWN0b3IpJiZ0eXBlb2Ygci5jb25zdHJ1Y3Rvci5pc0J1ZmZlcj09ImZ1bmN0aW9uIiYmci5jb25zdHJ1Y3Rvci5pc0J1ZmZlcihyKX1mdW5jdGlvbiBQZShyKXtyZXR1cm4gUi5jYWxsKHIpPT09IltvYmplY3QgQXJyYXlCdWZmZXJdIn1mdW5jdGlvbiBudChyKXtyZXR1cm4gUi5jYWxsKHIpPT09IltvYmplY3QgRm9ybURhdGFdIn1mdW5jdGlvbiBpdChyKXt2YXIgZTtyZXR1cm4gdHlwZW9mIEFycmF5QnVmZmVyIT0idW5kZWZpbmVkIiYmQXJyYXlCdWZmZXIuaXNWaWV3P2U9QXJyYXlCdWZmZXIuaXNWaWV3KHIpOmU9ciYmci5idWZmZXImJlBlKHIuYnVmZmVyKSxlfWZ1bmN0aW9uIG90KHIpe3JldHVybiB0eXBlb2Ygcj09InN0cmluZyJ9ZnVuY3Rpb24gYXQocil7cmV0dXJuIHR5cGVvZiByPT0ibnVtYmVyIn1mdW5jdGlvbiBUZShyKXtyZXR1cm4gciE9PW51bGwmJnR5cGVvZiByPT0ib2JqZWN0In1mdW5jdGlvbiBIKHIpe2lmKFIuY2FsbChyKSE9PSJbb2JqZWN0IE9iamVjdF0iKXJldHVybiExO3ZhciBlPU9iamVjdC5nZXRQcm90b3R5cGVPZihyKTtyZXR1cm4gZT09PW51bGx8fGU9PT1PYmplY3QucHJvdG90eXBlfWZ1bmN0aW9uIHV0KHIpe3JldHVybiBSLmNhbGwocik9PT0iW29iamVjdCBEYXRlXSJ9ZnVuY3Rpb24gbHQocil7cmV0dXJuIFIuY2FsbChyKT09PSJbb2JqZWN0IEZpbGVdIn1mdW5jdGlvbiBjdChyKXtyZXR1cm4gUi5jYWxsKHIpPT09IltvYmplY3QgQmxvYl0ifWZ1bmN0aW9uIFJlKHIpe3JldHVybiBSLmNhbGwocik9PT0iW29iamVjdCBGdW5jdGlvbl0ifWZ1bmN0aW9uIGZ0KHIpe3JldHVybiBUZShyKSYmUmUoci5waXBlKX1mdW5jdGlvbiBodChyKXtyZXR1cm4gUi5jYWxsKHIpPT09IltvYmplY3QgVVJMU2VhcmNoUGFyYW1zXSJ9ZnVuY3Rpb24gZHQocil7cmV0dXJuIHIudHJpbT9yLnRyaW0oKTpyLnJlcGxhY2UoL15ccyt8XHMrJC9nLCIiKX1mdW5jdGlvbiBwdCgpe3JldHVybiB0eXBlb2YgbmF2aWdhdG9yIT0idW5kZWZpbmVkIiYmKG5hdmlnYXRvci5wcm9kdWN0PT09IlJlYWN0TmF0aXZlInx8bmF2aWdhdG9yLnByb2R1Y3Q9PT0iTmF0aXZlU2NyaXB0Inx8bmF2aWdhdG9yLnByb2R1Y3Q9PT0iTlMiKT8hMTp0eXBlb2Ygd2luZG93IT0idW5kZWZpbmVkIiYmdHlwZW9mIGRvY3VtZW50IT0idW5kZWZpbmVkIn1mdW5jdGlvbiBuZShyLGUpe2lmKCEocj09PW51bGx8fHR5cGVvZiByPT0idW5kZWZpbmVkIikpaWYodHlwZW9mIHIhPSJvYmplY3QiJiYocj1bcl0pLHJlKHIpKWZvcih2YXIgdD0wLHM9ci5sZW5ndGg7dDxzO3QrKyllLmNhbGwobnVsbCxyW3RdLHQscik7ZWxzZSBmb3IodmFyIG4gaW4gcilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocixuKSYmZS5jYWxsKG51bGwscltuXSxuLHIpfWZ1bmN0aW9uIGllKCl7dmFyIHI9e307ZnVuY3Rpb24gZShuLG8pe0gocltvXSkmJkgobik/cltvXT1pZShyW29dLG4pOkgobik/cltvXT1pZSh7fSxuKTpyZShuKT9yW29dPW4uc2xpY2UoKTpyW29dPW59Zm9yKHZhciB0PTAscz1hcmd1bWVudHMubGVuZ3RoO3Q8czt0KyspbmUoYXJndW1lbnRzW3RdLGUpO3JldHVybiByfWZ1bmN0aW9uIG10KHIsZSx0KXtyZXR1cm4gbmUoZSxmdW5jdGlvbihuLG8pe3QmJnR5cGVvZiBuPT0iZnVuY3Rpb24iP3Jbb109cnQobix0KTpyW29dPW59KSxyfWZ1bmN0aW9uIGd0KHIpe3JldHVybiByLmNoYXJDb2RlQXQoMCk9PT02NTI3OSYmKHI9ci5zbGljZSgxKSkscn12YXIgcD17aXNBcnJheTpyZSxpc0FycmF5QnVmZmVyOlBlLGlzQnVmZmVyOnN0LGlzRm9ybURhdGE6bnQsaXNBcnJheUJ1ZmZlclZpZXc6aXQsaXNTdHJpbmc6b3QsaXNOdW1iZXI6YXQsaXNPYmplY3Q6VGUsaXNQbGFpbk9iamVjdDpILGlzVW5kZWZpbmVkOnNlLGlzRGF0ZTp1dCxpc0ZpbGU6bHQsaXNCbG9iOmN0LGlzRnVuY3Rpb246UmUsaXNTdHJlYW06ZnQsaXNVUkxTZWFyY2hQYXJhbXM6aHQsaXNTdGFuZGFyZEJyb3dzZXJFbnY6cHQsZm9yRWFjaDpuZSxtZXJnZTppZSxleHRlbmQ6bXQsdHJpbTpkdCxzdHJpcEJPTTpndH0sTT1wO2Z1bmN0aW9uIFNlKHIpe3JldHVybiBlbmNvZGVVUklDb21wb25lbnQocikucmVwbGFjZSgvJTNBL2dpLCI6IikucmVwbGFjZSgvJTI0L2csIiQiKS5yZXBsYWNlKC8lMkMvZ2ksIiwiKS5yZXBsYWNlKC8lMjAvZywiKyIpLnJlcGxhY2UoLyU1Qi9naSwiWyIpLnJlcGxhY2UoLyU1RC9naSwiXSIpfXZhciBDZT1mdW5jdGlvbihlLHQscyl7aWYoIXQpcmV0dXJuIGU7dmFyIG47aWYocyluPXModCk7ZWxzZSBpZihNLmlzVVJMU2VhcmNoUGFyYW1zKHQpKW49dC50b1N0cmluZygpO2Vsc2V7dmFyIG89W107TS5mb3JFYWNoKHQsZnVuY3Rpb24obCxnKXtsPT09bnVsbHx8dHlwZW9mIGw9PSJ1bmRlZmluZWQifHwoTS5pc0FycmF5KGwpP2c9ZysiW10iOmw9W2xdLE0uZm9yRWFjaChsLGZ1bmN0aW9uKGYpe00uaXNEYXRlKGYpP2Y9Zi50b0lTT1N0cmluZygpOk0uaXNPYmplY3QoZikmJihmPUpTT04uc3RyaW5naWZ5KGYpKSxvLnB1c2goU2UoZykrIj0iK1NlKGYpKX0pKX0pLG49by5qb2luKCImIil9aWYobil7dmFyIGk9ZS5pbmRleE9mKCIjIik7aSE9PS0xJiYoZT1lLnNsaWNlKDAsaSkpLGUrPShlLmluZGV4T2YoIj8iKT09PS0xPyI/IjoiJiIpK259cmV0dXJuIGV9LF90PXA7ZnVuY3Rpb24gcSgpe3RoaXMuaGFuZGxlcnM9W119cS5wcm90b3R5cGUudXNlPWZ1bmN0aW9uKGUsdCxzKXtyZXR1cm4gdGhpcy5oYW5kbGVycy5wdXNoKHtmdWxmaWxsZWQ6ZSxyZWplY3RlZDp0LHN5bmNocm9ub3VzOnM/cy5zeW5jaHJvbm91czohMSxydW5XaGVuOnM/cy5ydW5XaGVuOm51bGx9KSx0aGlzLmhhbmRsZXJzLmxlbmd0aC0xfSxxLnByb3RvdHlwZS5lamVjdD1mdW5jdGlvbihlKXt0aGlzLmhhbmRsZXJzW2VdJiYodGhpcy5oYW5kbGVyc1tlXT1udWxsKX0scS5wcm90b3R5cGUuZm9yRWFjaD1mdW5jdGlvbihlKXtfdC5mb3JFYWNoKHRoaXMuaGFuZGxlcnMsZnVuY3Rpb24ocyl7cyE9PW51bGwmJmUocyl9KX07dmFyIHl0PXEsYnQ9cCx3dD1mdW5jdGlvbihlLHQpe2J0LmZvckVhY2goZSxmdW5jdGlvbihuLG8pe28hPT10JiZvLnRvVXBwZXJDYXNlKCk9PT10LnRvVXBwZXJDYXNlKCkmJihlW3RdPW4sZGVsZXRlIGVbb10pfSl9LE9lPWZ1bmN0aW9uKGUsdCxzLG4sbyl7cmV0dXJuIGUuY29uZmlnPXQscyYmKGUuY29kZT1zKSxlLnJlcXVlc3Q9bixlLnJlc3BvbnNlPW8sZS5pc0F4aW9zRXJyb3I9ITAsZS50b0pTT049ZnVuY3Rpb24oKXtyZXR1cm57bWVzc2FnZTp0aGlzLm1lc3NhZ2UsbmFtZTp0aGlzLm5hbWUsZGVzY3JpcHRpb246dGhpcy5kZXNjcmlwdGlvbixudW1iZXI6dGhpcy5udW1iZXIsZmlsZU5hbWU6dGhpcy5maWxlTmFtZSxsaW5lTnVtYmVyOnRoaXMubGluZU51bWJlcixjb2x1bW5OdW1iZXI6dGhpcy5jb2x1bW5OdW1iZXIsc3RhY2s6dGhpcy5zdGFjayxjb25maWc6dGhpcy5jb25maWcsY29kZTp0aGlzLmNvZGUsc3RhdHVzOnRoaXMucmVzcG9uc2UmJnRoaXMucmVzcG9uc2Uuc3RhdHVzP3RoaXMucmVzcG9uc2Uuc3RhdHVzOm51bGx9fSxlfSx2dD1PZSxJZT1mdW5jdGlvbihlLHQscyxuLG8pe3ZhciBpPW5ldyBFcnJvcihlKTtyZXR1cm4gdnQoaSx0LHMsbixvKX0sRXQ9SWUsUHQ9ZnVuY3Rpb24oZSx0LHMpe3ZhciBuPXMuY29uZmlnLnZhbGlkYXRlU3RhdHVzOyFzLnN0YXR1c3x8IW58fG4ocy5zdGF0dXMpP2Uocyk6dChFdCgiUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgY29kZSAiK3Muc3RhdHVzLHMuY29uZmlnLG51bGwscy5yZXF1ZXN0LHMpKX0saj1wLFR0PWouaXNTdGFuZGFyZEJyb3dzZXJFbnYoKT9mdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbih0LHMsbixvLGksYSl7dmFyIGw9W107bC5wdXNoKHQrIj0iK2VuY29kZVVSSUNvbXBvbmVudChzKSksai5pc051bWJlcihuKSYmbC5wdXNoKCJleHBpcmVzPSIrbmV3IERhdGUobikudG9HTVRTdHJpbmcoKSksai5pc1N0cmluZyhvKSYmbC5wdXNoKCJwYXRoPSIrbyksai5pc1N0cmluZyhpKSYmbC5wdXNoKCJkb21haW49IitpKSxhPT09ITAmJmwucHVzaCgic2VjdXJlIiksZG9jdW1lbnQuY29va2llPWwuam9pbigiOyAiKX0scmVhZDpmdW5jdGlvbih0KXt2YXIgcz1kb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cCgiKF58O1xccyopKCIrdCsiKT0oW147XSopIikpO3JldHVybiBzP2RlY29kZVVSSUNvbXBvbmVudChzWzNdKTpudWxsfSxyZW1vdmU6ZnVuY3Rpb24odCl7dGhpcy53cml0ZSh0LCIiLERhdGUubm93KCktODY0ZTUpfX19KCk6ZnVuY3Rpb24oKXtyZXR1cm57d3JpdGU6ZnVuY3Rpb24oKXt9LHJlYWQ6ZnVuY3Rpb24oKXtyZXR1cm4gbnVsbH0scmVtb3ZlOmZ1bmN0aW9uKCl7fX19KCksUnQ9ZnVuY3Rpb24oZSl7cmV0dXJuL14oW2Etel1bYS16XGQrXC0uXSo6KT9cL1wvL2kudGVzdChlKX0sU3Q9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdD9lLnJlcGxhY2UoL1wvKyQvLCIiKSsiLyIrdC5yZXBsYWNlKC9eXC8rLywiIik6ZX0sQ3Q9UnQsT3Q9U3QsSXQ9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSYmIUN0KHQpP090KGUsdCk6dH0sb2U9cCxNdD1bImFnZSIsImF1dGhvcml6YXRpb24iLCJjb250ZW50LWxlbmd0aCIsImNvbnRlbnQtdHlwZSIsImV0YWciLCJleHBpcmVzIiwiZnJvbSIsImhvc3QiLCJpZi1tb2RpZmllZC1zaW5jZSIsImlmLXVubW9kaWZpZWQtc2luY2UiLCJsYXN0LW1vZGlmaWVkIiwibG9jYXRpb24iLCJtYXgtZm9yd2FyZHMiLCJwcm94eS1hdXRob3JpemF0aW9uIiwicmVmZXJlciIsInJldHJ5LWFmdGVyIiwidXNlci1hZ2VudCJdLHh0PWZ1bmN0aW9uKGUpe3ZhciB0PXt9LHMsbixvO3JldHVybiBlJiZvZS5mb3JFYWNoKGUuc3BsaXQoYApgKSxmdW5jdGlvbihhKXtpZihvPWEuaW5kZXhPZigiOiIpLHM9b2UudHJpbShhLnN1YnN0cigwLG8pKS50b0xvd2VyQ2FzZSgpLG49b2UudHJpbShhLnN1YnN0cihvKzEpKSxzKXtpZih0W3NdJiZNdC5pbmRleE9mKHMpPj0wKXJldHVybjtzPT09InNldC1jb29raWUiP3Rbc109KHRbc10/dFtzXTpbXSkuY29uY2F0KFtuXSk6dFtzXT10W3NdP3Rbc10rIiwgIituOm59fSksdH0sTWU9cCxBdD1NZS5pc1N0YW5kYXJkQnJvd3NlckVudigpP2Z1bmN0aW9uKCl7dmFyIGU9Lyhtc2llfHRyaWRlbnQpL2kudGVzdChuYXZpZ2F0b3IudXNlckFnZW50KSx0PWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImEiKSxzO2Z1bmN0aW9uIG4obyl7dmFyIGk9bztyZXR1cm4gZSYmKHQuc2V0QXR0cmlidXRlKCJocmVmIixpKSxpPXQuaHJlZiksdC5zZXRBdHRyaWJ1dGUoImhyZWYiLGkpLHtocmVmOnQuaHJlZixwcm90b2NvbDp0LnByb3RvY29sP3QucHJvdG9jb2wucmVwbGFjZSgvOiQvLCIiKToiIixob3N0OnQuaG9zdCxzZWFyY2g6dC5zZWFyY2g/dC5zZWFyY2gucmVwbGFjZSgvXlw/LywiIik6IiIsaGFzaDp0Lmhhc2g/dC5oYXNoLnJlcGxhY2UoL14jLywiIik6IiIsaG9zdG5hbWU6dC5ob3N0bmFtZSxwb3J0OnQucG9ydCxwYXRobmFtZTp0LnBhdGhuYW1lLmNoYXJBdCgwKT09PSIvIj90LnBhdGhuYW1lOiIvIit0LnBhdGhuYW1lfX1yZXR1cm4gcz1uKHdpbmRvdy5sb2NhdGlvbi5ocmVmKSxmdW5jdGlvbihpKXt2YXIgYT1NZS5pc1N0cmluZyhpKT9uKGkpOmk7cmV0dXJuIGEucHJvdG9jb2w9PT1zLnByb3RvY29sJiZhLmhvc3Q9PT1zLmhvc3R9fSgpOmZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuITB9fSgpO2Z1bmN0aW9uIGFlKHIpe3RoaXMubWVzc2FnZT1yfWFlLnByb3RvdHlwZS50b1N0cmluZz1mdW5jdGlvbigpe3JldHVybiJDYW5jZWwiKyh0aGlzLm1lc3NhZ2U/IjogIit0aGlzLm1lc3NhZ2U6IiIpfSxhZS5wcm90b3R5cGUuX19DQU5DRUxfXz0hMDt2YXIgRz1hZSxKPXAsa3Q9UHQsTnQ9VHQsVXQ9Q2UsQnQ9SXQsTHQ9eHQsRHQ9QXQsdWU9SWUsJHQ9VyxGdD1HLHhlPWZ1bmN0aW9uKGUpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihzLG4pe3ZhciBvPWUuZGF0YSxpPWUuaGVhZGVycyxhPWUucmVzcG9uc2VUeXBlLGw7ZnVuY3Rpb24gZygpe2UuY2FuY2VsVG9rZW4mJmUuY2FuY2VsVG9rZW4udW5zdWJzY3JpYmUobCksZS5zaWduYWwmJmUuc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoImFib3J0IixsKX1KLmlzRm9ybURhdGEobykmJmRlbGV0ZSBpWyJDb250ZW50LVR5cGUiXTt2YXIgdT1uZXcgWE1MSHR0cFJlcXVlc3Q7aWYoZS5hdXRoKXt2YXIgZj1lLmF1dGgudXNlcm5hbWV8fCIiLFA9ZS5hdXRoLnBhc3N3b3JkP3VuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudChlLmF1dGgucGFzc3dvcmQpKToiIjtpLkF1dGhvcml6YXRpb249IkJhc2ljICIrYnRvYShmKyI6IitQKX12YXIgXz1CdChlLmJhc2VVUkwsZS51cmwpO3Uub3BlbihlLm1ldGhvZC50b1VwcGVyQ2FzZSgpLFV0KF8sZS5wYXJhbXMsZS5wYXJhbXNTZXJpYWxpemVyKSwhMCksdS50aW1lb3V0PWUudGltZW91dDtmdW5jdGlvbiBldCgpe2lmKCEhdSl7dmFyIHY9ImdldEFsbFJlc3BvbnNlSGVhZGVycyJpbiB1P0x0KHUuZ2V0QWxsUmVzcG9uc2VIZWFkZXJzKCkpOm51bGwsQj0hYXx8YT09PSJ0ZXh0Inx8YT09PSJqc29uIj91LnJlc3BvbnNlVGV4dDp1LnJlc3BvbnNlLEk9e2RhdGE6QixzdGF0dXM6dS5zdGF0dXMsc3RhdHVzVGV4dDp1LnN0YXR1c1RleHQsaGVhZGVyczp2LGNvbmZpZzplLHJlcXVlc3Q6dX07a3QoZnVuY3Rpb24odmUpe3ModmUpLGcoKX0sZnVuY3Rpb24odmUpe24odmUpLGcoKX0sSSksdT1udWxsfX1pZigib25sb2FkZW5kImluIHU/dS5vbmxvYWRlbmQ9ZXQ6dS5vbnJlYWR5c3RhdGVjaGFuZ2U9ZnVuY3Rpb24oKXshdXx8dS5yZWFkeVN0YXRlIT09NHx8dS5zdGF0dXM9PT0wJiYhKHUucmVzcG9uc2VVUkwmJnUucmVzcG9uc2VVUkwuaW5kZXhPZigiZmlsZToiKT09PTApfHxzZXRUaW1lb3V0KGV0KX0sdS5vbmFib3J0PWZ1bmN0aW9uKCl7IXV8fChuKHVlKCJSZXF1ZXN0IGFib3J0ZWQiLGUsIkVDT05OQUJPUlRFRCIsdSkpLHU9bnVsbCl9LHUub25lcnJvcj1mdW5jdGlvbigpe24odWUoIk5ldHdvcmsgRXJyb3IiLGUsbnVsbCx1KSksdT1udWxsfSx1Lm9udGltZW91dD1mdW5jdGlvbigpe3ZhciBCPWUudGltZW91dD8idGltZW91dCBvZiAiK2UudGltZW91dCsibXMgZXhjZWVkZWQiOiJ0aW1lb3V0IGV4Y2VlZGVkIixJPWUudHJhbnNpdGlvbmFsfHwkdC50cmFuc2l0aW9uYWw7ZS50aW1lb3V0RXJyb3JNZXNzYWdlJiYoQj1lLnRpbWVvdXRFcnJvck1lc3NhZ2UpLG4odWUoQixlLEkuY2xhcmlmeVRpbWVvdXRFcnJvcj8iRVRJTUVET1VUIjoiRUNPTk5BQk9SVEVEIix1KSksdT1udWxsfSxKLmlzU3RhbmRhcmRCcm93c2VyRW52KCkpe3ZhciB0dD0oZS53aXRoQ3JlZGVudGlhbHN8fER0KF8pKSYmZS54c3JmQ29va2llTmFtZT9OdC5yZWFkKGUueHNyZkNvb2tpZU5hbWUpOnZvaWQgMDt0dCYmKGlbZS54c3JmSGVhZGVyTmFtZV09dHQpfSJzZXRSZXF1ZXN0SGVhZGVyImluIHUmJkouZm9yRWFjaChpLGZ1bmN0aW9uKEIsSSl7dHlwZW9mIG89PSJ1bmRlZmluZWQiJiZJLnRvTG93ZXJDYXNlKCk9PT0iY29udGVudC10eXBlIj9kZWxldGUgaVtJXTp1LnNldFJlcXVlc3RIZWFkZXIoSSxCKX0pLEouaXNVbmRlZmluZWQoZS53aXRoQ3JlZGVudGlhbHMpfHwodS53aXRoQ3JlZGVudGlhbHM9ISFlLndpdGhDcmVkZW50aWFscyksYSYmYSE9PSJqc29uIiYmKHUucmVzcG9uc2VUeXBlPWUucmVzcG9uc2VUeXBlKSx0eXBlb2YgZS5vbkRvd25sb2FkUHJvZ3Jlc3M9PSJmdW5jdGlvbiImJnUuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLGUub25Eb3dubG9hZFByb2dyZXNzKSx0eXBlb2YgZS5vblVwbG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZ1LnVwbG9hZCYmdS51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLGUub25VcGxvYWRQcm9ncmVzcyksKGUuY2FuY2VsVG9rZW58fGUuc2lnbmFsKSYmKGw9ZnVuY3Rpb24odil7IXV8fChuKCF2fHx2JiZ2LnR5cGU/bmV3IEZ0KCJjYW5jZWxlZCIpOnYpLHUuYWJvcnQoKSx1PW51bGwpfSxlLmNhbmNlbFRva2VuJiZlLmNhbmNlbFRva2VuLnN1YnNjcmliZShsKSxlLnNpZ25hbCYmKGUuc2lnbmFsLmFib3J0ZWQ/bCgpOmUuc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoImFib3J0IixsKSkpLG98fChvPW51bGwpLHUuc2VuZChvKX0pfSxoPXAsQWU9d3QsSHQ9T2UscXQ9eyJDb250ZW50LVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifTtmdW5jdGlvbiBrZShyLGUpeyFoLmlzVW5kZWZpbmVkKHIpJiZoLmlzVW5kZWZpbmVkKHJbIkNvbnRlbnQtVHlwZSJdKSYmKHJbIkNvbnRlbnQtVHlwZSJdPWUpfWZ1bmN0aW9uIGp0KCl7dmFyIHI7cmV0dXJuKHR5cGVvZiBYTUxIdHRwUmVxdWVzdCE9InVuZGVmaW5lZCJ8fHR5cGVvZiBwcm9jZXNzIT0idW5kZWZpbmVkIiYmT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHByb2Nlc3MpPT09IltvYmplY3QgcHJvY2Vzc10iKSYmKHI9eGUpLHJ9ZnVuY3Rpb24gR3QocixlLHQpe2lmKGguaXNTdHJpbmcocikpdHJ5e3JldHVybihlfHxKU09OLnBhcnNlKShyKSxoLnRyaW0ocil9Y2F0Y2gocyl7aWYocy5uYW1lIT09IlN5bnRheEVycm9yIil0aHJvdyBzfXJldHVybih0fHxKU09OLnN0cmluZ2lmeSkocil9dmFyIFY9e3RyYW5zaXRpb25hbDp7c2lsZW50SlNPTlBhcnNpbmc6ITAsZm9yY2VkSlNPTlBhcnNpbmc6ITAsY2xhcmlmeVRpbWVvdXRFcnJvcjohMX0sYWRhcHRlcjpqdCgpLHRyYW5zZm9ybVJlcXVlc3Q6W2Z1bmN0aW9uKGUsdCl7cmV0dXJuIEFlKHQsIkFjY2VwdCIpLEFlKHQsIkNvbnRlbnQtVHlwZSIpLGguaXNGb3JtRGF0YShlKXx8aC5pc0FycmF5QnVmZmVyKGUpfHxoLmlzQnVmZmVyKGUpfHxoLmlzU3RyZWFtKGUpfHxoLmlzRmlsZShlKXx8aC5pc0Jsb2IoZSk/ZTpoLmlzQXJyYXlCdWZmZXJWaWV3KGUpP2UuYnVmZmVyOmguaXNVUkxTZWFyY2hQYXJhbXMoZSk/KGtlKHQsImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDtjaGFyc2V0PXV0Zi04IiksZS50b1N0cmluZygpKTpoLmlzT2JqZWN0KGUpfHx0JiZ0WyJDb250ZW50LVR5cGUiXT09PSJhcHBsaWNhdGlvbi9qc29uIj8oa2UodCwiYXBwbGljYXRpb24vanNvbiIpLEd0KGUpKTplfV0sdHJhbnNmb3JtUmVzcG9uc2U6W2Z1bmN0aW9uKGUpe3ZhciB0PXRoaXMudHJhbnNpdGlvbmFsfHxWLnRyYW5zaXRpb25hbCxzPXQmJnQuc2lsZW50SlNPTlBhcnNpbmcsbj10JiZ0LmZvcmNlZEpTT05QYXJzaW5nLG89IXMmJnRoaXMucmVzcG9uc2VUeXBlPT09Impzb24iO2lmKG98fG4mJmguaXNTdHJpbmcoZSkmJmUubGVuZ3RoKXRyeXtyZXR1cm4gSlNPTi5wYXJzZShlKX1jYXRjaChpKXtpZihvKXRocm93IGkubmFtZT09PSJTeW50YXhFcnJvciI/SHQoaSx0aGlzLCJFX0pTT05fUEFSU0UiKTppfXJldHVybiBlfV0sdGltZW91dDowLHhzcmZDb29raWVOYW1lOiJYU1JGLVRPS0VOIix4c3JmSGVhZGVyTmFtZToiWC1YU1JGLVRPS0VOIixtYXhDb250ZW50TGVuZ3RoOi0xLG1heEJvZHlMZW5ndGg6LTEsdmFsaWRhdGVTdGF0dXM6ZnVuY3Rpb24oZSl7cmV0dXJuIGU+PTIwMCYmZTwzMDB9LGhlYWRlcnM6e2NvbW1vbjp7QWNjZXB0OiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L3BsYWluLCAqLyoifX19O2guZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiXSxmdW5jdGlvbihlKXtWLmhlYWRlcnNbZV09e319KSxoLmZvckVhY2goWyJwb3N0IiwicHV0IiwicGF0Y2giXSxmdW5jdGlvbihlKXtWLmhlYWRlcnNbZV09aC5tZXJnZShxdCl9KTt2YXIgVz1WLEp0PXAsVnQ9VyxXdD1mdW5jdGlvbihlLHQscyl7dmFyIG49dGhpc3x8VnQ7cmV0dXJuIEp0LmZvckVhY2gocyxmdW5jdGlvbihpKXtlPWkuY2FsbChuLGUsdCl9KSxlfSxOZT1mdW5jdGlvbihlKXtyZXR1cm4hIShlJiZlLl9fQ0FOQ0VMX18pfSxVZT1wLGxlPVd0LHp0PU5lLFF0PVcsWHQ9RztmdW5jdGlvbiBjZShyKXtpZihyLmNhbmNlbFRva2VuJiZyLmNhbmNlbFRva2VuLnRocm93SWZSZXF1ZXN0ZWQoKSxyLnNpZ25hbCYmci5zaWduYWwuYWJvcnRlZCl0aHJvdyBuZXcgWHQoImNhbmNlbGVkIil9dmFyIEt0PWZ1bmN0aW9uKGUpe2NlKGUpLGUuaGVhZGVycz1lLmhlYWRlcnN8fHt9LGUuZGF0YT1sZS5jYWxsKGUsZS5kYXRhLGUuaGVhZGVycyxlLnRyYW5zZm9ybVJlcXVlc3QpLGUuaGVhZGVycz1VZS5tZXJnZShlLmhlYWRlcnMuY29tbW9ufHx7fSxlLmhlYWRlcnNbZS5tZXRob2RdfHx7fSxlLmhlYWRlcnMpLFVlLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sZnVuY3Rpb24obil7ZGVsZXRlIGUuaGVhZGVyc1tuXX0pO3ZhciB0PWUuYWRhcHRlcnx8UXQuYWRhcHRlcjtyZXR1cm4gdChlKS50aGVuKGZ1bmN0aW9uKG4pe3JldHVybiBjZShlKSxuLmRhdGE9bGUuY2FsbChlLG4uZGF0YSxuLmhlYWRlcnMsZS50cmFuc2Zvcm1SZXNwb25zZSksbn0sZnVuY3Rpb24obil7cmV0dXJuIHp0KG4pfHwoY2UoZSksbiYmbi5yZXNwb25zZSYmKG4ucmVzcG9uc2UuZGF0YT1sZS5jYWxsKGUsbi5yZXNwb25zZS5kYXRhLG4ucmVzcG9uc2UuaGVhZGVycyxlLnRyYW5zZm9ybVJlc3BvbnNlKSkpLFByb21pc2UucmVqZWN0KG4pfSl9LHk9cCxCZT1mdW5jdGlvbihlLHQpe3Q9dHx8e307dmFyIHM9e307ZnVuY3Rpb24gbih1LGYpe3JldHVybiB5LmlzUGxhaW5PYmplY3QodSkmJnkuaXNQbGFpbk9iamVjdChmKT95Lm1lcmdlKHUsZik6eS5pc1BsYWluT2JqZWN0KGYpP3kubWVyZ2Uoe30sZik6eS5pc0FycmF5KGYpP2Yuc2xpY2UoKTpmfWZ1bmN0aW9uIG8odSl7aWYoeS5pc1VuZGVmaW5lZCh0W3VdKSl7aWYoIXkuaXNVbmRlZmluZWQoZVt1XSkpcmV0dXJuIG4odm9pZCAwLGVbdV0pfWVsc2UgcmV0dXJuIG4oZVt1XSx0W3VdKX1mdW5jdGlvbiBpKHUpe2lmKCF5LmlzVW5kZWZpbmVkKHRbdV0pKXJldHVybiBuKHZvaWQgMCx0W3VdKX1mdW5jdGlvbiBhKHUpe2lmKHkuaXNVbmRlZmluZWQodFt1XSkpe2lmKCF5LmlzVW5kZWZpbmVkKGVbdV0pKXJldHVybiBuKHZvaWQgMCxlW3VdKX1lbHNlIHJldHVybiBuKHZvaWQgMCx0W3VdKX1mdW5jdGlvbiBsKHUpe2lmKHUgaW4gdClyZXR1cm4gbihlW3VdLHRbdV0pO2lmKHUgaW4gZSlyZXR1cm4gbih2b2lkIDAsZVt1XSl9dmFyIGc9e3VybDppLG1ldGhvZDppLGRhdGE6aSxiYXNlVVJMOmEsdHJhbnNmb3JtUmVxdWVzdDphLHRyYW5zZm9ybVJlc3BvbnNlOmEscGFyYW1zU2VyaWFsaXplcjphLHRpbWVvdXQ6YSx0aW1lb3V0TWVzc2FnZTphLHdpdGhDcmVkZW50aWFsczphLGFkYXB0ZXI6YSxyZXNwb25zZVR5cGU6YSx4c3JmQ29va2llTmFtZTphLHhzcmZIZWFkZXJOYW1lOmEsb25VcGxvYWRQcm9ncmVzczphLG9uRG93bmxvYWRQcm9ncmVzczphLGRlY29tcHJlc3M6YSxtYXhDb250ZW50TGVuZ3RoOmEsbWF4Qm9keUxlbmd0aDphLHRyYW5zcG9ydDphLGh0dHBBZ2VudDphLGh0dHBzQWdlbnQ6YSxjYW5jZWxUb2tlbjphLHNvY2tldFBhdGg6YSxyZXNwb25zZUVuY29kaW5nOmEsdmFsaWRhdGVTdGF0dXM6bH07cmV0dXJuIHkuZm9yRWFjaChPYmplY3Qua2V5cyhlKS5jb25jYXQoT2JqZWN0LmtleXModCkpLGZ1bmN0aW9uKGYpe3ZhciBQPWdbZl18fG8sXz1QKGYpO3kuaXNVbmRlZmluZWQoXykmJlAhPT1sfHwoc1tmXT1fKX0pLHN9LExlPXt2ZXJzaW9uOiIwLjI1LjAifSxZdD1MZS52ZXJzaW9uLGZlPXt9O1sib2JqZWN0IiwiYm9vbGVhbiIsIm51bWJlciIsImZ1bmN0aW9uIiwic3RyaW5nIiwic3ltYm9sIl0uZm9yRWFjaChmdW5jdGlvbihyLGUpe2ZlW3JdPWZ1bmN0aW9uKHMpe3JldHVybiB0eXBlb2Ygcz09PXJ8fCJhIisoZTwxPyJuICI6IiAiKStyfX0pO3ZhciBEZT17fTtmZS50cmFuc2l0aW9uYWw9ZnVuY3Rpb24oZSx0LHMpe2Z1bmN0aW9uIG4obyxpKXtyZXR1cm4iW0F4aW9zIHYiK1l0KyJdIFRyYW5zaXRpb25hbCBvcHRpb24gJyIrbysiJyIraSsocz8iLiAiK3M6IiIpfXJldHVybiBmdW5jdGlvbihvLGksYSl7aWYoZT09PSExKXRocm93IG5ldyBFcnJvcihuKGksIiBoYXMgYmVlbiByZW1vdmVkIisodD8iIGluICIrdDoiIikpKTtyZXR1cm4gdCYmIURlW2ldJiYoRGVbaV09ITAsY29uc29sZS53YXJuKG4oaSwiIGhhcyBiZWVuIGRlcHJlY2F0ZWQgc2luY2UgdiIrdCsiIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5lYXIgZnV0dXJlIikpKSxlP2UobyxpLGEpOiEwfX07ZnVuY3Rpb24gWnQocixlLHQpe2lmKHR5cGVvZiByIT0ib2JqZWN0Iil0aHJvdyBuZXcgVHlwZUVycm9yKCJvcHRpb25zIG11c3QgYmUgYW4gb2JqZWN0Iik7Zm9yKHZhciBzPU9iamVjdC5rZXlzKHIpLG49cy5sZW5ndGg7bi0tID4wOyl7dmFyIG89c1tuXSxpPWVbb107aWYoaSl7dmFyIGE9cltvXSxsPWE9PT12b2lkIDB8fGkoYSxvLHIpO2lmKGwhPT0hMCl0aHJvdyBuZXcgVHlwZUVycm9yKCJvcHRpb24gIitvKyIgbXVzdCBiZSAiK2wpO2NvbnRpbnVlfWlmKHQhPT0hMCl0aHJvdyBFcnJvcigiVW5rbm93biBvcHRpb24gIitvKX19dmFyIGVyPXthc3NlcnRPcHRpb25zOlp0LHZhbGlkYXRvcnM6ZmV9LCRlPXAsdHI9Q2UsRmU9eXQsSGU9S3Qsej1CZSxxZT1lcix4PXFlLnZhbGlkYXRvcnM7ZnVuY3Rpb24gTChyKXt0aGlzLmRlZmF1bHRzPXIsdGhpcy5pbnRlcmNlcHRvcnM9e3JlcXVlc3Q6bmV3IEZlLHJlc3BvbnNlOm5ldyBGZX19TC5wcm90b3R5cGUucmVxdWVzdD1mdW5jdGlvbihlLHQpe2lmKHR5cGVvZiBlPT0ic3RyaW5nIj8odD10fHx7fSx0LnVybD1lKTp0PWV8fHt9LCF0LnVybCl0aHJvdyBuZXcgRXJyb3IoIlByb3ZpZGVkIGNvbmZpZyB1cmwgaXMgbm90IHZhbGlkIik7dD16KHRoaXMuZGVmYXVsdHMsdCksdC5tZXRob2Q/dC5tZXRob2Q9dC5tZXRob2QudG9Mb3dlckNhc2UoKTp0aGlzLmRlZmF1bHRzLm1ldGhvZD90Lm1ldGhvZD10aGlzLmRlZmF1bHRzLm1ldGhvZC50b0xvd2VyQ2FzZSgpOnQubWV0aG9kPSJnZXQiO3ZhciBzPXQudHJhbnNpdGlvbmFsO3MhPT12b2lkIDAmJnFlLmFzc2VydE9wdGlvbnMocyx7c2lsZW50SlNPTlBhcnNpbmc6eC50cmFuc2l0aW9uYWwoeC5ib29sZWFuKSxmb3JjZWRKU09OUGFyc2luZzp4LnRyYW5zaXRpb25hbCh4LmJvb2xlYW4pLGNsYXJpZnlUaW1lb3V0RXJyb3I6eC50cmFuc2l0aW9uYWwoeC5ib29sZWFuKX0sITEpO3ZhciBuPVtdLG89ITA7dGhpcy5pbnRlcmNlcHRvcnMucmVxdWVzdC5mb3JFYWNoKGZ1bmN0aW9uKF8pe3R5cGVvZiBfLnJ1bldoZW49PSJmdW5jdGlvbiImJl8ucnVuV2hlbih0KT09PSExfHwobz1vJiZfLnN5bmNocm9ub3VzLG4udW5zaGlmdChfLmZ1bGZpbGxlZCxfLnJlamVjdGVkKSl9KTt2YXIgaT1bXTt0aGlzLmludGVyY2VwdG9ycy5yZXNwb25zZS5mb3JFYWNoKGZ1bmN0aW9uKF8pe2kucHVzaChfLmZ1bGZpbGxlZCxfLnJlamVjdGVkKX0pO3ZhciBhO2lmKCFvKXt2YXIgbD1bSGUsdm9pZCAwXTtmb3IoQXJyYXkucHJvdG90eXBlLnVuc2hpZnQuYXBwbHkobCxuKSxsPWwuY29uY2F0KGkpLGE9UHJvbWlzZS5yZXNvbHZlKHQpO2wubGVuZ3RoOylhPWEudGhlbihsLnNoaWZ0KCksbC5zaGlmdCgpKTtyZXR1cm4gYX1mb3IodmFyIGc9dDtuLmxlbmd0aDspe3ZhciB1PW4uc2hpZnQoKSxmPW4uc2hpZnQoKTt0cnl7Zz11KGcpfWNhdGNoKFApe2YoUCk7YnJlYWt9fXRyeXthPUhlKGcpfWNhdGNoKFApe3JldHVybiBQcm9taXNlLnJlamVjdChQKX1mb3IoO2kubGVuZ3RoOylhPWEudGhlbihpLnNoaWZ0KCksaS5zaGlmdCgpKTtyZXR1cm4gYX0sTC5wcm90b3R5cGUuZ2V0VXJpPWZ1bmN0aW9uKGUpe2lmKCFlLnVybCl0aHJvdyBuZXcgRXJyb3IoIlByb3ZpZGVkIGNvbmZpZyB1cmwgaXMgbm90IHZhbGlkIik7cmV0dXJuIGU9eih0aGlzLmRlZmF1bHRzLGUpLHRyKGUudXJsLGUucGFyYW1zLGUucGFyYW1zU2VyaWFsaXplcikucmVwbGFjZSgvXlw/LywiIil9LCRlLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwib3B0aW9ucyJdLGZ1bmN0aW9uKGUpe0wucHJvdG90eXBlW2VdPWZ1bmN0aW9uKHQscyl7cmV0dXJuIHRoaXMucmVxdWVzdCh6KHN8fHt9LHttZXRob2Q6ZSx1cmw6dCxkYXRhOihzfHx7fSkuZGF0YX0pKX19KSwkZS5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7TC5wcm90b3R5cGVbZV09ZnVuY3Rpb24odCxzLG4pe3JldHVybiB0aGlzLnJlcXVlc3QoeihufHx7fSx7bWV0aG9kOmUsdXJsOnQsZGF0YTpzfSkpfX0pO3ZhciBycj1MLHNyPUc7ZnVuY3Rpb24gQShyKXtpZih0eXBlb2YgciE9ImZ1bmN0aW9uIil0aHJvdyBuZXcgVHlwZUVycm9yKCJleGVjdXRvciBtdXN0IGJlIGEgZnVuY3Rpb24uIik7dmFyIGU7dGhpcy5wcm9taXNlPW5ldyBQcm9taXNlKGZ1bmN0aW9uKG4pe2U9bn0pO3ZhciB0PXRoaXM7dGhpcy5wcm9taXNlLnRoZW4oZnVuY3Rpb24ocyl7aWYoISF0Ll9saXN0ZW5lcnMpe3ZhciBuLG89dC5fbGlzdGVuZXJzLmxlbmd0aDtmb3Iobj0wO248bztuKyspdC5fbGlzdGVuZXJzW25dKHMpO3QuX2xpc3RlbmVycz1udWxsfX0pLHRoaXMucHJvbWlzZS50aGVuPWZ1bmN0aW9uKHMpe3ZhciBuLG89bmV3IFByb21pc2UoZnVuY3Rpb24oaSl7dC5zdWJzY3JpYmUoaSksbj1pfSkudGhlbihzKTtyZXR1cm4gby5jYW5jZWw9ZnVuY3Rpb24oKXt0LnVuc3Vic2NyaWJlKG4pfSxvfSxyKGZ1bmN0aW9uKG4pe3QucmVhc29ufHwodC5yZWFzb249bmV3IHNyKG4pLGUodC5yZWFzb24pKX0pfUEucHJvdG90eXBlLnRocm93SWZSZXF1ZXN0ZWQ9ZnVuY3Rpb24oKXtpZih0aGlzLnJlYXNvbil0aHJvdyB0aGlzLnJlYXNvbn0sQS5wcm90b3R5cGUuc3Vic2NyaWJlPWZ1bmN0aW9uKGUpe2lmKHRoaXMucmVhc29uKXtlKHRoaXMucmVhc29uKTtyZXR1cm59dGhpcy5fbGlzdGVuZXJzP3RoaXMuX2xpc3RlbmVycy5wdXNoKGUpOnRoaXMuX2xpc3RlbmVycz1bZV19LEEucHJvdG90eXBlLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKGUpe2lmKCEhdGhpcy5fbGlzdGVuZXJzKXt2YXIgdD10aGlzLl9saXN0ZW5lcnMuaW5kZXhPZihlKTt0IT09LTEmJnRoaXMuX2xpc3RlbmVycy5zcGxpY2UodCwxKX19LEEuc291cmNlPWZ1bmN0aW9uKCl7dmFyIGUsdD1uZXcgQShmdW5jdGlvbihuKXtlPW59KTtyZXR1cm57dG9rZW46dCxjYW5jZWw6ZX19O3ZhciBucj1BLGlyPWZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbihzKXtyZXR1cm4gZS5hcHBseShudWxsLHMpfX0sb3I9cCxhcj1mdW5jdGlvbihlKXtyZXR1cm4gb3IuaXNPYmplY3QoZSkmJmUuaXNBeGlvc0Vycm9yPT09ITB9LGplPXAsdXI9RWUsUT1ycixscj1CZSxjcj1XO2Z1bmN0aW9uIEdlKHIpe3ZhciBlPW5ldyBRKHIpLHQ9dXIoUS5wcm90b3R5cGUucmVxdWVzdCxlKTtyZXR1cm4gamUuZXh0ZW5kKHQsUS5wcm90b3R5cGUsZSksamUuZXh0ZW5kKHQsZSksdC5jcmVhdGU9ZnVuY3Rpb24obil7cmV0dXJuIEdlKGxyKHIsbikpfSx0fXZhciBFPUdlKGNyKTtFLkF4aW9zPVEsRS5DYW5jZWw9RyxFLkNhbmNlbFRva2VuPW5yLEUuaXNDYW5jZWw9TmUsRS5WRVJTSU9OPUxlLnZlcnNpb24sRS5hbGw9ZnVuY3Rpb24oZSl7cmV0dXJuIFByb21pc2UuYWxsKGUpfSxFLnNwcmVhZD1pcixFLmlzQXhpb3NFcnJvcj1hcix0ZS5leHBvcnRzPUUsdGUuZXhwb3J0cy5kZWZhdWx0PUU7dmFyIGZyPXRlLmV4cG9ydHM7Y2xhc3MgY3tpc0VtcHR5KCl7cmV0dXJuIXRoaXMuaXNQcmVzZW50KCl9c3RhdGljIG9mKGUpe2lmKGUhPW51bGwpcmV0dXJuIG5ldyBKZShlKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJUaGUgcGFzc2VkIHZhbHVlIHdhcyBudWxsIG9yIHVuZGVmaW5lZC4iKX1zdGF0aWMgb2ZOb25OdWxsKGUpe3JldHVybiBjLm9mKGUpfXN0YXRpYyBvZk51bGxhYmxlKGUpe3JldHVybiBlIT1udWxsP25ldyBKZShlKTpuZXcgVmV9c3RhdGljIGVtcHR5KCl7cmV0dXJuIG5ldyBWZX1zdGF0aWMgZnJvbShlKXtzd2l0Y2goZS5raW5kKXtjYXNlInByZXNlbnQiOnJldHVybiBjLm9mKGUudmFsdWUpO2Nhc2UiZW1wdHkiOnJldHVybiBjLmVtcHR5KCk7ZGVmYXVsdDp0aHJvdyBuZXcgVHlwZUVycm9yKCJUaGUgcGFzc2VkIHZhbHVlIHdhcyBub3QgYW4gT3B0aW9uIHR5cGUuIil9fX1jbGFzcyBKZSBleHRlbmRzIGN7Y29uc3RydWN0b3IoZSl7c3VwZXIoKSx0aGlzLnBheWxvYWQ9ZX1pc1ByZXNlbnQoKXtyZXR1cm4hMH1nZXQoKXtyZXR1cm4gdGhpcy5wYXlsb2FkfWlmUHJlc2VudChlKXtlKHRoaXMucGF5bG9hZCl9aWZQcmVzZW50T3JFbHNlKGUsdCl7ZSh0aGlzLnBheWxvYWQpfWZpbHRlcihlKXtyZXR1cm4gZSh0aGlzLnBheWxvYWQpP3RoaXM6Yy5lbXB0eSgpfW1hcChlKXtjb25zdCB0PWUodGhpcy5wYXlsb2FkKTtyZXR1cm4gYy5vZk51bGxhYmxlKHQpfWZsYXRNYXAoZSl7cmV0dXJuIGUodGhpcy5wYXlsb2FkKX1vcihlKXtyZXR1cm4gdGhpc31vckVsc2UoZSl7cmV0dXJuIHRoaXMucGF5bG9hZH1vckVsc2VHZXQoZSl7cmV0dXJuIHRoaXMucGF5bG9hZH1vckVsc2VUaHJvdyhlKXtyZXR1cm4gdGhpcy5wYXlsb2FkfW9yTnVsbCgpe3JldHVybiB0aGlzLnBheWxvYWR9b3JVbmRlZmluZWQoKXtyZXR1cm4gdGhpcy5wYXlsb2FkfXRvT3B0aW9uKCl7cmV0dXJue2tpbmQ6InByZXNlbnQiLHZhbHVlOnRoaXMucGF5bG9hZH19bWF0Y2hlcyhlKXtyZXR1cm4gZS5wcmVzZW50KHRoaXMucGF5bG9hZCl9dG9KU09OKGUpe3JldHVybiB0aGlzLnBheWxvYWR9fWNsYXNzIFZlIGV4dGVuZHMgY3tpc1ByZXNlbnQoKXtyZXR1cm4hMX1jb25zdHJ1Y3Rvcigpe3N1cGVyKCl9Z2V0KCl7dGhyb3cgbmV3IFR5cGVFcnJvcigiVGhlIG9wdGlvbmFsIGlzIG5vdCBwcmVzZW50LiIpfWlmUHJlc2VudChlKXt9aWZQcmVzZW50T3JFbHNlKGUsdCl7dCgpfWZpbHRlcihlKXtyZXR1cm4gdGhpc31tYXAoZSl7cmV0dXJuIGMuZW1wdHkoKX1mbGF0TWFwKGUpe3JldHVybiBjLmVtcHR5KCl9b3IoZSl7cmV0dXJuIGUoKX1vckVsc2UoZSl7cmV0dXJuIGV9b3JFbHNlR2V0KGUpe3JldHVybiB0aGlzLm9yRWxzZShlKCkpfW9yRWxzZVRocm93KGUpe3Rocm93IGUoKX1vck51bGwoKXtyZXR1cm4gbnVsbH1vclVuZGVmaW5lZCgpe310b09wdGlvbigpe3JldHVybntraW5kOiJlbXB0eSJ9fW1hdGNoZXMoZSl7cmV0dXJuIGUuZW1wdHkoKX10b0pTT04oZSl7cmV0dXJuIG51bGx9fWNvbnN0IGhyPSIxLjIuNyI7ZnVuY3Rpb24gZHIocil7Z2xvYmFsVGhpcy5fdm9uYWdlTWVkaWFQcm9jZXNzb3JNZXRhZGF0YT1yfWZ1bmN0aW9uIHByKCl7cmV0dXJuIGdsb2JhbFRoaXMuX3ZvbmFnZU1lZGlhUHJvY2Vzc29yTWV0YWRhdGF9Y2xhc3MgYntjb25zdHJ1Y3Rvcigpe2NvbnN0IGU9cHIoKTt0aGlzLl9yZXBvcnQ9e2FjdGlvbjpjLmVtcHR5KCksYXBwbGljYXRpb25JZDpjLm9mTnVsbGFibGUoZSE9PXZvaWQgMCYmZSE9bnVsbD9lLmFwcElkOm51bGwpLHRpbWVzdGFtcDpEYXRlLm5vdygpLGZwczpjLmVtcHR5KCksZnJhbWVzVHJhbnNmb3JtZWQ6Yy5lbXB0eSgpLGd1aWQ6Yy5lbXB0eSgpLGhpZ2hlc3RGcmFtZVRyYW5zZm9ybUNwdTpjLmVtcHR5KCksbWVzc2FnZTpjLmVtcHR5KCksc291cmNlOmMub2ZOdWxsYWJsZShlIT09dm9pZCAwJiZlIT1udWxsP2Uuc291cmNlVHlwZTpudWxsKSx0cmFuc2Zvcm1lZEZwczpjLmVtcHR5KCksdHJhbnNmb3JtZXJUeXBlOmMuZW1wdHkoKSx2YXJpYXRpb246Yy5lbXB0eSgpLHZpZGVvSGVpZ2h0OmMuZW1wdHkoKSx2aWRlb1dpZHRoOmMuZW1wdHkoKSx2ZXJzaW9uOmhyLGVycm9yOmMuZW1wdHkoKSxwcm94eVVybDpjLm9mTnVsbGFibGUoZSE9PXZvaWQgMCYmZSE9bnVsbD9lLnByb3h5VXJsOm51bGwpfX1hY3Rpb24oZSl7cmV0dXJuIHRoaXMuX3JlcG9ydC5hY3Rpb249Yy5vZk51bGxhYmxlKGUpLHRoaXN9ZnJhbWVzVHJhbnNmb3JtZWQoZSl7cmV0dXJuIHRoaXMuX3JlcG9ydC5mcmFtZXNUcmFuc2Zvcm1lZD1jLm9mTnVsbGFibGUoZSksdGhpc31mcHMoZSl7cmV0dXJuIHRoaXMuX3JlcG9ydC5mcHM9Yy5vZk51bGxhYmxlKGUpLHRoaXN9Z3VpZChlKXtyZXR1cm4gdGhpcy5fcmVwb3J0Lmd1aWQ9Yy5vZk51bGxhYmxlKGUpLHRoaXN9bWVzc2FnZShlKXtyZXR1cm4gdGhpcy5fcmVwb3J0Lm1lc3NhZ2U9Yy5vZk51bGxhYmxlKGUpLHRoaXN9dHJhbnNmb3JtZWRGcHMoZSl7cmV0dXJuIHRoaXMuX3JlcG9ydC50cmFuc2Zvcm1lZEZwcz1jLm9mTnVsbGFibGUoZSksdGhpc310cmFuc2Zvcm1lclR5cGUoZSl7cmV0dXJuIHRoaXMuX3JlcG9ydC50cmFuc2Zvcm1lclR5cGU9Yy5vZk51bGxhYmxlKGUpLHRoaXN9dmFyaWF0aW9uKGUpe3JldHVybiB0aGlzLl9yZXBvcnQudmFyaWF0aW9uPWMub2ZOdWxsYWJsZShlKSx0aGlzfXZpZGVvSGVpZ2h0KGUpe3JldHVybiB0aGlzLl9yZXBvcnQudmlkZW9IZWlnaHQ9Yy5vZk51bGxhYmxlKGUpLHRoaXN9dmlkZW9XaWR0aChlKXtyZXR1cm4gdGhpcy5fcmVwb3J0LnZpZGVvV2lkdGg9Yy5vZk51bGxhYmxlKGUpLHRoaXN9ZXJyb3IoZSl7cmV0dXJuIHRoaXMuX3JlcG9ydC5lcnJvcj1jLm9mTnVsbGFibGUoZSksdGhpc31idWlsZCgpe3JldHVybiB0aGlzLl9yZXBvcnR9fWNvbnN0IG1yPXI9PkpTT04uc3RyaW5naWZ5KHIsKGUsdCk9PntpZih0IT09bnVsbClyZXR1cm4gdH0pO2NsYXNzIHd7c3RhdGljIHJlcG9ydChlKXtyZXR1cm4gbmV3IFByb21pc2UoKHQscyk9PntpZihlLmFwcGxpY2F0aW9uSWQuaXNFbXB0eSgpfHxlLnNvdXJjZS5pc0VtcHR5KCkpe3QoInN1Y2Nlc3MiKTtyZXR1cm59bGV0IG49ZnIuY3JlYXRlKCksbz17dGltZW91dDoxZTQsdGltZW91dEVycm9yTWVzc2FnZToiUmVxdWVzdCB0aW1lb3V0IixoZWFkZXJzOnsiQ29udGVudC1UeXBlIjoiYXBwbGljYXRpb24vanNvbiJ9fSxpPSJobGcudG9rYm94LmNvbS9wcm9kL2xvZ2dpbmcvdmNwX3dlYnJ0YyI7aWYoZS5wcm94eVVybC5pc0VtcHR5KCkpaT0iaHR0cHM6Ly8iK2k7ZWxzZXtsZXQgYTtlLnByb3h5VXJsLmdldCgpLnNsaWNlKGUucHJveHlVcmwuZ2V0KCkubGVuZ3RoLTEpIT09Ii8iP2E9ZS5wcm94eVVybC5nZXQoKSsiLyI6YT1lLnByb3h5VXJsLmdldCgpLGk9YStpfW4ucG9zdChpLG1yKGUpLG8pLnRoZW4oYT0+e2NvbnNvbGUubG9nKGEpLHQoInN1Y2Nlc3MiKX0pLmNhdGNoKGE9Pntjb25zb2xlLmxvZyhhKSxzKGEpfSl9KX19dmFyIFgsZ3I9bmV3IFVpbnQ4QXJyYXkoMTYpO2Z1bmN0aW9uIF9yKCl7aWYoIVgmJihYPXR5cGVvZiBjcnlwdG8hPSJ1bmRlZmluZWQiJiZjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzJiZjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzLmJpbmQoY3J5cHRvKXx8dHlwZW9mIG1zQ3J5cHRvIT0idW5kZWZpbmVkIiYmdHlwZW9mIG1zQ3J5cHRvLmdldFJhbmRvbVZhbHVlcz09ImZ1bmN0aW9uIiYmbXNDcnlwdG8uZ2V0UmFuZG9tVmFsdWVzLmJpbmQobXNDcnlwdG8pLCFYKSl0aHJvdyBuZXcgRXJyb3IoImNyeXB0by5nZXRSYW5kb21WYWx1ZXMoKSBub3Qgc3VwcG9ydGVkLiBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3V1aWRqcy91dWlkI2dldHJhbmRvbXZhbHVlcy1ub3Qtc3VwcG9ydGVkIik7cmV0dXJuIFgoZ3IpfXZhciB5cj0vXig/OlswLTlhLWZdezh9LVswLTlhLWZdezR9LVsxLTVdWzAtOWEtZl17M30tWzg5YWJdWzAtOWEtZl17M30tWzAtOWEtZl17MTJ9fDAwMDAwMDAwLTAwMDAtMDAwMC0wMDAwLTAwMDAwMDAwMDAwMCkkL2k7ZnVuY3Rpb24gYnIocil7cmV0dXJuIHR5cGVvZiByPT0ic3RyaW5nIiYmeXIudGVzdChyKX1mb3IodmFyIGQ9W10saGU9MDtoZTwyNTY7KytoZSlkLnB1c2goKGhlKzI1NikudG9TdHJpbmcoMTYpLnN1YnN0cigxKSk7ZnVuY3Rpb24gd3Iocil7dmFyIGU9YXJndW1lbnRzLmxlbmd0aD4xJiZhcmd1bWVudHNbMV0hPT12b2lkIDA/YXJndW1lbnRzWzFdOjAsdD0oZFtyW2UrMF1dK2RbcltlKzFdXStkW3JbZSsyXV0rZFtyW2UrM11dKyItIitkW3JbZSs0XV0rZFtyW2UrNV1dKyItIitkW3JbZSs2XV0rZFtyW2UrN11dKyItIitkW3JbZSs4XV0rZFtyW2UrOV1dKyItIitkW3JbZSsxMF1dK2RbcltlKzExXV0rZFtyW2UrMTJdXStkW3JbZSsxM11dK2RbcltlKzE0XV0rZFtyW2UrMTVdXSkudG9Mb3dlckNhc2UoKTtpZighYnIodCkpdGhyb3cgVHlwZUVycm9yKCJTdHJpbmdpZmllZCBVVUlEIGlzIGludmFsaWQiKTtyZXR1cm4gdH1mdW5jdGlvbiBXZShyLGUsdCl7cj1yfHx7fTt2YXIgcz1yLnJhbmRvbXx8KHIucm5nfHxfcikoKTtpZihzWzZdPXNbNl0mMTV8NjQsc1s4XT1zWzhdJjYzfDEyOCxlKXt0PXR8fDA7Zm9yKHZhciBuPTA7bjwxNjsrK24pZVt0K25dPXNbbl07cmV0dXJuIGV9cmV0dXJuIHdyKHMpfWNvbnN0IFM9bmV3IFdlYWtNYXAsSz1uZXcgV2Vha01hcCxEPW5ldyBXZWFrTWFwLGRlPVN5bWJvbCgiYW55UHJvZHVjZXIiKSx6ZT1Qcm9taXNlLnJlc29sdmUoKSxZPVN5bWJvbCgibGlzdGVuZXJBZGRlZCIpLFo9U3ltYm9sKCJsaXN0ZW5lclJlbW92ZWQiKTtsZXQgcGU9ITE7ZnVuY3Rpb24gayhyKXtpZih0eXBlb2YgciE9InN0cmluZyImJnR5cGVvZiByIT0ic3ltYm9sIil0aHJvdyBuZXcgVHlwZUVycm9yKCJldmVudE5hbWUgbXVzdCBiZSBhIHN0cmluZyBvciBhIHN5bWJvbCIpfWZ1bmN0aW9uIGVlKHIpe2lmKHR5cGVvZiByIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImxpc3RlbmVyIG11c3QgYmUgYSBmdW5jdGlvbiIpfWZ1bmN0aW9uIE4ocixlKXtjb25zdCB0PUsuZ2V0KHIpO3JldHVybiB0LmhhcyhlKXx8dC5zZXQoZSxuZXcgU2V0KSx0LmdldChlKX1mdW5jdGlvbiAkKHIsZSl7Y29uc3QgdD10eXBlb2YgZT09InN0cmluZyJ8fHR5cGVvZiBlPT0ic3ltYm9sIj9lOmRlLHM9RC5nZXQocik7cmV0dXJuIHMuaGFzKHQpfHxzLnNldCh0LG5ldyBTZXQpLHMuZ2V0KHQpfWZ1bmN0aW9uIHZyKHIsZSx0KXtjb25zdCBzPUQuZ2V0KHIpO2lmKHMuaGFzKGUpKWZvcihjb25zdCBuIG9mIHMuZ2V0KGUpKW4uZW5xdWV1ZSh0KTtpZihzLmhhcyhkZSkpe2NvbnN0IG49UHJvbWlzZS5hbGwoW2UsdF0pO2Zvcihjb25zdCBvIG9mIHMuZ2V0KGRlKSlvLmVucXVldWUobil9fWZ1bmN0aW9uIFFlKHIsZSl7ZT1BcnJheS5pc0FycmF5KGUpP2U6W2VdO2xldCB0PSExLHM9KCk9Pnt9LG49W107Y29uc3Qgbz17ZW5xdWV1ZShpKXtuLnB1c2goaSkscygpfSxmaW5pc2goKXt0PSEwLHMoKX19O2Zvcihjb25zdCBpIG9mIGUpJChyLGkpLmFkZChvKTtyZXR1cm57YXN5bmMgbmV4dCgpe3JldHVybiBuP24ubGVuZ3RoPT09MD90PyhuPXZvaWQgMCx0aGlzLm5leHQoKSk6KGF3YWl0IG5ldyBQcm9taXNlKGk9PntzPWl9KSx0aGlzLm5leHQoKSk6e2RvbmU6ITEsdmFsdWU6YXdhaXQgbi5zaGlmdCgpfTp7ZG9uZTohMH19LGFzeW5jIHJldHVybihpKXtuPXZvaWQgMDtmb3IoY29uc3QgYSBvZiBlKSQocixhKS5kZWxldGUobyk7cmV0dXJuIHMoKSxhcmd1bWVudHMubGVuZ3RoPjA/e2RvbmU6ITAsdmFsdWU6YXdhaXQgaX06e2RvbmU6ITB9fSxbU3ltYm9sLmFzeW5jSXRlcmF0b3JdKCl7cmV0dXJuIHRoaXN9fX1mdW5jdGlvbiBYZShyKXtpZihyPT09dm9pZCAwKXJldHVybiBLZTtpZighQXJyYXkuaXNBcnJheShyKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJgbWV0aG9kTmFtZXNgIG11c3QgYmUgYW4gYXJyYXkgb2Ygc3RyaW5ncyIpO2Zvcihjb25zdCBlIG9mIHIpaWYoIUtlLmluY2x1ZGVzKGUpKXRocm93IHR5cGVvZiBlIT0ic3RyaW5nIj9uZXcgVHlwZUVycm9yKCJgbWV0aG9kTmFtZXNgIGVsZW1lbnQgbXVzdCBiZSBhIHN0cmluZyIpOm5ldyBFcnJvcihgJHtlfSBpcyBub3QgRW1pdHRlcnkgbWV0aG9kYCk7cmV0dXJuIHJ9Y29uc3QgbWU9cj0+cj09PVl8fHI9PT1aO2NsYXNzIE97c3RhdGljIG1peGluKGUsdCl7cmV0dXJuIHQ9WGUodCkscz0+e2lmKHR5cGVvZiBzIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImB0YXJnZXRgIG11c3QgYmUgZnVuY3Rpb24iKTtmb3IoY29uc3QgaSBvZiB0KWlmKHMucHJvdG90eXBlW2ldIT09dm9pZCAwKXRocm93IG5ldyBFcnJvcihgVGhlIHByb3BlcnR5IFxgJHtpfVxgIGFscmVhZHkgZXhpc3RzIG9uIFxgdGFyZ2V0XGBgKTtmdW5jdGlvbiBuKCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLGUse2VudW1lcmFibGU6ITEsdmFsdWU6bmV3IE99KSx0aGlzW2VdfU9iamVjdC5kZWZpbmVQcm9wZXJ0eShzLnByb3RvdHlwZSxlLHtlbnVtZXJhYmxlOiExLGdldDpufSk7Y29uc3Qgbz1pPT5mdW5jdGlvbiguLi5hKXtyZXR1cm4gdGhpc1tlXVtpXSguLi5hKX07Zm9yKGNvbnN0IGkgb2YgdClPYmplY3QuZGVmaW5lUHJvcGVydHkocy5wcm90b3R5cGUsaSx7ZW51bWVyYWJsZTohMSx2YWx1ZTpvKGkpfSk7cmV0dXJuIHN9fXN0YXRpYyBnZXQgaXNEZWJ1Z0VuYWJsZWQoKXtpZih0eXBlb2YgcHJvY2VzcyE9Im9iamVjdCIpcmV0dXJuIHBlO2NvbnN0e2VudjplfT1wcm9jZXNzfHx7ZW52Ont9fTtyZXR1cm4gZS5ERUJVRz09PSJlbWl0dGVyeSJ8fGUuREVCVUc9PT0iKiJ8fHBlfXN0YXRpYyBzZXQgaXNEZWJ1Z0VuYWJsZWQoZSl7cGU9ZX1jb25zdHJ1Y3RvcihlPXt9KXtTLnNldCh0aGlzLG5ldyBTZXQpLEsuc2V0KHRoaXMsbmV3IE1hcCksRC5zZXQodGhpcyxuZXcgTWFwKSx0aGlzLmRlYnVnPWUuZGVidWd8fHt9LHRoaXMuZGVidWcuZW5hYmxlZD09PXZvaWQgMCYmKHRoaXMuZGVidWcuZW5hYmxlZD0hMSksdGhpcy5kZWJ1Zy5sb2dnZXJ8fCh0aGlzLmRlYnVnLmxvZ2dlcj0odCxzLG4sbyk9PntvPUpTT04uc3RyaW5naWZ5KG8pLHR5cGVvZiBuPT0ic3ltYm9sIiYmKG49bi50b1N0cmluZygpKTtjb25zdCBpPW5ldyBEYXRlLGE9YCR7aS5nZXRIb3VycygpfToke2kuZ2V0TWludXRlcygpfToke2kuZ2V0U2Vjb25kcygpfS4ke2kuZ2V0TWlsbGlzZWNvbmRzKCl9YDtjb25zb2xlLmxvZyhgWyR7YX1dW2VtaXR0ZXJ5OiR7dH1dWyR7c31dIEV2ZW50IE5hbWU6ICR7bn0KCWRhdGE6ICR7b31gKX0pfWxvZ0lmRGVidWdFbmFibGVkKGUsdCxzKXsoTy5pc0RlYnVnRW5hYmxlZHx8dGhpcy5kZWJ1Zy5lbmFibGVkKSYmdGhpcy5kZWJ1Zy5sb2dnZXIoZSx0aGlzLmRlYnVnLm5hbWUsdCxzKX1vbihlLHQpe2VlKHQpLGU9QXJyYXkuaXNBcnJheShlKT9lOltlXTtmb3IoY29uc3QgcyBvZiBlKWsocyksTih0aGlzLHMpLmFkZCh0KSx0aGlzLmxvZ0lmRGVidWdFbmFibGVkKCJzdWJzY3JpYmUiLHMsdm9pZCAwKSxtZShzKXx8dGhpcy5lbWl0KFkse2V2ZW50TmFtZTpzLGxpc3RlbmVyOnR9KTtyZXR1cm4gdGhpcy5vZmYuYmluZCh0aGlzLGUsdCl9b2ZmKGUsdCl7ZWUodCksZT1BcnJheS5pc0FycmF5KGUpP2U6W2VdO2Zvcihjb25zdCBzIG9mIGUpayhzKSxOKHRoaXMscykuZGVsZXRlKHQpLHRoaXMubG9nSWZEZWJ1Z0VuYWJsZWQoInVuc3Vic2NyaWJlIixzLHZvaWQgMCksbWUocyl8fHRoaXMuZW1pdChaLHtldmVudE5hbWU6cyxsaXN0ZW5lcjp0fSl9b25jZShlKXtyZXR1cm4gbmV3IFByb21pc2UodD0+e2NvbnN0IHM9dGhpcy5vbihlLG49PntzKCksdChuKX0pfSl9ZXZlbnRzKGUpe2U9QXJyYXkuaXNBcnJheShlKT9lOltlXTtmb3IoY29uc3QgdCBvZiBlKWsodCk7cmV0dXJuIFFlKHRoaXMsZSl9YXN5bmMgZW1pdChlLHQpe2soZSksdGhpcy5sb2dJZkRlYnVnRW5hYmxlZCgiZW1pdCIsZSx0KSx2cih0aGlzLGUsdCk7Y29uc3Qgcz1OKHRoaXMsZSksbj1TLmdldCh0aGlzKSxvPVsuLi5zXSxpPW1lKGUpP1tdOlsuLi5uXTthd2FpdCB6ZSxhd2FpdCBQcm9taXNlLmFsbChbLi4uby5tYXAoYXN5bmMgYT0+e2lmKHMuaGFzKGEpKXJldHVybiBhKHQpfSksLi4uaS5tYXAoYXN5bmMgYT0+e2lmKG4uaGFzKGEpKXJldHVybiBhKGUsdCl9KV0pfWFzeW5jIGVtaXRTZXJpYWwoZSx0KXtrKGUpLHRoaXMubG9nSWZEZWJ1Z0VuYWJsZWQoImVtaXRTZXJpYWwiLGUsdCk7Y29uc3Qgcz1OKHRoaXMsZSksbj1TLmdldCh0aGlzKSxvPVsuLi5zXSxpPVsuLi5uXTthd2FpdCB6ZTtmb3IoY29uc3QgYSBvZiBvKXMuaGFzKGEpJiZhd2FpdCBhKHQpO2Zvcihjb25zdCBhIG9mIGkpbi5oYXMoYSkmJmF3YWl0IGEoZSx0KX1vbkFueShlKXtyZXR1cm4gZWUoZSksdGhpcy5sb2dJZkRlYnVnRW5hYmxlZCgic3Vic2NyaWJlQW55Iix2b2lkIDAsdm9pZCAwKSxTLmdldCh0aGlzKS5hZGQoZSksdGhpcy5lbWl0KFkse2xpc3RlbmVyOmV9KSx0aGlzLm9mZkFueS5iaW5kKHRoaXMsZSl9YW55RXZlbnQoKXtyZXR1cm4gUWUodGhpcyl9b2ZmQW55KGUpe2VlKGUpLHRoaXMubG9nSWZEZWJ1Z0VuYWJsZWQoInVuc3Vic2NyaWJlQW55Iix2b2lkIDAsdm9pZCAwKSx0aGlzLmVtaXQoWix7bGlzdGVuZXI6ZX0pLFMuZ2V0KHRoaXMpLmRlbGV0ZShlKX1jbGVhckxpc3RlbmVycyhlKXtlPUFycmF5LmlzQXJyYXkoZSk/ZTpbZV07Zm9yKGNvbnN0IHQgb2YgZSlpZih0aGlzLmxvZ0lmRGVidWdFbmFibGVkKCJjbGVhciIsdCx2b2lkIDApLHR5cGVvZiB0PT0ic3RyaW5nInx8dHlwZW9mIHQ9PSJzeW1ib2wiKXtOKHRoaXMsdCkuY2xlYXIoKTtjb25zdCBzPSQodGhpcyx0KTtmb3IoY29uc3QgbiBvZiBzKW4uZmluaXNoKCk7cy5jbGVhcigpfWVsc2V7Uy5nZXQodGhpcykuY2xlYXIoKTtmb3IoY29uc3QgcyBvZiBLLmdldCh0aGlzKS52YWx1ZXMoKSlzLmNsZWFyKCk7Zm9yKGNvbnN0IHMgb2YgRC5nZXQodGhpcykudmFsdWVzKCkpe2Zvcihjb25zdCBuIG9mIHMpbi5maW5pc2goKTtzLmNsZWFyKCl9fX1saXN0ZW5lckNvdW50KGUpe2U9QXJyYXkuaXNBcnJheShlKT9lOltlXTtsZXQgdD0wO2Zvcihjb25zdCBzIG9mIGUpe2lmKHR5cGVvZiBzPT0ic3RyaW5nIil7dCs9Uy5nZXQodGhpcykuc2l6ZStOKHRoaXMscykuc2l6ZSskKHRoaXMscykuc2l6ZSskKHRoaXMpLnNpemU7Y29udGludWV9dHlwZW9mIHMhPSJ1bmRlZmluZWQiJiZrKHMpLHQrPVMuZ2V0KHRoaXMpLnNpemU7Zm9yKGNvbnN0IG4gb2YgSy5nZXQodGhpcykudmFsdWVzKCkpdCs9bi5zaXplO2Zvcihjb25zdCBuIG9mIEQuZ2V0KHRoaXMpLnZhbHVlcygpKXQrPW4uc2l6ZX1yZXR1cm4gdH1iaW5kTWV0aG9kcyhlLHQpe2lmKHR5cGVvZiBlIT0ib2JqZWN0Inx8ZT09PW51bGwpdGhyb3cgbmV3IFR5cGVFcnJvcigiYHRhcmdldGAgbXVzdCBiZSBhbiBvYmplY3QiKTt0PVhlKHQpO2Zvcihjb25zdCBzIG9mIHQpe2lmKGVbc10hPT12b2lkIDApdGhyb3cgbmV3IEVycm9yKGBUaGUgcHJvcGVydHkgXGAke3N9XGAgYWxyZWFkeSBleGlzdHMgb24gXGB0YXJnZXRcYGApO09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHMse2VudW1lcmFibGU6ITEsdmFsdWU6dGhpc1tzXS5iaW5kKHRoaXMpfSl9fX1jb25zdCBLZT1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhPLnByb3RvdHlwZSkuZmlsdGVyKHI9PnIhPT0iY29uc3RydWN0b3IiKTtPYmplY3QuZGVmaW5lUHJvcGVydHkoTywibGlzdGVuZXJBZGRlZCIse3ZhbHVlOlksd3JpdGFibGU6ITEsZW51bWVyYWJsZTohMCxjb25maWd1cmFibGU6ITF9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoTywibGlzdGVuZXJSZW1vdmVkIix7dmFsdWU6Wix3cml0YWJsZTohMSxlbnVtZXJhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMX0pO3ZhciBnZT1PO2Z1bmN0aW9uIEVyKHIpe3JldHVybiB0eXBlb2Ygcj09Im9iamVjdCImJnIhPT1udWxsJiYibWVzc2FnZSJpbiByJiZ0eXBlb2Ygci5tZXNzYWdlPT0ic3RyaW5nIn1mdW5jdGlvbiBQcihyKXtpZihFcihyKSlyZXR1cm4gcjt0cnl7cmV0dXJuIG5ldyBFcnJvcihKU09OLnN0cmluZ2lmeShyKSl9Y2F0Y2h7cmV0dXJuIG5ldyBFcnJvcihTdHJpbmcocikpfX1mdW5jdGlvbiBfZShyKXtyZXR1cm4gUHIocikubWVzc2FnZX12YXIgeWU7KGZ1bmN0aW9uKHIpe3IuRlBTX0RST1A9ImZwc19kcm9wIn0pKHllfHwoeWU9e30pKTtjb25zdCBUcj01MDAsUnI9Ljg7Y2xhc3MgU3IgZXh0ZW5kcyBnZXtjb25zdHJ1Y3RvcihlLHQpe3N1cGVyKCksdGhpcy5pbmRleF89dCx0aGlzLnV1aWRfPVdlKCksdGhpcy5mcmFtZXNUcmFuc2Zvcm1lZF89MCx0aGlzLnRyYW5zZm9ybWVyXz1lLHRoaXMuc2hvdWxkU3RvcF89ITEsdGhpcy5pc0ZsYXNoZWRfPSExLHRoaXMuZnJhbWVzRnJvbVNvdXJjZV89MCx0aGlzLmZwc189MCx0aGlzLm1lZGlhVHJhbnNmb3JtZXJRb3NSZXBvcnRTdGFydFRpbWVzdGFtcF89MCx0aGlzLnZpZGVvSGVpZ2h0Xz0wLHRoaXMudmlkZW9XaWR0aF89MCx0aGlzLnRyYWNrRXhwZWN0ZWRSYXRlXz0tMSx0aGlzLnRyYW5zZm9ybWVyVHlwZV89IkN1c3RvbSIsImdldFRyYW5zZm9ybWVyVHlwZSJpbiBlJiYodGhpcy50cmFuc2Zvcm1lclR5cGVfPWUuZ2V0VHJhbnNmb3JtZXJUeXBlKCkpO2NvbnN0IHM9bmV3IGIoKS5hY3Rpb24oIk1lZGlhVHJhbnNmb3JtZXIiKS5ndWlkKHRoaXMudXVpZF8pLnRyYW5zZm9ybWVyVHlwZSh0aGlzLnRyYW5zZm9ybWVyVHlwZV8pLnZhcmlhdGlvbigiQ3JlYXRlIikuYnVpbGQoKTt3LnJlcG9ydChzKX1zZXRUcmFja0V4cGVjdGVkUmF0ZShlKXt0aGlzLnRyYWNrRXhwZWN0ZWRSYXRlXz1lfWFzeW5jIHN0YXJ0KGUpe2lmKHRoaXMuY29udHJvbGxlcl89ZSx0aGlzLnRyYW5zZm9ybWVyXyYmdHlwZW9mIHRoaXMudHJhbnNmb3JtZXJfLnN0YXJ0PT0iZnVuY3Rpb24iKXRyeXthd2FpdCB0aGlzLnRyYW5zZm9ybWVyXy5zdGFydChlKX1jYXRjaCh0KXtjb25zdCBzPW5ldyBiKCkuYWN0aW9uKCJNZWRpYVRyYW5zZm9ybWVyIikuZ3VpZCh0aGlzLnV1aWRfKS5tZXNzYWdlKFQuZXJyb3JzLnRyYW5zZm9ybWVyX3N0YXJ0KS50cmFuc2Zvcm1lclR5cGUodGhpcy50cmFuc2Zvcm1lclR5cGVfKS52YXJpYXRpb24oIkVycm9yIikuZXJyb3IoX2UodCkpLmJ1aWxkKCk7dy5yZXBvcnQocyk7Y29uc3Qgbj17ZXZlbnRNZXRhRGF0YTp7dHJhbnNmb3JtZXJJbmRleDp0aGlzLmluZGV4X30sZXJyb3I6dCxmdW5jdGlvbjoic3RhcnQifTt0aGlzLmVtaXQoImVycm9yIixuKX19YXN5bmMgdHJhbnNmb3JtKGUsdCl7dmFyIHMsbixvLGk7aWYodGhpcy5tZWRpYVRyYW5zZm9ybWVyUW9zUmVwb3J0U3RhcnRUaW1lc3RhbXBfPT09MCYmKHRoaXMubWVkaWFUcmFuc2Zvcm1lclFvc1JlcG9ydFN0YXJ0VGltZXN0YW1wXz1EYXRlLm5vdygpKSxlIGluc3RhbmNlb2YgVmlkZW9GcmFtZSYmKHRoaXMudmlkZW9IZWlnaHRfPShzPWU9PW51bGw/dm9pZCAwOmUuZGlzcGxheUhlaWdodCkhPW51bGw/czowLHRoaXMudmlkZW9XaWR0aF89KG49ZT09bnVsbD92b2lkIDA6ZS5kaXNwbGF5V2lkdGgpIT1udWxsP246MCksKyt0aGlzLmZyYW1lc0Zyb21Tb3VyY2VfLHRoaXMudHJhbnNmb3JtZXJfKWlmKHRoaXMuc2hvdWxkU3RvcF8pY29uc29sZS53YXJuKCJbUGlwZWxpbmVdIGZsdXNoIGZyb20gdHJhbnNmb3JtIiksZS5jbG9zZSgpLHRoaXMuZmx1c2godCksdC50ZXJtaW5hdGUoKTtlbHNlIHRyeXthd2FpdCgoaT0obz10aGlzLnRyYW5zZm9ybWVyXykudHJhbnNmb3JtKT09bnVsbD92b2lkIDA6aS5jYWxsKG8sZSx0KSksKyt0aGlzLmZyYW1lc1RyYW5zZm9ybWVkXyx0aGlzLmZyYW1lc1RyYW5zZm9ybWVkXz09PVRyJiZ0aGlzLm1lZGlhVHJhbnNmb3JtZXJRb3NSZXBvcnQoKX1jYXRjaChhKXtjb25zdCBsPW5ldyBiKCkuYWN0aW9uKCJNZWRpYVRyYW5zZm9ybWVyIikuZ3VpZCh0aGlzLnV1aWRfKS5tZXNzYWdlKFQuZXJyb3JzLnRyYW5zZm9ybWVyX3RyYW5zZm9ybSkudHJhbnNmb3JtZXJUeXBlKHRoaXMudHJhbnNmb3JtZXJUeXBlXykudmFyaWF0aW9uKCJFcnJvciIpLmVycm9yKF9lKGEpKS5idWlsZCgpO3cucmVwb3J0KGwpO2NvbnN0IGc9e2V2ZW50TWV0YURhdGE6e3RyYW5zZm9ybWVySW5kZXg6dGhpcy5pbmRleF99LGVycm9yOmEsZnVuY3Rpb246InRyYW5zZm9ybSJ9O3RoaXMuZW1pdCgiZXJyb3IiLGcpfX1hc3luYyBmbHVzaChlKXtpZih0aGlzLnRyYW5zZm9ybWVyXyYmdHlwZW9mIHRoaXMudHJhbnNmb3JtZXJfLmZsdXNoPT0iZnVuY3Rpb24iJiYhdGhpcy5pc0ZsYXNoZWRfKXt0aGlzLmlzRmxhc2hlZF89ITA7dHJ5e2F3YWl0IHRoaXMudHJhbnNmb3JtZXJfLmZsdXNoKGUpfWNhdGNoKHMpe2NvbnN0IG49bmV3IGIoKS5hY3Rpb24oIk1lZGlhVHJhbnNmb3JtZXIiKS5ndWlkKHRoaXMudXVpZF8pLm1lc3NhZ2UoVC5lcnJvcnMudHJhbnNmb3JtZXJfZmx1c2gpLnRyYW5zZm9ybWVyVHlwZSh0aGlzLnRyYW5zZm9ybWVyVHlwZV8pLnZhcmlhdGlvbigiRXJyb3IiKS5lcnJvcihfZShzKSkuYnVpbGQoKTt3LnJlcG9ydChuKTtjb25zdCBvPXtldmVudE1ldGFEYXRhOnt0cmFuc2Zvcm1lckluZGV4OnRoaXMuaW5kZXhffSxlcnJvcjpzLGZ1bmN0aW9uOiJmbHVzaCJ9O3RoaXMuZW1pdCgiZXJyb3IiLG8pfX10aGlzLm1lZGlhVHJhbnNmb3JtZXJRb3NSZXBvcnQoKTtjb25zdCB0PW5ldyBiKCkuYWN0aW9uKCJNZWRpYVRyYW5zZm9ybWVyIikuZ3VpZCh0aGlzLnV1aWRfKS50cmFuc2Zvcm1lclR5cGUodGhpcy50cmFuc2Zvcm1lclR5cGVfKS52YXJpYXRpb24oIkRlbGV0ZSIpLmJ1aWxkKCk7dy5yZXBvcnQodCl9c3RvcCgpe2NvbnNvbGUubG9nKCJbUGlwZWxpbmVdIFN0b3Agc3RyZWFtLiIpLHRoaXMuY29udHJvbGxlcl8mJih0aGlzLmZsdXNoKHRoaXMuY29udHJvbGxlcl8pLHRoaXMuY29udHJvbGxlcl8udGVybWluYXRlKCkpLHRoaXMuc2hvdWxkU3RvcF89ITB9bWVkaWFUcmFuc2Zvcm1lclFvc1JlcG9ydCgpe2xldCBlPShEYXRlLm5vdygpLXRoaXMubWVkaWFUcmFuc2Zvcm1lclFvc1JlcG9ydFN0YXJ0VGltZXN0YW1wXykvMWUzLHQ9dGhpcy5mcmFtZXNGcm9tU291cmNlXy9lLHM9dGhpcy5mcmFtZXNUcmFuc2Zvcm1lZF8vZTtpZih0aGlzLnRyYWNrRXhwZWN0ZWRSYXRlXyE9LTEmJnRoaXMudHJhY2tFeHBlY3RlZFJhdGVfKlJyPnQpe2NvbnN0IG89e2V2ZW50TWV0YURhdGE6e3RyYW5zZm9ybWVySW5kZXg6dGhpcy5pbmRleF99LHdhcm5pbmdUeXBlOnllLkZQU19EUk9QLGRyb3BJbmZvOntyZXF1ZXN0ZWQ6dGhpcy50cmFja0V4cGVjdGVkUmF0ZV8sY3VycmVudDp0fX07dGhpcy5lbWl0KCJ3YXJuIixvKX1jb25zdCBuPW5ldyBiKCkuYWN0aW9uKCJNZWRpYVRyYW5zZm9ybWVyIikuZnBzKHQpLnRyYW5zZm9ybWVkRnBzKHMpLmZyYW1lc1RyYW5zZm9ybWVkKHRoaXMuZnJhbWVzVHJhbnNmb3JtZWRfKS5ndWlkKHRoaXMudXVpZF8pLnRyYW5zZm9ybWVyVHlwZSh0aGlzLnRyYW5zZm9ybWVyVHlwZV8pLnZpZGVvSGVpZ2h0KHRoaXMudmlkZW9IZWlnaHRfKS52aWRlb1dpZHRoKHRoaXMudmlkZW9XaWR0aF8pLnZhcmlhdGlvbigiUW9TIikuYnVpbGQoKTt3LnJlcG9ydChuKSx0aGlzLm1lZGlhVHJhbnNmb3JtZXJRb3NSZXBvcnRTdGFydFRpbWVzdGFtcF89MCx0aGlzLmZyYW1lc0Zyb21Tb3VyY2VfPTAsdGhpcy5mcmFtZXNUcmFuc2Zvcm1lZF89MH19Y2xhc3MgQ3IgZXh0ZW5kcyBnZXtjb25zdHJ1Y3RvcihlKXtzdXBlcigpLHRoaXMudHJhbnNmb3JtZXJzXz1bXSx0aGlzLnRyYWNrRXhwZWN0ZWRSYXRlXz0tMTtmb3IobGV0IHQ9MDt0PGUubGVuZ3RoO3QrKyl7bGV0IHM9bmV3IFNyKGVbdF0sdCk7cy5vbigiZXJyb3IiLG49Pnt0aGlzLmVtaXQoImVycm9yIixuKX0pLHMub24oIndhcm4iLG49Pnt0aGlzLmVtaXQoIndhcm4iLG4pfSksdGhpcy50cmFuc2Zvcm1lcnNfLnB1c2gocyl9fXNldFRyYWNrRXhwZWN0ZWRSYXRlKGUpe3RoaXMudHJhY2tFeHBlY3RlZFJhdGVfPWU7Zm9yKGxldCB0IG9mIHRoaXMudHJhbnNmb3JtZXJzXyl0LnNldFRyYWNrRXhwZWN0ZWRSYXRlKHRoaXMudHJhY2tFeHBlY3RlZFJhdGVfKX1hc3luYyBzdGFydChlLHQpe2lmKCF0aGlzLnRyYW5zZm9ybWVyc198fHRoaXMudHJhbnNmb3JtZXJzXy5sZW5ndGg9PT0wKXtjb25zb2xlLmxvZygiW1BpcGVsaW5lXSBObyB0cmFuc2Zvcm1lcnMuIik7cmV0dXJufXRyeXtsZXQgcz1lO2ZvcihsZXQgbiBvZiB0aGlzLnRyYW5zZm9ybWVyc18pZT1lLnBpcGVUaHJvdWdoKG5ldyBUcmFuc2Zvcm1TdHJlYW0obikpO2UucGlwZVRvKHQpLnRoZW4oYXN5bmMoKT0+e2NvbnNvbGUubG9nKCJbUGlwZWxpbmVdIFNldHVwLiIpLGF3YWl0IHQuYWJvcnQoKSxhd2FpdCBzLmNhbmNlbCgpLHRoaXMuZW1pdCgicGlwZWxpbmVJbmZvIix7bWVzc2FnZToicGlwZWxpbmVfZW5kZWQifSl9KS5jYXRjaChhc3luYyBuPT57ZS5jYW5jZWwoKS50aGVuKCgpPT57Y29uc29sZS5sb2coIltQaXBlbGluZV0gU2h1dHRpbmcgZG93biBzdHJlYW1zIGFmdGVyIGFib3J0LiIpfSkuY2F0Y2gobz0+e2NvbnNvbGUuZXJyb3IoIltQaXBlbGluZV0gRXJyb3IgZnJvbSBzdHJlYW0gdHJhbnNmb3JtOiIsbyl9KSxhd2FpdCB0LmFib3J0KG4pLGF3YWl0IHMuY2FuY2VsKG4pLHRoaXMuZW1pdCgicGlwZWxpbmVJbmZvIix7bWVzc2FnZToicGlwZWxpbmVfZW5kZWRfd2l0aF9lcnJvciJ9KX0pfWNhdGNoe3RoaXMuZW1pdCgicGlwZWxpbmVJbmZvIix7bWVzc2FnZToicGlwZWxpbmVfc3RhcnRlZF93aXRoX2Vycm9yIn0pLHRoaXMuZGVzdHJveSgpO3JldHVybn10aGlzLmVtaXQoInBpcGVsaW5lSW5mbyIse21lc3NhZ2U6InBpcGVsaW5lX3N0YXJ0ZWQifSksY29uc29sZS5sb2coIltQaXBlbGluZV0gUGlwZWxpbmUgc3RhcnRlZC4iKX1hc3luYyBkZXN0cm95KCl7Y29uc29sZS5sb2coIltQaXBlbGluZV0gRGVzdHJveWluZyBQaXBlbGluZS4iKTtmb3IobGV0IGUgb2YgdGhpcy50cmFuc2Zvcm1lcnNfKWUuc3RvcCgpfX1jbGFzcyBPciBleHRlbmRzIGdle2NvbnN0cnVjdG9yKCl7c3VwZXIoKSx0aGlzLnV1aWRfPVdlKCksdGhpcy50cmFja0V4cGVjdGVkUmF0ZV89LTE7Y29uc3QgZT1uZXcgYigpLmFjdGlvbigiTWVkaWFQcm9jZXNzb3IiKS5ndWlkKHRoaXMudXVpZF8pLnZhcmlhdGlvbigiQ3JlYXRlIikuYnVpbGQoKTt3LnJlcG9ydChlKX1zZXRUcmFja0V4cGVjdGVkUmF0ZShlKXt0aGlzLnRyYWNrRXhwZWN0ZWRSYXRlXz1lLHRoaXMucGlwZWxpbmVfJiZ0aGlzLnBpcGVsaW5lXy5zZXRUcmFja0V4cGVjdGVkUmF0ZSh0aGlzLnRyYWNrRXhwZWN0ZWRSYXRlXyl9dHJhbnNmb3JtKGUsdCl7cmV0dXJuIHRoaXMucmVhZGFibGVfPWUsdGhpcy53cml0YWJsZV89dCx0aGlzLnRyYW5zZm9ybUludGVybmFsKCl9dHJhbnNmb3JtSW50ZXJuYWwoKXtyZXR1cm4gbmV3IFByb21pc2UoKGUsdCk9PntpZighdGhpcy50cmFuc2Zvcm1lcnNffHx0aGlzLnRyYW5zZm9ybWVyc18ubGVuZ3RoPT09MCl7Y29uc3Qgbj1uZXcgYigpLmFjdGlvbigiTWVkaWFQcm9jZXNzb3IiKS5ndWlkKHRoaXMudXVpZF8pLm1lc3NhZ2UoVC5lcnJvcnMudHJhbnNmb3JtZXJfbm9uZSkudmFyaWF0aW9uKCJFcnJvciIpLmJ1aWxkKCk7dy5yZXBvcnQobiksdCgiW01lZGlhUHJvY2Vzc29yXSBOZWVkIHRvIHNldCB0cmFuc2Zvcm1lcnMuIik7cmV0dXJufWlmKCF0aGlzLnJlYWRhYmxlXyl7Y29uc3Qgbj1uZXcgYigpLmFjdGlvbigiTWVkaWFQcm9jZXNzb3IiKS5ndWlkKHRoaXMudXVpZF8pLm1lc3NhZ2UoVC5lcnJvcnMucmVhZGFibGVfbnVsbCkudmFyaWF0aW9uKCJFcnJvciIpLmJ1aWxkKCk7dy5yZXBvcnQobiksdCgiW01lZGlhUHJvY2Vzc29yXSBSZWFkYWJsZSBpcyBudWxsLiIpO3JldHVybn1pZighdGhpcy53cml0YWJsZV8pe2NvbnN0IG49bmV3IGIoKS5hY3Rpb24oIk1lZGlhUHJvY2Vzc29yIikuZ3VpZCh0aGlzLnV1aWRfKS5tZXNzYWdlKFQuZXJyb3JzLndyaXRhYmxlX251bGwpLnZhcmlhdGlvbigiRXJyb3IiKS5idWlsZCgpO3cucmVwb3J0KG4pLHQoIltNZWRpYVByb2Nlc3Nvcl0gV3JpdGFibGUgaXMgbnVsbC4iKTtyZXR1cm59bGV0IHM9ITE7dGhpcy5waXBlbGluZV8mJihzPSEwLHRoaXMucGlwZWxpbmVfLmNsZWFyTGlzdGVuZXJzKCksdGhpcy5waXBlbGluZV8uZGVzdHJveSgpKSx0aGlzLnBpcGVsaW5lXz1uZXcgQ3IodGhpcy50cmFuc2Zvcm1lcnNfKSx0aGlzLnBpcGVsaW5lXy5vbigid2FybiIsbj0+e3RoaXMuZW1pdCgid2FybiIsbil9KSx0aGlzLnBpcGVsaW5lXy5vbigiZXJyb3IiLG49Pnt0aGlzLmVtaXQoImVycm9yIixuKX0pLHRoaXMucGlwZWxpbmVfLm9uKCJwaXBlbGluZUluZm8iLG49PntzJiYobi5tZXNzYWdlPT09InBpcGVsaW5lX3N0YXJ0ZWQiP24ubWVzc2FnZT0icGlwZWxpbmVfcmVzdGFydGVkIjpuLm1lc3NhZ2U9PT0icGlwZWxpbmVfc3RhcnRlZF93aXRoX2Vycm9yIiYmKG4ubWVzc2FnZT0icGlwZWxpbmVfcmVzdGFydGVkX3dpdGhfZXJyb3IiKSksdGhpcy5lbWl0KCJwaXBlbGluZUluZm8iLG4pfSksdGhpcy50cmFja0V4cGVjdGVkUmF0ZV8hPS0xJiZ0aGlzLnBpcGVsaW5lXy5zZXRUcmFja0V4cGVjdGVkUmF0ZSh0aGlzLnRyYWNrRXhwZWN0ZWRSYXRlXyksdGhpcy5waXBlbGluZV8uc3RhcnQodGhpcy5yZWFkYWJsZV8sdGhpcy53cml0YWJsZV8pLnRoZW4oKCk9PntlKCl9KS5jYXRjaChuPT57dChuKX0pfSl9c2V0VHJhbnNmb3JtZXJzKGUpe2NvbnN0IHQ9bmV3IGIoKS5hY3Rpb24oIk1lZGlhUHJvY2Vzc29yIikuZ3VpZCh0aGlzLnV1aWRfKS5tZXNzYWdlKFQudXBkYXRlcy50cmFuc2Zvcm1lcl9uZXcpLnZhcmlhdGlvbigiVXBkYXRlIikuYnVpbGQoKTtyZXR1cm4gdy5yZXBvcnQodCksdGhpcy50cmFuc2Zvcm1lcnNfPWUsdGhpcy5yZWFkYWJsZV8mJnRoaXMud3JpdGFibGVfP3RoaXMudHJhbnNmb3JtSW50ZXJuYWwoKTpQcm9taXNlLnJlc29sdmUoKX1kZXN0cm95KCl7cmV0dXJuIG5ldyBQcm9taXNlKGU9Pnt0aGlzLnBpcGVsaW5lXyYmdGhpcy5waXBlbGluZV8uZGVzdHJveSgpO2NvbnN0IHQ9bmV3IGIoKS5hY3Rpb24oIk1lZGlhUHJvY2Vzc29yIikuZ3VpZCh0aGlzLnV1aWRfKS52YXJpYXRpb24oIkRlbGV0ZSIpLmJ1aWxkKCk7dy5yZXBvcnQodCksZSgpfSl9fXZhciBGPShyPT4oci5Mb3c9IkxvdyIsci5IaWdoPSJIaWdoIixyKSkoRnx8e30pO2NsYXNzIFlle2NvbnN0cnVjdG9yKGUpe3R5cGVvZiBlPT0ibnVtYmVyIj8odGhpcy5ibHVyRmlsdGVyXz0iYmx1cigiK2UrInB4KSIsdGhpcy5ibHVyXz1lKToodGhpcy5ibHVyRmlsdGVyXz1lPT09Ri5IaWdoPyJibHVyKDE1cHgpIjoiYmx1cig1cHgpIix0aGlzLmJsdXJfPWU9PT1GLkhpZ2g/MTU6NSl9aXNIaWdoQmx1cigpe3JldHVybiB0aGlzLmJsdXJfPjV9ZGVzdHJveSgpe3JldHVybiBuZXcgUHJvbWlzZShlPT57ZSgpfSl9cnVuUG9zdFByb2Nlc3NpbmcoZSx0KXt0cnl7ZS5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb249ImRlc3RpbmF0aW9uLW92ZXIiLGUuZmlsdGVyPXRoaXMuYmx1ckZpbHRlcl8sZS5kcmF3SW1hZ2UodCwwLDAsdC53aWR0aCx0LmhlaWdodCl9Y2F0Y2gocyl7Y29uc29sZS5sb2coIltCbHVyUG9zdFByb2Nlc3NdIEZhaWxlZCB0byBkcmF3IGNhbnZhcyIscyl9fX1jbGFzcyBaZXtjb25zdHJ1Y3Rvcigpe31kZXN0cm95KCl7cmV0dXJuIG5ldyBQcm9taXNlKGU9Pnt0aGlzLmJnSW1hZ2VfJiZ0aGlzLmJnSW1hZ2VfLmNsb3NlKCksZSgpfSl9c2V0VmlydHVhbEJHSW1hZ2UoZSl7dGhpcy5iZ0ltYWdlXyYmdGhpcy5iZ0ltYWdlXy5jbG9zZSgpLHRoaXMuYmdJbWFnZV89ZX1hc3luYyBydW5Qb3N0UHJvY2Vzc2luZyhlLHQpe2lmKHRoaXMuYmdJbWFnZV8pe2lmKHRoaXMuYmdJbWFnZV8ud2lkdGghPXQud2lkdGh8fHRoaXMuYmdJbWFnZV8uaGVpZ2h0IT10LmhlaWdodCl7Y29uc3Qgcz0iaGlnaCIsbj17cmVzaXplV2lkdGg6dC53aWR0aCxyZXNpemVIZWlnaHQ6dC5oZWlnaHQscmVzaXplUXVhbGl0eTpzfTt0cnl7dGhpcy5iZ0ltYWdlXz1hd2FpdCBjcmVhdGVJbWFnZUJpdG1hcCh0aGlzLmJnSW1hZ2VfLG4pfWNhdGNoKG8pe3Rocm93IG99fWUuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uPSJkZXN0aW5hdGlvbi1vdmVyIixlLmRyYXdJbWFnZSh0aGlzLmJnSW1hZ2VfLDAsMCx0aGlzLmJnSW1hZ2VfLndpZHRoLHRoaXMuYmdJbWFnZV8uaGVpZ2h0KX19fWNsYXNzIElye2NvbnN0cnVjdG9yKGU9MS8wKXt0aGlzLmNhcGFjaXR5PWUsdGhpcy5zdG9yYWdlPVtdfWVucXVldWUoZSl7aWYodGhpcy5zaXplKCk9PT10aGlzLmNhcGFjaXR5KXRocm93IEVycm9yKCJRdWV1ZSBoYXMgcmVhY2hlZCBtYXggY2FwYWNpdHksIHlvdSBjYW5ub3QgYWRkIG1vcmUgaXRlbXMiKTt0aGlzLnN0b3JhZ2UucHVzaChlKX1kZXF1ZXVlKCl7cmV0dXJuIHRoaXMuc3RvcmFnZS5zaGlmdCgpfXNpemUoKXtyZXR1cm4gdGhpcy5zdG9yYWdlLmxlbmd0aH19Y29uc3QgYmU9Y2xhc3N7Y29uc3RydWN0b3IoKXt0aGlzLnF1ZXVlXz1uZXcgSXJ9Y2xlYXJRdWV1ZShyKXtmb3IoO3RoaXMucXVldWVfLnNpemUoKT4wOyl0aGlzLnF1ZXVlXy5kZXF1ZXVlKCkuY2xvc2UoKX1zZXRWaWRlb1JlYWRhYmxlKHIpe3JldHVybiBuZXcgUHJvbWlzZSgoZSx0KT0+e3RoaXMuZnJhbWVSZWFkZXJfPXIuZ2V0UmVhZGVyKCksdGhpcy5mcmFtZVJlYWRlcl8ucmVhZCgpLnRoZW4ocz0+e3RoaXMucHJvY2Vzc0ZyYW1lKHMpfSkuY2F0Y2gocz0+e3Qocyl9KSxlKCl9KX1kZXN0cm95KCl7cmV0dXJuIG5ldyBQcm9taXNlKGFzeW5jKHIsZSk9Pnt2YXIgdDt0aGlzLmNsZWFyUXVldWUoITApLHRoaXMuZnJhbWVSZWFkZXJfPyh0PXRoaXMuZnJhbWVSZWFkZXJfKT09bnVsbHx8dC5jYW5jZWwoKS50aGVuKCgpPT57cigpfSkuY2F0Y2gocz0+e2Uocyl9KTpyKCl9KX1wcm9jZXNzRnJhbWUocil7aWYoIXIuZG9uZSl7aWYoIXRoaXMuZnJhbWVSZWFkZXJfKXtyLnZhbHVlLmNsb3NlKCk7cmV0dXJufWZvcig7dGhpcy5xdWV1ZV8uc2l6ZSgpPj1iZS5OVU1CRVJfT0ZfRlJBTUVTX1RPX0NMRUFSOyl7bGV0IGU9dGhpcy5xdWV1ZV8uZGVxdWV1ZSgpO2UmJmUuY2xvc2UoKX10aGlzLnF1ZXVlXy5lbnF1ZXVlKHIudmFsdWUpLHRoaXMuZnJhbWVSZWFkZXJfLnJlYWQoKS50aGVuKGU9Pnt0aGlzLnByb2Nlc3NGcmFtZShlKX0pLmNhdGNoKGU9Pntjb25zb2xlLmVycm9yKGUpfSl9fXJ1blBvc3RQcm9jZXNzaW5nKHIsZSl7dHJ5e2lmKHIuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uPSJkZXN0aW5hdGlvbi1vdmVyIix0aGlzLnF1ZXVlXy5zaXplKCk+YmUuTlVNQkVSX09GX0ZSQU1FU19UT19DTEVBUiYmdGhpcy5jbGVhclF1ZXVlKCExKSx0aGlzLnF1ZXVlXy5zaXplKCk+MCl7Y29uc3QgdD10aGlzLnF1ZXVlXy5kZXF1ZXVlKCk7ci5kcmF3SW1hZ2UodCwwLDAsZS53aWR0aCxlLmhlaWdodCksdC5jbG9zZSgpfX1jYXRjaCh0KXtjb25zb2xlLmVycm9yKCJbVmlkZW9Qb3N0UHJvY2Vzc10gRmFpbGVkIHRvIGRyYXcgY2FudmFzIix0KX19fTtsZXQgd2U9YmU7d2UuTlVNQkVSX09GX0ZSQU1FU19UT19DTEVBUj01O2NsYXNzIE1ye2NvbnN0cnVjdG9yKGUpe3R5cGVvZiBlPT0ibnVtYmVyIj8odGhpcy5ibHVyRmlsdGVyXz0iYmx1cigiK2UrInB4KSIsdGhpcy5ibHVyXz1lKToodGhpcy5ibHVyRmlsdGVyXz1lPT09Ri5IaWdoPyJibHVyKDE1cHgpIjoiYmx1cig1cHgpIix0aGlzLmJsdXJfPWU9PT1GLkhpZ2g/MTU6NSl9aXNIaWdoQmx1cigpe3JldHVybiB0aGlzLmJsdXJfPjV9ZGVzdHJveSgpe3JldHVybiBuZXcgUHJvbWlzZShlPT57ZSgpfSl9cnVuUG9zdFByb2Nlc3NpbmcoZSx0KXt0cnl7ZS5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb249InNvdXJjZS1pbiIsZS5maWx0ZXI9dGhpcy5ibHVyRmlsdGVyXyxlLmRyYXdJbWFnZSh0LDAsMCx0LndpZHRoLHQuaGVpZ2h0KSxlLmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbj0iZGVzdGluYXRpb24tb3ZlciIsZS5maWx0ZXI9ImJsdXIoMHB4KSIsZS5kcmF3SW1hZ2UodCwwLDAsdC53aWR0aCx0LmhlaWdodCl9Y2F0Y2gocyl7Y29uc29sZS5sb2coIltCbHVyUG9zdFByb2Nlc3NdIEZhaWxlZCB0byBkcmF3IGNhbnZhcyIscyl9fX1jb25zdCBtPWNsYXNze2NvbnN0cnVjdG9yKCl7aWYodGhpcy5sYXN0UHJvY2Vzc2VkVGltZXN0YW1wXz0wLHRoaXMubmV3SW5wdXRDb3VudGVyPTAsdGhpcy50aW1lckdhcF89bS5CTFVSX1BST0NFU1NfR0FQX01JQ1JPX1NFQ09ORF9MT1csdGhpcy5yZXN1bHRDYW52YXNfPW5ldyBPZmZzY3JlZW5DYW52YXMoMSwxKSx0aGlzLnJlc3VsdEN0eF89dGhpcy5yZXN1bHRDYW52YXNfLmdldENvbnRleHQoIjJkIix7YWxwaGE6ITEsZGVzeW5jaHJvbml6ZWQ6ITB9KSwhdGhpcy5yZXN1bHRDdHhfKXRocm93IG5ldyBFcnJvcigiVW5hYmxlIHRvIGNyZWF0ZSBPZmZzY3JlZW5DYW52YXNSZW5kZXJpbmdDb250ZXh0MkQiKTtpZih0aGlzLnNlZ21lbnRhdGlvbk1hc2tDYW52YXNfPW5ldyBPZmZzY3JlZW5DYW52YXMobS5TRUxGSUVfV0lEVEgsbS5TRUxGSUVfSElHSFQpLHRoaXMuc2VnbWVudGF0aW9uTWFza0N0eF89dGhpcy5zZWdtZW50YXRpb25NYXNrQ2FudmFzXy5nZXRDb250ZXh0KCIyZCIse2FscGhhOiExLGRlc3luY2hyb25pemVkOiEwfSksIXRoaXMuc2VnbWVudGF0aW9uTWFza0N0eF8pdGhyb3cgbmV3IEVycm9yKCJVbmFibGUgdG8gY3JlYXRlIE9mZnNjcmVlbkNhbnZhc1JlbmRlcmluZ0NvbnRleHQyRCIpfWluaXQocil7dGhpcy5wcm9jZXNzRnJhbWVDYj1yfWFzeW5jIHNldEJhY2tncm91bmRPcHRpb25zKHIpe2lmKHR5cGVvZiB0aGlzLnBvc3RQcm9jZXNzSW50ZXJmYWNlXyE9InVuZGVmaW5lZCIpdHJ5e2F3YWl0IHRoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfLmRlc3Ryb3koKX1jYXRjaChlKXt0aHJvdyBlfWlmKHIudHJhbnNmb3JtZXJUeXBlPT09IlZpcnR1YWxCYWNrZ3JvdW5kIil0aGlzLnRpbWVyR2FwXz1tLlZJUlRVQUxfUFJPQ0VTU19HQVBfTUlDUk9fU0VDT05ELHRoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfPW5ldyBaZTtlbHNlIGlmKHIudHJhbnNmb3JtZXJUeXBlPT09IkJhY2tncm91bmRCbHVyIil7bGV0IGU9cjt0aGlzLnBvc3RQcm9jZXNzSW50ZXJmYWNlXz1uZXcgWWUoZS5yYWRpdXMpLHRoaXMudGltZXJHYXBfPXRoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfLmlzSGlnaEJsdXIoKT9tLkJMVVJfUFJPQ0VTU19HQVBfTUlDUk9fU0VDT05EX0hJR0g6bS5CTFVSX1BST0NFU1NfR0FQX01JQ1JPX1NFQ09ORF9MT1d9ZWxzZSBpZihyLnRyYW5zZm9ybWVyVHlwZT09PSJWaWRlb0JhY2tncm91bmQiKXRoaXMudGltZXJHYXBfPW0uVklERU9fUFJPQ0VTU19HQVBfTUlDUk9fU0VDT05ELHRoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfPW5ldyB3ZTtlbHNlIGlmKHIudHJhbnNmb3JtZXJUeXBlPT09IlNpbHVldGVCbHVyIil7bGV0IGU9cjt0aGlzLnBvc3RQcm9jZXNzSW50ZXJmYWNlXz1uZXcgTXIoZS5yYWRpdXMpLHRoaXMudGltZXJHYXBfPXRoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfLmlzSGlnaEJsdXIoKT9tLkJMVVJfUFJPQ0VTU19HQVBfTUlDUk9fU0VDT05EX0hJR0g6bS5CTFVSX1BST0NFU1NfR0FQX01JQ1JPX1NFQ09ORF9MT1d9ZWxzZSB0aGlzLnBvc3RQcm9jZXNzSW50ZXJmYWNlXz1uZXcgWWUsdGhpcy50aW1lckdhcF89dGhpcy5wb3N0UHJvY2Vzc0ludGVyZmFjZV8uaXNIaWdoQmx1cigpP20uQkxVUl9QUk9DRVNTX0dBUF9NSUNST19TRUNPTkRfSElHSDptLkJMVVJfUFJPQ0VTU19HQVBfTUlDUk9fU0VDT05EX0xPV31jbG9zZSgpe3JldHVybiBuZXcgUHJvbWlzZSgocixlKT0+e3RoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfP3RoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfLmRlc3Ryb3koKS50aGVuKCgpPT57cigpfSkuY2F0Y2godD0+e2UodCl9KTpyKCl9KX1zdGFydCgpe31hc3luYyB0cmFuc2Zvcm0ocixlKXsodGhpcy5yZXN1bHRDYW52YXNfLndpZHRoIT1yLmRpc3BsYXlXaWR0aHx8dGhpcy5yZXN1bHRDYW52YXNfLmhlaWdodCE9ci5kaXNwbGF5SGVpZ2h0KSYmKHRoaXMucmVzdWx0Q2FudmFzXy53aWR0aD1yLmRpc3BsYXlXaWR0aCx0aGlzLnJlc3VsdENhbnZhc18uaGVpZ2h0PXIuZGlzcGxheUhlaWdodCk7Y29uc3QgdD1yLnRpbWVzdGFtcDtjcmVhdGVJbWFnZUJpdG1hcChyKS50aGVuKHM9PntyLmNsb3NlKCksdGhpcy5wcm9jZXNzRnJhbWUoZSxzLHQpfSkuY2F0Y2gocz0+e2UuZW5xdWV1ZShyKX0pfXByb2Nlc3NGcmFtZShyLGUsdCl7KHRoaXMubmV3SW5wdXRDb3VudGVyPG0uTkVXX0lOUFVUX05VTUJFUl9PRl9SVU5TfHx0LXRoaXMubGFzdFByb2Nlc3NlZFRpbWVzdGFtcF8+PXRoaXMudGltZXJHYXBfKSYmKHRoaXMubGFzdFByb2Nlc3NlZFRpbWVzdGFtcF89dCx0aGlzLnByb2Nlc3NTb3VyY2UoZSksdGhpcy5uZXdJbnB1dENvdW50ZXI8bS5ORVdfSU5QVVRfTlVNQkVSX09GX1JVTlMmJnRoaXMubmV3SW5wdXRDb3VudGVyKyspLHRoaXMucmVzdWx0Q3R4Xy5zYXZlKCksdGhpcy5yZXN1bHRDdHhfLmNsZWFyUmVjdCgwLDAsdGhpcy5yZXN1bHRDYW52YXNfLndpZHRoLHRoaXMucmVzdWx0Q2FudmFzXy5oZWlnaHQpLHRoaXMuc2VnbWVudGF0aW9uTWFza0ltYWdlXyYmKHRoaXMucmVzdWx0Q3R4Xy5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb249ImNvcHkiLHRoaXMucmVzdWx0Q3R4Xy5kcmF3SW1hZ2UodGhpcy5zZWdtZW50YXRpb25NYXNrSW1hZ2VfLDAsMCx0aGlzLnNlZ21lbnRhdGlvbk1hc2tJbWFnZV8ud2lkdGgsdGhpcy5zZWdtZW50YXRpb25NYXNrSW1hZ2VfLmhlaWdodCwwLDAsdGhpcy5yZXN1bHRDYW52YXNfLndpZHRoLHRoaXMucmVzdWx0Q2FudmFzXy5oZWlnaHQpKSx0aGlzLnJlc3VsdEN0eF8uZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uPSJzb3VyY2UtYXRvcCIsdGhpcy5yZXN1bHRDdHhfLmZpbHRlcj0ibm9uZSIsdGhpcy5yZXN1bHRDdHhfLmRyYXdJbWFnZShlLDAsMCxlLndpZHRoLGUuaGVpZ2h0KSx0aGlzLnBvc3RQcm9jZXNzSW50ZXJmYWNlXyYmdGhpcy5wb3N0UHJvY2Vzc0ludGVyZmFjZV8ucnVuUG9zdFByb2Nlc3NpbmcodGhpcy5yZXN1bHRDdHhfLGUpLHRoaXMucmVzdWx0Q3R4Xy5yZXN0b3JlKCksci5lbnF1ZXVlKG5ldyBWaWRlb0ZyYW1lKHRoaXMucmVzdWx0Q2FudmFzXyx7dGltZXN0YW1wOnQsYWxwaGE6ImRpc2NhcmQifSkpLGUuY2xvc2UoKX1wcm9jZXNzU291cmNlKHIpe2lmKHRoaXMuc2VnbWVudGF0aW9uTWFza0N0eF8uY2xlYXJSZWN0KDAsMCx0aGlzLnNlZ21lbnRhdGlvbk1hc2tDYW52YXNfLndpZHRoLHRoaXMuc2VnbWVudGF0aW9uTWFza0NhbnZhc18uaGVpZ2h0KSx0aGlzLnNlZ21lbnRhdGlvbk1hc2tDdHhfLmRyYXdJbWFnZShyLDAsMCxyLndpZHRoLHIuaGVpZ2h0LDAsMCx0aGlzLnNlZ21lbnRhdGlvbk1hc2tDYW52YXNfLndpZHRoLHRoaXMuc2VnbWVudGF0aW9uTWFza0NhbnZhc18uaGVpZ2h0KSx0aGlzLnByb2Nlc3NGcmFtZUNiKXtsZXQgZT10aGlzLnNlZ21lbnRhdGlvbk1hc2tDYW52YXNfLnRyYW5zZmVyVG9JbWFnZUJpdG1hcCgpO3RoaXMucHJvY2Vzc0ZyYW1lQ2IoZSl9fWZsdXNoKCl7fWdldFRyYW5zZm9ybWVyVHlwZSgpe3JldHVybiJCYWNrZ3JvdW5kVHJhbnNmb3JtZXIifXJlc2V0TmV3SW5wdXRDb3VuZXIoKXt0aGlzLm5ld0lucHV0Q291bnRlcj0wfXNldFZpZGVvQkdSZWFkYWJsZShyKXtyZXR1cm4gbmV3IFByb21pc2UoKGUsdCk9Pnt0aGlzLnBvc3RQcm9jZXNzSW50ZXJmYWNlXyBpbnN0YW5jZW9mIHdlP3RoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfLnNldFZpZGVvUmVhZGFibGUocikudGhlbigoKT0+e2UoKX0pLmNhdGNoKHM9Pnt0KHMpfSk6dCgicG9zdCBwcm9jZXNzIGlzIG5vdCB2aWRlbyIpfSl9c2V0VmlydHVhbEJHSW1hZ2Uocil7cmV0dXJuIG5ldyBQcm9taXNlKChlLHQpPT57dGhpcy5wb3N0UHJvY2Vzc0ludGVyZmFjZV8gaW5zdGFuY2VvZiBaZT8odGhpcy5wb3N0UHJvY2Vzc0ludGVyZmFjZV8uc2V0VmlydHVhbEJHSW1hZ2UociksZSgpKTp0KCJwb3N0IHByb2Nlc3MgaXMgbm90IHZpZGVvIil9KX1zZXRTZWdtZW50YXRpb25NYXNrSW1hZ2Uocil7dGhpcy5zZWdtZW50YXRpb25NYXNrSW1hZ2VfJiZ0aGlzLnNlZ21lbnRhdGlvbk1hc2tJbWFnZV8uY2xvc2UoKSx0aGlzLnNlZ21lbnRhdGlvbk1hc2tJbWFnZV89cn19O2xldCBDPW07Qy5CTFVSX1BST0NFU1NfR0FQX01JQ1JPX1NFQ09ORF9MT1c9MTVlNCxDLkJMVVJfUFJPQ0VTU19HQVBfTUlDUk9fU0VDT05EX0hJR0g9NGU0LEMuVklERU9fUFJPQ0VTU19HQVBfTUlDUk9fU0VDT05EPTJlNSxDLlZJUlRVQUxfUFJPQ0VTU19HQVBfTUlDUk9fU0VDT05EPTE1ZTQsQy5ORVdfSU5QVVRfTlVNQkVSX09GX1JVTlM9MzAsQy5TRUxGSUVfV0lEVEg9MjU2LEMuU0VMRklFX0hJR0hUPTE0NDtmdW5jdGlvbiB4cihyKXtyZXR1cm4gdHlwZW9mIHI9PSJvYmplY3QiJiZyIT09bnVsbCYmIm1lc3NhZ2UiaW4gciYmdHlwZW9mIHIubWVzc2FnZT09InN0cmluZyJ9ZnVuY3Rpb24gQXIocil7aWYoeHIocikpcmV0dXJuIHI7dHJ5e3JldHVybiBuZXcgRXJyb3IoSlNPTi5zdHJpbmdpZnkocikpfWNhdGNoe3JldHVybiBuZXcgRXJyb3IoU3RyaW5nKHIpKX19ZnVuY3Rpb24gVShyKXtyZXR1cm4gdHlwZW9mIHI9PSJ1bmRlZmluZWQiPyIiOkFyKHIpLm1lc3NhZ2V9aWYodHlwZW9mIGltcG9ydFNjcmlwdHM9PSJmdW5jdGlvbiIpe2xldCByPWZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBQcm9taXNlKChzLG4pPT57ZT1uZXcgT3IsZS5vbigiZXJyb3IiLGk9Pntjb25zdCBhPXtjYWxsYmFja1R5cGU6Im1lZGlhX3Byb2Nlc3Nvcl9lcnJvcl9ldmVudCIsbWVzc2FnZTppfTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShhKSl9KSxlLm9uKCJ3YXJuIixpPT57Y29uc3QgYT17Y2FsbGJhY2tUeXBlOiJtZWRpYV9wcm9jZXNzb3Jfd2Fybl9ldmVudCIsbWVzc2FnZTppfTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShhKSl9KSxlLm9uKCJwaXBlbGluZUluZm8iLGk9Pntjb25zdCBhPXtjYWxsYmFja1R5cGU6Im1lZGlhX3Byb2Nlc3Nvcl9waXBlbGluZV9ldmVudCIsbWVzc2FnZTppfTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShhKSl9KSx0PW5ldyBDLHQuaW5pdChpPT57cG9zdE1lc3NhZ2UoaSxbaV0pfSk7bGV0IG89W107by5wdXNoKHQpLGUuc2V0VHJhbnNmb3JtZXJzKG8pLnRoZW4oKCk9PntzKCl9KS5jYXRjaChpPT57bihpKX0pfSl9LGUsdDtvbm1lc3NhZ2U9YXN5bmMgcz0+e2lmKHMuZGF0YSBpbnN0YW5jZW9mIEltYWdlQml0bWFwKXt0JiZ0LnNldFNlZ21lbnRhdGlvbk1hc2tJbWFnZShzLmRhdGEpO3JldHVybn1jb25zdHtvcGVyYXRpb246bn09cy5kYXRhO2lmKG49PT0iaW5pdCIpe2NvbnN0e21ldGFEYXRhOm99PXMuZGF0YTt0eXBlb2Ygbz09InN0cmluZyImJmRyKEpTT04ucGFyc2UobykpLHIoKS50aGVuKCgpPT57Y29uc3QgaT17Y2FsbGJhY2tUeXBlOiJzdWNjZXNzIixtZXNzYWdlOm59O3Bvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KGkpKX0pLmNhdGNoKGk9Pntjb25zdCBhPXtjYWxsYmFja1R5cGU6ImVycm9yIixtZXNzYWdlOm4sZXJyb3I6VShpKX07cG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoYSkpfSl9ZWxzZSBpZihuPT09InRyYW5zZm9ybSIpe2NvbnN0e3JlYWRhYmxlOm8sd3JpdGFibGU6aX09cy5kYXRhO3QucmVzZXROZXdJbnB1dENvdW5lcigpLGUudHJhbnNmb3JtKG8saSkudGhlbigoKT0+e2NvbnN0IGE9e2NhbGxiYWNrVHlwZToic3VjY2VzcyIsbWVzc2FnZTpufTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShhKSl9KS5jYXRjaChhPT57Y29uc3QgbD17Y2FsbGJhY2tUeXBlOiJlcnJvciIsbWVzc2FnZTpuLGVycm9yOlUoYSl9O3Bvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KGwpKX0pfWVsc2UgaWYobj09PSJkZXN0cm95Iil0LmNsb3NlKCkuZmluYWxseSgoKT0+e2UuZGVzdHJveSgpLnRoZW4oKCk9Pntjb25zdCBvPXtjYWxsYmFja1R5cGU6InN1Y2Nlc3MiLG1lc3NhZ2U6bn07cG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkobykpfSkuY2F0Y2gobz0+e2NvbnN0IGk9e2NhbGxiYWNrVHlwZToiZXJyb3IiLG1lc3NhZ2U6bixlcnJvcjpVKG8pfTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShpKSl9KX0pO2Vsc2UgaWYobj09PSJzZXRUcmFja0V4cGVjdGVkUmF0ZSIpe2Uuc2V0VHJhY2tFeHBlY3RlZFJhdGUocy5kYXRhLnJhdGUpO2NvbnN0IG89e2NhbGxiYWNrVHlwZToic3VjY2VzcyIsbWVzc2FnZTpufTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShvKSl9ZWxzZSBpZihuPT09InNldEJhY2tncm91bmRPcHRpb25zIil7Y29uc3R7YmFja2dyb3VuZE9wdGlvbnM6b309cy5kYXRhO3Quc2V0QmFja2dyb3VuZE9wdGlvbnMoSlNPTi5wYXJzZShvKSkudGhlbigoKT0+e2NvbnN0IGk9e2NhbGxiYWNrVHlwZToic3VjY2VzcyIsbWVzc2FnZTpufTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShpKSl9KS5jYXRjaChpPT57Y29uc3QgYT17Y2FsbGJhY2tUeXBlOiJlcnJvciIsbWVzc2FnZTpuLGVycm9yOlUoaSl9O3Bvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KGEpKX0pfWVsc2UgaWYobj09PSJzZXRWaWRlb0JHUmVhZGFibGUiKXtjb25zdHtyZWFkYWJsZTpvfT1zLmRhdGE7dC5zZXRWaWRlb0JHUmVhZGFibGUobykudGhlbigoKT0+e2NvbnN0IGk9e2NhbGxiYWNrVHlwZToic3VjY2VzcyIsbWVzc2FnZTpufTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShpKSl9KS5jYXRjaChpPT57Y29uc3QgYT17Y2FsbGJhY2tUeXBlOiJlcnJvciIsbWVzc2FnZTpuLGVycm9yOlUoaSl9O3Bvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KGEpKX0pfWVsc2UgaWYobj09PSJzZXRWaXJ0dWFsQkdJbWFnZSIpe2NvbnN0e2ltYWdlOm99PXMuZGF0YTt0LnNldFZpcnR1YWxCR0ltYWdlKG8pLnRoZW4oKCk9Pntjb25zdCBpPXtjYWxsYmFja1R5cGU6InN1Y2Nlc3MiLG1lc3NhZ2U6bn07cG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoaSkpfSkuY2F0Y2goaT0+e2NvbnN0IGE9e2NhbGxiYWNrVHlwZToiZXJyb3IiLG1lc3NhZ2U6bixlcnJvcjpVKGkpfTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShhKSl9KX19fX0pKCk7Cg==";
|
|
38746
|
+
const encodedJs = "KGZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2NsYXNzIFR7fVQudXBkYXRlcz17dHJhbnNmb3JtZXJfbmV3OiJOZXcgdHJhbnNmb3JtZXIiLHRyYW5zZm9ybWVyX251bGw6Ik51bGwgdHJhbnNmb3JtZXIifSxULmVycm9ycz17dHJhbnNmb3JtZXJfbm9uZToiTm8gdHJhbnNmb3JtZXJzIHByb3ZpZGVkIix0cmFuc2Zvcm1lcl9zdGFydDoiQ2Fubm90IHN0YXJ0IHRyYW5zZm9ybWVyIix0cmFuc2Zvcm1lcl90cmFuc2Zvcm06IkNhbm5vdCB0cmFuc2Zvcm0gZnJhbWUiLHRyYW5zZm9ybWVyX2ZsdXNoOiJDYW5ub3QgZmx1c2ggdHJhbnNmb3JtZXIiLHJlYWRhYmxlX251bGw6IlJlYWRhYmxlIGlzIG51bGwiLHdyaXRhYmxlX251bGw6IldyaXRhYmxlIGlzIG51bGwifTt2YXIgWT17ZXhwb3J0czp7fX0sRWU9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24oKXtmb3IodmFyIG49bmV3IEFycmF5KGFyZ3VtZW50cy5sZW5ndGgpLG89MDtvPG4ubGVuZ3RoO28rKyluW29dPWFyZ3VtZW50c1tvXTtyZXR1cm4gZS5hcHBseSh0LG4pfX0scnQ9RWUsUj1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nO2Z1bmN0aW9uIFoocil7cmV0dXJuIEFycmF5LmlzQXJyYXkocil9ZnVuY3Rpb24gZWUocil7cmV0dXJuIHR5cGVvZiByPT0idW5kZWZpbmVkIn1mdW5jdGlvbiBzdChyKXtyZXR1cm4gciE9PW51bGwmJiFlZShyKSYmci5jb25zdHJ1Y3RvciE9PW51bGwmJiFlZShyLmNvbnN0cnVjdG9yKSYmdHlwZW9mIHIuY29uc3RydWN0b3IuaXNCdWZmZXI9PSJmdW5jdGlvbiImJnIuY29uc3RydWN0b3IuaXNCdWZmZXIocil9ZnVuY3Rpb24gVGUocil7cmV0dXJuIFIuY2FsbChyKT09PSJbb2JqZWN0IEFycmF5QnVmZmVyXSJ9ZnVuY3Rpb24gbnQocil7cmV0dXJuIFIuY2FsbChyKT09PSJbb2JqZWN0IEZvcm1EYXRhXSJ9ZnVuY3Rpb24gaXQocil7dmFyIGU7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlciE9InVuZGVmaW5lZCImJkFycmF5QnVmZmVyLmlzVmlldz9lPUFycmF5QnVmZmVyLmlzVmlldyhyKTplPXImJnIuYnVmZmVyJiZUZShyLmJ1ZmZlciksZX1mdW5jdGlvbiBvdChyKXtyZXR1cm4gdHlwZW9mIHI9PSJzdHJpbmcifWZ1bmN0aW9uIGF0KHIpe3JldHVybiB0eXBlb2Ygcj09Im51bWJlciJ9ZnVuY3Rpb24gUmUocil7cmV0dXJuIHIhPT1udWxsJiZ0eXBlb2Ygcj09Im9iamVjdCJ9ZnVuY3Rpb24gRihyKXtpZihSLmNhbGwocikhPT0iW29iamVjdCBPYmplY3RdIilyZXR1cm4hMTt2YXIgZT1PYmplY3QuZ2V0UHJvdG90eXBlT2Yocik7cmV0dXJuIGU9PT1udWxsfHxlPT09T2JqZWN0LnByb3RvdHlwZX1mdW5jdGlvbiB1dChyKXtyZXR1cm4gUi5jYWxsKHIpPT09IltvYmplY3QgRGF0ZV0ifWZ1bmN0aW9uIGx0KHIpe3JldHVybiBSLmNhbGwocik9PT0iW29iamVjdCBGaWxlXSJ9ZnVuY3Rpb24gY3Qocil7cmV0dXJuIFIuY2FsbChyKT09PSJbb2JqZWN0IEJsb2JdIn1mdW5jdGlvbiBQZShyKXtyZXR1cm4gUi5jYWxsKHIpPT09IltvYmplY3QgRnVuY3Rpb25dIn1mdW5jdGlvbiBmdChyKXtyZXR1cm4gUmUocikmJlBlKHIucGlwZSl9ZnVuY3Rpb24gaHQocil7cmV0dXJuIFIuY2FsbChyKT09PSJbb2JqZWN0IFVSTFNlYXJjaFBhcmFtc10ifWZ1bmN0aW9uIGR0KHIpe3JldHVybiByLnRyaW0/ci50cmltKCk6ci5yZXBsYWNlKC9eXHMrfFxzKyQvZywiIil9ZnVuY3Rpb24gcHQoKXtyZXR1cm4gdHlwZW9mIG5hdmlnYXRvciE9InVuZGVmaW5lZCImJihuYXZpZ2F0b3IucHJvZHVjdD09PSJSZWFjdE5hdGl2ZSJ8fG5hdmlnYXRvci5wcm9kdWN0PT09Ik5hdGl2ZVNjcmlwdCJ8fG5hdmlnYXRvci5wcm9kdWN0PT09Ik5TIik/ITE6dHlwZW9mIHdpbmRvdyE9InVuZGVmaW5lZCImJnR5cGVvZiBkb2N1bWVudCE9InVuZGVmaW5lZCJ9ZnVuY3Rpb24gdGUocixlKXtpZighKHI9PT1udWxsfHx0eXBlb2Ygcj09InVuZGVmaW5lZCIpKWlmKHR5cGVvZiByIT0ib2JqZWN0IiYmKHI9W3JdKSxaKHIpKWZvcih2YXIgdD0wLHM9ci5sZW5ndGg7dDxzO3QrKyllLmNhbGwobnVsbCxyW3RdLHQscik7ZWxzZSBmb3IodmFyIG4gaW4gcilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocixuKSYmZS5jYWxsKG51bGwscltuXSxuLHIpfWZ1bmN0aW9uIHJlKCl7dmFyIHI9e307ZnVuY3Rpb24gZShuLG8pe0YocltvXSkmJkYobik/cltvXT1yZShyW29dLG4pOkYobik/cltvXT1yZSh7fSxuKTpaKG4pP3Jbb109bi5zbGljZSgpOnJbb109bn1mb3IodmFyIHQ9MCxzPWFyZ3VtZW50cy5sZW5ndGg7dDxzO3QrKyl0ZShhcmd1bWVudHNbdF0sZSk7cmV0dXJuIHJ9ZnVuY3Rpb24gbXQocixlLHQpe3JldHVybiB0ZShlLGZ1bmN0aW9uKG4sbyl7dCYmdHlwZW9mIG49PSJmdW5jdGlvbiI/cltvXT1ydChuLHQpOnJbb109bn0pLHJ9ZnVuY3Rpb24gZ3Qocil7cmV0dXJuIHIuY2hhckNvZGVBdCgwKT09PTY1Mjc5JiYocj1yLnNsaWNlKDEpKSxyfXZhciBwPXtpc0FycmF5OlosaXNBcnJheUJ1ZmZlcjpUZSxpc0J1ZmZlcjpzdCxpc0Zvcm1EYXRhOm50LGlzQXJyYXlCdWZmZXJWaWV3Oml0LGlzU3RyaW5nOm90LGlzTnVtYmVyOmF0LGlzT2JqZWN0OlJlLGlzUGxhaW5PYmplY3Q6Rixpc1VuZGVmaW5lZDplZSxpc0RhdGU6dXQsaXNGaWxlOmx0LGlzQmxvYjpjdCxpc0Z1bmN0aW9uOlBlLGlzU3RyZWFtOmZ0LGlzVVJMU2VhcmNoUGFyYW1zOmh0LGlzU3RhbmRhcmRCcm93c2VyRW52OnB0LGZvckVhY2g6dGUsbWVyZ2U6cmUsZXh0ZW5kOm10LHRyaW06ZHQsc3RyaXBCT006Z3R9LHg9cDtmdW5jdGlvbiBDZShyKXtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KHIpLnJlcGxhY2UoLyUzQS9naSwiOiIpLnJlcGxhY2UoLyUyNC9nLCIkIikucmVwbGFjZSgvJTJDL2dpLCIsIikucmVwbGFjZSgvJTIwL2csIisiKS5yZXBsYWNlKC8lNUIvZ2ksIlsiKS5yZXBsYWNlKC8lNUQvZ2ksIl0iKX12YXIgU2U9ZnVuY3Rpb24oZSx0LHMpe2lmKCF0KXJldHVybiBlO3ZhciBuO2lmKHMpbj1zKHQpO2Vsc2UgaWYoeC5pc1VSTFNlYXJjaFBhcmFtcyh0KSluPXQudG9TdHJpbmcoKTtlbHNle3ZhciBvPVtdO3guZm9yRWFjaCh0LGZ1bmN0aW9uKGwsbSl7bD09PW51bGx8fHR5cGVvZiBsPT0idW5kZWZpbmVkInx8KHguaXNBcnJheShsKT9tPW0rIltdIjpsPVtsXSx4LmZvckVhY2gobCxmdW5jdGlvbihmKXt4LmlzRGF0ZShmKT9mPWYudG9JU09TdHJpbmcoKTp4LmlzT2JqZWN0KGYpJiYoZj1KU09OLnN0cmluZ2lmeShmKSksby5wdXNoKENlKG0pKyI9IitDZShmKSl9KSl9KSxuPW8uam9pbigiJiIpfWlmKG4pe3ZhciBpPWUuaW5kZXhPZigiIyIpO2khPT0tMSYmKGU9ZS5zbGljZSgwLGkpKSxlKz0oZS5pbmRleE9mKCI/Iik9PT0tMT8iPyI6IiYiKStufXJldHVybiBlfSx5dD1wO2Z1bmN0aW9uIEwoKXt0aGlzLmhhbmRsZXJzPVtdfUwucHJvdG90eXBlLnVzZT1mdW5jdGlvbihlLHQscyl7cmV0dXJuIHRoaXMuaGFuZGxlcnMucHVzaCh7ZnVsZmlsbGVkOmUscmVqZWN0ZWQ6dCxzeW5jaHJvbm91czpzP3Muc3luY2hyb25vdXM6ITEscnVuV2hlbjpzP3MucnVuV2hlbjpudWxsfSksdGhpcy5oYW5kbGVycy5sZW5ndGgtMX0sTC5wcm90b3R5cGUuZWplY3Q9ZnVuY3Rpb24oZSl7dGhpcy5oYW5kbGVyc1tlXSYmKHRoaXMuaGFuZGxlcnNbZV09bnVsbCl9LEwucHJvdG90eXBlLmZvckVhY2g9ZnVuY3Rpb24oZSl7eXQuZm9yRWFjaCh0aGlzLmhhbmRsZXJzLGZ1bmN0aW9uKHMpe3MhPT1udWxsJiZlKHMpfSl9O3ZhciBfdD1MLHZ0PXAsYnQ9ZnVuY3Rpb24oZSx0KXt2dC5mb3JFYWNoKGUsZnVuY3Rpb24obixvKXtvIT09dCYmby50b1VwcGVyQ2FzZSgpPT09dC50b1VwcGVyQ2FzZSgpJiYoZVt0XT1uLGRlbGV0ZSBlW29dKX0pfSx4ZT1mdW5jdGlvbihlLHQscyxuLG8pe3JldHVybiBlLmNvbmZpZz10LHMmJihlLmNvZGU9cyksZS5yZXF1ZXN0PW4sZS5yZXNwb25zZT1vLGUuaXNBeGlvc0Vycm9yPSEwLGUudG9KU09OPWZ1bmN0aW9uKCl7cmV0dXJue21lc3NhZ2U6dGhpcy5tZXNzYWdlLG5hbWU6dGhpcy5uYW1lLGRlc2NyaXB0aW9uOnRoaXMuZGVzY3JpcHRpb24sbnVtYmVyOnRoaXMubnVtYmVyLGZpbGVOYW1lOnRoaXMuZmlsZU5hbWUsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsY29sdW1uTnVtYmVyOnRoaXMuY29sdW1uTnVtYmVyLHN0YWNrOnRoaXMuc3RhY2ssY29uZmlnOnRoaXMuY29uZmlnLGNvZGU6dGhpcy5jb2RlLHN0YXR1czp0aGlzLnJlc3BvbnNlJiZ0aGlzLnJlc3BvbnNlLnN0YXR1cz90aGlzLnJlc3BvbnNlLnN0YXR1czpudWxsfX0sZX0sd3Q9eGUsT2U9ZnVuY3Rpb24oZSx0LHMsbixvKXt2YXIgaT1uZXcgRXJyb3IoZSk7cmV0dXJuIHd0KGksdCxzLG4sbyl9LEV0PU9lLFR0PWZ1bmN0aW9uKGUsdCxzKXt2YXIgbj1zLmNvbmZpZy52YWxpZGF0ZVN0YXR1czshcy5zdGF0dXN8fCFufHxuKHMuc3RhdHVzKT9lKHMpOnQoRXQoIlJlcXVlc3QgZmFpbGVkIHdpdGggc3RhdHVzIGNvZGUgIitzLnN0YXR1cyxzLmNvbmZpZyxudWxsLHMucmVxdWVzdCxzKSl9LEQ9cCxSdD1ELmlzU3RhbmRhcmRCcm93c2VyRW52KCk/ZnVuY3Rpb24oKXtyZXR1cm57d3JpdGU6ZnVuY3Rpb24odCxzLG4sbyxpLGEpe3ZhciBsPVtdO2wucHVzaCh0KyI9IitlbmNvZGVVUklDb21wb25lbnQocykpLEQuaXNOdW1iZXIobikmJmwucHVzaCgiZXhwaXJlcz0iK25ldyBEYXRlKG4pLnRvR01UU3RyaW5nKCkpLEQuaXNTdHJpbmcobykmJmwucHVzaCgicGF0aD0iK28pLEQuaXNTdHJpbmcoaSkmJmwucHVzaCgiZG9tYWluPSIraSksYT09PSEwJiZsLnB1c2goInNlY3VyZSIpLGRvY3VtZW50LmNvb2tpZT1sLmpvaW4oIjsgIil9LHJlYWQ6ZnVuY3Rpb24odCl7dmFyIHM9ZG9jdW1lbnQuY29va2llLm1hdGNoKG5ldyBSZWdFeHAoIihefDtcXHMqKSgiK3QrIik9KFteO10qKSIpKTtyZXR1cm4gcz9kZWNvZGVVUklDb21wb25lbnQoc1szXSk6bnVsbH0scmVtb3ZlOmZ1bmN0aW9uKHQpe3RoaXMud3JpdGUodCwiIixEYXRlLm5vdygpLTg2NGU1KX19fSgpOmZ1bmN0aW9uKCl7cmV0dXJue3dyaXRlOmZ1bmN0aW9uKCl7fSxyZWFkOmZ1bmN0aW9uKCl7cmV0dXJuIG51bGx9LHJlbW92ZTpmdW5jdGlvbigpe319fSgpLFB0PWZ1bmN0aW9uKGUpe3JldHVybi9eKFthLXpdW2EtelxkK1wtLl0qOik/XC9cLy9pLnRlc3QoZSl9LEN0PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHQ/ZS5yZXBsYWNlKC9cLyskLywiIikrIi8iK3QucmVwbGFjZSgvXlwvKy8sIiIpOmV9LFN0PVB0LHh0PUN0LE90PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUmJiFTdCh0KT94dChlLHQpOnR9LHNlPXAsSXQ9WyJhZ2UiLCJhdXRob3JpemF0aW9uIiwiY29udGVudC1sZW5ndGgiLCJjb250ZW50LXR5cGUiLCJldGFnIiwiZXhwaXJlcyIsImZyb20iLCJob3N0IiwiaWYtbW9kaWZpZWQtc2luY2UiLCJpZi11bm1vZGlmaWVkLXNpbmNlIiwibGFzdC1tb2RpZmllZCIsImxvY2F0aW9uIiwibWF4LWZvcndhcmRzIiwicHJveHktYXV0aG9yaXphdGlvbiIsInJlZmVyZXIiLCJyZXRyeS1hZnRlciIsInVzZXItYWdlbnQiXSxNdD1mdW5jdGlvbihlKXt2YXIgdD17fSxzLG4sbztyZXR1cm4gZSYmc2UuZm9yRWFjaChlLnNwbGl0KGAKYCksZnVuY3Rpb24oYSl7aWYobz1hLmluZGV4T2YoIjoiKSxzPXNlLnRyaW0oYS5zdWJzdHIoMCxvKSkudG9Mb3dlckNhc2UoKSxuPXNlLnRyaW0oYS5zdWJzdHIobysxKSkscyl7aWYodFtzXSYmSXQuaW5kZXhPZihzKT49MClyZXR1cm47cz09PSJzZXQtY29va2llIj90W3NdPSh0W3NdP3Rbc106W10pLmNvbmNhdChbbl0pOnRbc109dFtzXT90W3NdKyIsICIrbjpufX0pLHR9LEllPXAsa3Q9SWUuaXNTdGFuZGFyZEJyb3dzZXJFbnYoKT9mdW5jdGlvbigpe3ZhciBlPS8obXNpZXx0cmlkZW50KS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCksdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIikscztmdW5jdGlvbiBuKG8pe3ZhciBpPW87cmV0dXJuIGUmJih0LnNldEF0dHJpYnV0ZSgiaHJlZiIsaSksaT10LmhyZWYpLHQuc2V0QXR0cmlidXRlKCJocmVmIixpKSx7aHJlZjp0LmhyZWYscHJvdG9jb2w6dC5wcm90b2NvbD90LnByb3RvY29sLnJlcGxhY2UoLzokLywiIik6IiIsaG9zdDp0Lmhvc3Qsc2VhcmNoOnQuc2VhcmNoP3Quc2VhcmNoLnJlcGxhY2UoL15cPy8sIiIpOiIiLGhhc2g6dC5oYXNoP3QuaGFzaC5yZXBsYWNlKC9eIy8sIiIpOiIiLGhvc3RuYW1lOnQuaG9zdG5hbWUscG9ydDp0LnBvcnQscGF0aG5hbWU6dC5wYXRobmFtZS5jaGFyQXQoMCk9PT0iLyI/dC5wYXRobmFtZToiLyIrdC5wYXRobmFtZX19cmV0dXJuIHM9bih3aW5kb3cubG9jYXRpb24uaHJlZiksZnVuY3Rpb24oaSl7dmFyIGE9SWUuaXNTdHJpbmcoaSk/bihpKTppO3JldHVybiBhLnByb3RvY29sPT09cy5wcm90b2NvbCYmYS5ob3N0PT09cy5ob3N0fX0oKTpmdW5jdGlvbigpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiEwfX0oKTtmdW5jdGlvbiBuZShyKXt0aGlzLm1lc3NhZ2U9cn1uZS5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4iQ2FuY2VsIisodGhpcy5tZXNzYWdlPyI6ICIrdGhpcy5tZXNzYWdlOiIiKX0sbmUucHJvdG90eXBlLl9fQ0FOQ0VMX189ITA7dmFyIHE9bmUsSD1wLEF0PVR0LE50PVJ0LCR0PVNlLFV0PU90LEJ0PU10LEZ0PWt0LGllPU9lLEx0PUosRHQ9cSxNZT1mdW5jdGlvbihlKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocyxuKXt2YXIgbz1lLmRhdGEsaT1lLmhlYWRlcnMsYT1lLnJlc3BvbnNlVHlwZSxsO2Z1bmN0aW9uIG0oKXtlLmNhbmNlbFRva2VuJiZlLmNhbmNlbFRva2VuLnVuc3Vic2NyaWJlKGwpLGUuc2lnbmFsJiZlLnNpZ25hbC5yZW1vdmVFdmVudExpc3RlbmVyKCJhYm9ydCIsbCl9SC5pc0Zvcm1EYXRhKG8pJiZkZWxldGUgaVsiQ29udGVudC1UeXBlIl07dmFyIHU9bmV3IFhNTEh0dHBSZXF1ZXN0O2lmKGUuYXV0aCl7dmFyIGY9ZS5hdXRoLnVzZXJuYW1lfHwiIixFPWUuYXV0aC5wYXNzd29yZD91bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoZS5hdXRoLnBhc3N3b3JkKSk6IiI7aS5BdXRob3JpemF0aW9uPSJCYXNpYyAiK2J0b2EoZisiOiIrRSl9dmFyIGc9VXQoZS5iYXNlVVJMLGUudXJsKTt1Lm9wZW4oZS5tZXRob2QudG9VcHBlckNhc2UoKSwkdChnLGUucGFyYW1zLGUucGFyYW1zU2VyaWFsaXplciksITApLHUudGltZW91dD1lLnRpbWVvdXQ7ZnVuY3Rpb24gZXQoKXtpZighIXUpe3ZhciBiPSJnZXRBbGxSZXNwb25zZUhlYWRlcnMiaW4gdT9CdCh1LmdldEFsbFJlc3BvbnNlSGVhZGVycygpKTpudWxsLE49IWF8fGE9PT0idGV4dCJ8fGE9PT0ianNvbiI/dS5yZXNwb25zZVRleHQ6dS5yZXNwb25zZSxTPXtkYXRhOk4sc3RhdHVzOnUuc3RhdHVzLHN0YXR1c1RleHQ6dS5zdGF0dXNUZXh0LGhlYWRlcnM6Yixjb25maWc6ZSxyZXF1ZXN0OnV9O0F0KGZ1bmN0aW9uKHdlKXtzKHdlKSxtKCl9LGZ1bmN0aW9uKHdlKXtuKHdlKSxtKCl9LFMpLHU9bnVsbH19aWYoIm9ubG9hZGVuZCJpbiB1P3Uub25sb2FkZW5kPWV0OnUub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7IXV8fHUucmVhZHlTdGF0ZSE9PTR8fHUuc3RhdHVzPT09MCYmISh1LnJlc3BvbnNlVVJMJiZ1LnJlc3BvbnNlVVJMLmluZGV4T2YoImZpbGU6Iik9PT0wKXx8c2V0VGltZW91dChldCl9LHUub25hYm9ydD1mdW5jdGlvbigpeyF1fHwobihpZSgiUmVxdWVzdCBhYm9ydGVkIixlLCJFQ09OTkFCT1JURUQiLHUpKSx1PW51bGwpfSx1Lm9uZXJyb3I9ZnVuY3Rpb24oKXtuKGllKCJOZXR3b3JrIEVycm9yIixlLG51bGwsdSkpLHU9bnVsbH0sdS5vbnRpbWVvdXQ9ZnVuY3Rpb24oKXt2YXIgTj1lLnRpbWVvdXQ/InRpbWVvdXQgb2YgIitlLnRpbWVvdXQrIm1zIGV4Y2VlZGVkIjoidGltZW91dCBleGNlZWRlZCIsUz1lLnRyYW5zaXRpb25hbHx8THQudHJhbnNpdGlvbmFsO2UudGltZW91dEVycm9yTWVzc2FnZSYmKE49ZS50aW1lb3V0RXJyb3JNZXNzYWdlKSxuKGllKE4sZSxTLmNsYXJpZnlUaW1lb3V0RXJyb3I/IkVUSU1FRE9VVCI6IkVDT05OQUJPUlRFRCIsdSkpLHU9bnVsbH0sSC5pc1N0YW5kYXJkQnJvd3NlckVudigpKXt2YXIgdHQ9KGUud2l0aENyZWRlbnRpYWxzfHxGdChnKSkmJmUueHNyZkNvb2tpZU5hbWU/TnQucmVhZChlLnhzcmZDb29raWVOYW1lKTp2b2lkIDA7dHQmJihpW2UueHNyZkhlYWRlck5hbWVdPXR0KX0ic2V0UmVxdWVzdEhlYWRlciJpbiB1JiZILmZvckVhY2goaSxmdW5jdGlvbihOLFMpe3R5cGVvZiBvPT0idW5kZWZpbmVkIiYmUy50b0xvd2VyQ2FzZSgpPT09ImNvbnRlbnQtdHlwZSI/ZGVsZXRlIGlbU106dS5zZXRSZXF1ZXN0SGVhZGVyKFMsTil9KSxILmlzVW5kZWZpbmVkKGUud2l0aENyZWRlbnRpYWxzKXx8KHUud2l0aENyZWRlbnRpYWxzPSEhZS53aXRoQ3JlZGVudGlhbHMpLGEmJmEhPT0ianNvbiImJih1LnJlc3BvbnNlVHlwZT1lLnJlc3BvbnNlVHlwZSksdHlwZW9mIGUub25Eb3dubG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZ1LmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixlLm9uRG93bmxvYWRQcm9ncmVzcyksdHlwZW9mIGUub25VcGxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmdS51cGxvYWQmJnUudXBsb2FkLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixlLm9uVXBsb2FkUHJvZ3Jlc3MpLChlLmNhbmNlbFRva2VufHxlLnNpZ25hbCkmJihsPWZ1bmN0aW9uKGIpeyF1fHwobighYnx8YiYmYi50eXBlP25ldyBEdCgiY2FuY2VsZWQiKTpiKSx1LmFib3J0KCksdT1udWxsKX0sZS5jYW5jZWxUb2tlbiYmZS5jYW5jZWxUb2tlbi5zdWJzY3JpYmUobCksZS5zaWduYWwmJihlLnNpZ25hbC5hYm9ydGVkP2woKTplLnNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsbCkpKSxvfHwobz1udWxsKSx1LnNlbmQobyl9KX0saD1wLGtlPWJ0LHF0PXhlLEh0PXsiQ29udGVudC1UeXBlIjoiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIn07ZnVuY3Rpb24gQWUocixlKXshaC5pc1VuZGVmaW5lZChyKSYmaC5pc1VuZGVmaW5lZChyWyJDb250ZW50LVR5cGUiXSkmJihyWyJDb250ZW50LVR5cGUiXT1lKX1mdW5jdGlvbiBqdCgpe3ZhciByO3JldHVybih0eXBlb2YgWE1MSHR0cFJlcXVlc3QhPSJ1bmRlZmluZWQifHx0eXBlb2YgcHJvY2VzcyE9InVuZGVmaW5lZCImJk9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChwcm9jZXNzKT09PSJbb2JqZWN0IHByb2Nlc3NdIikmJihyPU1lKSxyfWZ1bmN0aW9uIEp0KHIsZSx0KXtpZihoLmlzU3RyaW5nKHIpKXRyeXtyZXR1cm4oZXx8SlNPTi5wYXJzZSkociksaC50cmltKHIpfWNhdGNoKHMpe2lmKHMubmFtZSE9PSJTeW50YXhFcnJvciIpdGhyb3cgc31yZXR1cm4odHx8SlNPTi5zdHJpbmdpZnkpKHIpfXZhciBqPXt0cmFuc2l0aW9uYWw6e3NpbGVudEpTT05QYXJzaW5nOiEwLGZvcmNlZEpTT05QYXJzaW5nOiEwLGNsYXJpZnlUaW1lb3V0RXJyb3I6ITF9LGFkYXB0ZXI6anQoKSx0cmFuc2Zvcm1SZXF1ZXN0OltmdW5jdGlvbihlLHQpe3JldHVybiBrZSh0LCJBY2NlcHQiKSxrZSh0LCJDb250ZW50LVR5cGUiKSxoLmlzRm9ybURhdGEoZSl8fGguaXNBcnJheUJ1ZmZlcihlKXx8aC5pc0J1ZmZlcihlKXx8aC5pc1N0cmVhbShlKXx8aC5pc0ZpbGUoZSl8fGguaXNCbG9iKGUpP2U6aC5pc0FycmF5QnVmZmVyVmlldyhlKT9lLmJ1ZmZlcjpoLmlzVVJMU2VhcmNoUGFyYW1zKGUpPyhBZSh0LCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7Y2hhcnNldD11dGYtOCIpLGUudG9TdHJpbmcoKSk6aC5pc09iamVjdChlKXx8dCYmdFsiQ29udGVudC1UeXBlIl09PT0iYXBwbGljYXRpb24vanNvbiI/KEFlKHQsImFwcGxpY2F0aW9uL2pzb24iKSxKdChlKSk6ZX1dLHRyYW5zZm9ybVJlc3BvbnNlOltmdW5jdGlvbihlKXt2YXIgdD10aGlzLnRyYW5zaXRpb25hbHx8ai50cmFuc2l0aW9uYWwscz10JiZ0LnNpbGVudEpTT05QYXJzaW5nLG49dCYmdC5mb3JjZWRKU09OUGFyc2luZyxvPSFzJiZ0aGlzLnJlc3BvbnNlVHlwZT09PSJqc29uIjtpZihvfHxuJiZoLmlzU3RyaW5nKGUpJiZlLmxlbmd0aCl0cnl7cmV0dXJuIEpTT04ucGFyc2UoZSl9Y2F0Y2goaSl7aWYobyl0aHJvdyBpLm5hbWU9PT0iU3ludGF4RXJyb3IiP3F0KGksdGhpcywiRV9KU09OX1BBUlNFIik6aX1yZXR1cm4gZX1dLHRpbWVvdXQ6MCx4c3JmQ29va2llTmFtZToiWFNSRi1UT0tFTiIseHNyZkhlYWRlck5hbWU6IlgtWFNSRi1UT0tFTiIsbWF4Q29udGVudExlbmd0aDotMSxtYXhCb2R5TGVuZ3RoOi0xLHZhbGlkYXRlU3RhdHVzOmZ1bmN0aW9uKGUpe3JldHVybiBlPj0yMDAmJmU8MzAwfSxoZWFkZXJzOntjb21tb246e0FjY2VwdDoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9wbGFpbiwgKi8qIn19fTtoLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIl0sZnVuY3Rpb24oZSl7ai5oZWFkZXJzW2VdPXt9fSksaC5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7ai5oZWFkZXJzW2VdPWgubWVyZ2UoSHQpfSk7dmFyIEo9aixWdD1wLHp0PUosV3Q9ZnVuY3Rpb24oZSx0LHMpe3ZhciBuPXRoaXN8fHp0O3JldHVybiBWdC5mb3JFYWNoKHMsZnVuY3Rpb24oaSl7ZT1pLmNhbGwobixlLHQpfSksZX0sTmU9ZnVuY3Rpb24oZSl7cmV0dXJuISEoZSYmZS5fX0NBTkNFTF9fKX0sJGU9cCxvZT1XdCxHdD1OZSxRdD1KLFh0PXE7ZnVuY3Rpb24gYWUocil7aWYoci5jYW5jZWxUb2tlbiYmci5jYW5jZWxUb2tlbi50aHJvd0lmUmVxdWVzdGVkKCksci5zaWduYWwmJnIuc2lnbmFsLmFib3J0ZWQpdGhyb3cgbmV3IFh0KCJjYW5jZWxlZCIpfXZhciBLdD1mdW5jdGlvbihlKXthZShlKSxlLmhlYWRlcnM9ZS5oZWFkZXJzfHx7fSxlLmRhdGE9b2UuY2FsbChlLGUuZGF0YSxlLmhlYWRlcnMsZS50cmFuc2Zvcm1SZXF1ZXN0KSxlLmhlYWRlcnM9JGUubWVyZ2UoZS5oZWFkZXJzLmNvbW1vbnx8e30sZS5oZWFkZXJzW2UubWV0aG9kXXx8e30sZS5oZWFkZXJzKSwkZS5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCIsImNvbW1vbiJdLGZ1bmN0aW9uKG4pe2RlbGV0ZSBlLmhlYWRlcnNbbl19KTt2YXIgdD1lLmFkYXB0ZXJ8fFF0LmFkYXB0ZXI7cmV0dXJuIHQoZSkudGhlbihmdW5jdGlvbihuKXtyZXR1cm4gYWUoZSksbi5kYXRhPW9lLmNhbGwoZSxuLmRhdGEsbi5oZWFkZXJzLGUudHJhbnNmb3JtUmVzcG9uc2UpLG59LGZ1bmN0aW9uKG4pe3JldHVybiBHdChuKXx8KGFlKGUpLG4mJm4ucmVzcG9uc2UmJihuLnJlc3BvbnNlLmRhdGE9b2UuY2FsbChlLG4ucmVzcG9uc2UuZGF0YSxuLnJlc3BvbnNlLmhlYWRlcnMsZS50cmFuc2Zvcm1SZXNwb25zZSkpKSxQcm9taXNlLnJlamVjdChuKX0pfSx5PXAsVWU9ZnVuY3Rpb24oZSx0KXt0PXR8fHt9O3ZhciBzPXt9O2Z1bmN0aW9uIG4odSxmKXtyZXR1cm4geS5pc1BsYWluT2JqZWN0KHUpJiZ5LmlzUGxhaW5PYmplY3QoZik/eS5tZXJnZSh1LGYpOnkuaXNQbGFpbk9iamVjdChmKT95Lm1lcmdlKHt9LGYpOnkuaXNBcnJheShmKT9mLnNsaWNlKCk6Zn1mdW5jdGlvbiBvKHUpe2lmKHkuaXNVbmRlZmluZWQodFt1XSkpe2lmKCF5LmlzVW5kZWZpbmVkKGVbdV0pKXJldHVybiBuKHZvaWQgMCxlW3VdKX1lbHNlIHJldHVybiBuKGVbdV0sdFt1XSl9ZnVuY3Rpb24gaSh1KXtpZigheS5pc1VuZGVmaW5lZCh0W3VdKSlyZXR1cm4gbih2b2lkIDAsdFt1XSl9ZnVuY3Rpb24gYSh1KXtpZih5LmlzVW5kZWZpbmVkKHRbdV0pKXtpZigheS5pc1VuZGVmaW5lZChlW3VdKSlyZXR1cm4gbih2b2lkIDAsZVt1XSl9ZWxzZSByZXR1cm4gbih2b2lkIDAsdFt1XSl9ZnVuY3Rpb24gbCh1KXtpZih1IGluIHQpcmV0dXJuIG4oZVt1XSx0W3VdKTtpZih1IGluIGUpcmV0dXJuIG4odm9pZCAwLGVbdV0pfXZhciBtPXt1cmw6aSxtZXRob2Q6aSxkYXRhOmksYmFzZVVSTDphLHRyYW5zZm9ybVJlcXVlc3Q6YSx0cmFuc2Zvcm1SZXNwb25zZTphLHBhcmFtc1NlcmlhbGl6ZXI6YSx0aW1lb3V0OmEsdGltZW91dE1lc3NhZ2U6YSx3aXRoQ3JlZGVudGlhbHM6YSxhZGFwdGVyOmEscmVzcG9uc2VUeXBlOmEseHNyZkNvb2tpZU5hbWU6YSx4c3JmSGVhZGVyTmFtZTphLG9uVXBsb2FkUHJvZ3Jlc3M6YSxvbkRvd25sb2FkUHJvZ3Jlc3M6YSxkZWNvbXByZXNzOmEsbWF4Q29udGVudExlbmd0aDphLG1heEJvZHlMZW5ndGg6YSx0cmFuc3BvcnQ6YSxodHRwQWdlbnQ6YSxodHRwc0FnZW50OmEsY2FuY2VsVG9rZW46YSxzb2NrZXRQYXRoOmEscmVzcG9uc2VFbmNvZGluZzphLHZhbGlkYXRlU3RhdHVzOmx9O3JldHVybiB5LmZvckVhY2goT2JqZWN0LmtleXMoZSkuY29uY2F0KE9iamVjdC5rZXlzKHQpKSxmdW5jdGlvbihmKXt2YXIgRT1tW2ZdfHxvLGc9RShmKTt5LmlzVW5kZWZpbmVkKGcpJiZFIT09bHx8KHNbZl09Zyl9KSxzfSxCZT17dmVyc2lvbjoiMC4yNS4wIn0sWXQ9QmUudmVyc2lvbix1ZT17fTtbIm9iamVjdCIsImJvb2xlYW4iLCJudW1iZXIiLCJmdW5jdGlvbiIsInN0cmluZyIsInN5bWJvbCJdLmZvckVhY2goZnVuY3Rpb24ocixlKXt1ZVtyXT1mdW5jdGlvbihzKXtyZXR1cm4gdHlwZW9mIHM9PT1yfHwiYSIrKGU8MT8ibiAiOiIgIikrcn19KTt2YXIgRmU9e307dWUudHJhbnNpdGlvbmFsPWZ1bmN0aW9uKGUsdCxzKXtmdW5jdGlvbiBuKG8saSl7cmV0dXJuIltBeGlvcyB2IitZdCsiXSBUcmFuc2l0aW9uYWwgb3B0aW9uICciK28rIiciK2krKHM/Ii4gIitzOiIiKX1yZXR1cm4gZnVuY3Rpb24obyxpLGEpe2lmKGU9PT0hMSl0aHJvdyBuZXcgRXJyb3IobihpLCIgaGFzIGJlZW4gcmVtb3ZlZCIrKHQ/IiBpbiAiK3Q6IiIpKSk7cmV0dXJuIHQmJiFGZVtpXSYmKEZlW2ldPSEwLGNvbnNvbGUud2FybihuKGksIiBoYXMgYmVlbiBkZXByZWNhdGVkIHNpbmNlIHYiK3QrIiBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZWFyIGZ1dHVyZSIpKSksZT9lKG8saSxhKTohMH19O2Z1bmN0aW9uIFp0KHIsZSx0KXtpZih0eXBlb2YgciE9Im9iamVjdCIpdGhyb3cgbmV3IFR5cGVFcnJvcigib3B0aW9ucyBtdXN0IGJlIGFuIG9iamVjdCIpO2Zvcih2YXIgcz1PYmplY3Qua2V5cyhyKSxuPXMubGVuZ3RoO24tLSA+MDspe3ZhciBvPXNbbl0saT1lW29dO2lmKGkpe3ZhciBhPXJbb10sbD1hPT09dm9pZCAwfHxpKGEsbyxyKTtpZihsIT09ITApdGhyb3cgbmV3IFR5cGVFcnJvcigib3B0aW9uICIrbysiIG11c3QgYmUgIitsKTtjb250aW51ZX1pZih0IT09ITApdGhyb3cgRXJyb3IoIlVua25vd24gb3B0aW9uICIrbyl9fXZhciBlcj17YXNzZXJ0T3B0aW9uczpadCx2YWxpZGF0b3JzOnVlfSxMZT1wLHRyPVNlLERlPV90LHFlPUt0LFY9VWUsSGU9ZXIsTz1IZS52YWxpZGF0b3JzO2Z1bmN0aW9uICQocil7dGhpcy5kZWZhdWx0cz1yLHRoaXMuaW50ZXJjZXB0b3JzPXtyZXF1ZXN0Om5ldyBEZSxyZXNwb25zZTpuZXcgRGV9fSQucHJvdG90eXBlLnJlcXVlc3Q9ZnVuY3Rpb24oZSx0KXtpZih0eXBlb2YgZT09InN0cmluZyI/KHQ9dHx8e30sdC51cmw9ZSk6dD1lfHx7fSwhdC51cmwpdGhyb3cgbmV3IEVycm9yKCJQcm92aWRlZCBjb25maWcgdXJsIGlzIG5vdCB2YWxpZCIpO3Q9Vih0aGlzLmRlZmF1bHRzLHQpLHQubWV0aG9kP3QubWV0aG9kPXQubWV0aG9kLnRvTG93ZXJDYXNlKCk6dGhpcy5kZWZhdWx0cy5tZXRob2Q/dC5tZXRob2Q9dGhpcy5kZWZhdWx0cy5tZXRob2QudG9Mb3dlckNhc2UoKTp0Lm1ldGhvZD0iZ2V0Ijt2YXIgcz10LnRyYW5zaXRpb25hbDtzIT09dm9pZCAwJiZIZS5hc3NlcnRPcHRpb25zKHMse3NpbGVudEpTT05QYXJzaW5nOk8udHJhbnNpdGlvbmFsKE8uYm9vbGVhbiksZm9yY2VkSlNPTlBhcnNpbmc6Ty50cmFuc2l0aW9uYWwoTy5ib29sZWFuKSxjbGFyaWZ5VGltZW91dEVycm9yOk8udHJhbnNpdGlvbmFsKE8uYm9vbGVhbil9LCExKTt2YXIgbj1bXSxvPSEwO3RoaXMuaW50ZXJjZXB0b3JzLnJlcXVlc3QuZm9yRWFjaChmdW5jdGlvbihnKXt0eXBlb2YgZy5ydW5XaGVuPT0iZnVuY3Rpb24iJiZnLnJ1bldoZW4odCk9PT0hMXx8KG89byYmZy5zeW5jaHJvbm91cyxuLnVuc2hpZnQoZy5mdWxmaWxsZWQsZy5yZWplY3RlZCkpfSk7dmFyIGk9W107dGhpcy5pbnRlcmNlcHRvcnMucmVzcG9uc2UuZm9yRWFjaChmdW5jdGlvbihnKXtpLnB1c2goZy5mdWxmaWxsZWQsZy5yZWplY3RlZCl9KTt2YXIgYTtpZighbyl7dmFyIGw9W3FlLHZvaWQgMF07Zm9yKEFycmF5LnByb3RvdHlwZS51bnNoaWZ0LmFwcGx5KGwsbiksbD1sLmNvbmNhdChpKSxhPVByb21pc2UucmVzb2x2ZSh0KTtsLmxlbmd0aDspYT1hLnRoZW4obC5zaGlmdCgpLGwuc2hpZnQoKSk7cmV0dXJuIGF9Zm9yKHZhciBtPXQ7bi5sZW5ndGg7KXt2YXIgdT1uLnNoaWZ0KCksZj1uLnNoaWZ0KCk7dHJ5e209dShtKX1jYXRjaChFKXtmKEUpO2JyZWFrfX10cnl7YT1xZShtKX1jYXRjaChFKXtyZXR1cm4gUHJvbWlzZS5yZWplY3QoRSl9Zm9yKDtpLmxlbmd0aDspYT1hLnRoZW4oaS5zaGlmdCgpLGkuc2hpZnQoKSk7cmV0dXJuIGF9LCQucHJvdG90eXBlLmdldFVyaT1mdW5jdGlvbihlKXtpZighZS51cmwpdGhyb3cgbmV3IEVycm9yKCJQcm92aWRlZCBjb25maWcgdXJsIGlzIG5vdCB2YWxpZCIpO3JldHVybiBlPVYodGhpcy5kZWZhdWx0cyxlKSx0cihlLnVybCxlLnBhcmFtcyxlLnBhcmFtc1NlcmlhbGl6ZXIpLnJlcGxhY2UoL15cPy8sIiIpfSxMZS5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsIm9wdGlvbnMiXSxmdW5jdGlvbihlKXskLnByb3RvdHlwZVtlXT1mdW5jdGlvbih0LHMpe3JldHVybiB0aGlzLnJlcXVlc3QoVihzfHx7fSx7bWV0aG9kOmUsdXJsOnQsZGF0YTooc3x8e30pLmRhdGF9KSl9fSksTGUuZm9yRWFjaChbInBvc3QiLCJwdXQiLCJwYXRjaCJdLGZ1bmN0aW9uKGUpeyQucHJvdG90eXBlW2VdPWZ1bmN0aW9uKHQscyxuKXtyZXR1cm4gdGhpcy5yZXF1ZXN0KFYobnx8e30se21ldGhvZDplLHVybDp0LGRhdGE6c30pKX19KTt2YXIgcnI9JCxzcj1xO2Z1bmN0aW9uIEkocil7aWYodHlwZW9mIHIhPSJmdW5jdGlvbiIpdGhyb3cgbmV3IFR5cGVFcnJvcigiZXhlY3V0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uLiIpO3ZhciBlO3RoaXMucHJvbWlzZT1uZXcgUHJvbWlzZShmdW5jdGlvbihuKXtlPW59KTt2YXIgdD10aGlzO3RoaXMucHJvbWlzZS50aGVuKGZ1bmN0aW9uKHMpe2lmKCEhdC5fbGlzdGVuZXJzKXt2YXIgbixvPXQuX2xpc3RlbmVycy5sZW5ndGg7Zm9yKG49MDtuPG87bisrKXQuX2xpc3RlbmVyc1tuXShzKTt0Ll9saXN0ZW5lcnM9bnVsbH19KSx0aGlzLnByb21pc2UudGhlbj1mdW5jdGlvbihzKXt2YXIgbixvPW5ldyBQcm9taXNlKGZ1bmN0aW9uKGkpe3Quc3Vic2NyaWJlKGkpLG49aX0pLnRoZW4ocyk7cmV0dXJuIG8uY2FuY2VsPWZ1bmN0aW9uKCl7dC51bnN1YnNjcmliZShuKX0sb30scihmdW5jdGlvbihuKXt0LnJlYXNvbnx8KHQucmVhc29uPW5ldyBzcihuKSxlKHQucmVhc29uKSl9KX1JLnByb3RvdHlwZS50aHJvd0lmUmVxdWVzdGVkPWZ1bmN0aW9uKCl7aWYodGhpcy5yZWFzb24pdGhyb3cgdGhpcy5yZWFzb259LEkucHJvdG90eXBlLnN1YnNjcmliZT1mdW5jdGlvbihlKXtpZih0aGlzLnJlYXNvbil7ZSh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaChlKTp0aGlzLl9saXN0ZW5lcnM9W2VdfSxJLnByb3RvdHlwZS51bnN1YnNjcmliZT1mdW5jdGlvbihlKXtpZighIXRoaXMuX2xpc3RlbmVycyl7dmFyIHQ9dGhpcy5fbGlzdGVuZXJzLmluZGV4T2YoZSk7dCE9PS0xJiZ0aGlzLl9saXN0ZW5lcnMuc3BsaWNlKHQsMSl9fSxJLnNvdXJjZT1mdW5jdGlvbigpe3ZhciBlLHQ9bmV3IEkoZnVuY3Rpb24obil7ZT1ufSk7cmV0dXJue3Rva2VuOnQsY2FuY2VsOmV9fTt2YXIgbnI9SSxpcj1mdW5jdGlvbihlKXtyZXR1cm4gZnVuY3Rpb24ocyl7cmV0dXJuIGUuYXBwbHkobnVsbCxzKX19LG9yPXAsYXI9ZnVuY3Rpb24oZSl7cmV0dXJuIG9yLmlzT2JqZWN0KGUpJiZlLmlzQXhpb3NFcnJvcj09PSEwfSxqZT1wLHVyPUVlLHo9cnIsbHI9VWUsY3I9SjtmdW5jdGlvbiBKZShyKXt2YXIgZT1uZXcgeihyKSx0PXVyKHoucHJvdG90eXBlLnJlcXVlc3QsZSk7cmV0dXJuIGplLmV4dGVuZCh0LHoucHJvdG90eXBlLGUpLGplLmV4dGVuZCh0LGUpLHQuY3JlYXRlPWZ1bmN0aW9uKG4pe3JldHVybiBKZShscihyLG4pKX0sdH12YXIgdz1KZShjcik7dy5BeGlvcz16LHcuQ2FuY2VsPXEsdy5DYW5jZWxUb2tlbj1ucix3LmlzQ2FuY2VsPU5lLHcuVkVSU0lPTj1CZS52ZXJzaW9uLHcuYWxsPWZ1bmN0aW9uKGUpe3JldHVybiBQcm9taXNlLmFsbChlKX0sdy5zcHJlYWQ9aXIsdy5pc0F4aW9zRXJyb3I9YXIsWS5leHBvcnRzPXcsWS5leHBvcnRzLmRlZmF1bHQ9dzt2YXIgZnI9WS5leHBvcnRzO2NsYXNzIGN7aXNFbXB0eSgpe3JldHVybiF0aGlzLmlzUHJlc2VudCgpfXN0YXRpYyBvZihlKXtpZihlIT1udWxsKXJldHVybiBuZXcgVmUoZSk7dGhyb3cgbmV3IFR5cGVFcnJvcigiVGhlIHBhc3NlZCB2YWx1ZSB3YXMgbnVsbCBvciB1bmRlZmluZWQuIil9c3RhdGljIG9mTm9uTnVsbChlKXtyZXR1cm4gYy5vZihlKX1zdGF0aWMgb2ZOdWxsYWJsZShlKXtyZXR1cm4gZSE9bnVsbD9uZXcgVmUoZSk6bmV3IHplfXN0YXRpYyBlbXB0eSgpe3JldHVybiBuZXcgemV9c3RhdGljIGZyb20oZSl7c3dpdGNoKGUua2luZCl7Y2FzZSJwcmVzZW50IjpyZXR1cm4gYy5vZihlLnZhbHVlKTtjYXNlImVtcHR5IjpyZXR1cm4gYy5lbXB0eSgpO2RlZmF1bHQ6dGhyb3cgbmV3IFR5cGVFcnJvcigiVGhlIHBhc3NlZCB2YWx1ZSB3YXMgbm90IGFuIE9wdGlvbiB0eXBlLiIpfX19Y2xhc3MgVmUgZXh0ZW5kcyBje2NvbnN0cnVjdG9yKGUpe3N1cGVyKCksdGhpcy5wYXlsb2FkPWV9aXNQcmVzZW50KCl7cmV0dXJuITB9Z2V0KCl7cmV0dXJuIHRoaXMucGF5bG9hZH1pZlByZXNlbnQoZSl7ZSh0aGlzLnBheWxvYWQpfWlmUHJlc2VudE9yRWxzZShlLHQpe2UodGhpcy5wYXlsb2FkKX1maWx0ZXIoZSl7cmV0dXJuIGUodGhpcy5wYXlsb2FkKT90aGlzOmMuZW1wdHkoKX1tYXAoZSl7Y29uc3QgdD1lKHRoaXMucGF5bG9hZCk7cmV0dXJuIGMub2ZOdWxsYWJsZSh0KX1mbGF0TWFwKGUpe3JldHVybiBlKHRoaXMucGF5bG9hZCl9b3IoZSl7cmV0dXJuIHRoaXN9b3JFbHNlKGUpe3JldHVybiB0aGlzLnBheWxvYWR9b3JFbHNlR2V0KGUpe3JldHVybiB0aGlzLnBheWxvYWR9b3JFbHNlVGhyb3coZSl7cmV0dXJuIHRoaXMucGF5bG9hZH1vck51bGwoKXtyZXR1cm4gdGhpcy5wYXlsb2FkfW9yVW5kZWZpbmVkKCl7cmV0dXJuIHRoaXMucGF5bG9hZH10b09wdGlvbigpe3JldHVybntraW5kOiJwcmVzZW50Iix2YWx1ZTp0aGlzLnBheWxvYWR9fW1hdGNoZXMoZSl7cmV0dXJuIGUucHJlc2VudCh0aGlzLnBheWxvYWQpfXRvSlNPTihlKXtyZXR1cm4gdGhpcy5wYXlsb2FkfX1jbGFzcyB6ZSBleHRlbmRzIGN7aXNQcmVzZW50KCl7cmV0dXJuITF9Y29uc3RydWN0b3IoKXtzdXBlcigpfWdldCgpe3Rocm93IG5ldyBUeXBlRXJyb3IoIlRoZSBvcHRpb25hbCBpcyBub3QgcHJlc2VudC4iKX1pZlByZXNlbnQoZSl7fWlmUHJlc2VudE9yRWxzZShlLHQpe3QoKX1maWx0ZXIoZSl7cmV0dXJuIHRoaXN9bWFwKGUpe3JldHVybiBjLmVtcHR5KCl9ZmxhdE1hcChlKXtyZXR1cm4gYy5lbXB0eSgpfW9yKGUpe3JldHVybiBlKCl9b3JFbHNlKGUpe3JldHVybiBlfW9yRWxzZUdldChlKXtyZXR1cm4gdGhpcy5vckVsc2UoZSgpKX1vckVsc2VUaHJvdyhlKXt0aHJvdyBlKCl9b3JOdWxsKCl7cmV0dXJuIG51bGx9b3JVbmRlZmluZWQoKXt9dG9PcHRpb24oKXtyZXR1cm57a2luZDoiZW1wdHkifX1tYXRjaGVzKGUpe3JldHVybiBlLmVtcHR5KCl9dG9KU09OKGUpe3JldHVybiBudWxsfX1jb25zdCBocj0iMS4yLjciO2Z1bmN0aW9uIGRyKHIpe2dsb2JhbFRoaXMuX3ZvbmFnZU1lZGlhUHJvY2Vzc29yTWV0YWRhdGE9cn1mdW5jdGlvbiBwcigpe3JldHVybiBnbG9iYWxUaGlzLl92b25hZ2VNZWRpYVByb2Nlc3Nvck1ldGFkYXRhfWNsYXNzIF97Y29uc3RydWN0b3IoKXtjb25zdCBlPXByKCk7dGhpcy5fcmVwb3J0PXthY3Rpb246Yy5lbXB0eSgpLGFwcGxpY2F0aW9uSWQ6Yy5vZk51bGxhYmxlKGUhPT12b2lkIDAmJmUhPW51bGw/ZS5hcHBJZDpudWxsKSx0aW1lc3RhbXA6RGF0ZS5ub3coKSxmcHM6Yy5lbXB0eSgpLGZyYW1lc1RyYW5zZm9ybWVkOmMuZW1wdHkoKSxndWlkOmMuZW1wdHkoKSxoaWdoZXN0RnJhbWVUcmFuc2Zvcm1DcHU6Yy5lbXB0eSgpLG1lc3NhZ2U6Yy5lbXB0eSgpLHNvdXJjZTpjLm9mTnVsbGFibGUoZSE9PXZvaWQgMCYmZSE9bnVsbD9lLnNvdXJjZVR5cGU6bnVsbCksdHJhbnNmb3JtZWRGcHM6Yy5lbXB0eSgpLHRyYW5zZm9ybWVyVHlwZTpjLmVtcHR5KCksdmFyaWF0aW9uOmMuZW1wdHkoKSx2aWRlb0hlaWdodDpjLmVtcHR5KCksdmlkZW9XaWR0aDpjLmVtcHR5KCksdmVyc2lvbjpocixlcnJvcjpjLmVtcHR5KCkscHJveHlVcmw6Yy5vZk51bGxhYmxlKGUhPT12b2lkIDAmJmUhPW51bGw/ZS5wcm94eVVybDpudWxsKX19YWN0aW9uKGUpe3JldHVybiB0aGlzLl9yZXBvcnQuYWN0aW9uPWMub2ZOdWxsYWJsZShlKSx0aGlzfWZyYW1lc1RyYW5zZm9ybWVkKGUpe3JldHVybiB0aGlzLl9yZXBvcnQuZnJhbWVzVHJhbnNmb3JtZWQ9Yy5vZk51bGxhYmxlKGUpLHRoaXN9ZnBzKGUpe3JldHVybiB0aGlzLl9yZXBvcnQuZnBzPWMub2ZOdWxsYWJsZShlKSx0aGlzfWd1aWQoZSl7cmV0dXJuIHRoaXMuX3JlcG9ydC5ndWlkPWMub2ZOdWxsYWJsZShlKSx0aGlzfW1lc3NhZ2UoZSl7cmV0dXJuIHRoaXMuX3JlcG9ydC5tZXNzYWdlPWMub2ZOdWxsYWJsZShlKSx0aGlzfXRyYW5zZm9ybWVkRnBzKGUpe3JldHVybiB0aGlzLl9yZXBvcnQudHJhbnNmb3JtZWRGcHM9Yy5vZk51bGxhYmxlKGUpLHRoaXN9dHJhbnNmb3JtZXJUeXBlKGUpe3JldHVybiB0aGlzLl9yZXBvcnQudHJhbnNmb3JtZXJUeXBlPWMub2ZOdWxsYWJsZShlKSx0aGlzfXZhcmlhdGlvbihlKXtyZXR1cm4gdGhpcy5fcmVwb3J0LnZhcmlhdGlvbj1jLm9mTnVsbGFibGUoZSksdGhpc312aWRlb0hlaWdodChlKXtyZXR1cm4gdGhpcy5fcmVwb3J0LnZpZGVvSGVpZ2h0PWMub2ZOdWxsYWJsZShlKSx0aGlzfXZpZGVvV2lkdGgoZSl7cmV0dXJuIHRoaXMuX3JlcG9ydC52aWRlb1dpZHRoPWMub2ZOdWxsYWJsZShlKSx0aGlzfWVycm9yKGUpe3JldHVybiB0aGlzLl9yZXBvcnQuZXJyb3I9Yy5vZk51bGxhYmxlKGUpLHRoaXN9YnVpbGQoKXtyZXR1cm4gdGhpcy5fcmVwb3J0fX1jb25zdCBtcj1yPT5KU09OLnN0cmluZ2lmeShyLChlLHQpPT57aWYodCE9PW51bGwpcmV0dXJuIHR9KTtjbGFzcyB2e3N0YXRpYyByZXBvcnQoZSl7cmV0dXJuIG5ldyBQcm9taXNlKCh0LHMpPT57aWYoZS5hcHBsaWNhdGlvbklkLmlzRW1wdHkoKXx8ZS5zb3VyY2UuaXNFbXB0eSgpKXt0KCJzdWNjZXNzIik7cmV0dXJufWxldCBuPWZyLmNyZWF0ZSgpLG89e3RpbWVvdXQ6MWU0LHRpbWVvdXRFcnJvck1lc3NhZ2U6IlJlcXVlc3QgdGltZW91dCIsaGVhZGVyczp7IkNvbnRlbnQtVHlwZSI6ImFwcGxpY2F0aW9uL2pzb24ifX0saT0iaGxnLnRva2JveC5jb20vcHJvZC9sb2dnaW5nL3ZjcF93ZWJydGMiO2lmKGUucHJveHlVcmwuaXNFbXB0eSgpKWk9Imh0dHBzOi8vIitpO2Vsc2V7bGV0IGE7ZS5wcm94eVVybC5nZXQoKS5zbGljZShlLnByb3h5VXJsLmdldCgpLmxlbmd0aC0xKSE9PSIvIj9hPWUucHJveHlVcmwuZ2V0KCkrIi8iOmE9ZS5wcm94eVVybC5nZXQoKSxpPWEraX1uLnBvc3QoaSxtcihlKSxvKS50aGVuKGE9Pntjb25zb2xlLmxvZyhhKSx0KCJzdWNjZXNzIil9KS5jYXRjaChhPT57Y29uc29sZS5sb2coYSkscyhhKX0pfSl9fXZhciBXLGdyPW5ldyBVaW50OEFycmF5KDE2KTtmdW5jdGlvbiB5cigpe2lmKCFXJiYoVz10eXBlb2YgY3J5cHRvIT0idW5kZWZpbmVkIiYmY3J5cHRvLmdldFJhbmRvbVZhbHVlcyYmY3J5cHRvLmdldFJhbmRvbVZhbHVlcy5iaW5kKGNyeXB0byl8fHR5cGVvZiBtc0NyeXB0byE9InVuZGVmaW5lZCImJnR5cGVvZiBtc0NyeXB0by5nZXRSYW5kb21WYWx1ZXM9PSJmdW5jdGlvbiImJm1zQ3J5cHRvLmdldFJhbmRvbVZhbHVlcy5iaW5kKG1zQ3J5cHRvKSwhVykpdGhyb3cgbmV3IEVycm9yKCJjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKCkgbm90IHN1cHBvcnRlZC4gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS91dWlkanMvdXVpZCNnZXRyYW5kb212YWx1ZXMtbm90LXN1cHBvcnRlZCIpO3JldHVybiBXKGdyKX12YXIgX3I9L14oPzpbMC05YS1mXXs4fS1bMC05YS1mXXs0fS1bMS01XVswLTlhLWZdezN9LVs4OWFiXVswLTlhLWZdezN9LVswLTlhLWZdezEyfXwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDApJC9pO2Z1bmN0aW9uIHZyKHIpe3JldHVybiB0eXBlb2Ygcj09InN0cmluZyImJl9yLnRlc3Qocil9Zm9yKHZhciBkPVtdLGxlPTA7bGU8MjU2OysrbGUpZC5wdXNoKChsZSsyNTYpLnRvU3RyaW5nKDE2KS5zdWJzdHIoMSkpO2Z1bmN0aW9uIGJyKHIpe3ZhciBlPWFyZ3VtZW50cy5sZW5ndGg+MSYmYXJndW1lbnRzWzFdIT09dm9pZCAwP2FyZ3VtZW50c1sxXTowLHQ9KGRbcltlKzBdXStkW3JbZSsxXV0rZFtyW2UrMl1dK2RbcltlKzNdXSsiLSIrZFtyW2UrNF1dK2RbcltlKzVdXSsiLSIrZFtyW2UrNl1dK2RbcltlKzddXSsiLSIrZFtyW2UrOF1dK2RbcltlKzldXSsiLSIrZFtyW2UrMTBdXStkW3JbZSsxMV1dK2RbcltlKzEyXV0rZFtyW2UrMTNdXStkW3JbZSsxNF1dK2RbcltlKzE1XV0pLnRvTG93ZXJDYXNlKCk7aWYoIXZyKHQpKXRocm93IFR5cGVFcnJvcigiU3RyaW5naWZpZWQgVVVJRCBpcyBpbnZhbGlkIik7cmV0dXJuIHR9ZnVuY3Rpb24gV2UocixlLHQpe3I9cnx8e307dmFyIHM9ci5yYW5kb218fChyLnJuZ3x8eXIpKCk7aWYoc1s2XT1zWzZdJjE1fDY0LHNbOF09c1s4XSY2M3wxMjgsZSl7dD10fHwwO2Zvcih2YXIgbj0wO248MTY7KytuKWVbdCtuXT1zW25dO3JldHVybiBlfXJldHVybiBicihzKX1jb25zdCBQPW5ldyBXZWFrTWFwLEc9bmV3IFdlYWtNYXAsVT1uZXcgV2Vha01hcCxjZT1TeW1ib2woImFueVByb2R1Y2VyIiksR2U9UHJvbWlzZS5yZXNvbHZlKCksUT1TeW1ib2woImxpc3RlbmVyQWRkZWQiKSxYPVN5bWJvbCgibGlzdGVuZXJSZW1vdmVkIik7bGV0IGZlPSExO2Z1bmN0aW9uIE0ocil7aWYodHlwZW9mIHIhPSJzdHJpbmciJiZ0eXBlb2YgciE9InN5bWJvbCIpdGhyb3cgbmV3IFR5cGVFcnJvcigiZXZlbnROYW1lIG11c3QgYmUgYSBzdHJpbmcgb3IgYSBzeW1ib2wiKX1mdW5jdGlvbiBLKHIpe2lmKHR5cGVvZiByIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImxpc3RlbmVyIG11c3QgYmUgYSBmdW5jdGlvbiIpfWZ1bmN0aW9uIGsocixlKXtjb25zdCB0PUcuZ2V0KHIpO3JldHVybiB0LmhhcyhlKXx8dC5zZXQoZSxuZXcgU2V0KSx0LmdldChlKX1mdW5jdGlvbiBCKHIsZSl7Y29uc3QgdD10eXBlb2YgZT09InN0cmluZyJ8fHR5cGVvZiBlPT0ic3ltYm9sIj9lOmNlLHM9VS5nZXQocik7cmV0dXJuIHMuaGFzKHQpfHxzLnNldCh0LG5ldyBTZXQpLHMuZ2V0KHQpfWZ1bmN0aW9uIHdyKHIsZSx0KXtjb25zdCBzPVUuZ2V0KHIpO2lmKHMuaGFzKGUpKWZvcihjb25zdCBuIG9mIHMuZ2V0KGUpKW4uZW5xdWV1ZSh0KTtpZihzLmhhcyhjZSkpe2NvbnN0IG49UHJvbWlzZS5hbGwoW2UsdF0pO2Zvcihjb25zdCBvIG9mIHMuZ2V0KGNlKSlvLmVucXVldWUobil9fWZ1bmN0aW9uIFFlKHIsZSl7ZT1BcnJheS5pc0FycmF5KGUpP2U6W2VdO2xldCB0PSExLHM9KCk9Pnt9LG49W107Y29uc3Qgbz17ZW5xdWV1ZShpKXtuLnB1c2goaSkscygpfSxmaW5pc2goKXt0PSEwLHMoKX19O2Zvcihjb25zdCBpIG9mIGUpQihyLGkpLmFkZChvKTtyZXR1cm57YXN5bmMgbmV4dCgpe3JldHVybiBuP24ubGVuZ3RoPT09MD90PyhuPXZvaWQgMCx0aGlzLm5leHQoKSk6KGF3YWl0IG5ldyBQcm9taXNlKGk9PntzPWl9KSx0aGlzLm5leHQoKSk6e2RvbmU6ITEsdmFsdWU6YXdhaXQgbi5zaGlmdCgpfTp7ZG9uZTohMH19LGFzeW5jIHJldHVybihpKXtuPXZvaWQgMDtmb3IoY29uc3QgYSBvZiBlKUIocixhKS5kZWxldGUobyk7cmV0dXJuIHMoKSxhcmd1bWVudHMubGVuZ3RoPjA/e2RvbmU6ITAsdmFsdWU6YXdhaXQgaX06e2RvbmU6ITB9fSxbU3ltYm9sLmFzeW5jSXRlcmF0b3JdKCl7cmV0dXJuIHRoaXN9fX1mdW5jdGlvbiBYZShyKXtpZihyPT09dm9pZCAwKXJldHVybiBLZTtpZighQXJyYXkuaXNBcnJheShyKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJgbWV0aG9kTmFtZXNgIG11c3QgYmUgYW4gYXJyYXkgb2Ygc3RyaW5ncyIpO2Zvcihjb25zdCBlIG9mIHIpaWYoIUtlLmluY2x1ZGVzKGUpKXRocm93IHR5cGVvZiBlIT0ic3RyaW5nIj9uZXcgVHlwZUVycm9yKCJgbWV0aG9kTmFtZXNgIGVsZW1lbnQgbXVzdCBiZSBhIHN0cmluZyIpOm5ldyBFcnJvcihgJHtlfSBpcyBub3QgRW1pdHRlcnkgbWV0aG9kYCk7cmV0dXJuIHJ9Y29uc3QgaGU9cj0+cj09PVF8fHI9PT1YO2NsYXNzIEN7c3RhdGljIG1peGluKGUsdCl7cmV0dXJuIHQ9WGUodCkscz0+e2lmKHR5cGVvZiBzIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImB0YXJnZXRgIG11c3QgYmUgZnVuY3Rpb24iKTtmb3IoY29uc3QgaSBvZiB0KWlmKHMucHJvdG90eXBlW2ldIT09dm9pZCAwKXRocm93IG5ldyBFcnJvcihgVGhlIHByb3BlcnR5IFxgJHtpfVxgIGFscmVhZHkgZXhpc3RzIG9uIFxgdGFyZ2V0XGBgKTtmdW5jdGlvbiBuKCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLGUse2VudW1lcmFibGU6ITEsdmFsdWU6bmV3IEN9KSx0aGlzW2VdfU9iamVjdC5kZWZpbmVQcm9wZXJ0eShzLnByb3RvdHlwZSxlLHtlbnVtZXJhYmxlOiExLGdldDpufSk7Y29uc3Qgbz1pPT5mdW5jdGlvbiguLi5hKXtyZXR1cm4gdGhpc1tlXVtpXSguLi5hKX07Zm9yKGNvbnN0IGkgb2YgdClPYmplY3QuZGVmaW5lUHJvcGVydHkocy5wcm90b3R5cGUsaSx7ZW51bWVyYWJsZTohMSx2YWx1ZTpvKGkpfSk7cmV0dXJuIHN9fXN0YXRpYyBnZXQgaXNEZWJ1Z0VuYWJsZWQoKXtpZih0eXBlb2YgcHJvY2VzcyE9Im9iamVjdCIpcmV0dXJuIGZlO2NvbnN0e2VudjplfT1wcm9jZXNzfHx7ZW52Ont9fTtyZXR1cm4gZS5ERUJVRz09PSJlbWl0dGVyeSJ8fGUuREVCVUc9PT0iKiJ8fGZlfXN0YXRpYyBzZXQgaXNEZWJ1Z0VuYWJsZWQoZSl7ZmU9ZX1jb25zdHJ1Y3RvcihlPXt9KXtQLnNldCh0aGlzLG5ldyBTZXQpLEcuc2V0KHRoaXMsbmV3IE1hcCksVS5zZXQodGhpcyxuZXcgTWFwKSx0aGlzLmRlYnVnPWUuZGVidWd8fHt9LHRoaXMuZGVidWcuZW5hYmxlZD09PXZvaWQgMCYmKHRoaXMuZGVidWcuZW5hYmxlZD0hMSksdGhpcy5kZWJ1Zy5sb2dnZXJ8fCh0aGlzLmRlYnVnLmxvZ2dlcj0odCxzLG4sbyk9PntvPUpTT04uc3RyaW5naWZ5KG8pLHR5cGVvZiBuPT0ic3ltYm9sIiYmKG49bi50b1N0cmluZygpKTtjb25zdCBpPW5ldyBEYXRlLGE9YCR7aS5nZXRIb3VycygpfToke2kuZ2V0TWludXRlcygpfToke2kuZ2V0U2Vjb25kcygpfS4ke2kuZ2V0TWlsbGlzZWNvbmRzKCl9YDtjb25zb2xlLmxvZyhgWyR7YX1dW2VtaXR0ZXJ5OiR7dH1dWyR7c31dIEV2ZW50IE5hbWU6ICR7bn0KCWRhdGE6ICR7b31gKX0pfWxvZ0lmRGVidWdFbmFibGVkKGUsdCxzKXsoQy5pc0RlYnVnRW5hYmxlZHx8dGhpcy5kZWJ1Zy5lbmFibGVkKSYmdGhpcy5kZWJ1Zy5sb2dnZXIoZSx0aGlzLmRlYnVnLm5hbWUsdCxzKX1vbihlLHQpe0sodCksZT1BcnJheS5pc0FycmF5KGUpP2U6W2VdO2Zvcihjb25zdCBzIG9mIGUpTShzKSxrKHRoaXMscykuYWRkKHQpLHRoaXMubG9nSWZEZWJ1Z0VuYWJsZWQoInN1YnNjcmliZSIscyx2b2lkIDApLGhlKHMpfHx0aGlzLmVtaXQoUSx7ZXZlbnROYW1lOnMsbGlzdGVuZXI6dH0pO3JldHVybiB0aGlzLm9mZi5iaW5kKHRoaXMsZSx0KX1vZmYoZSx0KXtLKHQpLGU9QXJyYXkuaXNBcnJheShlKT9lOltlXTtmb3IoY29uc3QgcyBvZiBlKU0ocyksayh0aGlzLHMpLmRlbGV0ZSh0KSx0aGlzLmxvZ0lmRGVidWdFbmFibGVkKCJ1bnN1YnNjcmliZSIscyx2b2lkIDApLGhlKHMpfHx0aGlzLmVtaXQoWCx7ZXZlbnROYW1lOnMsbGlzdGVuZXI6dH0pfW9uY2UoZSl7cmV0dXJuIG5ldyBQcm9taXNlKHQ9Pntjb25zdCBzPXRoaXMub24oZSxuPT57cygpLHQobil9KX0pfWV2ZW50cyhlKXtlPUFycmF5LmlzQXJyYXkoZSk/ZTpbZV07Zm9yKGNvbnN0IHQgb2YgZSlNKHQpO3JldHVybiBRZSh0aGlzLGUpfWFzeW5jIGVtaXQoZSx0KXtNKGUpLHRoaXMubG9nSWZEZWJ1Z0VuYWJsZWQoImVtaXQiLGUsdCksd3IodGhpcyxlLHQpO2NvbnN0IHM9ayh0aGlzLGUpLG49UC5nZXQodGhpcyksbz1bLi4uc10saT1oZShlKT9bXTpbLi4ubl07YXdhaXQgR2UsYXdhaXQgUHJvbWlzZS5hbGwoWy4uLm8ubWFwKGFzeW5jIGE9PntpZihzLmhhcyhhKSlyZXR1cm4gYSh0KX0pLC4uLmkubWFwKGFzeW5jIGE9PntpZihuLmhhcyhhKSlyZXR1cm4gYShlLHQpfSldKX1hc3luYyBlbWl0U2VyaWFsKGUsdCl7TShlKSx0aGlzLmxvZ0lmRGVidWdFbmFibGVkKCJlbWl0U2VyaWFsIixlLHQpO2NvbnN0IHM9ayh0aGlzLGUpLG49UC5nZXQodGhpcyksbz1bLi4uc10saT1bLi4ubl07YXdhaXQgR2U7Zm9yKGNvbnN0IGEgb2YgbylzLmhhcyhhKSYmYXdhaXQgYSh0KTtmb3IoY29uc3QgYSBvZiBpKW4uaGFzKGEpJiZhd2FpdCBhKGUsdCl9b25BbnkoZSl7cmV0dXJuIEsoZSksdGhpcy5sb2dJZkRlYnVnRW5hYmxlZCgic3Vic2NyaWJlQW55Iix2b2lkIDAsdm9pZCAwKSxQLmdldCh0aGlzKS5hZGQoZSksdGhpcy5lbWl0KFEse2xpc3RlbmVyOmV9KSx0aGlzLm9mZkFueS5iaW5kKHRoaXMsZSl9YW55RXZlbnQoKXtyZXR1cm4gUWUodGhpcyl9b2ZmQW55KGUpe0soZSksdGhpcy5sb2dJZkRlYnVnRW5hYmxlZCgidW5zdWJzY3JpYmVBbnkiLHZvaWQgMCx2b2lkIDApLHRoaXMuZW1pdChYLHtsaXN0ZW5lcjplfSksUC5nZXQodGhpcykuZGVsZXRlKGUpfWNsZWFyTGlzdGVuZXJzKGUpe2U9QXJyYXkuaXNBcnJheShlKT9lOltlXTtmb3IoY29uc3QgdCBvZiBlKWlmKHRoaXMubG9nSWZEZWJ1Z0VuYWJsZWQoImNsZWFyIix0LHZvaWQgMCksdHlwZW9mIHQ9PSJzdHJpbmcifHx0eXBlb2YgdD09InN5bWJvbCIpe2sodGhpcyx0KS5jbGVhcigpO2NvbnN0IHM9Qih0aGlzLHQpO2Zvcihjb25zdCBuIG9mIHMpbi5maW5pc2goKTtzLmNsZWFyKCl9ZWxzZXtQLmdldCh0aGlzKS5jbGVhcigpO2Zvcihjb25zdCBzIG9mIEcuZ2V0KHRoaXMpLnZhbHVlcygpKXMuY2xlYXIoKTtmb3IoY29uc3QgcyBvZiBVLmdldCh0aGlzKS52YWx1ZXMoKSl7Zm9yKGNvbnN0IG4gb2YgcyluLmZpbmlzaCgpO3MuY2xlYXIoKX19fWxpc3RlbmVyQ291bnQoZSl7ZT1BcnJheS5pc0FycmF5KGUpP2U6W2VdO2xldCB0PTA7Zm9yKGNvbnN0IHMgb2YgZSl7aWYodHlwZW9mIHM9PSJzdHJpbmciKXt0Kz1QLmdldCh0aGlzKS5zaXplK2sodGhpcyxzKS5zaXplK0IodGhpcyxzKS5zaXplK0IodGhpcykuc2l6ZTtjb250aW51ZX10eXBlb2YgcyE9InVuZGVmaW5lZCImJk0ocyksdCs9UC5nZXQodGhpcykuc2l6ZTtmb3IoY29uc3QgbiBvZiBHLmdldCh0aGlzKS52YWx1ZXMoKSl0Kz1uLnNpemU7Zm9yKGNvbnN0IG4gb2YgVS5nZXQodGhpcykudmFsdWVzKCkpdCs9bi5zaXplfXJldHVybiB0fWJpbmRNZXRob2RzKGUsdCl7aWYodHlwZW9mIGUhPSJvYmplY3QifHxlPT09bnVsbCl0aHJvdyBuZXcgVHlwZUVycm9yKCJgdGFyZ2V0YCBtdXN0IGJlIGFuIG9iamVjdCIpO3Q9WGUodCk7Zm9yKGNvbnN0IHMgb2YgdCl7aWYoZVtzXSE9PXZvaWQgMCl0aHJvdyBuZXcgRXJyb3IoYFRoZSBwcm9wZXJ0eSBcYCR7c31cYCBhbHJlYWR5IGV4aXN0cyBvbiBcYHRhcmdldFxgYCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KGUscyx7ZW51bWVyYWJsZTohMSx2YWx1ZTp0aGlzW3NdLmJpbmQodGhpcyl9KX19fWNvbnN0IEtlPU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKEMucHJvdG90eXBlKS5maWx0ZXIocj0+ciE9PSJjb25zdHJ1Y3RvciIpO09iamVjdC5kZWZpbmVQcm9wZXJ0eShDLCJsaXN0ZW5lckFkZGVkIix7dmFsdWU6USx3cml0YWJsZTohMSxlbnVtZXJhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShDLCJsaXN0ZW5lclJlbW92ZWQiLHt2YWx1ZTpYLHdyaXRhYmxlOiExLGVudW1lcmFibGU6ITAsY29uZmlndXJhYmxlOiExfSk7dmFyIGRlPUM7ZnVuY3Rpb24gRXIocil7cmV0dXJuIHR5cGVvZiByPT0ib2JqZWN0IiYmciE9PW51bGwmJiJtZXNzYWdlImluIHImJnR5cGVvZiByLm1lc3NhZ2U9PSJzdHJpbmcifWZ1bmN0aW9uIFRyKHIpe2lmKEVyKHIpKXJldHVybiByO3RyeXtyZXR1cm4gbmV3IEVycm9yKEpTT04uc3RyaW5naWZ5KHIpKX1jYXRjaHtyZXR1cm4gbmV3IEVycm9yKFN0cmluZyhyKSl9fWZ1bmN0aW9uIHBlKHIpe3JldHVybiBUcihyKS5tZXNzYWdlfXZhciBtZTsoZnVuY3Rpb24ocil7ci5GUFNfRFJPUD0iZnBzX2Ryb3AifSkobWV8fChtZT17fSkpO2NvbnN0IFJyPTUwMCxQcj0uODtjbGFzcyBDciBleHRlbmRzIGRle2NvbnN0cnVjdG9yKGUsdCl7c3VwZXIoKSx0aGlzLmluZGV4Xz10LHRoaXMudXVpZF89V2UoKSx0aGlzLmZyYW1lc1RyYW5zZm9ybWVkXz0wLHRoaXMudHJhbnNmb3JtZXJfPWUsdGhpcy5zaG91bGRTdG9wXz0hMSx0aGlzLmlzRmxhc2hlZF89ITEsdGhpcy5mcmFtZXNGcm9tU291cmNlXz0wLHRoaXMuZnBzXz0wLHRoaXMubWVkaWFUcmFuc2Zvcm1lclFvc1JlcG9ydFN0YXJ0VGltZXN0YW1wXz0wLHRoaXMudmlkZW9IZWlnaHRfPTAsdGhpcy52aWRlb1dpZHRoXz0wLHRoaXMudHJhY2tFeHBlY3RlZFJhdGVfPS0xLHRoaXMudHJhbnNmb3JtZXJUeXBlXz0iQ3VzdG9tIiwiZ2V0VHJhbnNmb3JtZXJUeXBlImluIGUmJih0aGlzLnRyYW5zZm9ybWVyVHlwZV89ZS5nZXRUcmFuc2Zvcm1lclR5cGUoKSk7Y29uc3Qgcz1uZXcgXygpLmFjdGlvbigiTWVkaWFUcmFuc2Zvcm1lciIpLmd1aWQodGhpcy51dWlkXykudHJhbnNmb3JtZXJUeXBlKHRoaXMudHJhbnNmb3JtZXJUeXBlXykudmFyaWF0aW9uKCJDcmVhdGUiKS5idWlsZCgpO3YucmVwb3J0KHMpfXNldFRyYWNrRXhwZWN0ZWRSYXRlKGUpe3RoaXMudHJhY2tFeHBlY3RlZFJhdGVfPWV9YXN5bmMgc3RhcnQoZSl7aWYodGhpcy5jb250cm9sbGVyXz1lLHRoaXMudHJhbnNmb3JtZXJfJiZ0eXBlb2YgdGhpcy50cmFuc2Zvcm1lcl8uc3RhcnQ9PSJmdW5jdGlvbiIpdHJ5e2F3YWl0IHRoaXMudHJhbnNmb3JtZXJfLnN0YXJ0KGUpfWNhdGNoKHQpe2NvbnN0IHM9bmV3IF8oKS5hY3Rpb24oIk1lZGlhVHJhbnNmb3JtZXIiKS5ndWlkKHRoaXMudXVpZF8pLm1lc3NhZ2UoVC5lcnJvcnMudHJhbnNmb3JtZXJfc3RhcnQpLnRyYW5zZm9ybWVyVHlwZSh0aGlzLnRyYW5zZm9ybWVyVHlwZV8pLnZhcmlhdGlvbigiRXJyb3IiKS5lcnJvcihwZSh0KSkuYnVpbGQoKTt2LnJlcG9ydChzKTtjb25zdCBuPXtldmVudE1ldGFEYXRhOnt0cmFuc2Zvcm1lckluZGV4OnRoaXMuaW5kZXhffSxlcnJvcjp0LGZ1bmN0aW9uOiJzdGFydCJ9O3RoaXMuZW1pdCgiZXJyb3IiLG4pfX1hc3luYyB0cmFuc2Zvcm0oZSx0KXt2YXIgcyxuLG8saTtpZih0aGlzLm1lZGlhVHJhbnNmb3JtZXJRb3NSZXBvcnRTdGFydFRpbWVzdGFtcF89PT0wJiYodGhpcy5tZWRpYVRyYW5zZm9ybWVyUW9zUmVwb3J0U3RhcnRUaW1lc3RhbXBfPURhdGUubm93KCkpLGUgaW5zdGFuY2VvZiBWaWRlb0ZyYW1lJiYodGhpcy52aWRlb0hlaWdodF89KHM9ZT09bnVsbD92b2lkIDA6ZS5kaXNwbGF5SGVpZ2h0KSE9bnVsbD9zOjAsdGhpcy52aWRlb1dpZHRoXz0obj1lPT1udWxsP3ZvaWQgMDplLmRpc3BsYXlXaWR0aCkhPW51bGw/bjowKSwrK3RoaXMuZnJhbWVzRnJvbVNvdXJjZV8sdGhpcy50cmFuc2Zvcm1lcl8paWYodGhpcy5zaG91bGRTdG9wXyljb25zb2xlLndhcm4oIltQaXBlbGluZV0gZmx1c2ggZnJvbSB0cmFuc2Zvcm0iKSxlLmNsb3NlKCksdGhpcy5mbHVzaCh0KSx0LnRlcm1pbmF0ZSgpO2Vsc2UgdHJ5e2F3YWl0KChpPShvPXRoaXMudHJhbnNmb3JtZXJfKS50cmFuc2Zvcm0pPT1udWxsP3ZvaWQgMDppLmNhbGwobyxlLHQpKSwrK3RoaXMuZnJhbWVzVHJhbnNmb3JtZWRfLHRoaXMuZnJhbWVzVHJhbnNmb3JtZWRfPT09UnImJnRoaXMubWVkaWFUcmFuc2Zvcm1lclFvc1JlcG9ydCgpfWNhdGNoKGEpe2NvbnN0IGw9bmV3IF8oKS5hY3Rpb24oIk1lZGlhVHJhbnNmb3JtZXIiKS5ndWlkKHRoaXMudXVpZF8pLm1lc3NhZ2UoVC5lcnJvcnMudHJhbnNmb3JtZXJfdHJhbnNmb3JtKS50cmFuc2Zvcm1lclR5cGUodGhpcy50cmFuc2Zvcm1lclR5cGVfKS52YXJpYXRpb24oIkVycm9yIikuZXJyb3IocGUoYSkpLmJ1aWxkKCk7di5yZXBvcnQobCk7Y29uc3QgbT17ZXZlbnRNZXRhRGF0YTp7dHJhbnNmb3JtZXJJbmRleDp0aGlzLmluZGV4X30sZXJyb3I6YSxmdW5jdGlvbjoidHJhbnNmb3JtIn07dGhpcy5lbWl0KCJlcnJvciIsbSl9fWFzeW5jIGZsdXNoKGUpe2lmKHRoaXMudHJhbnNmb3JtZXJfJiZ0eXBlb2YgdGhpcy50cmFuc2Zvcm1lcl8uZmx1c2g9PSJmdW5jdGlvbiImJiF0aGlzLmlzRmxhc2hlZF8pe3RoaXMuaXNGbGFzaGVkXz0hMDt0cnl7YXdhaXQgdGhpcy50cmFuc2Zvcm1lcl8uZmx1c2goZSl9Y2F0Y2gocyl7Y29uc3Qgbj1uZXcgXygpLmFjdGlvbigiTWVkaWFUcmFuc2Zvcm1lciIpLmd1aWQodGhpcy51dWlkXykubWVzc2FnZShULmVycm9ycy50cmFuc2Zvcm1lcl9mbHVzaCkudHJhbnNmb3JtZXJUeXBlKHRoaXMudHJhbnNmb3JtZXJUeXBlXykudmFyaWF0aW9uKCJFcnJvciIpLmVycm9yKHBlKHMpKS5idWlsZCgpO3YucmVwb3J0KG4pO2NvbnN0IG89e2V2ZW50TWV0YURhdGE6e3RyYW5zZm9ybWVySW5kZXg6dGhpcy5pbmRleF99LGVycm9yOnMsZnVuY3Rpb246ImZsdXNoIn07dGhpcy5lbWl0KCJlcnJvciIsbyl9fXRoaXMubWVkaWFUcmFuc2Zvcm1lclFvc1JlcG9ydCgpO2NvbnN0IHQ9bmV3IF8oKS5hY3Rpb24oIk1lZGlhVHJhbnNmb3JtZXIiKS5ndWlkKHRoaXMudXVpZF8pLnRyYW5zZm9ybWVyVHlwZSh0aGlzLnRyYW5zZm9ybWVyVHlwZV8pLnZhcmlhdGlvbigiRGVsZXRlIikuYnVpbGQoKTt2LnJlcG9ydCh0KX1zdG9wKCl7Y29uc29sZS5sb2coIltQaXBlbGluZV0gU3RvcCBzdHJlYW0uIiksdGhpcy5jb250cm9sbGVyXyYmKHRoaXMuZmx1c2godGhpcy5jb250cm9sbGVyXyksdGhpcy5jb250cm9sbGVyXy50ZXJtaW5hdGUoKSksdGhpcy5zaG91bGRTdG9wXz0hMH1tZWRpYVRyYW5zZm9ybWVyUW9zUmVwb3J0KCl7bGV0IGU9KERhdGUubm93KCktdGhpcy5tZWRpYVRyYW5zZm9ybWVyUW9zUmVwb3J0U3RhcnRUaW1lc3RhbXBfKS8xZTMsdD10aGlzLmZyYW1lc0Zyb21Tb3VyY2VfL2Uscz10aGlzLmZyYW1lc1RyYW5zZm9ybWVkXy9lO2lmKHRoaXMudHJhY2tFeHBlY3RlZFJhdGVfIT0tMSYmdGhpcy50cmFja0V4cGVjdGVkUmF0ZV8qUHI+dCl7Y29uc3Qgbz17ZXZlbnRNZXRhRGF0YTp7dHJhbnNmb3JtZXJJbmRleDp0aGlzLmluZGV4X30sd2FybmluZ1R5cGU6bWUuRlBTX0RST1AsZHJvcEluZm86e3JlcXVlc3RlZDp0aGlzLnRyYWNrRXhwZWN0ZWRSYXRlXyxjdXJyZW50OnR9fTt0aGlzLmVtaXQoIndhcm4iLG8pfWNvbnN0IG49bmV3IF8oKS5hY3Rpb24oIk1lZGlhVHJhbnNmb3JtZXIiKS5mcHModCkudHJhbnNmb3JtZWRGcHMocykuZnJhbWVzVHJhbnNmb3JtZWQodGhpcy5mcmFtZXNUcmFuc2Zvcm1lZF8pLmd1aWQodGhpcy51dWlkXykudHJhbnNmb3JtZXJUeXBlKHRoaXMudHJhbnNmb3JtZXJUeXBlXykudmlkZW9IZWlnaHQodGhpcy52aWRlb0hlaWdodF8pLnZpZGVvV2lkdGgodGhpcy52aWRlb1dpZHRoXykudmFyaWF0aW9uKCJRb1MiKS5idWlsZCgpO3YucmVwb3J0KG4pLHRoaXMubWVkaWFUcmFuc2Zvcm1lclFvc1JlcG9ydFN0YXJ0VGltZXN0YW1wXz0wLHRoaXMuZnJhbWVzRnJvbVNvdXJjZV89MCx0aGlzLmZyYW1lc1RyYW5zZm9ybWVkXz0wfX1jbGFzcyBTciBleHRlbmRzIGRle2NvbnN0cnVjdG9yKGUpe3N1cGVyKCksdGhpcy50cmFuc2Zvcm1lcnNfPVtdLHRoaXMudHJhY2tFeHBlY3RlZFJhdGVfPS0xO2ZvcihsZXQgdD0wO3Q8ZS5sZW5ndGg7dCsrKXtsZXQgcz1uZXcgQ3IoZVt0XSx0KTtzLm9uKCJlcnJvciIsbj0+e3RoaXMuZW1pdCgiZXJyb3IiLG4pfSkscy5vbigid2FybiIsbj0+e3RoaXMuZW1pdCgid2FybiIsbil9KSx0aGlzLnRyYW5zZm9ybWVyc18ucHVzaChzKX19c2V0VHJhY2tFeHBlY3RlZFJhdGUoZSl7dGhpcy50cmFja0V4cGVjdGVkUmF0ZV89ZTtmb3IobGV0IHQgb2YgdGhpcy50cmFuc2Zvcm1lcnNfKXQuc2V0VHJhY2tFeHBlY3RlZFJhdGUodGhpcy50cmFja0V4cGVjdGVkUmF0ZV8pfWFzeW5jIHN0YXJ0KGUsdCl7aWYoIXRoaXMudHJhbnNmb3JtZXJzX3x8dGhpcy50cmFuc2Zvcm1lcnNfLmxlbmd0aD09PTApe2NvbnNvbGUubG9nKCJbUGlwZWxpbmVdIE5vIHRyYW5zZm9ybWVycy4iKTtyZXR1cm59dHJ5e2xldCBzPWU7Zm9yKGxldCBuIG9mIHRoaXMudHJhbnNmb3JtZXJzXyllPWUucGlwZVRocm91Z2gobmV3IFRyYW5zZm9ybVN0cmVhbShuKSk7ZS5waXBlVG8odCkudGhlbihhc3luYygpPT57Y29uc29sZS5sb2coIltQaXBlbGluZV0gU2V0dXAuIiksYXdhaXQgdC5hYm9ydCgpLGF3YWl0IHMuY2FuY2VsKCksdGhpcy5lbWl0KCJwaXBlbGluZUluZm8iLHttZXNzYWdlOiJwaXBlbGluZV9lbmRlZCJ9KX0pLmNhdGNoKGFzeW5jIG49PntlLmNhbmNlbCgpLnRoZW4oKCk9Pntjb25zb2xlLmxvZygiW1BpcGVsaW5lXSBTaHV0dGluZyBkb3duIHN0cmVhbXMgYWZ0ZXIgYWJvcnQuIil9KS5jYXRjaChvPT57Y29uc29sZS5lcnJvcigiW1BpcGVsaW5lXSBFcnJvciBmcm9tIHN0cmVhbSB0cmFuc2Zvcm06IixvKX0pLGF3YWl0IHQuYWJvcnQobiksYXdhaXQgcy5jYW5jZWwobiksdGhpcy5lbWl0KCJwaXBlbGluZUluZm8iLHttZXNzYWdlOiJwaXBlbGluZV9lbmRlZF93aXRoX2Vycm9yIn0pfSl9Y2F0Y2h7dGhpcy5lbWl0KCJwaXBlbGluZUluZm8iLHttZXNzYWdlOiJwaXBlbGluZV9zdGFydGVkX3dpdGhfZXJyb3IifSksdGhpcy5kZXN0cm95KCk7cmV0dXJufXRoaXMuZW1pdCgicGlwZWxpbmVJbmZvIix7bWVzc2FnZToicGlwZWxpbmVfc3RhcnRlZCJ9KSxjb25zb2xlLmxvZygiW1BpcGVsaW5lXSBQaXBlbGluZSBzdGFydGVkLiIpfWFzeW5jIGRlc3Ryb3koKXtjb25zb2xlLmxvZygiW1BpcGVsaW5lXSBEZXN0cm95aW5nIFBpcGVsaW5lLiIpO2ZvcihsZXQgZSBvZiB0aGlzLnRyYW5zZm9ybWVyc18pZS5zdG9wKCl9fWNsYXNzIHhyIGV4dGVuZHMgZGV7Y29uc3RydWN0b3IoKXtzdXBlcigpLHRoaXMudXVpZF89V2UoKSx0aGlzLnRyYWNrRXhwZWN0ZWRSYXRlXz0tMTtjb25zdCBlPW5ldyBfKCkuYWN0aW9uKCJNZWRpYVByb2Nlc3NvciIpLmd1aWQodGhpcy51dWlkXykudmFyaWF0aW9uKCJDcmVhdGUiKS5idWlsZCgpO3YucmVwb3J0KGUpfXNldFRyYWNrRXhwZWN0ZWRSYXRlKGUpe3RoaXMudHJhY2tFeHBlY3RlZFJhdGVfPWUsdGhpcy5waXBlbGluZV8mJnRoaXMucGlwZWxpbmVfLnNldFRyYWNrRXhwZWN0ZWRSYXRlKHRoaXMudHJhY2tFeHBlY3RlZFJhdGVfKX10cmFuc2Zvcm0oZSx0KXtyZXR1cm4gdGhpcy5yZWFkYWJsZV89ZSx0aGlzLndyaXRhYmxlXz10LHRoaXMudHJhbnNmb3JtSW50ZXJuYWwoKX10cmFuc2Zvcm1JbnRlcm5hbCgpe3JldHVybiBuZXcgUHJvbWlzZSgoZSx0KT0+e2lmKCF0aGlzLnRyYW5zZm9ybWVyc198fHRoaXMudHJhbnNmb3JtZXJzXy5sZW5ndGg9PT0wKXtjb25zdCBuPW5ldyBfKCkuYWN0aW9uKCJNZWRpYVByb2Nlc3NvciIpLmd1aWQodGhpcy51dWlkXykubWVzc2FnZShULmVycm9ycy50cmFuc2Zvcm1lcl9ub25lKS52YXJpYXRpb24oIkVycm9yIikuYnVpbGQoKTt2LnJlcG9ydChuKSx0KCJbTWVkaWFQcm9jZXNzb3JdIE5lZWQgdG8gc2V0IHRyYW5zZm9ybWVycy4iKTtyZXR1cm59aWYoIXRoaXMucmVhZGFibGVfKXtjb25zdCBuPW5ldyBfKCkuYWN0aW9uKCJNZWRpYVByb2Nlc3NvciIpLmd1aWQodGhpcy51dWlkXykubWVzc2FnZShULmVycm9ycy5yZWFkYWJsZV9udWxsKS52YXJpYXRpb24oIkVycm9yIikuYnVpbGQoKTt2LnJlcG9ydChuKSx0KCJbTWVkaWFQcm9jZXNzb3JdIFJlYWRhYmxlIGlzIG51bGwuIik7cmV0dXJufWlmKCF0aGlzLndyaXRhYmxlXyl7Y29uc3Qgbj1uZXcgXygpLmFjdGlvbigiTWVkaWFQcm9jZXNzb3IiKS5ndWlkKHRoaXMudXVpZF8pLm1lc3NhZ2UoVC5lcnJvcnMud3JpdGFibGVfbnVsbCkudmFyaWF0aW9uKCJFcnJvciIpLmJ1aWxkKCk7di5yZXBvcnQobiksdCgiW01lZGlhUHJvY2Vzc29yXSBXcml0YWJsZSBpcyBudWxsLiIpO3JldHVybn1sZXQgcz0hMTt0aGlzLnBpcGVsaW5lXyYmKHM9ITAsdGhpcy5waXBlbGluZV8uY2xlYXJMaXN0ZW5lcnMoKSx0aGlzLnBpcGVsaW5lXy5kZXN0cm95KCkpLHRoaXMucGlwZWxpbmVfPW5ldyBTcih0aGlzLnRyYW5zZm9ybWVyc18pLHRoaXMucGlwZWxpbmVfLm9uKCJ3YXJuIixuPT57dGhpcy5lbWl0KCJ3YXJuIixuKX0pLHRoaXMucGlwZWxpbmVfLm9uKCJlcnJvciIsbj0+e3RoaXMuZW1pdCgiZXJyb3IiLG4pfSksdGhpcy5waXBlbGluZV8ub24oInBpcGVsaW5lSW5mbyIsbj0+e3MmJihuLm1lc3NhZ2U9PT0icGlwZWxpbmVfc3RhcnRlZCI/bi5tZXNzYWdlPSJwaXBlbGluZV9yZXN0YXJ0ZWQiOm4ubWVzc2FnZT09PSJwaXBlbGluZV9zdGFydGVkX3dpdGhfZXJyb3IiJiYobi5tZXNzYWdlPSJwaXBlbGluZV9yZXN0YXJ0ZWRfd2l0aF9lcnJvciIpKSx0aGlzLmVtaXQoInBpcGVsaW5lSW5mbyIsbil9KSx0aGlzLnRyYWNrRXhwZWN0ZWRSYXRlXyE9LTEmJnRoaXMucGlwZWxpbmVfLnNldFRyYWNrRXhwZWN0ZWRSYXRlKHRoaXMudHJhY2tFeHBlY3RlZFJhdGVfKSx0aGlzLnBpcGVsaW5lXy5zdGFydCh0aGlzLnJlYWRhYmxlXyx0aGlzLndyaXRhYmxlXykudGhlbigoKT0+e2UoKX0pLmNhdGNoKG49Pnt0KG4pfSl9KX1zZXRUcmFuc2Zvcm1lcnMoZSl7Y29uc3QgdD1uZXcgXygpLmFjdGlvbigiTWVkaWFQcm9jZXNzb3IiKS5ndWlkKHRoaXMudXVpZF8pLm1lc3NhZ2UoVC51cGRhdGVzLnRyYW5zZm9ybWVyX25ldykudmFyaWF0aW9uKCJVcGRhdGUiKS5idWlsZCgpO3JldHVybiB2LnJlcG9ydCh0KSx0aGlzLnRyYW5zZm9ybWVyc189ZSx0aGlzLnJlYWRhYmxlXyYmdGhpcy53cml0YWJsZV8/dGhpcy50cmFuc2Zvcm1JbnRlcm5hbCgpOlByb21pc2UucmVzb2x2ZSgpfWRlc3Ryb3koKXtyZXR1cm4gbmV3IFByb21pc2UoZT0+e3RoaXMucGlwZWxpbmVfJiZ0aGlzLnBpcGVsaW5lXy5kZXN0cm95KCk7Y29uc3QgdD1uZXcgXygpLmFjdGlvbigiTWVkaWFQcm9jZXNzb3IiKS5ndWlkKHRoaXMudXVpZF8pLnZhcmlhdGlvbigiRGVsZXRlIikuYnVpbGQoKTt2LnJlcG9ydCh0KSxlKCl9KX19dmFyIGdlPShyPT4oci5Mb3c9IkxvdyIsci5IaWdoPSJIaWdoIixyKSkoZ2V8fHt9KTtjbGFzcyBZZXtjb25zdHJ1Y3RvcihlKXt0eXBlb2YgZT09Im51bWJlciI/dGhpcy5ibHVyRmlsdGVyXz0iYmx1cigiK2UrInB4KSI6dGhpcy5ibHVyRmlsdGVyXz1lPT09Z2UuSGlnaD8iYmx1cigxMHB4KSI6ImJsdXIoNXB4KSJ9ZGVzdHJveSgpe3JldHVybiBuZXcgUHJvbWlzZShlPT57ZSgpfSl9cnVuUG9zdFByb2Nlc3NpbmcoZSx0KXt0cnl7ZS5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb249ImRlc3RpbmF0aW9uLW92ZXIiLGUuZmlsdGVyPXRoaXMuYmx1ckZpbHRlcl8sZS5kcmF3SW1hZ2UodCwwLDAsdC53aWR0aCx0LmhlaWdodCl9Y2F0Y2gocyl7Y29uc29sZS5sb2coIltCbHVyUG9zdFByb2Nlc3NdIEZhaWxlZCB0byBkcmF3IGNhbnZhcyIscyl9fX1jbGFzcyBaZXtjb25zdHJ1Y3Rvcigpe31kZXN0cm95KCl7cmV0dXJuIG5ldyBQcm9taXNlKGU9Pnt0aGlzLmJnSW1hZ2VfJiZ0aGlzLmJnSW1hZ2VfLmNsb3NlKCksZSgpfSl9c2V0VmlydHVhbEJHSW1hZ2UoZSl7dGhpcy5iZ0ltYWdlXyYmdGhpcy5iZ0ltYWdlXy5jbG9zZSgpLHRoaXMuYmdJbWFnZV89ZX1hc3luYyBydW5Qb3N0UHJvY2Vzc2luZyhlLHQpe2lmKHRoaXMuYmdJbWFnZV8pe2lmKHRoaXMuYmdJbWFnZV8ud2lkdGghPXQud2lkdGh8fHRoaXMuYmdJbWFnZV8uaGVpZ2h0IT10LmhlaWdodCl7Y29uc3Qgcz0iaGlnaCIsbj17cmVzaXplV2lkdGg6dC53aWR0aCxyZXNpemVIZWlnaHQ6dC5oZWlnaHQscmVzaXplUXVhbGl0eTpzfTt0cnl7dGhpcy5iZ0ltYWdlXz1hd2FpdCBjcmVhdGVJbWFnZUJpdG1hcCh0aGlzLmJnSW1hZ2VfLG4pfWNhdGNoKG8pe3Rocm93IG99fWUuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uPSJkZXN0aW5hdGlvbi1vdmVyIixlLmRyYXdJbWFnZSh0aGlzLmJnSW1hZ2VfLDAsMCx0aGlzLmJnSW1hZ2VfLndpZHRoLHRoaXMuYmdJbWFnZV8uaGVpZ2h0KX19fWNsYXNzIE9ye2NvbnN0cnVjdG9yKGU9MS8wKXt0aGlzLmNhcGFjaXR5PWUsdGhpcy5zdG9yYWdlPVtdfWVucXVldWUoZSl7aWYodGhpcy5zaXplKCk9PT10aGlzLmNhcGFjaXR5KXRocm93IEVycm9yKCJRdWV1ZSBoYXMgcmVhY2hlZCBtYXggY2FwYWNpdHksIHlvdSBjYW5ub3QgYWRkIG1vcmUgaXRlbXMiKTt0aGlzLnN0b3JhZ2UucHVzaChlKX1kZXF1ZXVlKCl7cmV0dXJuIHRoaXMuc3RvcmFnZS5zaGlmdCgpfXNpemUoKXtyZXR1cm4gdGhpcy5zdG9yYWdlLmxlbmd0aH19Y29uc3QgeWU9Y2xhc3N7Y29uc3RydWN0b3IoKXt0aGlzLnF1ZXVlXz1uZXcgT3J9Y2xlYXJRdWV1ZShyKXtmb3IoO3RoaXMucXVldWVfLnNpemUoKT4wOyl0aGlzLnF1ZXVlXy5kZXF1ZXVlKCkuY2xvc2UoKX1zZXRWaWRlb1JlYWRhYmxlKHIpe3JldHVybiBuZXcgUHJvbWlzZSgoZSx0KT0+e3RoaXMuZnJhbWVSZWFkZXJfPXIuZ2V0UmVhZGVyKCksdGhpcy5mcmFtZVJlYWRlcl8ucmVhZCgpLnRoZW4ocz0+e3RoaXMucHJvY2Vzc0ZyYW1lKHMpfSkuY2F0Y2gocz0+e3Qocyl9KSxlKCl9KX1kZXN0cm95KCl7cmV0dXJuIG5ldyBQcm9taXNlKGFzeW5jKHIsZSk9Pnt2YXIgdDt0aGlzLmNsZWFyUXVldWUoITApLHRoaXMuZnJhbWVSZWFkZXJfPyh0PXRoaXMuZnJhbWVSZWFkZXJfKT09bnVsbHx8dC5jYW5jZWwoKS50aGVuKCgpPT57cigpfSkuY2F0Y2gocz0+e2Uocyl9KTpyKCl9KX1wcm9jZXNzRnJhbWUocil7aWYoIXIuZG9uZSl7aWYoIXRoaXMuZnJhbWVSZWFkZXJfKXtyLnZhbHVlLmNsb3NlKCk7cmV0dXJufWZvcig7dGhpcy5xdWV1ZV8uc2l6ZSgpPj15ZS5OVU1CRVJfT0ZfRlJBTUVTX1RPX0NMRUFSOyl7bGV0IGU9dGhpcy5xdWV1ZV8uZGVxdWV1ZSgpO2UmJmUuY2xvc2UoKX10aGlzLnF1ZXVlXy5lbnF1ZXVlKHIudmFsdWUpLHRoaXMuZnJhbWVSZWFkZXJfLnJlYWQoKS50aGVuKGU9Pnt0aGlzLnByb2Nlc3NGcmFtZShlKX0pLmNhdGNoKGU9Pntjb25zb2xlLmVycm9yKGUpfSl9fXJ1blBvc3RQcm9jZXNzaW5nKHIsZSl7dHJ5e2lmKHIuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uPSJkZXN0aW5hdGlvbi1vdmVyIix0aGlzLnF1ZXVlXy5zaXplKCk+eWUuTlVNQkVSX09GX0ZSQU1FU19UT19DTEVBUiYmdGhpcy5jbGVhclF1ZXVlKCExKSx0aGlzLnF1ZXVlXy5zaXplKCk+MCl7Y29uc3QgdD10aGlzLnF1ZXVlXy5kZXF1ZXVlKCk7ci5kcmF3SW1hZ2UodCwwLDAsZS53aWR0aCxlLmhlaWdodCksdC5jbG9zZSgpfX1jYXRjaCh0KXtjb25zb2xlLmVycm9yKCJbVmlkZW9Qb3N0UHJvY2Vzc10gRmFpbGVkIHRvIGRyYXcgY2FudmFzIix0KX19fTtsZXQgX2U9eWU7X2UuTlVNQkVSX09GX0ZSQU1FU19UT19DTEVBUj01O2NsYXNzIElye2NvbnN0cnVjdG9yKGUpe3R5cGVvZiBlPT0ibnVtYmVyIj90aGlzLmJsdXJGaWx0ZXJfPSJibHVyKCIrZSsicHgpIjp0aGlzLmJsdXJGaWx0ZXJfPWU9PT1nZS5IaWdoPyJibHVyKDEwcHgpIjoiYmx1cig1cHgpIn1kZXN0cm95KCl7cmV0dXJuIG5ldyBQcm9taXNlKGU9PntlKCl9KX1ydW5Qb3N0UHJvY2Vzc2luZyhlLHQpe3RyeXtlLmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbj0ic291cmNlLWluIixlLmZpbHRlcj10aGlzLmJsdXJGaWx0ZXJfLGUuZHJhd0ltYWdlKHQsMCwwLHQud2lkdGgsdC5oZWlnaHQpLGUuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uPSJkZXN0aW5hdGlvbi1vdmVyIixlLmZpbHRlcj0iYmx1cigwcHgpIixlLmRyYXdJbWFnZSh0LDAsMCx0LndpZHRoLHQuaGVpZ2h0KX1jYXRjaChzKXtjb25zb2xlLmxvZygiW0JsdXJQb3N0UHJvY2Vzc10gRmFpbGVkIHRvIGRyYXcgY2FudmFzIixzKX19fWNvbnN0IHZlPWNsYXNze2NvbnN0cnVjdG9yKCl7aWYodGhpcy5yZXN1bHRDYW52YXNfPW5ldyBPZmZzY3JlZW5DYW52YXMoMSwxKSx0aGlzLnJlc3VsdEN0eF89dGhpcy5yZXN1bHRDYW52YXNfLmdldENvbnRleHQoIjJkIix7ZGVzeW5jaHJvbml6ZWQ6ITB9KSwhdGhpcy5yZXN1bHRDdHhfKXRocm93IG5ldyBFcnJvcigiVW5hYmxlIHRvIGNyZWF0ZSBPZmZzY3JlZW5DYW52YXNSZW5kZXJpbmdDb250ZXh0MkQiKTtpZih0aGlzLnNlZ21lbnRhdGlvbk1hc2tDYW52YXNfPW5ldyBPZmZzY3JlZW5DYW52YXModmUuU0VMRklFX1dJRFRILHZlLlNFTEZJRV9ISUdIVCksdGhpcy5zZWdtZW50YXRpb25NYXNrQ3R4Xz10aGlzLnNlZ21lbnRhdGlvbk1hc2tDYW52YXNfLmdldENvbnRleHQoIjJkIix7YWxwaGE6ITEsZGVzeW5jaHJvbml6ZWQ6ITB9KSwhdGhpcy5zZWdtZW50YXRpb25NYXNrQ3R4Xyl0aHJvdyBuZXcgRXJyb3IoIlVuYWJsZSB0byBjcmVhdGUgT2Zmc2NyZWVuQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJEIik7aWYodGhpcy5zZWdtZW50YXRpb25SZXN1bHRzQ2FudmFzXz1uZXcgT2Zmc2NyZWVuQ2FudmFzKDEsMSksdGhpcy5zZWdtZW50YXRpb25SZXN1bHRzQ3R4Xz10aGlzLnNlZ21lbnRhdGlvblJlc3VsdHNDYW52YXNfLmdldENvbnRleHQoIjJkIix7ZGVzeW5jaHJvbml6ZWQ6ITB9KSwhdGhpcy5zZWdtZW50YXRpb25SZXN1bHRzQ3R4Xyl0aHJvdyBuZXcgRXJyb3IoIlVuYWJsZSB0byBjcmVhdGUgT2Zmc2NyZWVuQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJEIil9aW5pdChyKXt0aGlzLnByb2Nlc3NGcmFtZUNiPXJ9YXN5bmMgc2V0QmFja2dyb3VuZE9wdGlvbnMocil7aWYodHlwZW9mIHRoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfIT0idW5kZWZpbmVkIil0cnl7YXdhaXQgdGhpcy5wb3N0UHJvY2Vzc0ludGVyZmFjZV8uZGVzdHJveSgpfWNhdGNoKGUpe3Rocm93IGV9aWYoci50cmFuc2Zvcm1lclR5cGU9PT0iVmlydHVhbEJhY2tncm91bmQiKXRoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfPW5ldyBaZTtlbHNlIGlmKHIudHJhbnNmb3JtZXJUeXBlPT09IkJhY2tncm91bmRCbHVyIil7bGV0IGU9cjt0aGlzLnBvc3RQcm9jZXNzSW50ZXJmYWNlXz1uZXcgWWUoZS5yYWRpdXMpfWVsc2UgaWYoci50cmFuc2Zvcm1lclR5cGU9PT0iVmlkZW9CYWNrZ3JvdW5kIil0aGlzLnBvc3RQcm9jZXNzSW50ZXJmYWNlXz1uZXcgX2U7ZWxzZSBpZihyLnRyYW5zZm9ybWVyVHlwZT09PSJTaWx1ZXRlQmx1ciIpe2xldCBlPXI7dGhpcy5wb3N0UHJvY2Vzc0ludGVyZmFjZV89bmV3IElyKGUucmFkaXVzKX1lbHNlIHRoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfPW5ldyBZZX1jbG9zZSgpe3JldHVybiBuZXcgUHJvbWlzZSgocixlKT0+e3RoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfP3RoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfLmRlc3Ryb3koKS50aGVuKCgpPT57cigpfSkuY2F0Y2godD0+e2UodCl9KTpyKCl9KX1zdGFydCgpe31hc3luYyB0cmFuc2Zvcm0ocixlKXsodGhpcy5yZXN1bHRDYW52YXNfLndpZHRoIT1yLmRpc3BsYXlXaWR0aHx8dGhpcy5yZXN1bHRDYW52YXNfLmhlaWdodCE9ci5kaXNwbGF5SGVpZ2h0KSYmKHRoaXMucmVzdWx0Q2FudmFzXy53aWR0aD1yLmRpc3BsYXlXaWR0aCx0aGlzLnJlc3VsdENhbnZhc18uaGVpZ2h0PXIuZGlzcGxheUhlaWdodCk7Y29uc3QgdD1yLnRpbWVzdGFtcDtjcmVhdGVJbWFnZUJpdG1hcChyKS50aGVuKHM9PntyLmNsb3NlKCksdGhpcy5wcm9jZXNzRnJhbWUoZSxzLHQpfSkuY2F0Y2gocz0+e2UuZW5xdWV1ZShyKX0pfXByb2Nlc3NGcmFtZShyLGUsdCl7dGhpcy5wcm9jZXNzU291cmNlKGUpLHRoaXMucmVzdWx0Q3R4Xy5zYXZlKCksdGhpcy5yZXN1bHRDdHhfLmNsZWFyUmVjdCgwLDAsdGhpcy5yZXN1bHRDYW52YXNfLndpZHRoLHRoaXMucmVzdWx0Q2FudmFzXy5oZWlnaHQpLHRoaXMucmVzdWx0Q3R4Xy5kcmF3SW1hZ2UodGhpcy5zZWdtZW50YXRpb25SZXN1bHRzQ2FudmFzXywwLDAsdGhpcy5zZWdtZW50YXRpb25NYXNrQ2FudmFzXy53aWR0aCx0aGlzLnNlZ21lbnRhdGlvbk1hc2tDYW52YXNfLmhlaWdodCwwLDAsdGhpcy5yZXN1bHRDYW52YXNfLndpZHRoLHRoaXMucmVzdWx0Q2FudmFzXy5oZWlnaHQpLHRoaXMucmVzdWx0Q3R4Xy5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb249InNvdXJjZS1pbiIsdGhpcy5yZXN1bHRDdHhfLmZpbHRlcj0ibm9uZSIsdGhpcy5yZXN1bHRDdHhfLmRyYXdJbWFnZShlLDAsMCxlLndpZHRoLGUuaGVpZ2h0LDAsMCx0aGlzLnJlc3VsdENhbnZhc18ud2lkdGgsdGhpcy5yZXN1bHRDYW52YXNfLmhlaWdodCksdGhpcy5wb3N0UHJvY2Vzc0ludGVyZmFjZV8mJnRoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfLnJ1blBvc3RQcm9jZXNzaW5nKHRoaXMucmVzdWx0Q3R4XyxlKSx0aGlzLnJlc3VsdEN0eF8ucmVzdG9yZSgpLHIuZW5xdWV1ZShuZXcgVmlkZW9GcmFtZSh0aGlzLnJlc3VsdENhbnZhc18se3RpbWVzdGFtcDp0LGFscGhhOiJkaXNjYXJkIn0pKSxlLmNsb3NlKCl9cHJvY2Vzc1NvdXJjZShyKXtpZih0aGlzLnNlZ21lbnRhdGlvbk1hc2tDdHhfLmNsZWFyUmVjdCgwLDAsdGhpcy5zZWdtZW50YXRpb25NYXNrQ2FudmFzXy53aWR0aCx0aGlzLnNlZ21lbnRhdGlvbk1hc2tDYW52YXNfLmhlaWdodCksdGhpcy5zZWdtZW50YXRpb25NYXNrQ3R4Xy5kcmF3SW1hZ2UociwwLDAsci53aWR0aCxyLmhlaWdodCwwLDAsdGhpcy5zZWdtZW50YXRpb25NYXNrQ2FudmFzXy53aWR0aCx0aGlzLnNlZ21lbnRhdGlvbk1hc2tDYW52YXNfLmhlaWdodCksdGhpcy5wcm9jZXNzRnJhbWVDYil7bGV0IGU9dGhpcy5zZWdtZW50YXRpb25NYXNrQ2FudmFzXy50cmFuc2ZlclRvSW1hZ2VCaXRtYXAoKTt0aGlzLnByb2Nlc3NGcmFtZUNiKGUpfX1mbHVzaCgpe31nZXRUcmFuc2Zvcm1lclR5cGUoKXtyZXR1cm4iQmFja2dyb3VuZFRyYW5zZm9ybWVyIn1zZXRWaWRlb0JHUmVhZGFibGUocil7cmV0dXJuIG5ldyBQcm9taXNlKChlLHQpPT57dGhpcy5wb3N0UHJvY2Vzc0ludGVyZmFjZV8gaW5zdGFuY2VvZiBfZT90aGlzLnBvc3RQcm9jZXNzSW50ZXJmYWNlXy5zZXRWaWRlb1JlYWRhYmxlKHIpLnRoZW4oKCk9PntlKCl9KS5jYXRjaChzPT57dChzKX0pOnQoInBvc3QgcHJvY2VzcyBpcyBub3QgdmlkZW8iKX0pfXNldFZpcnR1YWxCR0ltYWdlKHIpe3JldHVybiBuZXcgUHJvbWlzZSgoZSx0KT0+e3RoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfIGluc3RhbmNlb2YgWmU/KHRoaXMucG9zdFByb2Nlc3NJbnRlcmZhY2VfLnNldFZpcnR1YWxCR0ltYWdlKHIpLGUoKSk6dCgicG9zdCBwcm9jZXNzIGlzIG5vdCB2aWRlbyIpfSl9c2V0U2VnbWVudGF0aW9uTWFza0ltYWdlKHIpeyhyLmhlaWdodCE9dGhpcy5zZWdtZW50YXRpb25SZXN1bHRzQ2FudmFzXy5oZWlnaHR8fHIud2lkdGghPXRoaXMuc2VnbWVudGF0aW9uUmVzdWx0c0NhbnZhc18ud2lkdGgpJiYodGhpcy5zZWdtZW50YXRpb25SZXN1bHRzQ2FudmFzXy53aWR0aD1yLndpZHRoLHRoaXMuc2VnbWVudGF0aW9uUmVzdWx0c0NhbnZhc18uaGVpZ2h0PXIuaGVpZ2h0KSx0aGlzLnNlZ21lbnRhdGlvblJlc3VsdHNDdHhfLmNsZWFyUmVjdCgwLDAsdGhpcy5zZWdtZW50YXRpb25SZXN1bHRzQ2FudmFzXy53aWR0aCx0aGlzLnNlZ21lbnRhdGlvblJlc3VsdHNDYW52YXNfLmhlaWdodCksdGhpcy5zZWdtZW50YXRpb25SZXN1bHRzQ3R4Xy5kcmF3SW1hZ2UociwwLDApO2xldCBlPXRoaXMuc2VnbWVudGF0aW9uUmVzdWx0c0N0eF8uZ2V0SW1hZ2VEYXRhKDAsMCx0aGlzLnNlZ21lbnRhdGlvblJlc3VsdHNDYW52YXNfLndpZHRoLHRoaXMuc2VnbWVudGF0aW9uUmVzdWx0c0NhbnZhc18uaGVpZ2h0KSx0PXRoaXMuc2VnbWVudGF0aW9uUmVzdWx0c0NhbnZhc18ud2lkdGgqdGhpcy5zZWdtZW50YXRpb25SZXN1bHRzQ2FudmFzXy5oZWlnaHQ7Zm9yKGxldCBzPTA7czx0O3MrKyllLmRhdGFbcyo0XTwxMDAmJihlLmRhdGFbcyo0XT0wKTt0aGlzLnNlZ21lbnRhdGlvblJlc3VsdHNDdHhfLmNsZWFyUmVjdCgwLDAsdGhpcy5zZWdtZW50YXRpb25SZXN1bHRzQ2FudmFzXy53aWR0aCx0aGlzLnNlZ21lbnRhdGlvblJlc3VsdHNDYW52YXNfLmhlaWdodCksdGhpcy5zZWdtZW50YXRpb25SZXN1bHRzQ3R4Xy5wdXRJbWFnZURhdGEoZSwwLDApLHIuY2xvc2UoKX19O2xldCBiZT12ZTtiZS5TRUxGSUVfV0lEVEg9MjU2LGJlLlNFTEZJRV9ISUdIVD0xNDQ7ZnVuY3Rpb24gTXIocil7cmV0dXJuIHR5cGVvZiByPT0ib2JqZWN0IiYmciE9PW51bGwmJiJtZXNzYWdlImluIHImJnR5cGVvZiByLm1lc3NhZ2U9PSJzdHJpbmcifWZ1bmN0aW9uIGtyKHIpe2lmKE1yKHIpKXJldHVybiByO3RyeXtyZXR1cm4gbmV3IEVycm9yKEpTT04uc3RyaW5naWZ5KHIpKX1jYXRjaHtyZXR1cm4gbmV3IEVycm9yKFN0cmluZyhyKSl9fWZ1bmN0aW9uIEEocil7cmV0dXJuIHR5cGVvZiByPT0idW5kZWZpbmVkIj8iIjprcihyKS5tZXNzYWdlfWlmKHR5cGVvZiBpbXBvcnRTY3JpcHRzPT0iZnVuY3Rpb24iKXtsZXQgcj1mdW5jdGlvbigpe3JldHVybiBuZXcgUHJvbWlzZSgocyxuKT0+e2U9bmV3IHhyLGUub24oImVycm9yIixpPT57Y29uc3QgYT17Y2FsbGJhY2tUeXBlOiJtZWRpYV9wcm9jZXNzb3JfZXJyb3JfZXZlbnQiLG1lc3NhZ2U6aX07cG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoYSkpfSksZS5vbigid2FybiIsaT0+e2NvbnN0IGE9e2NhbGxiYWNrVHlwZToibWVkaWFfcHJvY2Vzc29yX3dhcm5fZXZlbnQiLG1lc3NhZ2U6aX07cG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoYSkpfSksZS5vbigicGlwZWxpbmVJbmZvIixpPT57Y29uc3QgYT17Y2FsbGJhY2tUeXBlOiJtZWRpYV9wcm9jZXNzb3JfcGlwZWxpbmVfZXZlbnQiLG1lc3NhZ2U6aX07cG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoYSkpfSksdD1uZXcgYmUsdC5pbml0KGk9Pntwb3N0TWVzc2FnZShpLFtpXSl9KTtsZXQgbz1bXTtvLnB1c2godCksZS5zZXRUcmFuc2Zvcm1lcnMobykudGhlbigoKT0+e3MoKX0pLmNhdGNoKGk9PntuKGkpfSl9KX0sZSx0O29ubWVzc2FnZT1hc3luYyBzPT57aWYocy5kYXRhIGluc3RhbmNlb2YgSW1hZ2VCaXRtYXApe3QmJnQuc2V0U2VnbWVudGF0aW9uTWFza0ltYWdlKHMuZGF0YSk7cmV0dXJufWNvbnN0e29wZXJhdGlvbjpufT1zLmRhdGE7aWYobj09PSJpbml0Iil7Y29uc3R7bWV0YURhdGE6b309cy5kYXRhO3R5cGVvZiBvPT0ic3RyaW5nIiYmZHIoSlNPTi5wYXJzZShvKSkscigpLnRoZW4oKCk9Pntjb25zdCBpPXtjYWxsYmFja1R5cGU6InN1Y2Nlc3MiLG1lc3NhZ2U6bn07cG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoaSkpfSkuY2F0Y2goaT0+e2NvbnN0IGE9e2NhbGxiYWNrVHlwZToiZXJyb3IiLG1lc3NhZ2U6bixlcnJvcjpBKGkpfTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShhKSl9KX1lbHNlIGlmKG49PT0idHJhbnNmb3JtIil7Y29uc3R7cmVhZGFibGU6byx3cml0YWJsZTppfT1zLmRhdGE7ZS50cmFuc2Zvcm0obyxpKS50aGVuKCgpPT57Y29uc3QgYT17Y2FsbGJhY2tUeXBlOiJzdWNjZXNzIixtZXNzYWdlOm59O3Bvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KGEpKX0pLmNhdGNoKGE9Pntjb25zdCBsPXtjYWxsYmFja1R5cGU6ImVycm9yIixtZXNzYWdlOm4sZXJyb3I6QShhKX07cG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkobCkpfSl9ZWxzZSBpZihuPT09ImRlc3Ryb3kiKXQuY2xvc2UoKS5maW5hbGx5KCgpPT57ZS5kZXN0cm95KCkudGhlbigoKT0+e2NvbnN0IG89e2NhbGxiYWNrVHlwZToic3VjY2VzcyIsbWVzc2FnZTpufTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShvKSl9KS5jYXRjaChvPT57Y29uc3QgaT17Y2FsbGJhY2tUeXBlOiJlcnJvciIsbWVzc2FnZTpuLGVycm9yOkEobyl9O3Bvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KGkpKX0pfSk7ZWxzZSBpZihuPT09InNldFRyYWNrRXhwZWN0ZWRSYXRlIil7ZS5zZXRUcmFja0V4cGVjdGVkUmF0ZShzLmRhdGEucmF0ZSk7Y29uc3Qgbz17Y2FsbGJhY2tUeXBlOiJzdWNjZXNzIixtZXNzYWdlOm59O3Bvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KG8pKX1lbHNlIGlmKG49PT0ic2V0QmFja2dyb3VuZE9wdGlvbnMiKXtjb25zdHtiYWNrZ3JvdW5kT3B0aW9uczpvfT1zLmRhdGE7dC5zZXRCYWNrZ3JvdW5kT3B0aW9ucyhKU09OLnBhcnNlKG8pKS50aGVuKCgpPT57Y29uc3QgaT17Y2FsbGJhY2tUeXBlOiJzdWNjZXNzIixtZXNzYWdlOm59O3Bvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KGkpKX0pLmNhdGNoKGk9Pntjb25zdCBhPXtjYWxsYmFja1R5cGU6ImVycm9yIixtZXNzYWdlOm4sZXJyb3I6QShpKX07cG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoYSkpfSl9ZWxzZSBpZihuPT09InNldFZpZGVvQkdSZWFkYWJsZSIpe2NvbnN0e3JlYWRhYmxlOm99PXMuZGF0YTt0LnNldFZpZGVvQkdSZWFkYWJsZShvKS50aGVuKCgpPT57Y29uc3QgaT17Y2FsbGJhY2tUeXBlOiJzdWNjZXNzIixtZXNzYWdlOm59O3Bvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KGkpKX0pLmNhdGNoKGk9Pntjb25zdCBhPXtjYWxsYmFja1R5cGU6ImVycm9yIixtZXNzYWdlOm4sZXJyb3I6QShpKX07cG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoYSkpfSl9ZWxzZSBpZihuPT09InNldFZpcnR1YWxCR0ltYWdlIil7Y29uc3R7aW1hZ2U6b309cy5kYXRhO3Quc2V0VmlydHVhbEJHSW1hZ2UobykudGhlbigoKT0+e2NvbnN0IGk9e2NhbGxiYWNrVHlwZToic3VjY2VzcyIsbWVzc2FnZTpufTtwb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShpKSl9KS5jYXRjaChpPT57Y29uc3QgYT17Y2FsbGJhY2tUeXBlOiJlcnJvciIsbWVzc2FnZTpuLGVycm9yOkEoaSl9O3Bvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KGEpKX0pfX19fSkoKTsK";
|
|
38559
38747
|
const blob = typeof window !== "undefined" && window.Blob && new Blob([atob(encodedJs)], { type: "text/javascript;charset=utf-8" });
|
|
38560
38748
|
function WorkerWrapper() {
|
|
38561
38749
|
const objURL = blob && (window.URL || window.webkitURL).createObjectURL(blob);
|
|
@@ -61522,6 +61710,7 @@ class VonageAssetsLoaderHelper {
|
|
|
61522
61710
|
canplayAbortSignal.abort();
|
|
61523
61711
|
reject("loading error:" + e);
|
|
61524
61712
|
}, { once: true, signal: errorAbortSignal.signal });
|
|
61713
|
+
bgvideo.crossOrigin = "anonymous";
|
|
61525
61714
|
bgvideo.src = videoUri;
|
|
61526
61715
|
});
|
|
61527
61716
|
}
|
|
@@ -61539,6 +61728,7 @@ class VonageAssetsLoaderHelper {
|
|
|
61539
61728
|
img.onerror = function(e) {
|
|
61540
61729
|
reject(e);
|
|
61541
61730
|
};
|
|
61731
|
+
img.crossOrigin = "anonymous";
|
|
61542
61732
|
img.src = imageUri;
|
|
61543
61733
|
});
|
|
61544
61734
|
}
|
|
@@ -64147,6 +64337,134 @@ module.exports = function SessionFactory(deps) {
|
|
|
64147
64337
|
|
|
64148
64338
|
publisher._.unpublishFromSession(this, 'unpublished');
|
|
64149
64339
|
};
|
|
64340
|
+
/**
|
|
64341
|
+
* Sets the ICE configuration for all connections in a session. This replaces any previously
|
|
64342
|
+
* set ICE configurations.
|
|
64343
|
+
*
|
|
64344
|
+
* <p>
|
|
64345
|
+
* This is a <em>beta</em> feature. It is available for projects that use the
|
|
64346
|
+
* <a href="https://tokbox.com/developer/guides/configurable-turn-servers/">configurable
|
|
64347
|
+
* TURN server add-on</a>.
|
|
64348
|
+
*
|
|
64349
|
+
* @see <a href="OT.html#initSession">OT.initSession()</a>
|
|
64350
|
+
*
|
|
64351
|
+
* @param {IceConfig} newIceConfig This object defines the ICE configuration. It has the
|
|
64352
|
+
* following propoerties;
|
|
64353
|
+
*
|
|
64354
|
+
* <p>
|
|
64355
|
+
* <ul>
|
|
64356
|
+
* <li>
|
|
64357
|
+
* <code>includeServers</code></code> (String) — Set this to 'custom' and client will use
|
|
64358
|
+
* only the custom TURN servers you provide in the <code>customServers</code> property
|
|
64359
|
+
* of the <code>newIceConfig</code> parameter. Set this to 'all' and the client will use
|
|
64360
|
+
* both the custom TURN servers you provide along with OpenTok TURN servers.
|
|
64361
|
+
* </li>
|
|
64362
|
+
*
|
|
64363
|
+
* <li>
|
|
64364
|
+
* <code>transportPolicy</code></code> (String) — Set this to 'all' (the default) and
|
|
64365
|
+
* the client will use all ICE transport types (such as host, srflx, and TURN) to establish
|
|
64366
|
+
* media connectivity. Set this to 'relay' to force connectivity through TURN always
|
|
64367
|
+
* and ignore all other ICE candidates.
|
|
64368
|
+
* </li>
|
|
64369
|
+
*
|
|
64370
|
+
* <li>
|
|
64371
|
+
* <p>
|
|
64372
|
+
* <code>customServers</code></code> (Array) — Set this to an array of objects defining
|
|
64373
|
+
* your custom TURN servers. Each object corresponds to one custom TURN server, and it
|
|
64374
|
+
* includes the following properties:
|
|
64375
|
+
* </p>
|
|
64376
|
+
* <p>
|
|
64377
|
+
* <ul>
|
|
64378
|
+
* <li>
|
|
64379
|
+
* <code>urls</code> (String or Array of Strings) — A string or an array of strings,
|
|
64380
|
+
* where each string is a URL supported by the TURN server (and this may be only one URL).
|
|
64381
|
+
* </li>
|
|
64382
|
+
*
|
|
64383
|
+
* <li>
|
|
64384
|
+
* <code>username</code> (String, optional) — The username for the TURN server defined
|
|
64385
|
+
* in this object.
|
|
64386
|
+
* </li>
|
|
64387
|
+
*
|
|
64388
|
+
* <li>
|
|
64389
|
+
* <code>credential</code> (String, optional) — The credential string for the TURN server
|
|
64390
|
+
* defined in this object.
|
|
64391
|
+
* </li>
|
|
64392
|
+
* </ul>
|
|
64393
|
+
* </p>
|
|
64394
|
+
* </li>
|
|
64395
|
+
*
|
|
64396
|
+
* </ul>
|
|
64397
|
+
* </p>
|
|
64398
|
+
*
|
|
64399
|
+
* @method #setIceConfig
|
|
64400
|
+
*
|
|
64401
|
+
* @memberOf Session
|
|
64402
|
+
*/
|
|
64403
|
+
|
|
64404
|
+
|
|
64405
|
+
this.setIceConfig = /*#__PURE__*/function () {
|
|
64406
|
+
var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(newIceConfig) {
|
|
64407
|
+
var extractServersFromIceConfig, processedIceServers;
|
|
64408
|
+
return _regenerator.default.wrap(function _callee$(_context) {
|
|
64409
|
+
while (1) switch (_context.prev = _context.next) {
|
|
64410
|
+
case 0:
|
|
64411
|
+
validateIceConfig(newIceConfig);
|
|
64412
|
+
analytics.logEvent({
|
|
64413
|
+
action: 'setIceConfig',
|
|
64414
|
+
variation: 'Attempt',
|
|
64415
|
+
payload: {
|
|
64416
|
+
newIceConfig
|
|
64417
|
+
}
|
|
64418
|
+
}); // future publishers will need the new iceConfig
|
|
64419
|
+
|
|
64420
|
+
iceConfig = newIceConfig;
|
|
64421
|
+
|
|
64422
|
+
extractServersFromIceConfig = iceConfigObject => ({
|
|
64423
|
+
iceServers: iceConfigObject.customServers,
|
|
64424
|
+
iceTransportPolicy: iceConfigObject.transportPolicy
|
|
64425
|
+
});
|
|
64426
|
+
|
|
64427
|
+
processedIceServers = extractServersFromIceConfig(newIceConfig);
|
|
64428
|
+
_context.prev = 5;
|
|
64429
|
+
_context.next = 8;
|
|
64430
|
+
return Promise.all(sessionObjects.publishers.map(pub => pub._.setIceConfig(processedIceServers)).concat(sessionObjects.subscribers.map(sub => sub._.setIceConfig(processedIceServers))));
|
|
64431
|
+
|
|
64432
|
+
case 8:
|
|
64433
|
+
_context.next = 14;
|
|
64434
|
+
break;
|
|
64435
|
+
|
|
64436
|
+
case 10:
|
|
64437
|
+
_context.prev = 10;
|
|
64438
|
+
_context.t0 = _context["catch"](5);
|
|
64439
|
+
analytics.logEvent({
|
|
64440
|
+
action: 'setIceConfig',
|
|
64441
|
+
variation: 'Failure',
|
|
64442
|
+
payload: {
|
|
64443
|
+
newIceConfig
|
|
64444
|
+
}
|
|
64445
|
+
});
|
|
64446
|
+
throw _context.t0;
|
|
64447
|
+
|
|
64448
|
+
case 14:
|
|
64449
|
+
analytics.logEvent({
|
|
64450
|
+
action: 'setIceConfig',
|
|
64451
|
+
variation: 'Success',
|
|
64452
|
+
payload: {
|
|
64453
|
+
newIceConfig
|
|
64454
|
+
}
|
|
64455
|
+
});
|
|
64456
|
+
|
|
64457
|
+
case 15:
|
|
64458
|
+
case "end":
|
|
64459
|
+
return _context.stop();
|
|
64460
|
+
}
|
|
64461
|
+
}, _callee, null, [[5, 10]]);
|
|
64462
|
+
}));
|
|
64463
|
+
|
|
64464
|
+
return function (_x) {
|
|
64465
|
+
return _ref3.apply(this, arguments);
|
|
64466
|
+
};
|
|
64467
|
+
}();
|
|
64150
64468
|
/**
|
|
64151
64469
|
* Subscribes to a stream that is available to the session. You can get an array of
|
|
64152
64470
|
* available streams from the <code>streams</code> property of the <code>sessionConnected</code>
|
|
@@ -64744,9 +65062,9 @@ module.exports = function SessionFactory(deps) {
|
|
|
64744
65062
|
return;
|
|
64745
65063
|
}
|
|
64746
65064
|
|
|
64747
|
-
const event = new Events.
|
|
65065
|
+
const event = new Events.CaptionReceivedEvent(caption, streamId);
|
|
64748
65066
|
event.target = this;
|
|
64749
|
-
this.trigger(eventNames.
|
|
65067
|
+
this.trigger(eventNames.SUBSCRIBER_CAPTION_RECEIVED, event);
|
|
64750
65068
|
this.dispatchEvent(event);
|
|
64751
65069
|
}.bind(this),
|
|
64752
65070
|
|
|
@@ -64830,7 +65148,7 @@ module.exports = function SessionFactory(deps) {
|
|
|
64830
65148
|
|
|
64831
65149
|
if (!_token) {
|
|
64832
65150
|
// @todo why would this happen before connect() where a token is set?
|
|
64833
|
-
// Need a token for getting
|
|
65151
|
+
// Need a token for getting ICE servers from GSI
|
|
64834
65152
|
return Promise.resolve({
|
|
64835
65153
|
transportPolicy: _session && _session.sessionInfo && _session.sessionInfo.clientCandidates,
|
|
64836
65154
|
servers: [],
|
|
@@ -64849,7 +65167,7 @@ module.exports = function SessionFactory(deps) {
|
|
|
64849
65167
|
_session._.setIceServers(sessionInfo.iceServers);
|
|
64850
65168
|
|
|
64851
65169
|
if (!_iceServerDetails) {
|
|
64852
|
-
// No
|
|
65170
|
+
// No ICE servers provided by GSI
|
|
64853
65171
|
return {
|
|
64854
65172
|
transportPolicy: _session.sessionInfo.clientCandidates,
|
|
64855
65173
|
servers: [],
|
|
@@ -65609,53 +65927,53 @@ module.exports = function SessionFactory(deps) {
|
|
|
65609
65927
|
});
|
|
65610
65928
|
|
|
65611
65929
|
this.setEncryptionSecret = /*#__PURE__*/function () {
|
|
65612
|
-
var
|
|
65613
|
-
return _regenerator.default.wrap(function
|
|
65614
|
-
while (1) switch (
|
|
65930
|
+
var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(secret) {
|
|
65931
|
+
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
65932
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
65615
65933
|
case 0:
|
|
65616
65934
|
if (initialEncryptionSecret) {
|
|
65617
|
-
|
|
65935
|
+
_context2.next = 3;
|
|
65618
65936
|
break;
|
|
65619
65937
|
}
|
|
65620
65938
|
|
|
65621
65939
|
logging.error('Encryption secret must first be set in initSession.');
|
|
65622
|
-
return
|
|
65940
|
+
return _context2.abrupt("return");
|
|
65623
65941
|
|
|
65624
65942
|
case 3:
|
|
65625
|
-
|
|
65943
|
+
_context2.prev = 3;
|
|
65626
65944
|
validateSecret(secret);
|
|
65627
|
-
|
|
65945
|
+
_context2.next = 10;
|
|
65628
65946
|
break;
|
|
65629
65947
|
|
|
65630
65948
|
case 7:
|
|
65631
|
-
|
|
65632
|
-
|
|
65633
|
-
throw otError(errors.INVALID_ENCRYPTION_SECRET, new Error(`setEncryptionSecret: ${
|
|
65949
|
+
_context2.prev = 7;
|
|
65950
|
+
_context2.t0 = _context2["catch"](3);
|
|
65951
|
+
throw otError(errors.INVALID_ENCRYPTION_SECRET, new Error(`setEncryptionSecret: ${_context2.t0.message}`));
|
|
65634
65952
|
|
|
65635
65953
|
case 10:
|
|
65636
|
-
|
|
65637
|
-
|
|
65954
|
+
_context2.prev = 10;
|
|
65955
|
+
_context2.next = 13;
|
|
65638
65956
|
return _this.keyStore.set(sessionId, secret);
|
|
65639
65957
|
|
|
65640
65958
|
case 13:
|
|
65641
|
-
|
|
65959
|
+
_context2.next = 18;
|
|
65642
65960
|
break;
|
|
65643
65961
|
|
|
65644
65962
|
case 15:
|
|
65645
|
-
|
|
65646
|
-
|
|
65963
|
+
_context2.prev = 15;
|
|
65964
|
+
_context2.t1 = _context2["catch"](10);
|
|
65647
65965
|
|
|
65648
|
-
_logging.error(`Error in setEncryptionSecret}: ${
|
|
65966
|
+
_logging.error(`Error in setEncryptionSecret}: ${_context2.t1.message}`);
|
|
65649
65967
|
|
|
65650
65968
|
case 18:
|
|
65651
65969
|
case "end":
|
|
65652
|
-
return
|
|
65970
|
+
return _context2.stop();
|
|
65653
65971
|
}
|
|
65654
|
-
},
|
|
65972
|
+
}, _callee2, null, [[3, 7], [10, 15]]);
|
|
65655
65973
|
}));
|
|
65656
65974
|
|
|
65657
|
-
return function (
|
|
65658
|
-
return
|
|
65975
|
+
return function (_x2) {
|
|
65976
|
+
return _ref4.apply(this, arguments);
|
|
65659
65977
|
};
|
|
65660
65978
|
}();
|
|
65661
65979
|
|