audio2d
Version:
Easy to use API to add the power of web audio to your game.
553 lines (487 loc) • 39.2 kB
JavaScript
'use strict';
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AudioClip = void 0;
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _AudioClipState = require("./enums/AudioClipState");
/**
* An audio clip represents a piece of audio, which is either an audio html element or an audio boffer, as
* a playable clip with extra properties.
*/
var AudioClip = /*#__PURE__*/function () {
/**
* The name of the audio clip.
*
* @private
*
* @property {string}
*/
/**
* A reference to the audio to play.
*
* @private
*
* @property
*/
/**
* The audio buffer source of the clip.
*
* @private
*
* @property {AudioBufferSourceNode}
*/
/**
* A reference to the options for this audio clip.
*
* @private
*
* @property {AudioClipOptions}
*/
/**
* A reference to the gain node for this clip.
*
* @private
*
* @property {GainNode}
*/
/**
* The current state of this clip.
*
* @private
*
* @property {AudioClipState}
*/
/**
* The number of times this clip has been played.
*
* @private
*
* @property
*/
/**
* The time that this clip start being played at.
*
* @private
*
* @property {number}
*/
/**
* When the clip is paused, this will keep track of when it was paused so it can be resumed at that time.
*
* @private
*
* @property {number}
*/
/**
* The current time of the clip.
*
* @private
*
* @property {number}
*/
/**
* The duration of the clip.
*
* @private
*
* @property {number}
*/
/**
* The volume of this audio clip.
*
* @private
*
* @property {number}
*
* @default 100
*/
/**
* Keeps track of the previous volume of the clip.
*
* @private
*
* @property {number}
*/
/**
* A reference to the nodes that have been added for this clip.
*
* @private
*
* @property {Array<Node>}
*/
/**
* A reference to the nodes that have been added in a way that allows them to be retrieved easily.
*
* @private
*
* @property {*}
*/
/**
* Indicates whether this audio clip is played on a loop or not.
*
* @property {boolean}
*
* @default false
*/
/**
* @param {string} name The name of the audio clip.
* @param {AudioBuffer} audio The AudioBuffer that contains the audio of the clip.
* @param {AudioClipOptions} [options] The options passed to this audio clip.
*/
function AudioClip(name, audio, options) {
(0, _classCallCheck2["default"])(this, AudioClip);
(0, _defineProperty2["default"])(this, "_name", void 0);
(0, _defineProperty2["default"])(this, "_audio", void 0);
(0, _defineProperty2["default"])(this, "_source", void 0);
(0, _defineProperty2["default"])(this, "_options", void 0);
(0, _defineProperty2["default"])(this, "_gain", void 0);
(0, _defineProperty2["default"])(this, "_state", _AudioClipState.AudioClipState.STOPPED);
(0, _defineProperty2["default"])(this, "_timesPlayed", 0);
(0, _defineProperty2["default"])(this, "_timeStartedAt", 0);
(0, _defineProperty2["default"])(this, "_timePausedAt", 0);
(0, _defineProperty2["default"])(this, "_currentTime", 0);
(0, _defineProperty2["default"])(this, "_duration", void 0);
(0, _defineProperty2["default"])(this, "_volume", 100);
(0, _defineProperty2["default"])(this, "_previousVolume", 1);
(0, _defineProperty2["default"])(this, "_nodesref", []);
(0, _defineProperty2["default"])(this, "_nodes", {});
(0, _defineProperty2["default"])(this, "loop", false);
this._name = name;
this._audio = audio;
this._duration = audio.duration;
this._options = options;
this._gain = this._options.ctx.createGain();
this._gain.connect(this._options.ctx.destination);
if (this._options.trigger) this._setupTrigger();
if (!this._options.markers) this._options.markers = [];
}
/**
* Gets the name of the audio clip.
*
* @returns {string}
*/
(0, _createClass2["default"])(AudioClip, [{
key: "addNode",
/**
* Adds a custom node from `app.nodes[nodeName]`.
*
* @param {Node} node The node to add to this clip.
*
* @example
*
* const track = a2d.addAudio('track-1', track1Buffer);
*
* const bf = a2d.nodes.biquadFilter();
* track.addNode(bf);
*/
value: function addNode(node) {
this._nodes[node.name] = node.instance;
this._nodesref.push(node);
if (this._nodesref.length === 1) return;
var latestNode = this._nodesref[this._nodesref.length - 2];
node.instance.connect(latestNode.instance);
}
/**
* Plays this audio clip.
*
* @param {string} marker The name of the marker of the part of the clip to play.
*
* @example
*
* const sfxMarkers = [{ name: 'walk', start: 1500, duration: 1000 }, { name: 'fall': start: 2500, duration: 1500 }];
* const sfx = a2d.addAudio('sfx', sfxBuffer, { markers: sxfMarkers });
*
* // play just the falling sound.
* sfx.play('fall');
*/
}, {
key: "play",
value: function play(marker) {
var offset = this._timePausedAt;
this._source = this._options.ctx.createBufferSource();
this._source.buffer = this._audio;
this._source.loop = this.loop;
this._connectNodes();
this._oncomplete();
if (marker) {
var _this$_options$marker;
var clipMarker = (_this$_options$marker = this._options.markers) === null || _this$_options$marker === void 0 ? void 0 : _this$_options$marker.find(function (m) {
return m.name === marker;
});
if (!clipMarker) return;
this._source.start(0, clipMarker.start / 1000, clipMarker.duration ? clipMarker.duration / 1000 : undefined);
this._resetA2DMarkers(clipMarker);
} else {
this._source.start();
}
this._timeStartedAt = this._options.ctx.currentTime - offset;
this._timePausedAt = 0;
this._state = _AudioClipState.AudioClipState.PLAYING;
this._timesPlayed++;
}
/**
* Pause the currently playing audio.
*
* @example
*
* const sfx = a2d.addAudio('sfx', sfxBuffer);
* sfx.play();
*
* setTimeout(() => {
* sfx.pause();
* }, 1000);
*/
}, {
key: "pause",
value: function pause() {
var _this$_options$marker2;
var elapsed = this._options.ctx.currentTime - this._timeStartedAt;
this.stop();
this._timePausedAt = elapsed;
(_this$_options$marker2 = this._options.markers) === null || _this$_options$marker2 === void 0 ? void 0 : _this$_options$marker2.push({
name: 'a2d-pause',
start: this._timePausedAt * 1000
});
this._state = _AudioClipState.AudioClipState.PAUSED;
}
/**
* Resumes playing this clip from when it was paused.
*
* @example
*
* const sfx = a2d.addAudio('sfx', sfxBuffer);
* sfx.play();
* sfx.pause();
*
* setTimeout(() => {
* sfx.resume();
* }, 1000);
*/
}, {
key: "resume",
value: function resume() {
this.play('a2d-pause');
}
/**
* Stops the playback of this audio.
*
* @returns {AudioClip} Returns this for chaining.
*
* @example
*
* const sfx = a2d.addAudio('sfx', sfxBuffer);
*
* sfx.play();
* sfx.stop();
*/
}, {
key: "stop",
value: function stop() {
this._source.disconnect();
this._source = this._options.ctx.createBufferSource();
this._timePausedAt = 0;
this._timeStartedAt = 0;
this._state = _AudioClipState.AudioClipState.STOPPED;
}
/**
* Seeks to a specific time in the clip.
*
* @param {number} time The time, in milliseconds, to seek to.
*/
}, {
key: "seek",
value: function seek(time) {
var _this$_options$marker3;
if (!time) return;
if (time > this.duration * 1000) {
console.warn('The time to seek to is greater than the duration of the clip.');
return;
}
if (this._state === _AudioClipState.AudioClipState.PLAYING) this.stop();
(_this$_options$marker3 = this._options.markers) === null || _this$_options$marker3 === void 0 ? void 0 : _this$_options$marker3.push({
name: 'a2d-seek',
start: time
});
this.play('a2d-seek');
}
/**
* Mutes this clip.
*
* @example
*
* const sfx = a2d.addAudio('sfx', sfxBuffer);
*
* sfx.play();
* sfx.mute();
*/
}, {
key: "mute",
value: function mute() {
this._previousVolume = this.volume;
this.volume = 0;
}
/**
* Puts the volume back to the value it was at before the clip was muted.
*
* @example
*
* const sfx = a2d.addAudio('sfx', sfxBuffer);
* sfx.play();
*
* sfx.mute();
* sfx.unmute();
*/
}, {
key: "unmute",
value: function unmute() {
this.volume = this._previousVolume;
}
/**
* Sets up an onclick event on a trigger element if one was provided in the options.
*
* @private
*/
}, {
key: "_setupTrigger",
value: function _setupTrigger() {
var _this = this;
var el = document.querySelector(this._options.trigger);
if (!el) return;
el.addEventListener('click', function () {
return _this.play();
});
}
/**
* Connects the nodes that have been added through `addNode`.
*
* @private
*/
}, {
key: "_connectNodes",
value: function _connectNodes() {
if (this._nodesref.length > 0) {
var firstNode = this._nodesref[0];
var latestNode = this._nodesref[this._nodesref.length - 1];
this._source.connect(latestNode.instance);
firstNode.instance.connect(this._gain);
} else {
this._source.connect(this._gain);
}
}
/**
* Specify what happens when a clip is finished playing.
*
* @private
*/
}, {
key: "_oncomplete",
value: function _oncomplete() {
var _this2 = this;
this._source.onended = function () {
_this2._state = _AudioClipState.AudioClipState.STOPPED;
_this2._source.onended = null;
};
}
/**
* Resets any markers set internally.
*
* @private
*
* @param {Marker} clipMarker The marker to check if should be removed.
*/
}, {
key: "_resetA2DMarkers",
value: function _resetA2DMarkers(clipMarker) {
if (clipMarker.name.includes('a2d')) {
var _this$_options$marker4;
this._options.markers = (_this$_options$marker4 = this._options.markers) === null || _this$_options$marker4 === void 0 ? void 0 : _this$_options$marker4.filter(function (marker) {
!marker.name.includes('a2d');
});
}
}
}, {
key: "name",
get: function get() {
return this._name;
}
/**
* Gets the current state of the audio clip.
*
* @returns {string}
*/
}, {
key: "state",
get: function get() {
return this._state;
}
/**
* Gets the number of times that this clip has been played.
*
* @returns {number}
*/
}, {
key: "timesPlayed",
get: function get() {
return this._timesPlayed;
}
/**
* Gets the current time of the clip.
*
* @returns {number}
*/
}, {
key: "currentTime",
get: function get() {
if (this._state === _AudioClipState.AudioClipState.PAUSED) return this._timePausedAt;
if (this._state === _AudioClipState.AudioClipState.PLAYING) return this._options.ctx.currentTime - this._timeStartedAt;
return 0;
}
/**
* Gets the duration of the clip.
*
* @returns {number}
*/
}, {
key: "duration",
get: function get() {
return this._duration;
}
/**
* Gets the volume of this clip.
*
* @returns {number}
*/
}, {
key: "volume",
get: function get() {
return this._volume;
}
/**
* Sets the volume of this clip.
*
* @param {number} vol The new volume of the clip.
*/
,
set: function set(vol) {
this._volume = vol;
this._gain.gain.setValueAtTime(this._volume / 100, this._options.ctx.currentTime);
}
/**
* Gets the created nodes.
*
* @returns {*}
*/
}, {
key: "nodes",
get: function get() {
return this._nodes;
}
}]);
return AudioClip;
}();
exports.AudioClip = AudioClip;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9hdWRpb19jbGlwLnRzIl0sIm5hbWVzIjpbIkF1ZGlvQ2xpcCIsIm5hbWUiLCJhdWRpbyIsIm9wdGlvbnMiLCJBdWRpb0NsaXBTdGF0ZSIsIlNUT1BQRUQiLCJfbmFtZSIsIl9hdWRpbyIsIl9kdXJhdGlvbiIsImR1cmF0aW9uIiwiX29wdGlvbnMiLCJfZ2FpbiIsImN0eCIsImNyZWF0ZUdhaW4iLCJjb25uZWN0IiwiZGVzdGluYXRpb24iLCJ0cmlnZ2VyIiwiX3NldHVwVHJpZ2dlciIsIm1hcmtlcnMiLCJub2RlIiwiX25vZGVzIiwiaW5zdGFuY2UiLCJfbm9kZXNyZWYiLCJwdXNoIiwibGVuZ3RoIiwibGF0ZXN0Tm9kZSIsIm1hcmtlciIsIm9mZnNldCIsIl90aW1lUGF1c2VkQXQiLCJfc291cmNlIiwiY3JlYXRlQnVmZmVyU291cmNlIiwiYnVmZmVyIiwibG9vcCIsIl9jb25uZWN0Tm9kZXMiLCJfb25jb21wbGV0ZSIsImNsaXBNYXJrZXIiLCJmaW5kIiwibSIsInN0YXJ0IiwidW5kZWZpbmVkIiwiX3Jlc2V0QTJETWFya2VycyIsIl90aW1lU3RhcnRlZEF0IiwiY3VycmVudFRpbWUiLCJfc3RhdGUiLCJQTEFZSU5HIiwiX3RpbWVzUGxheWVkIiwiZWxhcHNlZCIsInN0b3AiLCJQQVVTRUQiLCJwbGF5IiwiZGlzY29ubmVjdCIsInRpbWUiLCJjb25zb2xlIiwid2FybiIsIl9wcmV2aW91c1ZvbHVtZSIsInZvbHVtZSIsImVsIiwiZG9jdW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiYWRkRXZlbnRMaXN0ZW5lciIsImZpcnN0Tm9kZSIsIm9uZW5kZWQiLCJpbmNsdWRlcyIsImZpbHRlciIsIl92b2x1bWUiLCJ2b2wiLCJnYWluIiwic2V0VmFsdWVBdFRpbWUiXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7QUFPQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtJQUNhQSxTO0FBQ1Q7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FB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ZCxDQUFrQjhCLFdBQWxCLEdBQWdDLEtBQUtELGNBQTVDO0FBRTVDLGFBQU8sQ0FBUDtBQUNIO0FBRUQ7QUFDSjtBQUNBO0FBQ0E7QUFDQTs7Ozt3QkFDMkI7QUFBRSxhQUFPLEtBQUtqQyxTQUFaO0FBQXdCO0FBRWpEO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7Ozs7d0JBQ3lCO0FBQUUsYUFBTyxLQUFLd0QsT0FBWjtBQUFzQjtBQUU3QztBQUNKO0FBQ0E7QUFDQTtBQUNBOztzQkFDZUMsRyxFQUFhO0FBQ3BCLFdBQUtELE9BQUwsR0FBZUMsR0FBZjs7QUFDQSxXQUFLdEQsS0FBTCxDQUFXdUQsSUFBWCxDQUFnQkMsY0FBaEIsQ0FBK0IsS0FBS0gsT0FBTCxHQUFlLEdBQTlDLEVBQW1ELEtBQUt0RCxRQUFMLENBQWNFLEdBQWQsQ0FBa0I4QixXQUFyRTtBQUNIO0FBRUQ7QUFDSjtBQUNBO0FBQ0E7QUFDQTs7Ozt3QkFDcUI7QUFBRSxhQUFPLEtBQUt0QixNQUFaO0FBQXFCIiwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBzdHJpY3QnXHJcblxyXG5pbXBvcnQgeyBBdWRpb0NsaXBPcHRpb25zIH0gZnJvbSAnLi9pbnRlcmZhY2VzL0F1ZGlvQ2xpcE9wdGlvbnMnO1xyXG5cclxuaW1wb3J0IHsgTm9kZSB9IGZyb20gJy4vaW50ZXJmYWNlcy9Ob2RlJztcclxuaW1wb3J0IHsgTWFya2VyIH0gZnJvbSAnLi9pbnRlcmZhY2VzL01hcmtlcic7XHJcblxyXG5pbXBvcnQgeyBBdWRpb0NsaXBTdGF0ZSB9IGZyb20gJy4vZW51bXMvQXVkaW9DbGlwU3RhdGUnXHJcblxyXG4vKipcclxuICogQW4gYXVkaW8gY2xpcCByZXByZXNlbnRzIGEgcGllY2Ugb2YgYXVkaW8sIHdoaWNoIGlzIGVpdGhlciBhbiBhdWRpbyBodG1sIGVsZW1lbnQgb3IgYW4gYXVkaW8gYm9mZmVyLCBhc1xyXG4gKiBhIHBsYXlhYmxlIGNsaXAgd2l0aCBleHRyYSBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuZXhwb3J0IGNsYXNzIEF1ZGlvQ2xpcCB7XHJcbiAgICAvKipcclxuICAgICAqIFRoZSBuYW1lIG9mIHRoZSBhdWRpbyBjbGlwLlxyXG4gICAgICogXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICogXHJcbiAgICAgKiBAcHJvcGVydHkge3N0cmluZ31cclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfbmFtZTogc3RyaW5nO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQSByZWZlcmVuY2UgdG8gdGhlIGF1ZGlvIHRvIHBsYXkuXHJcbiAgICAgKiBcclxuICAgICAqIEBwcml2YXRlXHJcbiAgICAgKiBcclxuICAgICAqIEBwcm9wZXJ0eSBcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfYXVkaW86IGFueTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBhdWRpbyBidWZmZXIgc291cmNlIG9mIHRoZSBjbGlwLlxyXG4gICAgICogXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICogXHJcbiAgICAgKiBAcHJvcGVydHkge0F1ZGlvQnVmZmVyU291cmNlTm9kZX1cclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfc291cmNlITogQXVkaW9CdWZmZXJTb3VyY2VOb2RlO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQSByZWZlcmVuY2UgdG8gdGhlIG9wdGlvbnMgZm9yIHRoaXMgYXVkaW8gY2xpcC5cclxuICAgICAqIFxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqIFxyXG4gICAgICogQHByb3BlcnR5IHtBdWRpb0NsaXBPcHRpb25zfVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9vcHRpb25zOiBBdWRpb0NsaXBPcHRpb25zO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQSByZWZlcmVuY2UgdG8gdGhlIGdhaW4gbm9kZSBmb3IgdGhpcyBjbGlwLlxyXG4gICAgICogXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICogXHJcbiAgICAgKiBAcHJvcGVydHkge0dhaW5Ob2RlfVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9nYWluOiBHYWluTm9kZTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBjdXJyZW50IHN0YXRlIG9mIHRoaXMgY2xpcC5cclxuICAgICAqIFxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqIFxyXG4gICAgICogQHByb3BlcnR5IHtBdWRpb0NsaXBTdGF0ZX1cclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfc3RhdGU6IEF1ZGlvQ2xpcFN0YXRlID0gQXVkaW9DbGlwU3RhdGUuU1RPUFBFRDtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBudW1iZXIgb2YgdGltZXMgdGhpcyBjbGlwIGhhcyBiZWVuIHBsYXllZC5cclxuICAgICAqIFxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqIFxyXG4gICAgICogQHByb3BlcnR5IFxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF90aW1lc1BsYXllZDogbnVtYmVyID0gMDtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSB0aW1lIHRoYXQgdGhpcyBjbGlwIHN0YXJ0IGJlaW5nIHBsYXllZCBhdC5cclxuICAgICAqIFxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqIFxyXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9XHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgX3RpbWVTdGFydGVkQXQ6IG51bWJlciA9IDA7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBXaGVuIHRoZSBjbGlwIGlzIHBhdXNlZCwgdGhpcyB3aWxsIGtlZXAgdHJhY2sgb2Ygd2hlbiBpdCB3YXMgcGF1c2VkIHNvIGl0IGNhbiBiZSByZXN1bWVkIGF0IHRoYXQgdGltZS5cclxuICAgICAqIFxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqIFxyXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9XHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgX3RpbWVQYXVzZWRBdDogbnVtYmVyID0gMDtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBjdXJyZW50IHRpbWUgb2YgdGhlIGNsaXAuXHJcbiAgICAgKiBcclxuICAgICAqIEBwcml2YXRlXHJcbiAgICAgKiBcclxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9jdXJyZW50VGltZTogbnVtYmVyID0gMDtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBkdXJhdGlvbiBvZiB0aGUgY2xpcC5cclxuICAgICAqIFxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqIFxyXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9XHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgX2R1cmF0aW9uOiBudW1iZXI7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUaGUgdm9sdW1lIG9mIHRoaXMgYXVkaW8gY2xpcC5cclxuICAgICAqIFxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqIFxyXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9XHJcbiAgICAgKiBcclxuICAgICAqIEBkZWZhdWx0IDEwMFxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF92b2x1bWU6IG51bWJlciA9IDEwMDtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEtlZXBzIHRyYWNrIG9mIHRoZSBwcmV2aW91cyB2b2x1bWUgb2YgdGhlIGNsaXAuXHJcbiAgICAgKiBcclxuICAgICAqIEBwcml2YXRlXHJcbiAgICAgKiBcclxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9wcmV2aW91c1ZvbHVtZTogbnVtYmVyID0gMTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEEgcmVmZXJlbmNlIHRvIHRoZSBub2RlcyB0aGF0IGhhdmUgYmVlbiBhZGRlZCBmb3IgdGhpcyBjbGlwLlxyXG4gICAgICogXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICogXHJcbiAgICAgKiBAcHJvcGVydHkge0FycmF5PE5vZGU+fVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9ub2Rlc3JlZjogQXJyYXk8Tm9kZT4gPSBbXTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEEgcmVmZXJlbmNlIHRvIHRoZSBub2RlcyB0aGF0IGhhdmUgYmVlbiBhZGRlZCBpbiBhIHdheSB0aGF0IGFsbG93cyB0aGVtIHRvIGJlIHJldHJpZXZlZCBlYXNpbHkuXHJcbiAgICAgKiBcclxuICAgICAqIEBwcml2YXRlXHJcbiAgICAgKiBcclxuICAgICAqIEBwcm9wZXJ0eSB7Kn1cclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfbm9kZXM6IGFueSA9IHt9O1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogSW5kaWNhdGVzIHdoZXRoZXIgdGhpcyBhdWRpbyBjbGlwIGlzIHBsYXllZCBvbiBhIGxvb3Agb3Igbm90LlxyXG4gICAgICogXHJcbiAgICAgKiBAcHJvcGVydHkge2Jvb2xlYW59XHJcbiAgICAgKiBcclxuICAgICAqIEBkZWZhdWx0IGZhbHNlXHJcbiAgICAgKi9cclxuICAgIGxvb3A6IGJvb2xlYW4gPSBmYWxzZTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIFRoZSBuYW1lIG9mIHRoZSBhdWRpbyBjbGlwLlxyXG4gICAgICogQHBhcmFtIHtBdWRpb0J1ZmZlcn0gYXVkaW8gVGhlIEF1ZGlvQnVmZmVyIHRoYXQgY29udGFpbnMgdGhlIGF1ZGlvIG9mIHRoZSBjbGlwLlxyXG4gICAgICogQHBhcmFtIHtBdWRpb0NsaXBPcHRpb25zfSBbb3B0aW9uc10gVGhlIG9wdGlvbnMgcGFzc2VkIHRvIHRoaXMgYXVkaW8gY2xpcC5cclxuICAgICAqL1xyXG4gICAgY29uc3RydWN0b3IobmFtZTogc3RyaW5nLCBhdWRpbzogQXVkaW9CdWZmZXIsIG9wdGlvbnM6IEF1ZGlvQ2xpcE9wdGlvbnMpIHtcclxuICAgICAgICB0aGlzLl9uYW1lID0gbmFtZTtcclxuICAgICAgICB0aGlzLl9hdWRpbyA9IGF1ZGlvO1xyXG4gICAgICAgIHRoaXMuX2R1cmF0aW9uID0gYXVkaW8uZHVyYXRpb247XHJcbiAgICAgICAgdGhpcy5fb3B0aW9ucyA9IG9wdGlvbnM7XHJcblxyXG4gICAgICAgIHRoaXMuX2dhaW4gPSB0aGlzLl9vcHRpb25zLmN0eC5jcmVhdGVHYWluKCk7XHJcbiAgICAgICAgdGhpcy5fZ2Fpbi5jb25uZWN0KHRoaXMuX29wdGlvbnMuY3R4LmRlc3RpbmF0aW9uKTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuX29wdGlvbnMudHJpZ2dlcikgdGhpcy5fc2V0dXBUcmlnZ2VyKCk7XHJcbiAgICAgICAgaWYgKCF0aGlzLl9vcHRpb25zLm1hcmtlcnMpIHRoaXMuX29wdGlvbnMubWFya2VycyA9IFtdO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogR2V0cyB0aGUgbmFtZSBvZiB0aGUgYXVkaW8gY2xpcC5cclxuICAgICAqIFxyXG4gICAgICogQHJldHVybnMge3N0cmluZ31cclxuICAgICAqL1xyXG4gICAgZ2V0IG5hbWUoKTogc3RyaW5nIHsgcmV0dXJuIHRoaXMuX25hbWU7IH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEdldHMgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIGF1ZGlvIGNsaXAuXHJcbiAgICAgKiBcclxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9XHJcbiAgICAgKi9cclxuICAgIGdldCBzdGF0ZSgpOiBzdHJpbmcgeyByZXR1cm4gdGhpcy5fc3RhdGU7IH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEdldHMgdGhlIG51bWJlciBvZiB0aW1lcyB0aGF0IHRoaXMgY2xpcCBoYXMgYmVlbiBwbGF5ZWQuXHJcbiAgICAgKiBcclxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9XHJcbiAgICAgKi9cclxuICAgIGdldCB0aW1lc1BsYXllZCgpOiBudW1iZXIgeyByZXR1cm4gdGhpcy5fdGltZXNQbGF5ZWQ7IH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEdldHMgdGhlIGN1cnJlbnQgdGltZSBvZiB0aGUgY2xpcC5cclxuICAgICAqIFxyXG4gICAgICogQHJldHVybnMge251bWJlcn1cclxuICAgICAqL1xyXG4gICAgZ2V0IGN1cnJlbnRUaW1lKCk6IG51bWJlciB7XHJcbiAgICAgICAgaWYgKHRoaXMuX3N0YXRlID09PSBBdWRpb0NsaXBTdGF0ZS5QQVVTRUQpIHJldHVybiB0aGlzLl90aW1lUGF1c2VkQXQ7XHJcbiAgICAgICAgaWYgKHRoaXMuX3N0YXRlID09PSBBdWRpb0NsaXBTdGF0ZS5QTEFZSU5HKSByZXR1cm4gdGhpcy5fb3B0aW9ucy5jdHguY3VycmVudFRpbWUgLSB0aGlzLl90aW1lU3RhcnRlZEF0O1xyXG5cclxuICAgICAgICByZXR1cm4gMDtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEdldHMgdGhlIGR1cmF0aW9uIG9mIHRoZSBjbGlwLlxyXG4gICAgICogXHJcbiAgICAgKiBAcmV0dXJucyB7bnVtYmVyfVxyXG4gICAgICovXHJcbiAgICBnZXQgZHVyYXRpb24oKTogbnVtYmVyIHsgcmV0dXJuIHRoaXMuX2R1cmF0aW9uOyB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBHZXRzIHRoZSB2b2x1bWUgb2YgdGhpcyBjbGlwLlxyXG4gICAgICogXHJcbiAgICAgKiBAcmV0dXJucyB7bnVtYmVyfVxyXG4gICAgICovXHJcbiAgICBnZXQgdm9sdW1lKCk6IG51bWJlciB7IHJldHVybiB0aGlzLl92b2x1bWU7IH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFNldHMgdGhlIHZvbHVtZSBvZiB0aGlzIGNsaXAuXHJcbiAgICAgKiBcclxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB2b2wgVGhlIG5ldyB2b2x1bWUgb2YgdGhlIGNsaXAuXHJcbiAgICAgKi9cclxuICAgIHNldCB2b2x1bWUodm9sOiBudW1iZXIpIHtcclxuICAgICAgICB0aGlzLl92b2x1bWUgPSB2b2w7XHJcbiAgICAgICAgdGhpcy5fZ2Fpbi5nYWluLnNldFZhbHVlQXRUaW1lKHRoaXMuX3ZvbHVtZSAvIDEwMCwgdGhpcy5fb3B0aW9ucy5jdHguY3VycmVudFRpbWUpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogR2V0cyB0aGUgY3JlYXRlZCBub2Rlcy5cclxuICAgICAqIFxyXG4gICAgICogQHJldHVybnMgeyp9XHJcbiAgICAgKi9cclxuICAgIGdldCBub2RlcygpOiBhbnkgeyByZXR1cm4gdGhpcy5fbm9kZXM7IH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEFkZHMgYSBjdXN0b20gbm9kZSBmcm9tIGBhcHAubm9kZXNbbm9kZU5hbWVdYC5cclxuICAgICAqIFxyXG4gICAgICogQHBhcmFtIHtOb2RlfSBub2RlIFRoZSBub2RlIHRvIGFkZCB0byB0aGlzIGNsaXAuXHJcbiAgICAgKiBcclxuICAgICAqIEBleGFtcGxlXHJcbiAgICAgKiBcclxuICAgICAqIGNvbnN0IHRyYWNrID0gYTJkLmFkZEF1ZGlvKCd0cmFjay0xJywgdHJhY2sxQnVmZmVyKTtcclxuICAgICAqIFxyXG4gICAgICogY29uc3QgYmYgPSBhMmQubm9kZXMuYmlxdWFkRmlsdGVyKCk7XHJcbiAgICAgKiB0cmFjay5hZGROb2RlKGJmKTtcclxuICAgICAqL1xyXG4gICAgYWRkTm9kZShub2RlOiBOb2RlKSB7XHJcbiAgICAgICAgdGhpcy5fbm9kZXNbbm9kZS5uYW1lXSA9IG5vZGUuaW5zdGFuY2U7XHJcbiAgICAgICAgdGhpcy5fbm9kZXNyZWYucHVzaChub2RlKTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuX25vZGVzcmVmLmxlbmd0aCA9PT0gMSkgcmV0dXJuO1xyXG5cclxuICAgICAgICBjb25zdCBsYXRlc3ROb2RlOiBOb2RlID0gdGhpcy5fbm9kZXNyZWZbdGhpcy5fbm9kZXNyZWYubGVuZ3RoIC0gMl07XHJcbiAgICAgICAgbm9kZS5pbnN0YW5jZS5jb25uZWN0KGxhdGVzdE5vZGUuaW5zdGFuY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUGxheXMgdGhpcyBhdWRpbyBjbGlwLlxyXG4gICAgICogXHJcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbWFya2VyIFRoZSBuYW1lIG9mIHRoZSBtYXJrZXIgb2YgdGhlIHBhcnQgb2YgdGhlIGNsaXAgdG8gcGxheS5cclxuICAgICAqIFxyXG4gICAgICogQGV4YW1wbGVcclxuICAgICAqIFxyXG4gICAgICogY29uc3Qgc2Z4TWFya2VycyA9IFt7IG5hbWU6ICd3YWxrJywgc3RhcnQ6IDE1MDAsIGR1cmF0aW9uOiAxMDAwIH0sIHsgbmFtZTogJ2ZhbGwnOiBzdGFydDogMjUwMCwgZHVyYXRpb246IDE1MDAgfV07XHJcbiAgICAgKiBjb25zdCBzZnggPSBhMmQuYWRkQXVkaW8oJ3NmeCcsIHNmeEJ1ZmZlciwgeyBtYXJrZXJzOiBzeGZNYXJrZXJzIH0pO1xyXG4gICAgICogXHJcbiAgICAgKiAvLyBwbGF5IGp1c3QgdGhlIGZhbGxpbmcgc291bmQuXHJcbiAgICAgKiBzZngucGxheSgnZmFsbCcpO1xyXG4gICAgICovXHJcbiAgICBwbGF5KG1hcmtlcj86IHN0cmluZykge1xyXG4gICAgICAgIGNvbnN0IG9mZnNldDogbnVtYmVyID0gdGhpcy5fdGltZVBhdXNlZEF0O1xyXG5cclxuICAgICAgICB0aGlzLl9zb3VyY2UgPSB0aGlzLl9vcHRpb25zLmN0eC5jcmVhdGVCdWZmZXJTb3VyY2UoKTtcclxuICAgICAgICB0aGlzLl9zb3VyY2UuYnVmZmVyID0gdGhpcy5fYXVkaW87XHJcbiAgICAgICAgdGhpcy5fc291cmNlLmxvb3AgPSB0aGlzLmxvb3A7XHJcblxyXG4gICAgICAgIHRoaXMuX2Nvbm5lY3ROb2RlcygpO1xyXG4gICAgICAgIHRoaXMuX29uY29tcGxldGUoKTtcclxuXHJcbiAgICAgICAgaWYgKG1hcmtlcikge1xyXG4gICAgICAgICAgICBjb25zdCBjbGlwTWFya2VyOiAoTWFya2VyIHwgdW5kZWZpbmVkKSA9IHRoaXMuX29wdGlvbnMubWFya2Vycz8uZmluZCgobTogTWFya2VyKSA9PiBtLm5hbWUgPT09IG1hcmtlcik7XHJcbiAgICAgICAgICAgIGlmICghY2xpcE1hcmtlcikgcmV0dXJuO1xyXG5cclxuICAgICAgICAgICAgdGhpcy5fc291cmNlLnN0YXJ0KDAsIGNsaXBNYXJrZXIuc3RhcnQgLyAxMDAwLCBjbGlwTWFya2VyLmR1cmF0aW9uID8gY2xpcE1hcmtlci5kdXJhdGlvbiAvIDEwMDAgOiB1bmRlZmluZWQpO1xyXG4gICAgICAgICAgICB0aGlzLl9yZXNldEEyRE1hcmtlcnMoY2xpcE1hcmtlcik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5fc291cmNlLnN0YXJ0KCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLl90aW1lU3RhcnRlZEF0ID0gdGhpcy5fb3B0aW9ucy5jdHguY3VycmVudFRpbWUgLSBvZmZzZXQ7XHJcbiAgICAgICAgdGhpcy5fdGltZVBhdXNlZEF0ID0gMDtcclxuXHJcbiAgICAgICAgdGhpcy5fc3RhdGUgPSBBdWRpb0NsaXBTdGF0ZS5QTEFZSU5HO1xyXG4gICAgICAgIHRoaXMuX3RpbWVzUGxheWVkKys7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBQYXVzZSB0aGUgY3VycmVudGx5IHBsYXlpbmcgYXVkaW8uXHJcbiAgICAgKiBcclxuICAgICAqIEBleGFtcGxlXHJcbiAgICAgKiBcclxuICAgICAqIGNvbnN0IHNmeCA9IGEyZC5hZGRBdWRpbygnc2Z4Jywgc2Z4QnVmZmVyKTtcclxuICAgICAqIHNmeC5wbGF5KCk7XHJcbiAgICAgKiBcclxuICAgICAqIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICogICBzZngucGF1c2UoKTtcclxuICAgICAqIH0sIDEwMDApO1xyXG4gICAgICovXHJcbiAgICBwYXVzZSgpIHtcclxuICAgICAgICBjb25zdCBlbGFwc2VkOiBudW1iZXIgPSB0aGlzLl9vcHRpb25zLmN0eC5jdXJyZW50VGltZSAtIHRoaXMuX3RpbWVTdGFydGVkQXQ7XHJcblxyXG4gICAgICAgIHRoaXMuc3RvcCgpO1xyXG5cclxuICAgICAgICB0aGlzLl90aW1lUGF1c2VkQXQgPSBlbGFwc2VkXHJcbiAgICAgICAgdGhpcy5fb3B0aW9ucy5tYXJrZXJzPy5wdXNoKHsgbmFtZTogJ2EyZC1wYXVzZScsIHN0YXJ0OiB0aGlzLl90aW1lUGF1c2VkQXQgKiAxMDAwIH0pO1xyXG5cclxuICAgICAgICB0aGlzLl9zdGF0ZSA9IEF1ZGlvQ2xpcFN0YXRlLlBBVVNFRDtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFJlc3VtZXMgcGxheWluZyB0aGlzIGNsaXAgZnJvbSB3aGVuIGl0IHdhcyBwYXVzZWQuXHJcbiAgICAgKiBcclxuICAgICAqIEBleGFtcGxlXHJcbiAgICAgKiBcclxuICAgICAqIGNvbnN0IHNmeCA9IGEyZC5hZGRBdWRpbygnc2Z4Jywgc2Z4QnVmZmVyKTtcclxuICAgICAqIHNmeC5wbGF5KCk7XHJcbiAgICAgKiBzZngucGF1c2UoKTtcclxuICAgICAqIFxyXG4gICAgICogc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgKiAgIHNmeC5yZXN1bWUoKTtcclxuICAgICAqIH0sIDEwMDApO1xyXG4gICAgICovXHJcbiAgICByZXN1bWUoKSB7XHJcbiAgICAgICAgdGhpcy5wbGF5KCdhMmQtcGF1c2UnKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFN0b3BzIHRoZSBwbGF5YmFjayBvZiB0aGlzIGF1ZGlvLlxyXG4gICAgICogXHJcbiAgICAgKiBAcmV0dXJucyB7QXVkaW9DbGlwfSBSZXR1cm5zIHRoaXMgZm9yIGNoYWluaW5nLlxyXG4gICAgICogXHJcbiAgICAgKiBAZXhhbXBsZVxyXG4gICAgICogXHJcbiAgICAgKiBjb25zdCBzZnggPSBhMmQuYWRkQXVkaW8oJ3NmeCcsIHNmeEJ1ZmZlcik7XHJcbiAgICAgKiBcclxuICAgICAqIHNmeC5wbGF5KCk7XHJcbiAgICAgKiBzZnguc3RvcCgpO1xyXG4gICAgICovXHJcbiAgICBzdG9wKCkge1xyXG4gICAgICAgIHRoaXMuX3NvdXJjZS5kaXNjb25uZWN0KCk7XHJcbiAgICAgICAgdGhpcy5fc291cmNlID0gdGhpcy5fb3B0aW9ucy5jdHguY3JlYXRlQnVmZmVyU291cmNlKCk7XHJcblxyXG4gICAgICAgIHRoaXMuX3RpbWVQYXVzZWRBdCA9IDA7XHJcbiAgICAgICAgdGhpcy5fdGltZVN0YXJ0ZWRBdCA9IDA7XHJcblxyXG4gICAgICAgIHRoaXMuX3N0YXRlID0gQXVkaW9DbGlwU3RhdGUuU1RPUFBFRDtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFNlZWtzIHRvIGEgc3BlY2lmaWMgdGltZSBpbiB0aGUgY2xpcC5cclxuICAgICAqIFxyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHRpbWUgVGhlIHRpbWUsIGluIG1pbGxpc2Vjb25kcywgdG8gc2VlayB0by5cclxuICAgICAqL1xyXG4gICAgc2Vlayh0aW1lOiBudW1iZXIpIHtcclxuICAgICAgICBpZiAoIXRpbWUpIHJldHVybjtcclxuXHJcbiAgICAgICAgaWYgKHRpbWUgPiB0aGlzLmR1cmF0aW9uICogMTAwMCkge1xyXG4gICAgICAgICAgICBjb25zb2xlLndhcm4oJ1RoZSB0aW1lIHRvIHNlZWsgdG8gaXMgZ3JlYXRlciB0aGFuIHRoZSBkdXJhdGlvbiBvZiB0aGUgY2xpcC4nKTtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRoaXMuX3N0YXRlID09PSBBdWRpb0NsaXBTdGF0ZS5QTEFZSU5HKSB0aGlzLnN0b3AoKTtcclxuXHJcbiAgICAgICAgdGhpcy5fb3B0aW9ucy5tYXJrZXJzPy5wdXNoKHsgbmFtZTogJ2EyZC1zZWVrJywgc3RhcnQ6IHRpbWUgfSk7XHJcbiAgICAgICAgdGhpcy5wbGF5KCdhMmQtc2VlaycpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogTXV0ZXMgdGhpcyBjbGlwLlxyXG4gICAgICogXHJcbiAgICAgKiBAZXhhbXBsZVxyXG4gICAgICogXHJcbiAgICAgKiBjb25zdCBzZnggPSBhMmQuYWRkQXVkaW8oJ3NmeCcsIHNmeEJ1ZmZlcik7XHJcbiAgICAgKiBcclxuICAgICAqIHNmeC5wbGF5KCk7XHJcbiAgICAgKiBzZngubXV0ZSgpO1xyXG4gICAgICovXHJcbiAgICBtdXRlKCkge1xyXG4gICAgICAgIHRoaXMuX3ByZXZpb3VzVm9sdW1lID0gdGhpcy52b2x1bWU7XHJcbiAgICAgICAgdGhpcy52b2x1bWUgPSAwO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUHV0cyB0aGUgdm9sdW1lIGJhY2sgdG8gdGhlIHZhbHVlIGl0IHdhcyBhdCBiZWZvcmUgdGhlIGNsaXAgd2FzIG11dGVkLlxyXG4gICAgICogXHJcbiAgICAgKiBAZXhhbXBsZVxyXG4gICAgICogXHJcbiAgICAgKiBjb25zdCBzZnggPSBhMmQuYWRkQXVkaW8oJ3NmeCcsIHNmeEJ1ZmZlcik7XHJcbiAgICAgKiBzZngucGxheSgpO1xyXG4gICAgICogXHJcbiAgICAgKiBzZngubXV0ZSgpO1xyXG4gICAgICogc2Z4LnVubXV0ZSgpO1xyXG4gICAgICovXHJcbiAgICB1bm11dGUoKSB7XHJcbiAgICAgICAgdGhpcy52b2x1bWUgPSB0aGlzLl9wcmV2aW91c1ZvbHVtZTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFNldHMgdXAgYW4gb25jbGljayBldmVudCBvbiBhIHRyaWdnZXIgZWxlbWVudCBpZiBvbmUgd2FzIHByb3ZpZGVkIGluIHRoZSBvcHRpb25zLlxyXG4gICAgICogXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9zZXR1cFRyaWdnZXIoKSB7XHJcbiAgICAgICAgY29uc3QgZWw6IChIVE1MRWxlbWVudCB8IG51bGwpID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLl9vcHRpb25zLnRyaWdnZXIhKTtcclxuICAgICAgICBpZiAoIWVsKSByZXR1cm47XHJcblxyXG4gICAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4gdGhpcy5wbGF5KCkpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ29ubmVjdHMgdGhlIG5vZGVzIHRoYXQgaGF2ZSBiZWVuIGFkZGVkIHRocm91Z2ggYGFkZE5vZGVgLlxyXG4gICAgICogXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9jb25uZWN0Tm9kZXMoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuX25vZGVzcmVmLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgY29uc3QgZmlyc3ROb2RlOiBOb2RlID0gdGhpcy5fbm9kZXNyZWZbMF07XHJcbiAgICAgICAgICAgIGNvbnN0IGxhdGVzdE5vZGU6IE5vZGUgPSB0aGlzLl9ub2Rlc3JlZlt0aGlzLl9ub2Rlc3JlZi5sZW5ndGggLSAxXVxyXG5cclxuICAgICAgICAgICAgdGhpcy5fc291cmNlLmNvbm5lY3QobGF0ZXN0Tm9kZS5pbnN0YW5jZSk7XHJcblxyXG4gICAgICAgICAgICBmaXJzdE5vZGUuaW5zdGFuY2UuY29ubmVjdCh0aGlzLl9nYWluKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICB0aGlzLl9zb3VyY2UuY29ubmVjdCh0aGlzLl9nYWluKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBTcGVjaWZ5IHdoYXQgaGFwcGVucyB3aGVuIGEgY2xpcCBpcyBmaW5pc2hlZCBwbGF5aW5nLlxyXG4gICAgICogXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9vbmNvbXBsZXRlKCkge1xyXG4gICAgICAgIHRoaXMuX3NvdXJjZS5vbmVuZGVkID0gKCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLl9zdGF0ZSA9IEF1ZGlvQ2xpcFN0YXRlLlNUT1BQRUQ7XHJcbiAgICAgICAgICAgIHRoaXMuX3NvdXJjZS5vbmVuZGVkID0gbnVsbDtcclxuICAgICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmVzZXRzIGFueSBtYXJrZXJzIHNldCBpbnRlcm5hbGx5LlxyXG4gICAgICogXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICogXHJcbiAgICAgKiBAcGFyYW0ge01hcmtlcn0gY2xpcE1hcmtlciBUaGUgbWFya2VyIHRvIGNoZWNrIGlmIHNob3VsZCBiZSByZW1vdmVkLlxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9yZXNldEEyRE1hcmtlcnMoY2xpcE1hcmtlcjogTWFya2VyKSB7XHJcbiAgICAgICAgaWYgKGNsaXBNYXJrZXIubmFtZS5pbmNsdWRlcygnYTJkJykpIHtcclxuICAgICAgICAgICAgdGhpcy5fb3B0aW9ucy5tYXJrZXJzID0gdGhpcy5fb3B0aW9ucy5tYXJrZXJzPy5maWx0ZXIoKG1hcmtlcjogTWFya2VyKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAhbWFya2VyLm5hbWUuaW5jbHVkZXMoJ2EyZCcpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn0iXX0=