(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Loader = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0 && arguments[0] !== undefined ? arguments[0] : ''; var concurrency = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10; _classCallCheck(this, Loader); /** * The base url for all resources loaded by this loader. * * @member {string} */ this.baseUrl = baseUrl; /** * The progress percent of the loader going through the queue. * * @member {number} */ this.progress = 0; /** * Loading state of the loader, true if it is currently loading resources. * * @member {boolean} */ this.loading = false; /** * A querystring to append to every URL added to the loader. * * This should be a valid query string *without* the question-mark (`?`). The loader will * also *not* escape values for you. Make sure to escape your parameters with * [`encodeURIComponent`](https://mdn.io/encodeURIComponent) before assigning this property. * * @example * const loader = new Loader(); * * loader.defaultQueryString = 'user=me&password=secret'; * * // This will request 'image.png?user=me&password=secret' * loader.add('image.png').load(); * * loader.reset(); * * // This will request 'image.png?v=1&user=me&password=secret' * loader.add('iamge.png?v=1').load(); */ this.defaultQueryString = ''; /** * The middleware to run before loading each resource. * * @member {function[]} */ this._beforeMiddleware = []; /** * The middleware to run after loading each resource. * * @member {function[]} */ this._afterMiddleware = []; /** * The tracks the resources we are currently completing parsing for. * * @member {Resource[]} */ this._resourcesParsing = []; /** * The `_loadResource` function bound with this object context. * * @private * @member {function} * @param {Resource} r - The resource to load * @param {Function} d - The dequeue function * @return {undefined} */ this._boundLoadResource = function (r, d) { return _this._loadResource(r, d); }; /** * The resources waiting to be loaded. * * @private * @member {Resource[]} */ this._queue = async.queue(this._boundLoadResource, concurrency); this._queue.pause(); /** * All the resources for this loader keyed by name. * * @member {object} */ this.resources = {}; /** * Dispatched once per loaded or errored resource. * * The callback looks like {@link Loader.OnProgressSignal}. * * @member {Signal} */ this.onProgress = new _miniSignals2.default(); /** * Dispatched once per errored resource. * * The callback looks like {@link Loader.OnErrorSignal}. * * @member {Signal} */ this.onError = new _miniSignals2.default(); /** * Dispatched once per loaded resource. * * The callback looks like {@link Loader.OnLoadSignal}. * * @member {Signal} */ this.onLoad = new _miniSignals2.default(); /** * Dispatched when the loader begins to process the queue. * * The callback looks like {@link Loader.OnStartSignal}. * * @member {Signal} */ this.onStart = new _miniSignals2.default(); /** * Dispatched when the queued resources all load. * * The callback looks like {@link Loader.OnCompleteSignal}. * * @member {Signal} */ this.onComplete = new _miniSignals2.default(); /** * When the progress changes the loader and resource are disaptched. * * @memberof Loader * @callback OnProgressSignal * @param {Loader} loader - The loader the progress is advancing on. * @param {Resource} resource - The resource that has completed or failed to cause the progress to advance. */ /** * When an error occurrs the loader and resource are disaptched. * * @memberof Loader * @callback OnErrorSignal * @param {Loader} loader - The loader the error happened in. * @param {Resource} resource - The resource that caused the error. */ /** * When a load completes the loader and resource are disaptched. * * @memberof Loader * @callback OnLoadSignal * @param {Loader} loader - The loader that laoded the resource. * @param {Resource} resource - The resource that has completed loading. */ /** * When the loader starts loading resources it dispatches this callback. * * @memberof Loader * @callback OnStartSignal * @param {Loader} loader - The loader that has started loading resources. */ /** * When the loader completes loading resources it dispatches this callback. * * @memberof Loader * @callback OnCompleteSignal * @param {Loader} loader - The loader that has finished loading resources. */ } /** * Adds a resource (or multiple resources) to the loader queue. * * This function can take a wide variety of different parameters. The only thing that is always * required the url to load. All the following will work: * * ```js * loader * // normal param syntax * .add('key', 'http://...', function () {}) * .add('http://...', function () {}) * .add('http://...') * * // object syntax * .add({ * name: 'key2', * url: 'http://...' * }, function () {}) * .add({ * url: 'http://...' * }, function () {}) * .add({ * name: 'key3', * url: 'http://...' * onComplete: function () {} * }) * .add({ * url: 'https://...', * onComplete: function () {}, * crossOrigin: true * }) * * // you can also pass an array of objects or urls or both * .add([ * { name: 'key4', url: 'http://...', onComplete: function () {} }, * { url: 'http://...', onComplete: function () {} }, * 'http://...' * ]) * * // and you can use both params and options * .add('key', 'http://...', { crossOrigin: true }, function () {}) * .add('http://...', { crossOrigin: true }, function () {}); * ``` * * @param {string} [name] - The name of the resource to load, if not passed the url is used. * @param {string} [url] - The url for this resource, relative to the baseUrl of this loader. * @param {object} [options] - The options for the load. * @param {boolean} [options.crossOrigin] - Is this request cross-origin? Default is to determine automatically. * @param {Resource.LOAD_TYPE} [options.loadType=Resource.LOAD_TYPE.XHR] - How should this resource be loaded? * @param {Resource.XHR_RESPONSE_TYPE} [options.xhrType=Resource.XHR_RESPONSE_TYPE.DEFAULT] - How should * the data being loaded be interpreted when using XHR? * @param {object} [options.metadata] - Extra configuration for middleware and the Resource object. * @param {HTMLImageElement|HTMLAudioElement|HTMLVideoElement} [options.metadata.loadElement=null] - The * element to use for loading, instead of creating one. * @param {boolean} [options.metadata.skipSource=false] - Skips adding source(s) to the load element. This * is useful if you want to pass in a `loadElement` that you already added load sources to. * @param {function} [cb] - Function to call when this specific resource completes loading. * @return {Loader} Returns itself. */ Loader.prototype.add = function add(name, url, options, cb) { // special case of an array of objects or urls if (Array.isArray(name)) { for (var i = 0; i < name.length; ++i) { this.add(name[i]); } return this; } // if an object is passed instead of params if ((typeof name === 'undefined' ? 'undefined' : _typeof(name)) === 'object') { cb = url || name.callback || name.onComplete; options = name; url = name.url; name = name.name || name.key || name.url; } // case where no name is passed shift all args over by one. if (typeof url !== 'string') { cb = options; options = url; url = name; } // now that we shifted make sure we have a proper url. if (typeof url !== 'string') { throw new Error('No url passed to add resource to loader.'); } // options are optional so people might pass a function and no options if (typeof options === 'function') { cb = options; options = null; } // if loading already you can only add resources that have a parent. if (this.loading && (!options || !options.parentResource)) { throw new Error('Cannot add resources while the loader is running.'); } // check if resource already exists. if (this.resources[name]) { throw new Error('Resource named "' + name + '" already exists.'); } // add base url if this isn't an absolute url url = this._prepareUrl(url); // create the store the resource this.resources[name] = new _Resource2.default(name, url, options); if (typeof cb === 'function') { this.resources[name].onAfterMiddleware.once(cb); } // if actively loading, make sure to adjust progress chunks for that parent and its children if (this.loading) { var parent = options.parentResource; var incompleteChildren = []; for (var _i = 0; _i < parent.children.length; ++_i) { if (!parent.children[_i].isComplete) { incompleteChildren.push(parent.children[_i]); } } var fullChunk = parent.progressChunk * (incompleteChildren.length + 1); // +1 for parent var eachChunk = fullChunk / (incompleteChildren.length + 2); // +2 for parent & new child parent.children.push(this.resources[name]); parent.progressChunk = eachChunk; for (var _i2 = 0; _i2 < incompleteChildren.length; ++_i2) { incompleteChildren[_i2].progressChunk = eachChunk; } this.resources[name].progressChunk = eachChunk; } // add the resource to the queue this._queue.push(this.resources[name]); return this; }; /** * Sets up a middleware function that will run *before* the * resource is loaded. * * @method before * @param {function} fn - The middleware function to register. * @return {Loader} Returns itself. */ Loader.prototype.pre = function pre(fn) { this._beforeMiddleware.push(fn); return this; }; /** * Sets up a middleware function that will run *after* the * resource is loaded. * * @alias use * @method after * @param {function} fn - The middleware function to register. * @return {Loader} Returns itself. */ Loader.prototype.use = function use(fn) { this._afterMiddleware.push(fn); return this; }; /** * Resets the queue of the loader to prepare for a new load. * * @return {Loader} Returns itself. */ Loader.prototype.reset = function reset() { this.progress = 0; this.loading = false; this._queue.kill(); this._queue.pause(); // abort all resource loads for (var k in this.resources) { var res = this.resources[k]; if (res._onLoadBinding) { res._onLoadBinding.detach(); } if (res.isLoading) { res.abort(); } } this.resources = {}; return this; }; /** * Starts loading the queued resources. * * @param {function} [cb] - Optional callback that will be bound to the `complete` event. * @return {Loader} Returns itself. */ Loader.prototype.load = function load(cb) { // register complete callback if they pass one if (typeof cb === 'function') { this.onComplete.once(cb); } // if the queue has already started we are done here if (this.loading) { return this; } if (this._queue.idle()) { this._onStart(); this._onComplete(); } else { // distribute progress chunks var numTasks = this._queue._tasks.length; var chunk = 100 / numTasks; for (var i = 0; i < this._queue._tasks.length; ++i) { this._queue._tasks[i].data.progressChunk = chunk; } // notify we are starting this._onStart(); // start loading this._queue.resume(); } return this; }; /** * The number of resources to load concurrently. * * @member {number} * @default 10 */ /** * Prepares a url for usage based on the configuration of this object * * @private * @param {string} url - The url to prepare. * @return {string} The prepared url. */ Loader.prototype._prepareUrl = function _prepareUrl(url) { var parsedUrl = (0, _parseUri2.default)(url, { strictMode: true }); var result = void 0; // absolute url, just use it as is. if (parsedUrl.protocol || !parsedUrl.path || url.indexOf('//') === 0) { result = url; } // if baseUrl doesn't end in slash and url doesn't start with slash, then add a slash inbetween else if (this.baseUrl.length && this.baseUrl.lastIndexOf('/') !== this.baseUrl.length - 1 && url.charAt(0) !== '/') { result = this.baseUrl + '/' + url; } else { result = this.baseUrl + url; } // if we need to add a default querystring, there is a bit more work if (this.defaultQueryString) { var hash = rgxExtractUrlHash.exec(result)[0]; result = result.substr(0, result.length - hash.length); if (result.indexOf('?') !== -1) { result += '&' + this.defaultQueryString; } else { result += '?' + this.defaultQueryString; } result += hash; } return result; }; /** * Loads a single resource. * * @private * @param {Resource} resource - The resource to load. * @param {function} dequeue - The function to call when we need to dequeue this item. */ Loader.prototype._loadResource = function _loadResource(resource, dequeue) { var _this2 = this; resource._dequeue = dequeue; // run before middleware async.eachSeries(this._beforeMiddleware, function (fn, next) { fn.call(_this2, resource, function () { // if the before middleware marks the resource as complete, // break and don't process any more before middleware next(resource.isComplete ? {} : null); }); }, function () { if (resource.isComplete) { _this2._onLoad(resource); } else { resource._onLoadBinding = resource.onComplete.once(_this2._onLoad, _this2); resource.load(); } }, true); }; /** * Called once loading has started. * * @private */ Loader.prototype._onStart = function _onStart() { this.progress = 0; this.loading = true; this.onStart.dispatch(this); }; /** * Called once each resource has loaded. * * @private */ Loader.prototype._onComplete = function _onComplete() { this.progress = MAX_PROGRESS; this.loading = false; this.onComplete.dispatch(this, this.resources); }; /** * Called each time a resources is loaded. * * @private * @param {Resource} resource - The resource that was loaded */ Loader.prototype._onLoad = function _onLoad(resource) { var _this3 = this; resource._onLoadBinding = null; // remove this resource from the async queue, and add it to our list of resources that are being parsed this._resourcesParsing.push(resource); resource._dequeue(); // run all the after middleware for this resource async.eachSeries(this._afterMiddleware, function (fn, next) { fn.call(_this3, resource, next); }, function () { resource.onAfterMiddleware.dispatch(resource); _this3.progress += resource.progressChunk; _this3.onProgress.dispatch(_this3, resource); if (resource.error) { _this3.onError.dispatch(resource.error, _this3, resource); } else { _this3.onLoad.dispatch(_this3, resource); } _this3._resourcesParsing.splice(_this3._resourcesParsing.indexOf(resource), 1); // do completion check if (_this3._queue.idle() && _this3._resourcesParsing.length === 0) { _this3._onComplete(); } }, true); }; _createClass(Loader, [{ key: 'concurrency', get: function get() { return this._queue.concurrency; } // eslint-disable-next-line require-jsdoc , set: function set(concurrency) { this._queue.concurrency = concurrency; } }]); return Loader; }(); exports.default = Loader; },{"./Resource":2,"./async":3,"mini-signals":6,"parse-uri":7}],2:[function(require,module,exports){ 'use strict'; exports.__esModule = true; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _parseUri = require('parse-uri'); var _parseUri2 = _interopRequireDefault(_parseUri); var _miniSignals = require('mini-signals'); var _miniSignals2 = _interopRequireDefault(_miniSignals); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // tests is CORS is supported in XHR, if not we need to use XDR var useXdr = !!(window.XDomainRequest && !('withCredentials' in new XMLHttpRequest())); var tempAnchor = null; // some status constants var STATUS_NONE = 0; var STATUS_OK = 200; var STATUS_EMPTY = 204; var STATUS_IE_BUG_EMPTY = 1223; var STATUS_TYPE_OK = 2; // noop function _noop() {} /* empty */ /** * Manages the state and loading of a resource and all child resources. * * @class */ var Resource = function () { /** * Sets the load type to be used for a specific extension. * * @static * @param {string} extname - The extension to set the type for, e.g. "png" or "fnt" * @param {Resource.LOAD_TYPE} loadType - The load type to set it to. */ Resource.setExtensionLoadType = function setExtensionLoadType(extname, loadType) { setExtMap(Resource._loadTypeMap, extname, loadType); }; /** * Sets the load type to be used for a specific extension. * * @static * @param {string} extname - The extension to set the type for, e.g. "png" or "fnt" * @param {Resource.XHR_RESPONSE_TYPE} xhrType - The xhr type to set it to. */ Resource.setExtensionXhrType = function setExtensionXhrType(extname, xhrType) { setExtMap(Resource._xhrTypeMap, extname, xhrType); }; /** * @param {string} name - The name of the resource to load. * @param {string|string[]} url - The url for this resource, for audio/video loads you can pass * an array of sources. * @param {object} [options] - The options for the load. * @param {string|boolean} [options.crossOrigin] - Is this request cross-origin? Default is to * determine automatically. * @param {Resource.LOAD_TYPE} [options.loadType=Resource.LOAD_TYPE.XHR] - How should this resource * be loaded? * @param {Resource.XHR_RESPONSE_TYPE} [options.xhrType=Resource.XHR_RESPONSE_TYPE.DEFAULT] - How * should the data being loaded be interpreted when using XHR? * @param {object} [options.metadata] - Extra configuration for middleware and the Resource object. * @param {HTMLImageElement|HTMLAudioElement|HTMLVideoElement} [options.metadata.loadElement=null] - The * element to use for loading, instead of creating one. * @param {boolean} [options.metadata.skipSource=false] - Skips adding source(s) to the load element. This * is useful if you want to pass in a `loadElement` that you already added load sources to. * @param {string|string[]} [options.metadata.mimeType] - The mime type to use for the source element of a video/audio * elment. If the urls are an array, you can pass this as an array as well where each index is the mime type to * use for the corresponding url index. */ function Resource(name, url, options) { _classCallCheck(this, Resource); if (typeof name !== 'string' || typeof url !== 'string') { throw new Error('Both name and url are required for constructing a resource.'); } options = options || {}; /** * The state flags of this resource. * * @member {number} */ this._flags = 0; // set data url flag, needs to be set early for some _determineX checks to work. this._setFlag(Resource.STATUS_FLAGS.DATA_URL, url.indexOf('data:') === 0); /** * The name of this resource. * * @member {string} * @readonly */ this.name = name; /** * The url used to load this resource. * * @member {string} * @readonly */ this.url = url; /** * The extension used to load this resource. * * @member {string} * @readonly */ this.extension = this._getExtension(); /** * The data that was loaded by the resource. * * @member {any} */ this.data = null; /** * Is this request cross-origin? If unset, determined automatically. * * @member {string} */ this.crossOrigin = options.crossOrigin === true ? 'anonymous' : options.crossOrigin; /** * The method of loading to use for this resource. * * @member {Resource.LOAD_TYPE} */ this.loadType = options.loadType || this._determineLoadType(); /** * The type used to load the resource via XHR. If unset, determined automatically. * * @member {string} */ this.xhrType = options.xhrType; /** * Extra info for middleware, and controlling specifics about how the resource loads. * * Note that if you pass in a `loadElement`, the Resource class takes ownership of it. * Meaning it will modify it as it sees fit. * * @member {object} * @property {HTMLImageElement|HTMLAudioElement|HTMLVideoElement} [loadElement=null] - The * element to use for loading, instead of creating one. * @property {boolean} [skipSource=false] - Skips adding source(s) to the load element. This * is useful if you want to pass in a `loadElement` that you already added load sources * to. */ this.metadata = options.metadata || {}; /** * The error that occurred while loading (if any). * * @member {Error} * @readonly */ this.error = null; /** * The XHR object that was used to load this resource. This is only set * when `loadType` is `Resource.LOAD_TYPE.XHR`. * * @member {XMLHttpRequest} * @readonly */ this.xhr = null; /** * The child resources this resource owns. * * @member {Resource[]} * @readonly */ this.children = []; /** * The resource type. * * @member {Resource.TYPE} * @readonly */ this.type = Resource.TYPE.UNKNOWN; /** * The progress chunk owned by this resource. * * @member {number} * @readonly */ this.progressChunk = 0; /** * The `dequeue` method that will be used a storage place for the async queue dequeue method * used privately by the loader. * * @private * @member {function} */ this._dequeue = _noop; /** * Used a storage place for the on load binding used privately by the loader. * * @private * @member {function} */ this._onLoadBinding = null; /** * The `complete` function bound to this resource's context. * * @private * @member {function} */ this._boundComplete = this.complete.bind(this); /** * The `_onError` function bound to this resource's context. * * @private * @member {function} */ this._boundOnError = this._onError.bind(this); /** * The `_onProgress` function bound to this resource's context. * * @private * @member {function} */ this._boundOnProgress = this._onProgress.bind(this); // xhr callbacks this._boundXhrOnError = this._xhrOnError.bind(this); this._boundXhrOnAbort = this._xhrOnAbort.bind(this); this._boundXhrOnLoad = this._xhrOnLoad.bind(this); this._boundXdrOnTimeout = this._xdrOnTimeout.bind(this); /** * Dispatched when the resource beings to load. * * The callback looks like {@link Resource.OnStartSignal}. * * @member {Signal} */ this.onStart = new _miniSignals2.default(); /** * Dispatched each time progress of this resource load updates. * Not all resources types and loader systems can support this event * so sometimes it may not be available. If the resource * is being loaded on a modern browser, using XHR, and the remote server * properly sets Content-Length headers, then this will be available. * * The callback looks like {@link Resource.OnProgressSignal}. * * @member {Signal} */ this.onProgress = new _miniSignals2.default(); /** * Dispatched once this resource has loaded, if there was an error it will * be in the `error` property. * * The callback looks like {@link Resource.OnCompleteSignal}. * * @member {Signal} */ this.onComplete = new _miniSignals2.default(); /** * Dispatched after this resource has had all the *after* middleware run on it. * * The callback looks like {@link Resource.OnCompleteSignal}. * * @member {Signal} */ this.onAfterMiddleware = new _miniSignals2.default(); /** * When the resource starts to load. * * @memberof Resource * @callback OnStartSignal * @param {Resource} resource - The resource that the event happened on. */ /** * When the resource reports loading progress. * * @memberof Resource * @callback OnProgressSignal * @param {Resource} resource - The resource that the event happened on. * @param {number} percentage - The progress of the load in the range [0, 1]. */ /** * When the resource finishes loading. * * @memberof Resource * @callback OnCompleteSignal * @param {Resource} resource - The resource that the event happened on. */ } /** * Stores whether or not this url is a data url. * * @member {boolean} * @readonly */ /** * Marks the resource as complete. * */ Resource.prototype.complete = function complete() { // TODO: Clean this up in a wrapper or something...gross.... if (this.data && this.data.removeEventListener) { this.data.removeEventListener('error', this._boundOnError, false); this.data.removeEventListener('load', this._boundComplete, false); this.data.removeEventListener('progress', this._boundOnProgress, false); this.data.removeEventListener('canplaythrough', this._boundComplete, false); } if (this.xhr) { if (this.xhr.removeEventListener) { this.xhr.removeEventListener('error', this._boundXhrOnError, false); this.xhr.removeEventListener('abort', this._boundXhrOnAbort, false); this.xhr.removeEventListener('progress', this._boundOnProgress, false); this.xhr.removeEventListener('load', this._boundXhrOnLoad, false); } else { this.xhr.onerror = null; this.xhr.ontimeout = null; this.xhr.onprogress = null; this.xhr.onload = null; } } if (this.isComplete) { throw new Error('Complete called again for an already completed resource.'); } this._setFlag(Resource.STATUS_FLAGS.COMPLETE, true); this._setFlag(Resource.STATUS_FLAGS.LOADING, false); this.onComplete.dispatch(this); }; /** * Aborts the loading of this resource, with an optional message. * * @param {string} message - The message to use for the error */ Resource.prototype.abort = function abort(message) { // abort can be called multiple times, ignore subsequent calls. if (this.error) { return; } // store error this.error = new Error(message); // abort the actual loading if (this.xhr) { this.xhr.abort(); } else if (this.xdr) { this.xdr.abort(); } else if (this.data) { // single source if (this.data.src) { this.data.src = Resource.EMPTY_GIF; } // multi-source else { while (this.data.firstChild) { this.data.removeChild(this.data.firstChild); } } } // done now. this.complete(); }; /** * Kicks off loading of this resource. This method is asynchronous. * * @param {function} [cb] - Optional callback to call once the resource is loaded. */ Resource.prototype.load = function load(cb) { var _this = this; if (this.isLoading) { return; } if (this.isComplete) { if (cb) { setTimeout(function () { return cb(_this); }, 1); } return; } else if (cb) { this.onComplete.once(cb); } this._setFlag(Resource.STATUS_FLAGS.LOADING, true); this.onStart.dispatch(this); // if unset, determine the value if (this.crossOrigin === false || typeof this.crossOrigin !== 'string') { this.crossOrigin = this._determineCrossOrigin(this.url); } switch (this.loadType) { case Resource.LOAD_TYPE.IMAGE: this.type = Resource.TYPE.IMAGE; this._loadElement('image'); break; case Resource.LOAD_TYPE.AUDIO: this.type = Resource.TYPE.AUDIO; this._loadSourceElement('audio'); break; case Resource.LOAD_TYPE.VIDEO: this.type = Resource.TYPE.VIDEO; this._loadSourceElement('video'); break; case Resource.LOAD_TYPE.XHR: /* falls through */ default: if (useXdr && this.crossOrigin) { this._loadXdr(); } else { this._loadXhr(); } break; } }; /** * Checks if the flag is set. * * @private * @param {number} flag - The flag to check. * @return {boolean} True if the flag is set. */ Resource.prototype._hasFlag = function _hasFlag(flag) { return !!(this._flags & flag); }; /** * (Un)Sets the flag. * * @private * @param {number} flag - The flag to (un)set. * @param {boolean} value - Whether to set or (un)set the flag. */ Resource.prototype._setFlag = function _setFlag(flag, value) { this._flags = value ? this._flags | flag : this._flags & ~flag; }; /** * Loads this resources using an element that has a single source, * like an HTMLImageElement. * * @private * @param {string} type - The type of element to use. */ Resource.prototype._loadElement = function _loadElement(type) { if (this.metadata.loadElement) { this.data = this.metadata.loadElement; } else if (type === 'image' && typeof window.Image !== 'undefined') { this.data = new Image(); } else { this.data = document.createElement(type); } if (this.crossOrigin) { this.data.crossOrigin = this.crossOrigin; } if (!this.metadata.skipSource) { this.data.src = this.url; } this.data.addEventListener('error', this._boundOnError, false); this.data.addEventListener('load', this._boundComplete, false); this.data.addEventListener('progress', this._boundOnProgress, false); }; /** * Loads this resources using an element that has multiple sources, * like an HTMLAudioElement or HTMLVideoElement. * * @private * @param {string} type - The type of element to use. */ Resource.prototype._loadSourceElement = function _loadSourceElement(type) { if (this.metadata.loadElement) { this.data = this.metadata.loadElement; } else if (type === 'audio' && typeof window.Audio !== 'undefined') { this.data = new Audio(); } else { this.data = document.createElement(type); } if (this.data === null) { this.abort('Unsupported element: ' + type); return; } if (!this.metadata.skipSource) { // support for CocoonJS Canvas+ runtime, lacks document.createElement('source') if (navigator.isCocoonJS) { this.data.src = Array.isArray(this.url) ? this.url[0] : this.url; } else if (Array.isArray(this.url)) { var mimeTypes = this.metadata.mimeType; for (var i = 0; i < this.url.length; ++i) { this.data.appendChild(this._createSource(type, this.url[i], Array.isArray(mimeTypes) ? mimeTypes[i] : mimeTypes)); } } else { var _mimeTypes = this.metadata.mimeType; this.data.appendChild(this._createSource(type, this.url, Array.isArray(_mimeTypes) ? _mimeTypes[0] : _mimeTypes)); } } this.data.addEventListener('error', this._boundOnError, false); this.data.addEventListener('load', this._boundComplete, false); this.data.addEventListener('progress', this._boundOnProgress, false); this.data.addEventListener('canplaythrough', this._boundComplete, false); this.data.load(); }; /** * Loads this resources using an XMLHttpRequest. * * @private */ Resource.prototype._loadXhr = function _loadXhr() { // if unset, determine the value if (typeof this.xhrType !== 'string') { this.xhrType = this._determineXhrType(); } var xhr = this.xhr = new XMLHttpRequest(); // set the request type and url xhr.open('GET', this.url, true); // load json as text and parse it ourselves. We do this because some browsers // *cough* safari *cough* can't deal with it. if (this.xhrType === Resource.XHR_RESPONSE_TYPE.JSON || this.xhrType === Resource.XHR_RESPONSE_TYPE.DOCUMENT) { xhr.responseType = Resource.XHR_RESPONSE_TYPE.TEXT; } else { xhr.responseType = this.xhrType; } xhr.addEventListener('error', this._boundXhrOnError, false); xhr.addEventListener('abort', this._boundXhrOnAbort, false); xhr.addEventListener('progress', this._boundOnProgress, false); xhr.addEventListener('load', this._boundXhrOnLoad, false); xhr.send(); }; /** * Loads this resources using an XDomainRequest. This is here because we need to support IE9 (gross). * * @private */ Resource.prototype._loadXdr = function _loadXdr() { // if unset, determine the value if (typeof this.xhrType !== 'string') { this.xhrType = this._determineXhrType(); } var xdr = this.xhr = new XDomainRequest(); // XDomainRequest has a few quirks. Occasionally it will abort requests // A way to avoid this is to make sure ALL callbacks are set even if not used // More info here: http://stackoverflow.com/questions/15786966/xdomainrequest-aborts-post-on-ie-9 xdr.timeout = 5000; xdr.onerror = this._boundXhrOnError; xdr.ontimeout = this._boundXdrOnTimeout; xdr.onprogress = this._boundOnProgress; xdr.onload = this._boundXhrOnLoad; xdr.open('GET', this.url, true); // Note: The xdr.send() call is wrapped in a timeout to prevent an // issue with the interface where some requests are lost if multiple // XDomainRequests are being sent at the same time. // Some info here: https://github.com/photonstorm/phaser/issues/1248 setTimeout(function () { return xdr.send(); }, 1); }; /** * Creates a source used in loading via an element. * * @private * @param {string} type - The element type (video or audio). * @param {string} url - The source URL to load from. * @param {string} [mime] - The mime type of the video * @return {HTMLSourceElement} The source element. */ Resource.prototype._createSource = function _createSource(type, url, mime) { if (!mime) { mime = type + '/' + this._getExtension(url); } var source = document.createElement('source'); source.src = url; source.type = mime; return source; }; /** * Called if a load errors out. * * @param {Event} event - The error event from the element that emits it. * @private */ Resource.prototype._onError = function _onError(event) { this.abort('Failed to load element using: ' + event.target.nodeName); }; /** * Called if a load progress event fires for xhr/xdr. * * @private * @param {XMLHttpRequestProgressEvent|Event} event - Progress event. */ Resource.prototype._onProgress = function _onProgress(event) { if (event && event.lengthComputable) { this.onProgress.dispatch(this, event.loaded / event.total); } }; /** * Called if an error event fires for xhr/xdr. * * @private * @param {XMLHttpRequestErrorEvent|Event} event - Error event. */ Resource.prototype._xhrOnError = function _xhrOnError() { var xhr = this.xhr; this.abort(reqType(xhr) + ' Request failed. Status: ' + xhr.status + ', text: "' + xhr.statusText + '"'); }; /** * Called if an abort event fires for xhr. * * @private * @param {XMLHttpRequestAbortEvent} event - Abort Event */ Resource.prototype._xhrOnAbort = function _xhrOnAbort() { this.abort(reqType(this.xhr) + ' Request was aborted by the user.'); }; /** * Called if a timeout event fires for xdr. * * @private * @param {Event} event - Timeout event. */ Resource.prototype._xdrOnTimeout = function _xdrOnTimeout() { this.abort(reqType(this.xhr) + ' Request timed out.'); }; /** * Called when data successfully loads from an xhr/xdr request. * * @private * @param {XMLHttpRequestLoadEvent|Event} event - Load event */ Resource.prototype._xhrOnLoad = function _xhrOnLoad() { var xhr = this.xhr; var text = ''; var status = typeof xhr.status === 'undefined' ? STATUS_OK : xhr.status; // XDR has no `.status`, assume 200. // responseText is accessible only if responseType is '' or 'text' and on older browsers if (xhr.responseType === '' || xhr.responseType === 'text' || typeof xhr.responseType === 'undefined') { text = xhr.responseText; } // status can be 0 when using the `file://` protocol so we also check if a response is set. // If it has a response, we assume 200; otherwise a 0 status code with no contents is an aborted request. if (status === STATUS_NONE && (text.length > 0 || xhr.responseType === Resource.XHR_RESPONSE_TYPE.BUFFER)) { status = STATUS_OK; } // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request else if (status === STATUS_IE_BUG_EMPTY) { status = STATUS_EMPTY; } var statusType = status / 100 | 0; if (statusType === STATUS_TYPE_OK) { // if text, just return it if (this.xhrType === Resource.XHR_RESPONSE_TYPE.TEXT) { this.data = text; this.type = Resource.TYPE.TEXT; } // if json, parse into json object else if (this.xhrType === Resource.XHR_RESPONSE_TYPE.JSON) { try { this.data = JSON.parse(text); this.type = Resource.TYPE.JSON; } catch (e) { this.abort('Error trying to parse loaded json: ' + e); return; } } // if xml, parse into an xml document or div element else if (this.xhrType === Resource.XHR_RESPONSE_TYPE.DOCUMENT) { try { if (window.DOMParser) { var domparser = new DOMParser(); this.data = domparser.parseFromString(text, 'text/xml'); } else { var div = document.createElement('div'); div.innerHTML = text; this.data = div; } this.type = Resource.TYPE.XML; } catch (e) { this.abort('Error trying to parse loaded xml: ' + e); return; } } // other types just return the response else { this.data = xhr.response || text; } } else { this.abort('[' + xhr.status + '] ' + xhr.statusText + ': ' + xhr.responseURL); return; } this.complete(); }; /** * Sets the `crossOrigin` property for this resource based on if the url * for this resource is cross-origin. If crossOrigin was manually set, this * function does nothing. * * @private * @param {string} url - The url to test. * @param {object} [loc=window.location] - The location object to test against. * @return {string} The crossOrigin value to use (or empty string for none). */ Resource.prototype._determineCrossOrigin = function _determineCrossOrigin(url, loc) { // data: and javascript: urls are considered same-origin if (url.indexOf('data:') === 0) { return ''; } // default is window.location loc = loc || window.location; if (!tempAnchor) { tempAnchor = document.createElement('a'); } // let the browser determine the full href for the url of this resource and then // parse with the node url lib, we can't use the properties of the anchor element // because they don't work in IE9 :( tempAnchor.href = url; url = (0, _parseUri2.default)(tempAnchor.href, { strictMode: true }); var samePort = !url.port && loc.port === '' || url.port === loc.port; var protocol = url.protocol ? url.protocol + ':' : ''; // if cross origin if (url.host !== loc.hostname || !samePort || protocol !== loc.protocol) { return 'anonymous'; } return ''; }; /** * Determines the responseType of an XHR request based on the extension of the * resource being loaded. * * @private * @return {Resource.XHR_RESPONSE_TYPE} The responseType to use. */ Resource.prototype._determineXhrType = function _determineXhrType() { return Resource._xhrTypeMap[this.extension] || Resource.XHR_RESPONSE_TYPE.TEXT; }; /** * Determines the loadType of a resource based on the extension of the * resource being loaded. * * @private * @return {Resource.LOAD_TYPE} The loadType to use. */ Resource.prototype._determineLoadType = function _determineLoadType() { return Resource._loadTypeMap[this.extension] || Resource.LOAD_TYPE.XHR; }; /** * Extracts the extension (sans '.') of the file being loaded by the resource. * * @private * @return {string} The extension. */ Resource.prototype._getExtension = function _getExtension() { var url = this.url; var ext = ''; if (this.isDataUrl) { var slashIndex = url.indexOf('/'); ext = url.substring(slashIndex + 1, url.indexOf(';', slashIndex)); } else { var queryStart = url.indexOf('?'); var hashStart = url.indexOf('#'); var index = Math.min(queryStart > -1 ? queryStart : url.length, hashStart > -1 ? hashStart : url.length); url = url.substring(0, index); ext = url.substring(url.lastIndexOf('.') + 1); } return ext.toLowerCase(); }; /** * Determines the mime type of an XHR request based on the responseType of * resource being loaded. * * @private * @param {Resource.XHR_RESPONSE_TYPE} type - The type to get a mime type for. * @return {string} The mime type to use. */ Resource.prototype._getMimeFromXhrType = function _getMimeFromXhrType(type) { switch (type) { case Resource.XHR_RESPONSE_TYPE.BUFFER: return 'application/octet-binary'; case Resource.XHR_RESPONSE_TYPE.BLOB: return 'application/blob'; case Resource.XHR_RESPONSE_TYPE.DOCUMENT: return 'application/xml'; case Resource.XHR_RESPONSE_TYPE.JSON: return 'application/json'; case Resource.XHR_RESPONSE_TYPE.DEFAULT: case Resource.XHR_RESPONSE_TYPE.TEXT: /* falls through */ default: return 'text/plain'; } }; _createClass(Resource, [{ key: 'isDataUrl', get: function get() { return this._hasFlag(Resource.STATUS_FLAGS.DATA_URL); } /** * Describes if this resource has finished loading. Is true when the resource has completely * loaded. * * @member {boolean} * @readonly */ }, { key: 'isComplete', get: function get() { return this._hasFlag(Resource.STATUS_FLAGS.COMPLETE); } /** * Describes if this resource is currently loading. Is true when the resource starts loading, * and is false again when complete. * * @member {boolean} * @readonly */ }, { key: 'isLoading', get: function get() { return this._hasFlag(Resource.STATUS_FLAGS.LOADING); } }]); return Resource; }(); /** * The types of resources a resource could represent. * * @static * @readonly * @enum {number} */ exports.default = Resource; Resource.STATUS_FLAGS = { NONE: 0, DATA_URL: 1 << 0, COMPLETE: 1 << 1, LOADING: 1 << 2 }; /** * The types of resources a resource could represent. * * @static * @readonly * @enum {number} */ Resource.TYPE = { UNKNOWN: 0, JSON: 1, XML: 2, IMAGE: 3, AUDIO: 4, VIDEO: 5, TEXT: 6 }; /** * The types of loading a resource can use. * * @static * @readonly * @enum {number} */ Resource.LOAD_TYPE = { /** Uses XMLHttpRequest to load the resource. */ XHR: 1, /** Uses an `Image` object to load the resource. */ IMAGE: 2, /** Uses an `Audio` object to load the resource. */ AUDIO: 3, /** Uses a `Video` object to load the resource. */ VIDEO: 4 }; /** * The XHR ready states, used internally. * * @static * @readonly * @enum {string} */ Resource.XHR_RESPONSE_TYPE = { /** string */ DEFAULT: 'text', /** ArrayBuffer */ BUFFER: 'arraybuffer', /** Blob */ BLOB: 'blob', /** Document */ DOCUMENT: 'document', /** Object */ JSON: 'json', /** String */ TEXT: 'text' }; Resource._loadTypeMap = { // images gif: Resource.LOAD_TYPE.IMAGE, png: Resource.LOAD_TYPE.IMAGE, bmp: Resource.LOAD_TYPE.IMAGE, jpg: Resource.LOAD_TYPE.IMAGE, jpeg: Resource.LOAD_TYPE.IMAGE, tif: Resource.LOAD_TYPE.IMAGE, tiff: Resource.LOAD_TYPE.IMAGE, webp: Resource.LOAD_TYPE.IMAGE, tga: Resource.LOAD_TYPE.IMAGE, svg: Resource.LOAD_TYPE.IMAGE, 'svg+xml': Resource.LOAD_TYPE.IMAGE, // for SVG data urls // audio mp3: Resource.LOAD_TYPE.AUDIO, ogg: Resource.LOAD_TYPE.AUDIO, wav: Resource.LOAD_TYPE.AUDIO, // videos mp4: Resource.LOAD_TYPE.VIDEO, webm: Resource.LOAD_TYPE.VIDEO }; Resource._xhrTypeMap = { // xml xhtml: Resource.XHR_RESPONSE_TYPE.DOCUMENT, html: Resource.XHR_RESPONSE_TYPE.DOCUMENT, htm: Resource.XHR_RESPONSE_TYPE.DOCUMENT, xml: Resource.XHR_RESPONSE_TYPE.DOCUMENT, tmx: Resource.XHR_RESPONSE_TYPE.DOCUMENT, svg: Resource.XHR_RESPONSE_TYPE.DOCUMENT, // This was added to handle Tiled Tileset XML, but .tsx is also a TypeScript React Component. // Since it is way less likely for people to be loading TypeScript files instead of Tiled files, // this should probably be fine. tsx: Resource.XHR_RESPONSE_TYPE.DOCUMENT, // images gif: Resource.XHR_RESPONSE_TYPE.BLOB, png: Resource.XHR_RESPONSE_TYPE.BLOB, bmp: Resource.XHR_RESPONSE_TYPE.BLOB, jpg: Resource.XHR_RESPONSE_TYPE.BLOB, jpeg: Resource.XHR_RESPONSE_TYPE.BLOB, tif: Resource.XHR_RESPONSE_TYPE.BLOB, tiff: Resource.XHR_RESPONSE_TYPE.BLOB, webp: Resource.XHR_RESPONSE_TYPE.BLOB, tga: Resource.XHR_RESPONSE_TYPE.BLOB, // json json: Resource.XHR_RESPONSE_TYPE.JSON, // text text: Resource.XHR_RESPONSE_TYPE.TEXT, txt: Resource.XHR_RESPONSE_TYPE.TEXT, // fonts ttf: Resource.XHR_RESPONSE_TYPE.BUFFER, otf: Resource.XHR_RESPONSE_TYPE.BUFFER }; // We can't set the `src` attribute to empty string, so on abort we set it to this 1px transparent gif Resource.EMPTY_GIF = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='; /** * Quick helper to set a value on one of the extension maps. Ensures there is no * dot at the start of the extension. * * @ignore * @param {object} map - The map to set on. * @param {string} extname - The extension (or key) to set. * @param {number} val - The value to set. */ function setExtMap(map, extname, val) { if (extname && extname.indexOf('.') === 0) { extname = extname.substring(1); } if (!extname) { return; } map[extname] = val; } /** * Quick helper to get string xhr type. * * @ignore * @param {XMLHttpRequest|XDomainRequest} xhr - The request to check. * @return {string} The type. */ function reqType(xhr) { return xhr.toString().replace('object ', ''); } },{"mini-signals":6,"parse-uri":7}],3:[function(require,module,exports){ 'use strict'; exports.__esModule = true; exports.eachSeries = eachSeries; exports.queue = queue; /** * Smaller version of the async library constructs. * */ function _noop() {} /* empty */ /** * Iterates an array in series. * * @param {Array.<*>} array - Array to iterate. * @param {function} iterator - Function to call for each element. * @param {function} callback - Function to call when done, or on error. * @param {boolean} [deferNext=false] - Break synchronous each loop by calling next with a setTimeout of 1. */ function eachSeries(array, iterator, callback, deferNext) { var i = 0; var len = array.length; (function next(err) { if (err || i === len) { if (callback) { callback(err); } return; } if (deferNext) { setTimeout(function () { iterator(array[i++], next); }, 1); } else { iterator(array[i++], next); } })(); } /** * Ensures a function is only called once. * * @param {function} fn - The function to wrap. * @return {function} The wrapping function. */ function onlyOnce(fn) { return function onceWrapper() { if (fn === null) { throw new Error('Callback was already called.'); } var callFn = fn; fn = null; callFn.apply(this, arguments); }; } /** * Async queue implementation, * * @param {function} worker - The worker function to call for each task. * @param {number} concurrency - How many workers to run in parrallel. * @return {*} The async queue object. */ function queue(worker, concurrency) { if (concurrency == null) { // eslint-disable-line no-eq-null,eqeqeq concurrency = 1; } else if (concurrency === 0) { throw new Error('Concurrency must not be zero'); } var workers = 0; var q = { _tasks: [], concurrency: concurrency, saturated: _noop, unsaturated: _noop, buffer: concurrency / 4, empty: _noop, drain: _noop, error: _noop, started: false, paused: false, push: function push(data, callback) { _insert(data, false, callback); }, kill: function kill() { workers = 0; q.drain = _noop; q.started = false; q._tasks = []; }, unshift: function unshift(data, callback) { _insert(data, true, callback); }, process: function process() { while (!q.paused && workers < q.concurrency && q._tasks.length) { var task = q._tasks.shift(); if (q._tasks.length === 0) { q.empty(); } workers += 1; if (workers === q.concurrency) { q.saturated(); } worker(task.data, onlyOnce(_next(task))); } }, length: function length() { return q._tasks.length; }, running: function running() { return workers; }, idle: function idle() { return q._tasks.length + workers === 0; }, pause: function pause() { if (q.paused === true) { return; } q.paused = true; }, resume: function resume() { if (q.paused === false) { return; } q.paused = false; // Need to call q.process once per concurrent // worker to preserve full concurrency after pause for (var w = 1; w <= q.concurrency; w++) { q.process(); } } }; function _insert(data, insertAtFront, callback) { if (callback != null && typeof callback !== 'function') { // eslint-disable-line no-eq-null,eqeqeq throw new Error('task callback must be a function'); } q.started = true; if (data == null && q.idle()) { // eslint-disable-line no-eq-null,eqeqeq // call drain immediately if there are no tasks setTimeout(function () { return q.drain(); }, 1); return; } var item = { data: data, callback: typeof callback === 'function' ? callback : _noop }; if (insertAtFront) { q._tasks.unshift(item); } else { q._tasks.push(item); } setTimeout(function () { return q.process(); }, 1); } function _next(task) { return function next() { workers -= 1; task.callback.apply(task, arguments); if (arguments[0] != null) { // eslint-disable-line no-eq-null,eqeqeq q.error(arguments[0], task.data); } if (workers <= q.concurrency - q.buffer) { q.unsaturated(); } if (q.idle()) { q.drain(); } q.process(); }; } return q; } },{}],4:[function(require,module,exports){ 'use strict'; exports.__esModule = true; exports.encodeBinary = encodeBinary; var _keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; function encodeBinary(input) { var output = ''; var inx = 0; while (inx < input.length) { // Fill byte buffer array var bytebuffer = [0, 0, 0]; var encodedCharIndexes = [0, 0, 0, 0]; for (var jnx = 0; jnx < bytebuffer.length; ++jnx) { if (inx < input.length) { // throw away high-order byte, as documented at: // https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data bytebuffer[jnx] = input.charCodeAt(inx++) & 0xff; } else { bytebuffer[jnx] = 0; } } // Get each encoded character, 6 bits at a time // index 1: first 6 bits encodedCharIndexes[0] = bytebuffer[0] >> 2; // index 2: second 6 bits (2 least significant bits from input byte 1 + 4 most significant bits from byte 2) encodedCharIndexes[1] = (bytebuffer[0] & 0x3) << 4 | bytebuffer[1] >> 4; // index 3: third 6 bits (4 least significant bits from input byte 2 + 2 most significant bits from byte 3) encodedCharIndexes[2] = (bytebuffer[1] & 0x0f) << 2 | bytebuffer[2] >> 6; // index 3: forth 6 bits (6 least significant bits from input byte 3) encodedCharIndexes[3] = bytebuffer[2] & 0x3f; // Determine whether padding happened, and adjust accordingly var paddingBytes = inx - (input.length - 1); switch (paddingBytes) { case 2: // Set last 2 characters to padding char encodedCharIndexes[3] = 64; encodedCharIndexes[2] = 64; break; case 1: // Set last character to padding char encodedCharIndexes[3] = 64; break; default: break; // No padding - proceed } // Now we will grab each appropriate character out of our keystring // based on our index array and append it to the output string for (var _jnx = 0; _jnx < encodedCharIndexes.length; ++_jnx) { output += _keyStr.charAt(encodedCharIndexes[_jnx]); } } return output; } },{}],5:[function(require,module,exports){ 'use strict'; // import Loader from './Loader'; // import Resource from './Resource'; // import * as async from './async'; // import * as b64 from './b64'; /* eslint-disable no-undef */ var Loader = require('./Loader').default; var Resource = require('./Resource').default; var async = require('./async'); var b64 = require('./b64'); Loader.Resource = Resource; Loader.async = async; Loader.base64 = b64; // export manually, and also as default module.exports = Loader; // export default Loader; module.exports.default = Loader; },{"./Loader":1,"./Resource":2,"./async":3,"./b64":4}],6:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } var MiniSignalBinding = (function () { function MiniSignalBinding(fn, once, thisArg) { if (once === undefined) once = false; _classCallCheck(this, MiniSignalBinding); this._fn = fn; this._once = once; this._thisArg = thisArg; this._next = this._prev = this._owner = null; } _createClass(MiniSignalBinding, [{ key: 'detach', value: function detach() { if (this._owner === null) return false; this._owner.detach(this); return true; } }]); return MiniSignalBinding; })(); function _addMiniSignalBinding(self, node) { if (!self._head) { self._head = node; self._tail = node; } else { self._tail._next = node; node._prev = self._tail; self._tail = node; } node._owner = self; return node; } var MiniSignal = (function () { function MiniSignal() { _classCallCheck(this, MiniSignal); this._head = this._tail = undefined; } _createClass(MiniSignal, [{ key: 'handlers', value: function handlers() { var exists = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0]; var node = this._head; if (exists) return !!node; var ee = []; while (node) { ee.push(node); node = node._next; } return ee; } }, { key: 'has', value: function has(node) { if (!(node instanceof MiniSignalBinding)) { throw new Error('MiniSignal#has(): First arg must be a MiniSignalBinding object.'); } return node._owner === this; } }, { key: 'dispatch', value: function dispatch() { var node = this._head; if (!node) return false; while (node) { if (node._once) this.detach(node); node._fn.apply(node._thisArg, arguments); node = node._next; } return true; } }, { key: 'add', value: function add(fn) { var thisArg = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; if (typeof fn !== 'function') { throw new Error('MiniSignal#add(): First arg must be a Function.'); } return _addMiniSignalBinding(this, new MiniSignalBinding(fn, false, thisArg)); } }, { key: 'once', value: function once(fn) { var thisArg = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; if (typeof fn !== 'function') { throw new Error('MiniSignal#once(): First arg must be a Function.'); } return _addMiniSignalBinding(this, new MiniSignalBinding(fn, true, thisArg)); } }, { key: 'detach', value: function detach(node) { if (!(node instanceof MiniSignalBinding)) { throw new Error('MiniSignal#detach(): First arg must be a MiniSignalBinding object.'); } if (node._owner !== this) return this; if (node._prev) node._prev._next = node._next; if (node._next) node._next._prev = node._prev; if (node === this._head) { this._head = node._next; if (node._next === null) { this._tail = null; } } else if (node === this._tail) { this._tail = node._prev; this._tail._next = null; } node._owner = null; return this; } }, { key: 'detachAll', value: function detachAll() { var node = this._head; if (!node) return this; this._head = this._tail = null; while (node) { node._owner = null; node = node._next; } return this; } }]); return MiniSignal; })(); MiniSignal.MiniSignalBinding = MiniSignalBinding; exports['default'] = MiniSignal; module.exports = exports['default']; },{}],7:[function(require,module,exports){ 'use strict' module.exports = function parseURI (str, opts) { opts = opts || {} var o = { key: ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'], q: { name: 'queryKey', parser: /(?:^|&)([^&=]*)=?([^&]*)/g }, parser: { strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ } } var m = o.parser[opts.strictMode ? 'strict' : 'loose'].exec(str) var uri = {} var i = 14 while (i--) uri[o.key[i]] = m[i] || '' uri[o.q.name] = {} uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { if ($1) uri[o.q.name][$1] = $2 }) return uri } },{}]},{},[5])(5) }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJsaWIvTG9hZGVyLmpzIiwibGliL1Jlc291cmNlLmpzIiwibGliL2FzeW5jLmpzIiwibGliL2I2NC5qcyIsImxpYi9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9taW5pLXNpZ25hbHMvbGliL21pbmktc2lnbmFscy5qcyIsIm5vZGVfbW9kdWxlcy9wYXJzZS11cmkvaW5kZXguanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzb0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsb0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9NQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcktBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIid1c2Ugc3RyaWN0JztcblxuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZTtcblxudmFyIF90eXBlb2YgPSB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIFN5bWJvbC5pdGVyYXRvciA9PT0gXCJzeW1ib2xcIiA/IGZ1bmN0aW9uIChvYmopIHsgcmV0dXJuIHR5cGVvZiBvYmo7IH0gOiBmdW5jdGlvbiAob2JqKSB7IHJldHVybiBvYmogJiYgdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIG9iai5jb25zdHJ1Y3RvciA9PT0gU3ltYm9sICYmIG9iaiAhPT0gU3ltYm9sLnByb3RvdHlwZSA/IFwic3ltYm9sXCIgOiB0eXBlb2Ygb2JqOyB9O1xuXG52YXIgX2NyZWF0ZUNsYXNzID0gZnVuY3Rpb24gKCkgeyBmdW5jdGlvbiBkZWZpbmVQcm9wZXJ0aWVzKHRhcmdldCwgcHJvcHMpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCBwcm9wcy5sZW5ndGg7IGkrKykgeyB2YXIgZGVzY3JpcHRvciA9IHByb3BzW2ldOyBkZXNjcmlwdG9yLmVudW1lcmFibGUgPSBkZXNjcmlwdG9yLmVudW1lcmFibGUgfHwgZmFsc2U7IGRlc2NyaXB0b3IuY29uZmlndXJhYmxlID0gdHJ1ZTsgaWYgKFwidmFsdWVcIiBpbiBkZXNjcmlwdG9yKSBkZXNjcmlwdG9yLndyaXRhYmxlID0gdHJ1ZTsgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwgZGVzY3JpcHRvci5rZXksIGRlc2NyaXB0b3IpOyB9IH0gcmV0dXJuIGZ1bmN0aW9uIChDb25zdHJ1Y3RvciwgcHJvdG9Qcm9wcywgc3RhdGljUHJvcHMpIHsgaWYgKHByb3RvUHJvcHMpIGRlZmluZVByb3BlcnRpZXMoQ29uc3RydWN0b3IucHJvdG90eXBlLCBwcm90b1Byb3BzKTsgaWYgKHN0YXRpY1Byb3BzKSBkZWZpbmVQcm9wZXJ0aWVzKENvbnN0cnVjdG9yLCBzdGF0aWNQcm9wcyk7IHJldHVybiBDb25zdHJ1Y3RvcjsgfTsgfSgpO1xuXG52YXIgX21pbmlTaWduYWxzID0gcmVxdWlyZSgnbWluaS1zaWduYWxzJyk7XG5cbnZhciBfbWluaVNpZ25hbHMyID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChfbWluaVNpZ25hbHMpO1xuXG52YXIgX3BhcnNlVXJpID0gcmVxdWlyZSgncGFyc2UtdXJpJyk7XG5cbnZhciBfcGFyc2VVcmkyID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChfcGFyc2VVcmkpO1xuXG52YXIgX2FzeW5jID0gcmVxdWlyZSgnLi9hc3luYycpO1xuXG52YXIgYXN5bmMgPSBfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZChfYXN5bmMpO1xuXG52YXIgX1Jlc291cmNlID0gcmVxdWlyZSgnLi9SZXNvdXJjZScpO1xuXG52YXIgX1Jlc291cmNlMiA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQoX1Jlc291cmNlKTtcblxuZnVuY3Rpb24gX2ludGVyb3BSZXF1aXJlV2lsZGNhcmQob2JqKSB7IGlmIChvYmogJiYgb2JqLl9fZXNNb2R1bGUpIHsgcmV0dXJuIG9iajsgfSBlbHNlIHsgdmFyIG5ld09iaiA9IHt9OyBpZiAob2JqICE9IG51bGwpIHsgZm9yICh2YXIga2V5IGluIG9iaikgeyBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSkgbmV3T2JqW2tleV0gPSBvYmpba2V5XTsgfSB9IG5ld09iai5kZWZhdWx0ID0gb2JqOyByZXR1cm4gbmV3T2JqOyB9IH1cblxuZnVuY3Rpb24gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChvYmopIHsgcmV0dXJuIG9iaiAmJiBvYmouX19lc01vZHVsZSA/IG9iaiA6IHsgZGVmYXVsdDogb2JqIH07IH1cblxuZnVuY3Rpb24gX2NsYXNzQ2FsbENoZWNrKGluc3RhbmNlLCBDb25zdHJ1Y3RvcikgeyBpZiAoIShpbnN0YW5jZSBpbnN0YW5jZW9mIENvbnN0cnVjdG9yKSkgeyB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uXCIpOyB9IH1cblxuLy8gc29tZSBjb25zdGFudHNcbnZhciBNQVhfUFJPR1JFU1MgPSAxMDA7XG52YXIgcmd4RXh0cmFjdFVybEhhc2ggPSAvKCNbXFx3LV0rKT8kLztcblxuLyoqXG4gKiBNYW5hZ2VzIHRoZSBzdGF0ZSBhbmQgbG9hZGluZyBvZiBtdWx0aXBsZSByZXNvdXJjZXMgdG8gbG9hZC5cbiAqXG4gKiBAY2xhc3NcbiAqL1xuXG52YXIgTG9hZGVyID0gZnVuY3Rpb24gKCkge1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbYmFzZVVybD0nJ10gLSBUaGUgYmFzZSB1cmwgZm9yIGFsbCByZXNvdXJjZXMgbG9hZGVkIGJ5IHRoaXMgbG9hZGVyLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29uY3VycmVuY3k9MTBdIC0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgdG8gbG9hZCBjb25jdXJyZW50bHkuXG4gICAgICovXG4gICAgZnVuY3Rpb24gTG9hZGVyKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHZhciBiYXNlVXJsID0gYXJndW1lbnRzLmxlbmd0aCA+IDAgJiYgYXJndW1lbnRzWzBdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMF0gOiAnJztcbiAgICAgICAgdmFyIGNvbmN1cnJlbmN5ID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiAxMDtcblxuICAgICAgICBfY2xhc3NDYWxsQ2hlY2sodGhpcywgTG9hZGVyKTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGJhc2UgdXJsIGZvciBhbGwgcmVzb3VyY2VzIGxvYWRlZCBieSB0aGlzIGxvYWRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5iYXNlVXJsID0gYmFzZVVybDtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2dyZXNzIHBlcmNlbnQgb2YgdGhlIGxvYWRlciBnb2luZyB0aHJvdWdoIHRoZSBxdWV1ZS5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5wcm9ncmVzcyA9IDA7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvYWRpbmcgc3RhdGUgb2YgdGhlIGxvYWRlciwgdHJ1ZSBpZiBpdCBpcyBjdXJyZW50bHkgbG9hZGluZyByZXNvdXJjZXMuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLmxvYWRpbmcgPSBmYWxzZTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogQSBxdWVyeXN0cmluZyB0byBhcHBlbmQgdG8gZXZlcnkgVVJMIGFkZGVkIHRvIHRoZSBsb2FkZXIuXG4gICAgICAgICAqXG4gICAgICAgICAqIFRoaXMgc2hvdWxkIGJlIGEgdmFsaWQgcXVlcnkgc3RyaW5nICp3aXRob3V0KiB0aGUgcXVlc3Rpb24tbWFyayAoYD9gKS4gVGhlIGxvYWRlciB3aWxsXG4gICAgICAgICAqIGFsc28gKm5vdCogZXNjYXBlIHZhbHVlcyBmb3IgeW91LiBNYWtlIHN1cmUgdG8gZXNjYXBlIHlvdXIgcGFyYW1ldGVycyB3aXRoXG4gICAgICAgICAqIFtgZW5jb2RlVVJJQ29tcG9uZW50YF0oaHR0cHM6Ly9tZG4uaW8vZW5jb2RlVVJJQ29tcG9uZW50KSBiZWZvcmUgYXNzaWduaW5nIHRoaXMgcHJvcGVydHkuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqIGNvbnN0IGxvYWRlciA9IG5ldyBMb2FkZXIoKTtcbiAgICAgICAgICpcbiAgICAgICAgICogbG9hZGVyLmRlZmF1bHRRdWVyeVN0cmluZyA9ICd1c2VyPW1lJnBhc3N3b3JkPXNlY3JldCc7XG4gICAgICAgICAqXG4gICAgICAgICAqIC8vIFRoaXMgd2lsbCByZXF1ZXN0ICdpbWFnZS5wbmc/dXNlcj1tZSZwYXNzd29yZD1zZWNyZXQnXG4gICAgICAgICAqIGxvYWRlci5hZGQoJ2ltYWdlLnBuZycpLmxvYWQoKTtcbiAgICAgICAgICpcbiAgICAgICAgICogbG9hZGVyLnJlc2V0KCk7XG4gICAgICAgICAqXG4gICAgICAgICAqIC8vIFRoaXMgd2lsbCByZXF1ZXN0ICdpbWFnZS5wbmc/dj0xJnVzZXI9bWUmcGFzc3dvcmQ9c2VjcmV0J1xuICAgICAgICAgKiBsb2FkZXIuYWRkKCdpYW1nZS5wbmc/dj0xJykubG9hZCgpO1xuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5kZWZhdWx0UXVlcnlTdHJpbmcgPSAnJztcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIG1pZGRsZXdhcmUgdG8gcnVuIGJlZm9yZSBsb2FkaW5nIGVhY2ggcmVzb3VyY2UuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBtZW1iZXIge2Z1bmN0aW9uW119XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLl9iZWZvcmVNaWRkbGV3YXJlID0gW107XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBtaWRkbGV3YXJlIHRvIHJ1biBhZnRlciBsb2FkaW5nIGVhY2ggcmVzb3VyY2UuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBtZW1iZXIge2Z1bmN0aW9uW119XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLl9hZnRlck1pZGRsZXdhcmUgPSBbXTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHRyYWNrcyB0aGUgcmVzb3VyY2VzIHdlIGFyZSBjdXJyZW50bHkgY29tcGxldGluZyBwYXJzaW5nIGZvci5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7UmVzb3VyY2VbXX1cbiAgICAgICAgICovXG4gICAgICAgIHRoaXMuX3Jlc291cmNlc1BhcnNpbmcgPSBbXTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGBfbG9hZFJlc291cmNlYCBmdW5jdGlvbiBib3VuZCB3aXRoIHRoaXMgb2JqZWN0IGNvbnRleHQuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwcml2YXRlXG4gICAgICAgICAqIEBtZW1iZXIge2Z1bmN0aW9ufVxuICAgICAgICAgKiBAcGFyYW0ge1Jlc291cmNlfSByIC0gVGhlIHJlc291cmNlIHRvIGxvYWRcbiAgICAgICAgICogQHBhcmFtIHtGdW5jdGlvbn0gZCAtIFRoZSBkZXF1ZXVlIGZ1bmN0aW9uXG4gICAgICAgICAqIEByZXR1cm4ge3VuZGVmaW5lZH1cbiAgICAgICAgICovXG4gICAgICAgIHRoaXMuX2JvdW5kTG9hZFJlc291cmNlID0gZnVuY3Rpb24gKHIsIGQpIHtcbiAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJlc291cmNlKHIsIGQpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgbG9hZGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcHJpdmF0ZVxuICAgICAgICAgKiBAbWVtYmVyIHtSZXNvdXJjZVtdfVxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5fcXVldWUgPSBhc3luYy5xdWV1ZSh0aGlzLl9ib3VuZExvYWRSZXNvdXJjZSwgY29uY3VycmVuY3kpO1xuXG4gICAgICAgIHRoaXMuX3F1ZXVlLnBhdXNlKCk7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEFsbCB0aGUgcmVzb3VyY2VzIGZvciB0aGlzIGxvYWRlciBrZXllZCBieSBuYW1lLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtvYmplY3Q8c3RyaW5nLCBSZXNvdXJjZT59XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLnJlc291cmNlcyA9IHt9O1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBEaXNwYXRjaGVkIG9uY2UgcGVyIGxvYWRlZCBvciBlcnJvcmVkIHJlc291cmNlLlxuICAgICAgICAgKlxuICAgICAgICAgKiBUaGUgY2FsbGJhY2sgbG9va3MgbGlrZSB7QGxpbmsgTG9hZGVyLk9uUHJvZ3Jlc3NTaWduYWx9LlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtTaWduYWx9XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLm9uUHJvZ3Jlc3MgPSBuZXcgX21pbmlTaWduYWxzMi5kZWZhdWx0KCk7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIERpc3BhdGNoZWQgb25jZSBwZXIgZXJyb3JlZCByZXNvdXJjZS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGNhbGxiYWNrIGxvb2tzIGxpa2Uge0BsaW5rIExvYWRlci5PbkVycm9yU2lnbmFsfS5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7U2lnbmFsfVxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5vbkVycm9yID0gbmV3IF9taW5pU2lnbmFsczIuZGVmYXVsdCgpO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBEaXNwYXRjaGVkIG9uY2UgcGVyIGxvYWRlZCByZXNvdXJjZS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGNhbGxiYWNrIGxvb2tzIGxpa2Uge0BsaW5rIExvYWRlci5PbkxvYWRTaWduYWx9LlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtTaWduYWx9XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLm9uTG9hZCA9IG5ldyBfbWluaVNpZ25hbHMyLmRlZmF1bHQoKTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogRGlzcGF0Y2hlZCB3aGVuIHRoZSBsb2FkZXIgYmVnaW5zIHRvIHByb2Nlc3MgdGhlIHF1ZXVlLlxuICAgICAgICAgKlxuICAgICAgICAgKiBUaGUgY2FsbGJhY2sgbG9va3MgbGlrZSB7QGxpbmsgTG9hZGVyLk9uU3RhcnRTaWduYWx9LlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtTaWduYWx9XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLm9uU3RhcnQgPSBuZXcgX21pbmlTaWduYWxzMi5kZWZhdWx0KCk7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIERpc3BhdGNoZWQgd2hlbiB0aGUgcXVldWVkIHJlc291cmNlcyBhbGwgbG9hZC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGNhbGxiYWNrIGxvb2tzIGxpa2Uge0BsaW5rIExvYWRlci5PbkNvbXBsZXRlU2lnbmFsfS5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7U2lnbmFsfVxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5vbkNvbXBsZXRlID0gbmV3IF9taW5pU2lnbmFsczIuZGVmYXVsdCgpO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBXaGVuIHRoZSBwcm9ncmVzcyBjaGFuZ2VzIHRoZSBsb2FkZXIgYW5kIHJlc291cmNlIGFyZSBkaXNhcHRjaGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyb2YgTG9hZGVyXG4gICAgICAgICAqIEBjYWxsYmFjayBPblByb2dyZXNzU2lnbmFsXG4gICAgICAgICAqIEBwYXJhbSB7TG9hZGVyfSBsb2FkZXIgLSBUaGUgbG9hZGVyIHRoZSBwcm9ncmVzcyBpcyBhZHZhbmNpbmcgb24uXG4gICAgICAgICAqIEBwYXJhbSB7UmVzb3VyY2V9IHJlc291cmNlIC0gVGhlIHJlc291cmNlIHRoYXQgaGFzIGNvbXBsZXRlZCBvciBmYWlsZWQgdG8gY2F1c2UgdGhlIHByb2dyZXNzIHRvIGFkdmFuY2UuXG4gICAgICAgICAqL1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBXaGVuIGFuIGVycm9yIG9jY3VycnMgdGhlIGxvYWRlciBhbmQgcmVzb3VyY2UgYXJlIGRpc2FwdGNoZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBtZW1iZXJvZiBMb2FkZXJcbiAgICAgICAgICogQGNhbGxiYWNrIE9uRXJyb3JTaWduYWxcbiAgICAgICAgICogQHBhcmFtIHtMb2FkZXJ9IGxvYWRlciAtIFRoZSBsb2FkZXIgdGhlIGVycm9yIGhhcHBlbmVkIGluLlxuICAgICAgICAgKiBAcGFyYW0ge1Jlc291cmNlfSByZXNvdXJjZSAtIFRoZSByZXNvdXJjZSB0aGF0IGNhdXNlZCB0aGUgZXJyb3IuXG4gICAgICAgICAqL1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBXaGVuIGEgbG9hZCBjb21wbGV0ZXMgdGhlIGxvYWRlciBhbmQgcmVzb3VyY2UgYXJlIGRpc2FwdGNoZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBtZW1iZXJvZiBMb2FkZXJcbiAgICAgICAgICogQGNhbGxiYWNrIE9uTG9hZFNpZ25hbFxuICAgICAgICAgKiBAcGFyYW0ge0xvYWRlcn0gbG9hZGVyIC0gVGhlIGxvYWRlciB0aGF0IGxhb2RlZCB0aGUgcmVzb3VyY2UuXG4gICAgICAgICAqIEBwYXJhbSB7UmVzb3VyY2V9IHJlc291cmNlIC0gVGhlIHJlc291cmNlIHRoYXQgaGFzIGNvbXBsZXRlZCBsb2FkaW5nLlxuICAgICAgICAgKi9cblxuICAgICAgICAvKipcbiAgICAgICAgICogV2hlbiB0aGUgbG9hZGVyIHN0YXJ0cyBsb2FkaW5nIHJlc291cmNlcyBpdCBkaXNwYXRjaGVzIHRoaXMgY2FsbGJhY2suXG4gICAgICAgICAqXG4gICAgICAgICAqIEBtZW1iZXJvZiBMb2FkZXJcbiAgICAgICAgICogQGNhbGxiYWNrIE9uU3RhcnRTaWduYWxcbiAgICAgICAgICogQHBhcmFtIHtMb2FkZXJ9IGxvYWRlciAtIFRoZSBsb2FkZXIgdGhhdCBoYXMgc3RhcnRlZCBsb2FkaW5nIHJlc291cmNlcy5cbiAgICAgICAgICovXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZW4gdGhlIGxvYWRlciBjb21wbGV0ZXMgbG9hZGluZyByZXNvdXJjZXMgaXQgZGlzcGF0Y2hlcyB0aGlzIGNhbGxiYWNrLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyb2YgTG9hZGVyXG4gICAgICAgICAqIEBjYWxsYmFjayBPbkNvbXBsZXRlU2lnbmFsXG4gICAgICAgICAqIEBwYXJhbSB7TG9hZGVyfSBsb2FkZXIgLSBUaGUgbG9hZGVyIHRoYXQgaGFzIGZpbmlzaGVkIGxvYWRpbmcgcmVzb3VyY2VzLlxuICAgICAgICAgKi9cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGRzIGEgcmVzb3VyY2UgKG9yIG11bHRpcGxlIHJlc291cmNlcykgdG8gdGhlIGxvYWRlciBxdWV1ZS5cbiAgICAgKlxuICAgICAqIFRoaXMgZnVuY3Rpb24gY2FuIHRha2UgYSB3aWRlIHZhcmlldHkgb2YgZGlmZmVyZW50IHBhcmFtZXRlcnMuIFRoZSBvbmx5IHRoaW5nIHRoYXQgaXMgYWx3YXlzXG4gICAgICogcmVxdWlyZWQgdGhlIHVybCB0byBsb2FkLiBBbGwgdGhlIGZvbGxvd2luZyB3aWxsIHdvcms6XG4gICAgICpcbiAgICAgKiBgYGBqc1xuICAgICAqIGxvYWRlclxuICAgICAqICAgICAvLyBub3JtYWwgcGFyYW0gc3ludGF4XG4gICAgICogICAgIC5hZGQoJ2tleScsICdodHRwOi8vLi4uJywgZnVuY3Rpb24gKCkge30pXG4gICAgICogICAgIC5hZGQoJ2h0dHA6Ly8uLi4nLCBmdW5jdGlvbiAoKSB7fSlcbiAgICAgKiAgICAgLmFkZCgnaHR0cDovLy4uLicpXG4gICAgICpcbiAgICAgKiAgICAgLy8gb2JqZWN0IHN5bnRheFxuICAgICAqICAgICAuYWRkKHtcbiAgICAgKiAgICAgICAgIG5hbWU6ICdrZXkyJyxcbiAgICAgKiAgICAgICAgIHVybDogJ2h0dHA6Ly8uLi4nXG4gICAgICogICAgIH0sIGZ1bmN0aW9uICgpIHt9KVxuICAgICAqICAgICAuYWRkKHtcbiAgICAgKiAgICAgICAgIHVybDogJ2h0dHA6Ly8uLi4nXG4gICAgICogICAgIH0sIGZ1bmN0aW9uICgpIHt9KVxuICAgICAqICAgICAuYWRkKHtcbiAgICAgKiAgICAgICAgIG5hbWU6ICdrZXkzJyxcbiAgICAgKiAgICAgICAgIHVybDogJ2h0dHA6Ly8uLi4nXG4gICAgICogICAgICAgICBvbkNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7fVxuICAgICAqICAgICB9KVxuICAgICAqICAgICAuYWRkKHtcbiAgICAgKiAgICAgICAgIHVybDogJ2h0dHBzOi8vLi4uJyxcbiAgICAgKiAgICAgICAgIG9uQ29tcGxldGU6IGZ1bmN0aW9uICgpIHt9LFxuICAgICAqICAgICAgICAgY3Jvc3NPcmlnaW46IHRydWVcbiAgICAgKiAgICAgfSlcbiAgICAgKlxuICAgICAqICAgICAvLyB5b3UgY2FuIGFsc28gcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzIG9yIHVybHMgb3IgYm90aFxuICAgICAqICAgICAuYWRkKFtcbiAgICAgKiAgICAgICAgIHsgbmFtZTogJ2tleTQnLCB1cmw6ICdodHRwOi8vLi4uJywgb25Db21wbGV0ZTogZnVuY3Rpb24gKCkge30gfSxcbiAgICAgKiAgICAgICAgIHsgdXJsOiAnaHR0cDovLy4uLicsIG9uQ29tcGxldGU6IGZ1bmN0aW9uICgpIHt9IH0sXG4gICAgICogICAgICAgICAnaHR0cDovLy4uLidcbiAgICAgKiAgICAgXSlcbiAgICAgKlxuICAgICAqICAgICAvLyBhbmQgeW91IGNhbiB1c2UgYm90aCBwYXJhbXMgYW5kIG9wdGlvbnNcbiAgICAgKiAgICAgLmFkZCgna2V5JywgJ2h0dHA6Ly8uLi4nLCB7IGNyb3NzT3JpZ2luOiB0cnVlIH0sIGZ1bmN0aW9uICgpIHt9KVxuICAgICAqICAgICAuYWRkKCdodHRwOi8vLi4uJywgeyBjcm9zc09yaWdpbjogdHJ1ZSB9LCBmdW5jdGlvbiAoKSB7fSk7XG4gICAgICogYGBgXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW25hbWVdIC0gVGhlIG5hbWUgb2YgdGhlIHJlc291cmNlIHRvIGxvYWQsIGlmIG5vdCBwYXNzZWQgdGhlIHVybCBpcyB1c2VkLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbdXJsXSAtIFRoZSB1cmwgZm9yIHRoaXMgcmVzb3VyY2UsIHJlbGF0aXZlIHRvIHRoZSBiYXNlVXJsIG9mIHRoaXMgbG9hZGVyLlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc10gLSBUaGUgb3B0aW9ucyBmb3IgdGhlIGxvYWQuXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0aW9ucy5jcm9zc09yaWdpbl0gLSBJcyB0aGlzIHJlcXVlc3QgY3Jvc3Mtb3JpZ2luPyBEZWZhdWx0IGlzIHRvIGRldGVybWluZSBhdXRvbWF0aWNhbGx5LlxuICAgICAqIEBwYXJhbSB7UmVzb3VyY2UuTE9BRF9UWVBFfSBbb3B0aW9ucy5sb2FkVHlwZT1SZXNvdXJjZS5MT0FEX1RZUEUuWEhSXSAtIEhvdyBzaG91bGQgdGhpcyByZXNvdXJjZSBiZSBsb2FkZWQ/XG4gICAgICogQHBhcmFtIHtSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRX0gW29wdGlvbnMueGhyVHlwZT1SZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5ERUZBVUxUXSAtIEhvdyBzaG91bGRcbiAgICAgKiAgICAgIHRoZSBkYXRhIGJlaW5nIGxvYWRlZCBiZSBpbnRlcnByZXRlZCB3aGVuIHVzaW5nIFhIUj9cbiAgICAgKiBAcGFyYW0ge29iamVjdH0gW29wdGlvbnMubWV0YWRhdGFdIC0gRXh0cmEgY29uZmlndXJhdGlvbiBmb3IgbWlkZGxld2FyZSBhbmQgdGhlIFJlc291cmNlIG9iamVjdC5cbiAgICAgKiBAcGFyYW0ge0hUTUxJbWFnZUVsZW1lbnR8SFRNTEF1ZGlvRWxlbWVudHxIVE1MVmlkZW9FbGVtZW50fSBbb3B0aW9ucy5tZXRhZGF0YS5sb2FkRWxlbWVudD1udWxsXSAtIFRoZVxuICAgICAqICAgICAgZWxlbWVudCB0byB1c2UgZm9yIGxvYWRpbmcsIGluc3RlYWQgb2YgY3JlYXRpbmcgb25lLlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMubWV0YWRhdGEuc2tpcFNvdXJjZT1mYWxzZV0gLSBTa2lwcyBhZGRpbmcgc291cmNlKHMpIHRvIHRoZSBsb2FkIGVsZW1lbnQuIFRoaXNcbiAgICAgKiAgICAgIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBwYXNzIGluIGEgYGxvYWRFbGVtZW50YCB0aGF0IHlvdSBhbHJlYWR5IGFkZGVkIGxvYWQgc291cmNlcyB0by5cbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBbY2JdIC0gRnVuY3Rpb24gdG8gY2FsbCB3aGVuIHRoaXMgc3BlY2lmaWMgcmVzb3VyY2UgY29tcGxldGVzIGxvYWRpbmcuXG4gICAgICogQHJldHVybiB7TG9hZGVyfSBSZXR1cm5zIGl0c2VsZi5cbiAgICAgKi9cblxuXG4gICAgTG9hZGVyLnByb3RvdHlwZS5hZGQgPSBmdW5jdGlvbiBhZGQobmFtZSwgdXJsLCBvcHRpb25zLCBjYikge1xuICAgICAgICAvLyBzcGVjaWFsIGNhc2Ugb2YgYW4gYXJyYXkgb2Ygb2JqZWN0cyBvciB1cmxzXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KG5hbWUpKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5hbWUubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmFkZChuYW1lW2ldKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBpZiBhbiBvYmplY3QgaXMgcGFzc2VkIGluc3RlYWQgb2YgcGFyYW1zXG4gICAgICAgIGlmICgodHlwZW9mIG5hbWUgPT09ICd1bmRlZmluZWQnID8gJ3VuZGVmaW5lZCcgOiBfdHlwZW9mKG5hbWUpKSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIGNiID0gdXJsIHx8IG5hbWUuY2FsbGJhY2sgfHwgbmFtZS5vbkNvbXBsZXRlO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG5hbWU7XG4gICAgICAgICAgICB1cmwgPSBuYW1lLnVybDtcbiAgICAgICAgICAgIG5hbWUgPSBuYW1lLm5hbWUgfHwgbmFtZS5rZXkgfHwgbmFtZS51cmw7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBjYXNlIHdoZXJlIG5vIG5hbWUgaXMgcGFzc2VkIHNoaWZ0IGFsbCBhcmdzIG92ZXIgYnkgb25lLlxuICAgICAgICBpZiAodHlwZW9mIHVybCAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGNiID0gb3B0aW9ucztcbiAgICAgICAgICAgIG9wdGlvbnMgPSB1cmw7XG4gICAgICAgICAgICB1cmwgPSBuYW1lO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gbm93IHRoYXQgd2Ugc2hpZnRlZCBtYWtlIHN1cmUgd2UgaGF2ZSBhIHByb3BlciB1cmwuXG4gICAgICAgIGlmICh0eXBlb2YgdXJsICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1cmwgcGFzc2VkIHRvIGFkZCByZXNvdXJjZSB0byBsb2FkZXIuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBvcHRpb25zIGFyZSBvcHRpb25hbCBzbyBwZW9wbGUgbWlnaHQgcGFzcyBhIGZ1bmN0aW9uIGFuZCBubyBvcHRpb25zXG4gICAgICAgIGlmICh0eXBlb2Ygb3B0aW9ucyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgY2IgPSBvcHRpb25zO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBpZiBsb2FkaW5nIGFscmVhZHkgeW91IGNhbiBvbmx5IGFkZCByZXNvdXJjZXMgdGhhdCBoYXZlIGEgcGFyZW50LlxuICAgICAgICBpZiAodGhpcy5sb2FkaW5nICYmICghb3B0aW9ucyB8fCAhb3B0aW9ucy5wYXJlbnRSZXNvdXJjZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IGFkZCByZXNvdXJjZXMgd2hpbGUgdGhlIGxvYWRlciBpcyBydW5uaW5nLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgcmVzb3VyY2UgYWxyZWFkeSBleGlzdHMuXG4gICAgICAgIGlmICh0aGlzLnJlc291cmNlc1tuYW1lXSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdSZXNvdXJjZSBuYW1lZCBcIicgKyBuYW1lICsgJ1wiIGFscmVhZHkgZXhpc3RzLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gYWRkIGJhc2UgdXJsIGlmIHRoaXMgaXNuJ3QgYW4gYWJzb2x1dGUgdXJsXG4gICAgICAgIHVybCA9IHRoaXMuX3ByZXBhcmVVcmwodXJsKTtcblxuICAgICAgICAvLyBjcmVhdGUgdGhlIHN0b3JlIHRoZSByZXNvdXJjZVxuICAgICAgICB0aGlzLnJlc291cmNlc1tuYW1lXSA9IG5ldyBfUmVzb3VyY2UyLmRlZmF1bHQobmFtZSwgdXJsLCBvcHRpb25zKTtcblxuICAgICAgICBpZiAodHlwZW9mIGNiID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICB0aGlzLnJlc291cmNlc1tuYW1lXS5vbkFmdGVyTWlkZGxld2FyZS5vbmNlKGNiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGlmIGFjdGl2ZWx5IGxvYWRpbmcsIG1ha2Ugc3VyZSB0byBhZGp1c3QgcHJvZ3Jlc3MgY2h1bmtzIGZvciB0aGF0IHBhcmVudCBhbmQgaXRzIGNoaWxkcmVuXG4gICAgICAgIGlmICh0aGlzLmxvYWRpbmcpIHtcbiAgICAgICAgICAgIHZhciBwYXJlbnQgPSBvcHRpb25zLnBhcmVudFJlc291cmNlO1xuICAgICAgICAgICAgdmFyIGluY29tcGxldGVDaGlsZHJlbiA9IFtdO1xuXG4gICAgICAgICAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgcGFyZW50LmNoaWxkcmVuLmxlbmd0aDsgKytfaSkge1xuICAgICAgICAgICAgICAgIGlmICghcGFyZW50LmNoaWxkcmVuW19pXS5pc0NvbXBsZXRlKSB7XG4gICAgICAgICAgICAgICAgICAgIGluY29tcGxldGVDaGlsZHJlbi5wdXNoKHBhcmVudC5jaGlsZHJlbltfaV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGZ1bGxDaHVuayA9IHBhcmVudC5wcm9ncmVzc0NodW5rICogKGluY29tcGxldGVDaGlsZHJlbi5sZW5ndGggKyAxKTsgLy8gKzEgZm9yIHBhcmVudFxuICAgICAgICAgICAgdmFyIGVhY2hDaHVuayA9IGZ1bGxDaHVuayAvIChpbmNvbXBsZXRlQ2hpbGRyZW4ubGVuZ3RoICsgMik7IC8vICsyIGZvciBwYXJlbnQgJiBuZXcgY2hpbGRcblxuICAgICAgICAgICAgcGFyZW50LmNoaWxkcmVuLnB1c2godGhpcy5yZXNvdXJjZXNbbmFtZV0pO1xuICAgICAgICAgICAgcGFyZW50LnByb2dyZXNzQ2h1bmsgPSBlYWNoQ2h1bms7XG5cbiAgICAgICAgICAgIGZvciAodmFyIF9pMiA9IDA7IF9pMiA8IGluY29tcGxldGVDaGlsZHJlbi5sZW5ndGg7ICsrX2kyKSB7XG4gICAgICAgICAgICAgICAgaW5jb21wbGV0ZUNoaWxkcmVuW19pMl0ucHJvZ3Jlc3NDaHVuayA9IGVhY2hDaHVuaztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5yZXNvdXJjZXNbbmFtZV0ucHJvZ3Jlc3NDaHVuayA9IGVhY2hDaHVuaztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGFkZCB0aGUgcmVzb3VyY2UgdG8gdGhlIHF1ZXVlXG4gICAgICAgIHRoaXMuX3F1ZXVlLnB1c2godGhpcy5yZXNvdXJjZXNbbmFtZV0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHVwIGEgbWlkZGxld2FyZSBmdW5jdGlvbiB0aGF0IHdpbGwgcnVuICpiZWZvcmUqIHRoZVxuICAgICAqIHJlc291cmNlIGlzIGxvYWRlZC5cbiAgICAgKlxuICAgICAqIEBtZXRob2QgYmVmb3JlXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbiB0byByZWdpc3Rlci5cbiAgICAgKiBAcmV0dXJuIHtMb2FkZXJ9IFJldHVybnMgaXRzZWxmLlxuICAgICAqL1xuXG5cbiAgICBMb2FkZXIucHJvdG90eXBlLnByZSA9IGZ1bmN0aW9uIHByZShmbikge1xuICAgICAgICB0aGlzLl9iZWZvcmVNaWRkbGV3YXJlLnB1c2goZm4pO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHVwIGEgbWlkZGxld2FyZSBmdW5jdGlvbiB0aGF0IHdpbGwgcnVuICphZnRlciogdGhlXG4gICAgICogcmVzb3VyY2UgaXMgbG9hZGVkLlxuICAgICAqXG4gICAgICogQGFsaWFzIHVzZVxuICAgICAqIEBtZXRob2QgYWZ0ZXJcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uIHRvIHJlZ2lzdGVyLlxuICAgICAqIEByZXR1cm4ge0xvYWRlcn0gUmV0dXJucyBpdHNlbGYuXG4gICAgICovXG5cblxuICAgIExvYWRlci5wcm90b3R5cGUudXNlID0gZnVuY3Rpb24gdXNlKGZuKSB7XG4gICAgICAgIHRoaXMuX2FmdGVyTWlkZGxld2FyZS5wdXNoKGZuKTtcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmVzZXRzIHRoZSBxdWV1ZSBvZiB0aGUgbG9hZGVyIHRvIHByZXBhcmUgZm9yIGEgbmV3IGxvYWQuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtMb2FkZXJ9IFJldHVybnMgaXRzZWxmLlxuICAgICAqL1xuXG5cbiAgICBMb2FkZXIucHJvdG90eXBlLnJlc2V0ID0gZnVuY3Rpb24gcmVzZXQoKSB7XG4gICAgICAgIHRoaXMucHJvZ3Jlc3MgPSAwO1xuICAgICAgICB0aGlzLmxvYWRpbmcgPSBmYWxzZTtcblxuICAgICAgICB0aGlzLl9xdWV1ZS5raWxsKCk7XG4gICAgICAgIHRoaXMuX3F1ZXVlLnBhdXNlKCk7XG5cbiAgICAgICAgLy8gYWJvcnQgYWxsIHJlc291cmNlIGxvYWRzXG4gICAgICAgIGZvciAodmFyIGsgaW4gdGhpcy5yZXNvdXJjZXMpIHtcbiAgICAgICAgICAgIHZhciByZXMgPSB0aGlzLnJlc291cmNlc1trXTtcblxuICAgICAgICAgICAgaWYgKHJlcy5fb25Mb2FkQmluZGluZykge1xuICAgICAgICAgICAgICAgIHJlcy5fb25Mb2FkQmluZGluZy5kZXRhY2goKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHJlcy5pc0xvYWRpbmcpIHtcbiAgICAgICAgICAgICAgICByZXMuYWJvcnQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVzb3VyY2VzID0ge307XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0cyBsb2FkaW5nIHRoZSBxdWV1ZWQgcmVzb3VyY2VzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gW2NiXSAtIE9wdGlvbmFsIGNhbGxiYWNrIHRoYXQgd2lsbCBiZSBib3VuZCB0byB0aGUgYGNvbXBsZXRlYCBldmVudC5cbiAgICAgKiBAcmV0dXJuIHtMb2FkZXJ9IFJldHVybnMgaXRzZWxmLlxuICAgICAqL1xuXG5cbiAgICBMb2FkZXIucHJvdG90eXBlLmxvYWQgPSBmdW5jdGlvbiBsb2FkKGNiKSB7XG4gICAgICAgIC8vIHJlZ2lzdGVyIGNvbXBsZXRlIGNhbGxiYWNrIGlmIHRoZXkgcGFzcyBvbmVcbiAgICAgICAgaWYgKHR5cGVvZiBjYiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgdGhpcy5vbkNvbXBsZXRlLm9uY2UoY2IpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gaWYgdGhlIHF1ZXVlIGhhcyBhbHJlYWR5IHN0YXJ0ZWQgd2UgYXJlIGRvbmUgaGVyZVxuICAgICAgICBpZiAodGhpcy5sb2FkaW5nKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLl9xdWV1ZS5pZGxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuX29uU3RhcnQoKTtcbiAgICAgICAgICAgIHRoaXMuX29uQ29tcGxldGUoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIGRpc3RyaWJ1dGUgcHJvZ3Jlc3MgY2h1bmtzXG4gICAgICAgICAgICB2YXIgbnVtVGFza3MgPSB0aGlzLl9xdWV1ZS5fdGFza3MubGVuZ3RoO1xuICAgICAgICAgICAgdmFyIGNodW5rID0gMTAwIC8gbnVtVGFza3M7XG5cbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5fcXVldWUuX3Rhc2tzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fcXVldWUuX3Rhc2tzW2ldLmRhdGEucHJvZ3Jlc3NDaHVuayA9IGNodW5rO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBub3RpZnkgd2UgYXJlIHN0YXJ0aW5nXG4gICAgICAgICAgICB0aGlzLl9vblN0YXJ0KCk7XG5cbiAgICAgICAgICAgIC8vIHN0YXJ0IGxvYWRpbmdcbiAgICAgICAgICAgIHRoaXMuX3F1ZXVlLnJlc3VtZSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHRvIGxvYWQgY29uY3VycmVudGx5LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDEwXG4gICAgICovXG5cblxuICAgIC8qKlxuICAgICAqIFByZXBhcmVzIGEgdXJsIGZvciB1c2FnZSBiYXNlZCBvbiB0aGUgY29uZmlndXJhdGlvbiBvZiB0aGlzIG9iamVjdFxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIHVybCB0byBwcmVwYXJlLlxuICAgICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIHByZXBhcmVkIHVybC5cbiAgICAgKi9cbiAgICBMb2FkZXIucHJvdG90eXBlLl9wcmVwYXJlVXJsID0gZnVuY3Rpb24gX3ByZXBhcmVVcmwodXJsKSB7XG4gICAgICAgIHZhciBwYXJzZWRVcmwgPSAoMCwgX3BhcnNlVXJpMi5kZWZhdWx0KSh1cmwsIHsgc3RyaWN0TW9kZTogdHJ1ZSB9KTtcbiAgICAgICAgdmFyIHJlc3VsdCA9IHZvaWQgMDtcblxuICAgICAgICAvLyBhYnNvbHV0ZSB1cmwsIGp1c3QgdXNlIGl0IGFzIGlzLlxuICAgICAgICBpZiAocGFyc2VkVXJsLnByb3RvY29sIHx8ICFwYXJzZWRVcmwucGF0aCB8fCB1cmwuaW5kZXhPZignLy8nKSA9PT0gMCkge1xuICAgICAgICAgICAgcmVzdWx0ID0gdXJsO1xuICAgICAgICB9XG4gICAgICAgIC8vIGlmIGJhc2VVcmwgZG9lc24ndCBlbmQgaW4gc2xhc2ggYW5kIHVybCBkb2Vzbid0IHN0YXJ0IHdpdGggc2xhc2gsIHRoZW4gYWRkIGEgc2xhc2ggaW5iZXR3ZWVuXG4gICAgICAgIGVsc2UgaWYgKHRoaXMuYmFzZVVybC5sZW5ndGggJiYgdGhpcy5iYXNlVXJsLmxhc3RJbmRleE9mKCcvJykgIT09IHRoaXMuYmFzZVVybC5sZW5ndGggLSAxICYmIHVybC5jaGFyQXQoMCkgIT09ICcvJykge1xuICAgICAgICAgICAgICAgIHJlc3VsdCA9IHRoaXMuYmFzZVVybCArICcvJyArIHVybDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0ID0gdGhpcy5iYXNlVXJsICsgdXJsO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgIC8vIGlmIHdlIG5lZWQgdG8gYWRkIGEgZGVmYXVsdCBxdWVyeXN0cmluZywgdGhlcmUgaXMgYSBiaXQgbW9yZSB3b3JrXG4gICAgICAgIGlmICh0aGlzLmRlZmF1bHRRdWVyeVN0cmluZykge1xuICAgICAgICAgICAgdmFyIGhhc2ggPSByZ3hFeHRyYWN0VXJsSGFzaC5leGVjKHJlc3VsdClbMF07XG5cbiAgICAgICAgICAgIHJlc3VsdCA9IHJlc3VsdC5zdWJzdHIoMCwgcmVzdWx0Lmxlbmd0aCAtIGhhc2gubGVuZ3RoKTtcblxuICAgICAgICAgICAgaWYgKHJlc3VsdC5pbmRleE9mKCc/JykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9ICcmJyArIHRoaXMuZGVmYXVsdFF1ZXJ5U3RyaW5nO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXN1bHQgKz0gJz8nICsgdGhpcy5kZWZhdWx0UXVlcnlTdHJpbmc7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJlc3VsdCArPSBoYXNoO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogTG9hZHMgYSBzaW5nbGUgcmVzb3VyY2UuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7UmVzb3VyY2V9IHJlc291cmNlIC0gVGhlIHJlc291cmNlIHRvIGxvYWQuXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gZGVxdWV1ZSAtIFRoZSBmdW5jdGlvbiB0byBjYWxsIHdoZW4gd2UgbmVlZCB0byBkZXF1ZXVlIHRoaXMgaXRlbS5cbiAgICAgKi9cblxuXG4gICAgTG9hZGVyLnByb3RvdHlwZS5fbG9hZFJlc291cmNlID0gZnVuY3Rpb24gX2xvYWRSZXNvdXJjZShyZXNvdXJjZSwgZGVxdWV1ZSkge1xuICAgICAgICB2YXIgX3RoaXMyID0gdGhpcztcblxuICAgICAgICByZXNvdXJjZS5fZGVxdWV1ZSA9IGRlcXVldWU7XG5cbiAgICAgICAgLy8gcnVuIGJlZm9yZSBtaWRkbGV3YXJlXG4gICAgICAgIGFzeW5jLmVhY2hTZXJpZXModGhpcy5fYmVmb3JlTWlkZGxld2FyZSwgZnVuY3Rpb24gKGZuLCBuZXh0KSB7XG4gICAgICAgICAgICBmbi5jYWxsKF90aGlzMiwgcmVzb3VyY2UsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyBpZiB0aGUgYmVmb3JlIG1pZGRsZXdhcmUgbWFya3MgdGhlIHJlc291cmNlIGFzIGNvbXBsZXRlLFxuICAgICAgICAgICAgICAgIC8vIGJyZWFrIGFuZCBkb24ndCBwcm9jZXNzIGFueSBtb3JlIGJlZm9yZSBtaWRkbGV3YXJlXG4gICAgICAgICAgICAgICAgbmV4dChyZXNvdXJjZS5pc0NvbXBsZXRlID8ge30gOiBudWxsKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAocmVzb3VyY2UuaXNDb21wbGV0ZSkge1xuICAgICAgICAgICAgICAgIF90aGlzMi5fb25Mb2FkKHJlc291cmNlKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVzb3VyY2UuX29uTG9hZEJpbmRpbmcgPSByZXNvdXJjZS5vbkNvbXBsZXRlLm9uY2UoX3RoaXMyLl9vbkxvYWQsIF90aGlzMik7XG4gICAgICAgICAgICAgICAgcmVzb3VyY2UubG9hZCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCB0cnVlKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2FsbGVkIG9uY2UgbG9hZGluZyBoYXMgc3RhcnRlZC5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG5cblxuICAgIExvYWRlci5wcm90b3R5cGUuX29uU3RhcnQgPSBmdW5jdGlvbiBfb25TdGFydCgpIHtcbiAgICAgICAgdGhpcy5wcm9ncmVzcyA9IDA7XG4gICAgICAgIHRoaXMubG9hZGluZyA9IHRydWU7XG4gICAgICAgIHRoaXMub25TdGFydC5kaXNwYXRjaCh0aGlzKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2FsbGVkIG9uY2UgZWFjaCByZXNvdXJjZSBoYXMgbG9hZGVkLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cblxuXG4gICAgTG9hZGVyLnByb3RvdHlwZS5fb25Db21wbGV0ZSA9IGZ1bmN0aW9uIF9vbkNvbXBsZXRlKCkge1xuICAgICAgICB0aGlzLnByb2dyZXNzID0gTUFYX1BST0dSRVNTO1xuICAgICAgICB0aGlzLmxvYWRpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5vbkNvbXBsZXRlLmRpc3BhdGNoKHRoaXMsIHRoaXMucmVzb3VyY2VzKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2FsbGVkIGVhY2ggdGltZSBhIHJlc291cmNlcyBpcyBsb2FkZWQuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7UmVzb3VyY2V9IHJlc291cmNlIC0gVGhlIHJlc291cmNlIHRoYXQgd2FzIGxvYWRlZFxuICAgICAqL1xuXG5cbiAgICBMb2FkZXIucHJvdG90eXBlLl9vbkxvYWQgPSBmdW5jdGlvbiBfb25Mb2FkKHJlc291cmNlKSB7XG4gICAgICAgIHZhciBfdGhpczMgPSB0aGlzO1xuXG4gICAgICAgIHJlc291cmNlLl9vbkxvYWRCaW5kaW5nID0gbnVsbDtcblxuICAgICAgICAvLyByZW1vdmUgdGhpcyByZXNvdXJjZSBmcm9tIHRoZSBhc3luYyBxdWV1ZSwgYW5kIGFkZCBpdCB0byBvdXIgbGlzdCBvZiByZXNvdXJjZXMgdGhhdCBhcmUgYmVpbmcgcGFyc2VkXG4gICAgICAgIHRoaXMuX3Jlc291cmNlc1BhcnNpbmcucHVzaChyZXNvdXJjZSk7XG4gICAgICAgIHJlc291cmNlLl9kZXF1ZXVlKCk7XG5cbiAgICAgICAgLy8gcnVuIGFsbCB0aGUgYWZ0ZXIgbWlkZGxld2FyZSBmb3IgdGhpcyByZXNvdXJjZVxuICAgICAgICBhc3luYy5lYWNoU2VyaWVzKHRoaXMuX2FmdGVyTWlkZGxld2FyZSwgZnVuY3Rpb24gKGZuLCBuZXh0KSB7XG4gICAgICAgICAgICBmbi5jYWxsKF90aGlzMywgcmVzb3VyY2UsIG5leHQpO1xuICAgICAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXNvdXJjZS5vbkFmdGVyTWlkZGxld2FyZS5kaXNwYXRjaChyZXNvdXJjZSk7XG5cbiAgICAgICAgICAgIF90aGlzMy5wcm9ncmVzcyArPSByZXNvdXJjZS5wcm9ncmVzc0NodW5rO1xuICAgICAgICAgICAgX3RoaXMzLm9uUHJvZ3Jlc3MuZGlzcGF0Y2goX3RoaXMzLCByZXNvdXJjZSk7XG5cbiAgICAgICAgICAgIGlmIChyZXNvdXJjZS5lcnJvcikge1xuICAgICAgICAgICAgICAgIF90aGlzMy5vbkVycm9yLmRpc3BhdGNoKHJlc291cmNlLmVycm9yLCBfdGhpczMsIHJlc291cmNlKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgX3RoaXMzLm9uTG9hZC5kaXNwYXRjaChfdGhpczMsIHJlc291cmNlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgX3RoaXMzLl9yZXNvdXJjZXNQYXJzaW5nLnNwbGljZShfdGhpczMuX3Jlc291cmNlc1BhcnNpbmcuaW5kZXhPZihyZXNvdXJjZSksIDEpO1xuXG4gICAgICAgICAgICAvLyBkbyBjb21wbGV0aW9uIGNoZWNrXG4gICAgICAgICAgICBpZiAoX3RoaXMzLl9xdWV1ZS5pZGxlKCkgJiYgX3RoaXMzLl9yZXNvdXJjZXNQYXJzaW5nLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIF90aGlzMy5fb25Db21wbGV0ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCB0cnVlKTtcbiAgICB9O1xuXG4gICAgX2NyZWF0ZUNsYXNzKExvYWRlciwgW3tcbiAgICAgICAga2V5OiAnY29uY3VycmVuY3knLFxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9xdWV1ZS5jb25jdXJyZW5jeTtcbiAgICAgICAgfVxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVxdWlyZS1qc2RvY1xuICAgICAgICAsXG4gICAgICAgIHNldDogZnVuY3Rpb24gc2V0KGNvbmN1cnJlbmN5KSB7XG4gICAgICAgICAgICB0aGlzLl9xdWV1ZS5jb25jdXJyZW5jeSA9IGNvbmN1cnJlbmN5O1xuICAgICAgICB9XG4gICAgfV0pO1xuXG4gICAgcmV0dXJuIExvYWRlcjtcbn0oKTtcblxuZXhwb3J0cy5kZWZhdWx0ID0gTG9hZGVyO1xuLy8jIHNvdXJjZU1hcHBpbmdVUkw9TG9hZGVyLmpzLm1hcCIsIid1c2Ugc3RyaWN0JztcblxuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZTtcblxudmFyIF9jcmVhdGVDbGFzcyA9IGZ1bmN0aW9uICgpIHsgZnVuY3Rpb24gZGVmaW5lUHJvcGVydGllcyh0YXJnZXQsIHByb3BzKSB7IGZvciAodmFyIGkgPSAwOyBpIDwgcHJvcHMubGVuZ3RoOyBpKyspIHsgdmFyIGRlc2NyaXB0b3IgPSBwcm9wc1tpXTsgZGVzY3JpcHRvci5lbnVtZXJhYmxlID0gZGVzY3JpcHRvci5lbnVtZXJhYmxlIHx8IGZhbHNlOyBkZXNjcmlwdG9yLmNvbmZpZ3VyYWJsZSA9IHRydWU7IGlmIChcInZhbHVlXCIgaW4gZGVzY3JpcHRvcikgZGVzY3JpcHRvci53cml0YWJsZSA9IHRydWU7IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGRlc2NyaXB0b3Iua2V5LCBkZXNjcmlwdG9yKTsgfSB9IHJldHVybiBmdW5jdGlvbiAoQ29uc3RydWN0b3IsIHByb3RvUHJvcHMsIHN0YXRpY1Byb3BzKSB7IGlmIChwcm90b1Byb3BzKSBkZWZpbmVQcm9wZXJ0aWVzKENvbnN0cnVjdG9yLnByb3RvdHlwZSwgcHJvdG9Qcm9wcyk7IGlmIChzdGF0aWNQcm9wcykgZGVmaW5lUHJvcGVydGllcyhDb25zdHJ1Y3Rvciwgc3RhdGljUHJvcHMpOyByZXR1cm4gQ29uc3RydWN0b3I7IH07IH0oKTtcblxudmFyIF9wYXJzZVVyaSA9IHJlcXVpcmUoJ3BhcnNlLXVyaScpO1xuXG52YXIgX3BhcnNlVXJpMiA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQoX3BhcnNlVXJpKTtcblxudmFyIF9taW5pU2lnbmFscyA9IHJlcXVpcmUoJ21pbmktc2lnbmFscycpO1xuXG52YXIgX21pbmlTaWduYWxzMiA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQoX21pbmlTaWduYWxzKTtcblxuZnVuY3Rpb24gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChvYmopIHsgcmV0dXJuIG9iaiAmJiBvYmouX19lc01vZHVsZSA/IG9iaiA6IHsgZGVmYXVsdDogb2JqIH07IH1cblxuZnVuY3Rpb24gX2NsYXNzQ2FsbENoZWNrKGluc3RhbmNlLCBDb25zdHJ1Y3RvcikgeyBpZiAoIShpbnN0YW5jZSBpbnN0YW5jZW9mIENvbnN0cnVjdG9yKSkgeyB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uXCIpOyB9IH1cblxuLy8gdGVzdHMgaXMgQ09SUyBpcyBzdXBwb3J0ZWQgaW4gWEhSLCBpZiBub3Qgd2UgbmVlZCB0byB1c2UgWERSXG52YXIgdXNlWGRyID0gISEod2luZG93LlhEb21haW5SZXF1ZXN0ICYmICEoJ3dpdGhDcmVkZW50aWFscycgaW4gbmV3IFhNTEh0dHBSZXF1ZXN0KCkpKTtcbnZhciB0ZW1wQW5jaG9yID0gbnVsbDtcblxuLy8gc29tZSBzdGF0dXMgY29uc3RhbnRzXG52YXIgU1RBVFVTX05PTkUgPSAwO1xudmFyIFNUQVRVU19PSyA9IDIwMDtcbnZhciBTVEFUVVNfRU1QVFkgPSAyMDQ7XG52YXIgU1RBVFVTX0lFX0JVR19FTVBUWSA9IDEyMjM7XG52YXIgU1RBVFVTX1RZUEVfT0sgPSAyO1xuXG4vLyBub29wXG5mdW5jdGlvbiBfbm9vcCgpIHt9IC8qIGVtcHR5ICovXG5cbi8qKlxuICogTWFuYWdlcyB0aGUgc3RhdGUgYW5kIGxvYWRpbmcgb2YgYSByZXNvdXJjZSBhbmQgYWxsIGNoaWxkIHJlc291cmNlcy5cbiAqXG4gKiBAY2xhc3NcbiAqL1xuXG52YXIgUmVzb3VyY2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgbG9hZCB0eXBlIHRvIGJlIHVzZWQgZm9yIGEgc3BlY2lmaWMgZXh0ZW5zaW9uLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBleHRuYW1lIC0gVGhlIGV4dGVuc2lvbiB0byBzZXQgdGhlIHR5cGUgZm9yLCBlLmcuIFwicG5nXCIgb3IgXCJmbnRcIlxuICAgICAqIEBwYXJhbSB7UmVzb3VyY2UuTE9BRF9UWVBFfSBsb2FkVHlwZSAtIFRoZSBsb2FkIHR5cGUgdG8gc2V0IGl0IHRvLlxuICAgICAqL1xuICAgIFJlc291cmNlLnNldEV4dGVuc2lvbkxvYWRUeXBlID0gZnVuY3Rpb24gc2V0RXh0ZW5zaW9uTG9hZFR5cGUoZXh0bmFtZSwgbG9hZFR5cGUpIHtcbiAgICAgICAgc2V0RXh0TWFwKFJlc291cmNlLl9sb2FkVHlwZU1hcCwgZXh0bmFtZSwgbG9hZFR5cGUpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBsb2FkIHR5cGUgdG8gYmUgdXNlZCBmb3IgYSBzcGVjaWZpYyBleHRlbnNpb24uXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV4dG5hbWUgLSBUaGUgZXh0ZW5zaW9uIHRvIHNldCB0aGUgdHlwZSBmb3IsIGUuZy4gXCJwbmdcIiBvciBcImZudFwiXG4gICAgICogQHBhcmFtIHtSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRX0geGhyVHlwZSAtIFRoZSB4aHIgdHlwZSB0byBzZXQgaXQgdG8uXG4gICAgICovXG5cblxuICAgIFJlc291cmNlLnNldEV4dGVuc2lvblhoclR5cGUgPSBmdW5jdGlvbiBzZXRFeHRlbnNpb25YaHJUeXBlKGV4dG5hbWUsIHhoclR5cGUpIHtcbiAgICAgICAgc2V0RXh0TWFwKFJlc291cmNlLl94aHJUeXBlTWFwLCBleHRuYW1lLCB4aHJUeXBlKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgcmVzb3VyY2UgdG8gbG9hZC5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ3xzdHJpbmdbXX0gdXJsIC0gVGhlIHVybCBmb3IgdGhpcyByZXNvdXJjZSwgZm9yIGF1ZGlvL3ZpZGVvIGxvYWRzIHlvdSBjYW4gcGFzc1xuICAgICAqICAgICAgYW4gYXJyYXkgb2Ygc291cmNlcy5cbiAgICAgKiBAcGFyYW0ge29iamVjdH0gW29wdGlvbnNdIC0gVGhlIG9wdGlvbnMgZm9yIHRoZSBsb2FkLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfGJvb2xlYW59IFtvcHRpb25zLmNyb3NzT3JpZ2luXSAtIElzIHRoaXMgcmVxdWVzdCBjcm9zcy1vcmlnaW4/IERlZmF1bHQgaXMgdG9cbiAgICAgKiAgICAgIGRldGVybWluZSBhdXRvbWF0aWNhbGx5LlxuICAgICAqIEBwYXJhbSB7UmVzb3VyY2UuTE9BRF9UWVBFfSBbb3B0aW9ucy5sb2FkVHlwZT1SZXNvdXJjZS5MT0FEX1RZUEUuWEhSXSAtIEhvdyBzaG91bGQgdGhpcyByZXNvdXJjZVxuICAgICAqICAgICAgYmUgbG9hZGVkP1xuICAgICAqIEBwYXJhbSB7UmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEV9IFtvcHRpb25zLnhoclR5cGU9UmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEUuREVGQVVMVF0gLSBIb3dcbiAgICAgKiAgICAgIHNob3VsZCB0aGUgZGF0YSBiZWluZyBsb2FkZWQgYmUgaW50ZXJwcmV0ZWQgd2hlbiB1c2luZyBYSFI/XG4gICAgICogQHBhcmFtIHtvYmplY3R9IFtvcHRpb25zLm1ldGFkYXRhXSAtIEV4dHJhIGNvbmZpZ3VyYXRpb24gZm9yIG1pZGRsZXdhcmUgYW5kIHRoZSBSZXNvdXJjZSBvYmplY3QuXG4gICAgICogQHBhcmFtIHtIVE1MSW1hZ2VFbGVtZW50fEhUTUxBdWRpb0VsZW1lbnR8SFRNTFZpZGVvRWxlbWVudH0gW29wdGlvbnMubWV0YWRhdGEubG9hZEVsZW1lbnQ9bnVsbF0gLSBUaGVcbiAgICAgKiAgICAgIGVsZW1lbnQgdG8gdXNlIGZvciBsb2FkaW5nLCBpbnN0ZWFkIG9mIGNyZWF0aW5nIG9uZS5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLm1ldGFkYXRhLnNraXBTb3VyY2U9ZmFsc2VdIC0gU2tpcHMgYWRkaW5nIHNvdXJjZShzKSB0byB0aGUgbG9hZCBlbGVtZW50LiBUaGlzXG4gICAgICogICAgICBpcyB1c2VmdWwgaWYgeW91IHdhbnQgdG8gcGFzcyBpbiBhIGBsb2FkRWxlbWVudGAgdGhhdCB5b3UgYWxyZWFkeSBhZGRlZCBsb2FkIHNvdXJjZXMgdG8uXG4gICAgICogQHBhcmFtIHtzdHJpbmd8c3RyaW5nW119IFtvcHRpb25zLm1ldGFkYXRhLm1pbWVUeXBlXSAtIFRoZSBtaW1lIHR5cGUgdG8gdXNlIGZvciB0aGUgc291cmNlIGVsZW1lbnQgb2YgYSB2aWRlby9hdWRpb1xuICAgICAqICAgICAgZWxtZW50LiBJZiB0aGUgdXJscyBhcmUgYW4gYXJyYXksIHlvdSBjYW4gcGFzcyB0aGlzIGFzIGFuIGFycmF5IGFzIHdlbGwgd2hlcmUgZWFjaCBpbmRleCBpcyB0aGUgbWltZSB0eXBlIHRvXG4gICAgICogICAgICB1c2UgZm9yIHRoZSBjb3JyZXNwb25kaW5nIHVybCBpbmRleC5cbiAgICAgKi9cblxuXG4gICAgZnVuY3Rpb24gUmVzb3VyY2UobmFtZSwgdXJsLCBvcHRpb25zKSB7XG4gICAgICAgIF9jbGFzc0NhbGxDaGVjayh0aGlzLCBSZXNvdXJjZSk7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBuYW1lICE9PSAnc3RyaW5nJyB8fCB0eXBlb2YgdXJsICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdCb3RoIG5hbWUgYW5kIHVybCBhcmUgcmVxdWlyZWQgZm9yIGNvbnN0cnVjdGluZyBhIHJlc291cmNlLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBzdGF0ZSBmbGFncyBvZiB0aGlzIHJlc291cmNlLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLl9mbGFncyA9IDA7XG5cbiAgICAgICAgLy8gc2V0IGRhdGEgdXJsIGZsYWcsIG5lZWRzIHRvIGJlIHNldCBlYXJseSBmb3Igc29tZSBfZGV0ZXJtaW5lWCBjaGVja3MgdG8gd29yay5cbiAgICAgICAgdGhpcy5fc2V0RmxhZyhSZXNvdXJjZS5TVEFUVVNfRkxBR1MuREFUQV9VUkwsIHVybC5pbmRleE9mKCdkYXRhOicpID09PSAwKTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIG5hbWUgb2YgdGhpcyByZXNvdXJjZS5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7c3RyaW5nfVxuICAgICAgICAgKiBAcmVhZG9ubHlcbiAgICAgICAgICovXG4gICAgICAgIHRoaXMubmFtZSA9IG5hbWU7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSB1cmwgdXNlZCB0byBsb2FkIHRoaXMgcmVzb3VyY2UuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBtZW1iZXIge3N0cmluZ31cbiAgICAgICAgICogQHJlYWRvbmx5XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLnVybCA9IHVybDtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGV4dGVuc2lvbiB1c2VkIHRvIGxvYWQgdGhpcyByZXNvdXJjZS5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7c3RyaW5nfVxuICAgICAgICAgKiBAcmVhZG9ubHlcbiAgICAgICAgICovXG4gICAgICAgIHRoaXMuZXh0ZW5zaW9uID0gdGhpcy5fZ2V0RXh0ZW5zaW9uKCk7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBkYXRhIHRoYXQgd2FzIGxvYWRlZCBieSB0aGUgcmVzb3VyY2UuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBtZW1iZXIge2FueX1cbiAgICAgICAgICovXG4gICAgICAgIHRoaXMuZGF0YSA9IG51bGw7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIElzIHRoaXMgcmVxdWVzdCBjcm9zcy1vcmlnaW4/IElmIHVuc2V0LCBkZXRlcm1pbmVkIGF1dG9tYXRpY2FsbHkuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBtZW1iZXIge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRoaXMuY3Jvc3NPcmlnaW4gPSBvcHRpb25zLmNyb3NzT3JpZ2luID09PSB0cnVlID8gJ2Fub255bW91cycgOiBvcHRpb25zLmNyb3NzT3JpZ2luO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbWV0aG9kIG9mIGxvYWRpbmcgdG8gdXNlIGZvciB0aGlzIHJlc291cmNlLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtSZXNvdXJjZS5MT0FEX1RZUEV9XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLmxvYWRUeXBlID0gb3B0aW9ucy5sb2FkVHlwZSB8fCB0aGlzLl9kZXRlcm1pbmVMb2FkVHlwZSgpO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgdHlwZSB1c2VkIHRvIGxvYWQgdGhlIHJlc291cmNlIHZpYSBYSFIuIElmIHVuc2V0LCBkZXRlcm1pbmVkIGF1dG9tYXRpY2FsbHkuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBtZW1iZXIge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRoaXMueGhyVHlwZSA9IG9wdGlvbnMueGhyVHlwZTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogRXh0cmEgaW5mbyBmb3IgbWlkZGxld2FyZSwgYW5kIGNvbnRyb2xsaW5nIHNwZWNpZmljcyBhYm91dCBob3cgdGhlIHJlc291cmNlIGxvYWRzLlxuICAgICAgICAgKlxuICAgICAgICAgKiBOb3RlIHRoYXQgaWYgeW91IHBhc3MgaW4gYSBgbG9hZEVsZW1lbnRgLCB0aGUgUmVzb3VyY2UgY2xhc3MgdGFrZXMgb3duZXJzaGlwIG9mIGl0LlxuICAgICAgICAgKiBNZWFuaW5nIGl0IHdpbGwgbW9kaWZ5IGl0IGFzIGl0IHNlZXMgZml0LlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICAgICAqIEBwcm9wZXJ0eSB7SFRNTEltYWdlRWxlbWVudHxIVE1MQXVkaW9FbGVtZW50fEhUTUxWaWRlb0VsZW1lbnR9IFtsb2FkRWxlbWVudD1udWxsXSAtIFRoZVxuICAgICAgICAgKiAgZWxlbWVudCB0byB1c2UgZm9yIGxvYWRpbmcsIGluc3RlYWQgb2YgY3JlYXRpbmcgb25lLlxuICAgICAgICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IFtza2lwU291cmNlPWZhbHNlXSAtIFNraXBzIGFkZGluZyBzb3VyY2UocykgdG8gdGhlIGxvYWQgZWxlbWVudC4gVGhpc1xuICAgICAgICAgKiAgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIHBhc3MgaW4gYSBgbG9hZEVsZW1lbnRgIHRoYXQgeW91IGFscmVhZHkgYWRkZWQgbG9hZCBzb3VyY2VzXG4gICAgICAgICAqICB0by5cbiAgICAgICAgICovXG4gICAgICAgIHRoaXMubWV0YWRhdGEgPSBvcHRpb25zLm1ldGFkYXRhIHx8IHt9O1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZXJyb3IgdGhhdCBvY2N1cnJlZCB3aGlsZSBsb2FkaW5nIChpZiBhbnkpLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtFcnJvcn1cbiAgICAgICAgICogQHJlYWRvbmx5XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLmVycm9yID0gbnVsbDtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIFhIUiBvYmplY3QgdGhhdCB3YXMgdXNlZCB0byBsb2FkIHRoaXMgcmVzb3VyY2UuIFRoaXMgaXMgb25seSBzZXRcbiAgICAgICAgICogd2hlbiBgbG9hZFR5cGVgIGlzIGBSZXNvdXJjZS5MT0FEX1RZUEUuWEhSYC5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7WE1MSHR0cFJlcXVlc3R9XG4gICAgICAgICAqIEByZWFkb25seVxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy54aHIgPSBudWxsO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgY2hpbGQgcmVzb3VyY2VzIHRoaXMgcmVzb3VyY2Ugb3ducy5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7UmVzb3VyY2VbXX1cbiAgICAgICAgICogQHJlYWRvbmx5XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLmNoaWxkcmVuID0gW107XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSByZXNvdXJjZSB0eXBlLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtSZXNvdXJjZS5UWVBFfVxuICAgICAgICAgKiBAcmVhZG9ubHlcbiAgICAgICAgICovXG4gICAgICAgIHRoaXMudHlwZSA9IFJlc291cmNlLlRZUEUuVU5LTk9XTjtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2dyZXNzIGNodW5rIG93bmVkIGJ5IHRoaXMgcmVzb3VyY2UuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgICAgICogQHJlYWRvbmx5XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLnByb2dyZXNzQ2h1bmsgPSAwO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYGRlcXVldWVgIG1ldGhvZCB0aGF0IHdpbGwgYmUgdXNlZCBhIHN0b3JhZ2UgcGxhY2UgZm9yIHRoZSBhc3luYyBxdWV1ZSBkZXF1ZXVlIG1ldGhvZFxuICAgICAgICAgKiB1c2VkIHByaXZhdGVseSBieSB0aGUgbG9hZGVyLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcHJpdmF0ZVxuICAgICAgICAgKiBAbWVtYmVyIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHRoaXMuX2RlcXVldWUgPSBfbm9vcDtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVXNlZCBhIHN0b3JhZ2UgcGxhY2UgZm9yIHRoZSBvbiBsb2FkIGJpbmRpbmcgdXNlZCBwcml2YXRlbHkgYnkgdGhlIGxvYWRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogQHByaXZhdGVcbiAgICAgICAgICogQG1lbWJlciB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLl9vbkxvYWRCaW5kaW5nID0gbnVsbDtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGBjb21wbGV0ZWAgZnVuY3Rpb24gYm91bmQgdG8gdGhpcyByZXNvdXJjZSdzIGNvbnRleHQuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwcml2YXRlXG4gICAgICAgICAqIEBtZW1iZXIge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5fYm91bmRDb21wbGV0ZSA9IHRoaXMuY29tcGxldGUuYmluZCh0aGlzKTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGBfb25FcnJvcmAgZnVuY3Rpb24gYm91bmQgdG8gdGhpcyByZXNvdXJjZSdzIGNvbnRleHQuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwcml2YXRlXG4gICAgICAgICAqIEBtZW1iZXIge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5fYm91bmRPbkVycm9yID0gdGhpcy5fb25FcnJvci5iaW5kKHRoaXMpO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYF9vblByb2dyZXNzYCBmdW5jdGlvbiBib3VuZCB0byB0aGlzIHJlc291cmNlJ3MgY29udGV4dC5cbiAgICAgICAgICpcbiAgICAgICAgICogQHByaXZhdGVcbiAgICAgICAgICogQG1lbWJlciB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLl9ib3VuZE9uUHJvZ3Jlc3MgPSB0aGlzLl9vblByb2dyZXNzLmJpbmQodGhpcyk7XG5cbiAgICAgICAgLy8geGhyIGNhbGxiYWNrc1xuICAgICAgICB0aGlzLl9ib3VuZFhock9uRXJyb3IgPSB0aGlzLl94aHJPbkVycm9yLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2JvdW5kWGhyT25BYm9ydCA9IHRoaXMuX3hock9uQWJvcnQuYmluZCh0aGlzKTtcbiAgICAgICAgdGhpcy5fYm91bmRYaHJPbkxvYWQgPSB0aGlzLl94aHJPbkxvYWQuYmluZCh0aGlzKTtcbiAgICAgICAgdGhpcy5fYm91bmRYZHJPblRpbWVvdXQgPSB0aGlzLl94ZHJPblRpbWVvdXQuYmluZCh0aGlzKTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogRGlzcGF0Y2hlZCB3aGVuIHRoZSByZXNvdXJjZSBiZWluZ3MgdG8gbG9hZC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGNhbGxiYWNrIGxvb2tzIGxpa2Uge0BsaW5rIFJlc291cmNlLk9uU3RhcnRTaWduYWx9LlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtTaWduYWx9XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLm9uU3RhcnQgPSBuZXcgX21pbmlTaWduYWxzMi5kZWZhdWx0KCk7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIERpc3BhdGNoZWQgZWFjaCB0aW1lIHByb2dyZXNzIG9mIHRoaXMgcmVzb3VyY2UgbG9hZCB1cGRhdGVzLlxuICAgICAgICAgKiBOb3QgYWxsIHJlc291cmNlcyB0eXBlcyBhbmQgbG9hZGVyIHN5c3RlbXMgY2FuIHN1cHBvcnQgdGhpcyBldmVudFxuICAgICAgICAgKiBzbyBzb21ldGltZXMgaXQgbWF5IG5vdCBiZSBhdmFpbGFibGUuIElmIHRoZSByZXNvdXJjZVxuICAgICAgICAgKiBpcyBiZWluZyBsb2FkZWQgb24gYSBtb2Rlcm4gYnJvd3NlciwgdXNpbmcgWEhSLCBhbmQgdGhlIHJlbW90ZSBzZXJ2ZXJcbiAgICAgICAgICogcHJvcGVybHkgc2V0cyBDb250ZW50LUxlbmd0aCBoZWFkZXJzLCB0aGVuIHRoaXMgd2lsbCBiZSBhdmFpbGFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqIFRoZSBjYWxsYmFjayBsb29rcyBsaWtlIHtAbGluayBSZXNvdXJjZS5PblByb2dyZXNzU2lnbmFsfS5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7U2lnbmFsfVxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5vblByb2dyZXNzID0gbmV3IF9taW5pU2lnbmFsczIuZGVmYXVsdCgpO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBEaXNwYXRjaGVkIG9uY2UgdGhpcyByZXNvdXJjZSBoYXMgbG9hZGVkLCBpZiB0aGVyZSB3YXMgYW4gZXJyb3IgaXQgd2lsbFxuICAgICAgICAgKiBiZSBpbiB0aGUgYGVycm9yYCBwcm9wZXJ0eS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGNhbGxiYWNrIGxvb2tzIGxpa2Uge0BsaW5rIFJlc291cmNlLk9uQ29tcGxldGVTaWduYWx9LlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtTaWduYWx9XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLm9uQ29tcGxldGUgPSBuZXcgX21pbmlTaWduYWxzMi5kZWZhdWx0KCk7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIERpc3BhdGNoZWQgYWZ0ZXIgdGhpcyByZXNvdXJjZSBoYXMgaGFkIGFsbCB0aGUgKmFmdGVyKiBtaWRkbGV3YXJlIHJ1biBvbiBpdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGNhbGxiYWNrIGxvb2tzIGxpa2Uge0BsaW5rIFJlc291cmNlLk9uQ29tcGxldGVTaWduYWx9LlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyIHtTaWduYWx9XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLm9uQWZ0ZXJNaWRkbGV3YXJlID0gbmV3IF9taW5pU2lnbmFsczIuZGVmYXVsdCgpO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBXaGVuIHRoZSByZXNvdXJjZSBzdGFydHMgdG8gbG9hZC5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlcm9mIFJlc291cmNlXG4gICAgICAgICAqIEBjYWxsYmFjayBPblN0YXJ0U2lnbmFsXG4gICAgICAgICAqIEBwYXJhbSB7UmVzb3VyY2V9IHJlc291cmNlIC0gVGhlIHJlc291cmNlIHRoYXQgdGhlIGV2ZW50IGhhcHBlbmVkIG9uLlxuICAgICAgICAgKi9cblxuICAgICAgICAvKipcbiAgICAgICAgICogV2hlbiB0aGUgcmVzb3VyY2UgcmVwb3J0cyBsb2FkaW5nIHByb2dyZXNzLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyb2YgUmVzb3VyY2VcbiAgICAgICAgICogQGNhbGxiYWNrIE9uUHJvZ3Jlc3NTaWduYWxcbiAgICAgICAgICogQHBhcmFtIHtSZXNvdXJjZX0gcmVzb3VyY2UgLSBUaGUgcmVzb3VyY2UgdGhhdCB0aGUgZXZlbnQgaGFwcGVuZWQgb24uXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBwZXJjZW50YWdlIC0gVGhlIHByb2dyZXNzIG9mIHRoZSBsb2FkIGluIHRoZSByYW5nZSBbMCwgMV0uXG4gICAgICAgICAqL1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBXaGVuIHRoZSByZXNvdXJjZSBmaW5pc2hlcyBsb2FkaW5nLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyb2YgUmVzb3VyY2VcbiAgICAgICAgICogQGNhbGxiYWNrIE9uQ29tcGxldGVTaWduYWxcbiAgICAgICAgICogQHBhcmFtIHtSZXNvdXJjZX0gcmVzb3VyY2UgLSBUaGUgcmVzb3VyY2UgdGhhdCB0aGUgZXZlbnQgaGFwcGVuZWQgb24uXG4gICAgICAgICAqL1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFN0b3JlcyB3aGV0aGVyIG9yIG5vdCB0aGlzIHVybCBpcyBhIGRhdGEgdXJsLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cblxuXG4gICAgLyoqXG4gICAgICogTWFya3MgdGhlIHJlc291cmNlIGFzIGNvbXBsZXRlLlxuICAgICAqXG4gICAgICovXG4gICAgUmVzb3VyY2UucHJvdG90eXBlLmNvbXBsZXRlID0gZnVuY3Rpb24gY29tcGxldGUoKSB7XG4gICAgICAgIC8vIFRPRE86IENsZWFuIHRoaXMgdXAgaW4gYSB3cmFwcGVyIG9yIHNvbWV0aGluZy4uLmdyb3NzLi4uLlxuICAgICAgICBpZiAodGhpcy5kYXRhICYmIHRoaXMuZGF0YS5yZW1vdmVFdmVudExpc3RlbmVyKSB7XG4gICAgICAgICAgICB0aGlzLmRhdGEucmVtb3ZlRXZlbnRMaXN0ZW5lcignZXJyb3InLCB0aGlzLl9ib3VuZE9uRXJyb3IsIGZhbHNlKTtcbiAgICAgICAgICAgIHRoaXMuZGF0YS5yZW1vdmVFdmVudExpc3RlbmVyKCdsb2FkJywgdGhpcy5fYm91bmRDb21wbGV0ZSwgZmFsc2UpO1xuICAgICAgICAgICAgdGhpcy5kYXRhLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Byb2dyZXNzJywgdGhpcy5fYm91bmRPblByb2dyZXNzLCBmYWxzZSk7XG4gICAgICAgICAgICB0aGlzLmRhdGEucmVtb3ZlRXZlbnRMaXN0ZW5lcignY2FucGxheXRocm91Z2gnLCB0aGlzLl9ib3VuZENvbXBsZXRlLCBmYWxzZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy54aHIpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnhoci5yZW1vdmVFdmVudExpc3RlbmVyKSB7XG4gICAgICAgICAgICAgICAgdGhpcy54aHIucmVtb3ZlRXZlbnRMaXN0ZW5lcignZXJyb3InLCB0aGlzLl9ib3VuZFhock9uRXJyb3IsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICB0aGlzLnhoci5yZW1vdmVFdmVudExpc3RlbmVyKCdhYm9ydCcsIHRoaXMuX2JvdW5kWGhyT25BYm9ydCwgZmFsc2UpO1xuICAgICAgICAgICAgICAgIHRoaXMueGhyLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Byb2dyZXNzJywgdGhpcy5fYm91bmRPblByb2dyZXNzLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgdGhpcy54aHIucmVtb3ZlRXZlbnRMaXN0ZW5lcignbG9hZCcsIHRoaXMuX2JvdW5kWGhyT25Mb2FkLCBmYWxzZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMueGhyLm9uZXJyb3IgPSBudWxsO1xuICAgICAgICAgICAgICAgIHRoaXMueGhyLm9udGltZW91dCA9IG51bGw7XG4gICAgICAgICAgICAgICAgdGhpcy54aHIub25wcm9ncmVzcyA9IG51bGw7XG4gICAgICAgICAgICAgICAgdGhpcy54aHIub25sb2FkID0gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLmlzQ29tcGxldGUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tcGxldGUgY2FsbGVkIGFnYWluIGZvciBhbiBhbHJlYWR5IGNvbXBsZXRlZCByZXNvdXJjZS4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuX3NldEZsYWcoUmVzb3VyY2UuU1RBVFVTX0ZMQUdTLkNPTVBMRVRFLCB0cnVlKTtcbiAgICAgICAgdGhpcy5fc2V0RmxhZyhSZXNvdXJjZS5TVEFUVVNfRkxBR1MuTE9BRElORywgZmFsc2UpO1xuXG4gICAgICAgIHRoaXMub25Db21wbGV0ZS5kaXNwYXRjaCh0aGlzKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQWJvcnRzIHRoZSBsb2FkaW5nIG9mIHRoaXMgcmVzb3VyY2UsIHdpdGggYW4gb3B0aW9uYWwgbWVzc2FnZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gVGhlIG1lc3NhZ2UgdG8gdXNlIGZvciB0aGUgZXJyb3JcbiAgICAgKi9cblxuXG4gICAgUmVzb3VyY2UucHJvdG90eXBlLmFib3J0ID0gZnVuY3Rpb24gYWJvcnQobWVzc2FnZSkge1xuICAgICAgICAvLyBhYm9ydCBjYW4gYmUgY2FsbGVkIG11bHRpcGxlIHRpbWVzLCBpZ25vcmUgc3Vic2VxdWVudCBjYWxscy5cbiAgICAgICAgaWYgKHRoaXMuZXJyb3IpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHN0b3JlIGVycm9yXG4gICAgICAgIHRoaXMuZXJyb3IgPSBuZXcgRXJyb3IobWVzc2FnZSk7XG5cbiAgICAgICAgLy8gYWJvcnQgdGhlIGFjdHVhbCBsb2FkaW5nXG4gICAgICAgIGlmICh0aGlzLnhocikge1xuICAgICAgICAgICAgdGhpcy54aHIuYWJvcnQoKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnhkcikge1xuICAgICAgICAgICAgdGhpcy54ZHIuYWJvcnQoKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLmRhdGEpIHtcbiAgICAgICAgICAgIC8vIHNpbmdsZSBzb3VyY2VcbiAgICAgICAgICAgIGlmICh0aGlzLmRhdGEuc3JjKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5kYXRhLnNyYyA9IFJlc291cmNlLkVNUFRZX0dJRjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIG11bHRpLXNvdXJjZVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHdoaWxlICh0aGlzLmRhdGEuZmlyc3RDaGlsZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kYXRhLnJlbW92ZUNoaWxkKHRoaXMuZGF0YS5maXJzdENoaWxkKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGRvbmUgbm93LlxuICAgICAgICB0aGlzLmNvbXBsZXRlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEtpY2tzIG9mZiBsb2FkaW5nIG9mIHRoaXMgcmVzb3VyY2UuIFRoaXMgbWV0aG9kIGlzIGFzeW5jaHJvbm91cy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IFtjYl0gLSBPcHRpb25hbCBjYWxsYmFjayB0byBjYWxsIG9uY2UgdGhlIHJlc291cmNlIGlzIGxvYWRlZC5cbiAgICAgKi9cblxuXG4gICAgUmVzb3VyY2UucHJvdG90eXBlLmxvYWQgPSBmdW5jdGlvbiBsb2FkKGNiKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgaWYgKHRoaXMuaXNMb2FkaW5nKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5pc0NvbXBsZXRlKSB7XG4gICAgICAgICAgICBpZiAoY2IpIHtcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNiKF90aGlzKTtcbiAgICAgICAgICAgICAgICB9LCAxKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGVsc2UgaWYgKGNiKSB7XG4gICAgICAgICAgICB0aGlzLm9uQ29tcGxldGUub25jZShjYik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9zZXRGbGFnKFJlc291cmNlLlNUQVRVU19GTEFHUy5MT0FESU5HLCB0cnVlKTtcblxuICAgICAgICB0aGlzLm9uU3RhcnQuZGlzcGF0Y2godGhpcyk7XG5cbiAgICAgICAgLy8gaWYgdW5zZXQsIGRldGVybWluZSB0aGUgdmFsdWVcbiAgICAgICAgaWYgKHRoaXMuY3Jvc3NPcmlnaW4gPT09IGZhbHNlIHx8IHR5cGVvZiB0aGlzLmNyb3NzT3JpZ2luICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgdGhpcy5jcm9zc09yaWdpbiA9IHRoaXMuX2RldGVybWluZUNyb3NzT3JpZ2luKHRoaXMudXJsKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHN3aXRjaCAodGhpcy5sb2FkVHlwZSkge1xuICAgICAgICAgICAgY2FzZSBSZXNvdXJjZS5MT0FEX1RZUEUuSU1BR0U6XG4gICAgICAgICAgICAgICAgdGhpcy50eXBlID0gUmVzb3VyY2UuVFlQRS5JTUFHRTtcbiAgICAgICAgICAgICAgICB0aGlzLl9sb2FkRWxlbWVudCgnaW1hZ2UnKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSBSZXNvdXJjZS5MT0FEX1RZUEUuQVVESU86XG4gICAgICAgICAgICAgICAgdGhpcy50eXBlID0gUmVzb3VyY2UuVFlQRS5BVURJTztcbiAgICAgICAgICAgICAgICB0aGlzLl9sb2FkU291cmNlRWxlbWVudCgnYXVkaW8nKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSBSZXNvdXJjZS5MT0FEX1RZUEUuVklERU86XG4gICAgICAgICAgICAgICAgdGhpcy50eXBlID0gUmVzb3VyY2UuVFlQRS5WSURFTztcbiAgICAgICAgICAgICAgICB0aGlzLl9sb2FkU291cmNlRWxlbWVudCgndmlkZW8nKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSBSZXNvdXJjZS5MT0FEX1RZUEUuWEhSOlxuICAgICAgICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICBpZiAodXNlWGRyICYmIHRoaXMuY3Jvc3NPcmlnaW4pIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fbG9hZFhkcigpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2xvYWRYaHIoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIHRoZSBmbGFnIGlzIHNldC5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGZsYWcgLSBUaGUgZmxhZyB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBmbGFnIGlzIHNldC5cbiAgICAgKi9cblxuXG4gICAgUmVzb3VyY2UucHJvdG90eXBlLl9oYXNGbGFnID0gZnVuY3Rpb24gX2hhc0ZsYWcoZmxhZykge1xuICAgICAgICByZXR1cm4gISEodGhpcy5fZmxhZ3MgJiBmbGFnKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogKFVuKVNldHMgdGhlIGZsYWcuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBmbGFnIC0gVGhlIGZsYWcgdG8gKHVuKXNldC5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IHZhbHVlIC0gV2hldGhlciB0byBzZXQgb3IgKHVuKXNldCB0aGUgZmxhZy5cbiAgICAgKi9cblxuXG4gICAgUmVzb3VyY2UucHJvdG90eXBlLl9zZXRGbGFnID0gZnVuY3Rpb24gX3NldEZsYWcoZmxhZywgdmFsdWUpIHtcbiAgICAgICAgdGhpcy5fZmxhZ3MgPSB2YWx1ZSA/IHRoaXMuX2ZsYWdzIHwgZmxhZyA6IHRoaXMuX2ZsYWdzICYgfmZsYWc7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIExvYWRzIHRoaXMgcmVzb3VyY2VzIHVzaW5nIGFuIGVsZW1lbnQgdGhhdCBoYXMgYSBzaW5nbGUgc291cmNlLFxuICAgICAqIGxpa2UgYW4gSFRNTEltYWdlRWxlbWVudC5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgdHlwZSBvZiBlbGVtZW50IHRvIHVzZS5cbiAgICAgKi9cblxuXG4gICAgUmVzb3VyY2UucHJvdG90eXBlLl9sb2FkRWxlbWVudCA9IGZ1bmN0aW9uIF9sb2FkRWxlbWVudCh0eXBlKSB7XG4gICAgICAgIGlmICh0aGlzLm1ldGFkYXRhLmxvYWRFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLmRhdGEgPSB0aGlzLm1ldGFkYXRhLmxvYWRFbGVtZW50O1xuICAgICAgICB9IGVsc2UgaWYgKHR5cGUgPT09ICdpbWFnZScgJiYgdHlwZW9mIHdpbmRvdy5JbWFnZSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIHRoaXMuZGF0YSA9IG5ldyBJbWFnZSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5kYXRhID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCh0eXBlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLmNyb3NzT3JpZ2luKSB7XG4gICAgICAgICAgICB0aGlzLmRhdGEuY3Jvc3NPcmlnaW4gPSB0aGlzLmNyb3NzT3JpZ2luO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0aGlzLm1ldGFkYXRhLnNraXBTb3VyY2UpIHtcbiAgICAgICAgICAgIHRoaXMuZGF0YS5zcmMgPSB0aGlzLnVybDtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZGF0YS5hZGRFdmVudExpc3RlbmVyKCdlcnJvcicsIHRoaXMuX2JvdW5kT25FcnJvciwgZmFsc2UpO1xuICAgICAgICB0aGlzLmRhdGEuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIHRoaXMuX2JvdW5kQ29tcGxldGUsIGZhbHNlKTtcbiAgICAgICAgdGhpcy5kYXRhLmFkZEV2ZW50TGlzdGVuZXIoJ3Byb2dyZXNzJywgdGhpcy5fYm91bmRPblByb2dyZXNzLCBmYWxzZSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIExvYWRzIHRoaXMgcmVzb3VyY2VzIHVzaW5nIGFuIGVsZW1lbnQgdGhhdCBoYXMgbXVsdGlwbGUgc291cmNlcyxcbiAgICAgKiBsaWtlIGFuIEhUTUxBdWRpb0VsZW1lbnQgb3IgSFRNTFZpZGVvRWxlbWVudC5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgdHlwZSBvZiBlbGVtZW50IHRvIHVzZS5cbiAgICAgKi9cblxuXG4gICAgUmVzb3VyY2UucHJvdG90eXBlLl9sb2FkU291cmNlRWxlbWVudCA9IGZ1bmN0aW9uIF9sb2FkU291cmNlRWxlbWVudCh0eXBlKSB7XG4gICAgICAgIGlmICh0aGlzLm1ldGFkYXRhLmxvYWRFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLmRhdGEgPSB0aGlzLm1ldGFkYXRhLmxvYWRFbGVtZW50O1xuICAgICAgICB9IGVsc2UgaWYgKHR5cGUgPT09ICdhdWRpbycgJiYgdHlwZW9mIHdpbmRvdy5BdWRpbyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIHRoaXMuZGF0YSA9IG5ldyBBdWRpbygpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5kYXRhID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCh0eXBlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLmRhdGEgPT09IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMuYWJvcnQoJ1Vuc3VwcG9ydGVkIGVsZW1lbnQ6ICcgKyB0eXBlKTtcblxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0aGlzLm1ldGFkYXRhLnNraXBTb3VyY2UpIHtcbiAgICAgICAgICAgIC8vIHN1cHBvcnQgZm9yIENvY29vbkpTIENhbnZhcysgcnVudGltZSwgbGFja3MgZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc291cmNlJylcbiAgICAgICAgICAgIGlmIChuYXZpZ2F0b3IuaXNDb2Nvb25KUykge1xuICAgICAgICAgICAgICAgIHRoaXMuZGF0YS5zcmMgPSBBcnJheS5pc0FycmF5KHRoaXMudXJsKSA/IHRoaXMudXJsWzBdIDogdGhpcy51cmw7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkodGhpcy51cmwpKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1pbWVUeXBlcyA9IHRoaXMubWV0YWRhdGEubWltZVR5cGU7XG5cbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMudXJsLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZGF0YS5hcHBlbmRDaGlsZCh0aGlzLl9jcmVhdGVTb3VyY2UodHlwZSwgdGhpcy51cmxbaV0sIEFycmF5LmlzQXJyYXkobWltZVR5cGVzKSA/IG1pbWVUeXBlc1tpXSA6IG1pbWVUeXBlcykpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdmFyIF9taW1lVHlwZXMgPSB0aGlzLm1ldGFkYXRhLm1pbWVUeXBlO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5kYXRhLmFwcGVuZENoaWxkKHRoaXMuX2NyZWF0ZVNvdXJjZSh0eXBlLCB0aGlzLnVybCwgQXJyYXkuaXNBcnJheShfbWltZVR5cGVzKSA/IF9taW1lVHlwZXNbMF0gOiBfbWltZVR5cGVzKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmRhdGEuYWRkRXZlbnRMaXN0ZW5lcignZXJyb3InLCB0aGlzLl9ib3VuZE9uRXJyb3IsIGZhbHNlKTtcbiAgICAgICAgdGhpcy5kYXRhLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCB0aGlzLl9ib3VuZENvbXBsZXRlLCBmYWxzZSk7XG4gICAgICAgIHRoaXMuZGF0YS5hZGRFdmVudExpc3RlbmVyKCdwcm9ncmVzcycsIHRoaXMuX2JvdW5kT25Qcm9ncmVzcywgZmFsc2UpO1xuICAgICAgICB0aGlzLmRhdGEuYWRkRXZlbnRMaXN0ZW5lcignY2FucGxheXRocm91Z2gnLCB0aGlzLl9ib3VuZENvbXBsZXRlLCBmYWxzZSk7XG5cbiAgICAgICAgdGhpcy5kYXRhLmxvYWQoKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogTG9hZHMgdGhpcyByZXNvdXJjZXMgdXNpbmcgYW4gWE1MSHR0cFJlcXVlc3QuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuXG5cbiAgICBSZXNvdXJjZS5wcm90b3R5cGUuX2xvYWRYaHIgPSBmdW5jdGlvbiBfbG9hZFhocigpIHtcbiAgICAgICAgLy8gaWYgdW5zZXQsIGRldGVybWluZSB0aGUgdmFsdWVcbiAgICAgICAgaWYgKHR5cGVvZiB0aGlzLnhoclR5cGUgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICB0aGlzLnhoclR5cGUgPSB0aGlzLl9kZXRlcm1pbmVYaHJUeXBlKCk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgeGhyID0gdGhpcy54aHIgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTtcblxuICAgICAgICAvLyBzZXQgdGhlIHJlcXVlc3QgdHlwZSBhbmQgdXJsXG4gICAgICAgIHhoci5vcGVuKCdHRVQnLCB0aGlzLnVybCwgdHJ1ZSk7XG5cbiAgICAgICAgLy8gbG9hZCBqc29uIGFzIHRleHQgYW5kIHBhcnNlIGl0IG91cnNlbHZlcy4gV2UgZG8gdGhpcyBiZWNhdXNlIHNvbWUgYnJvd3NlcnNcbiAgICAgICAgLy8gKmNvdWdoKiBzYWZhcmkgKmNvdWdoKiBjYW4ndCBkZWFsIHdpdGggaXQuXG4gICAgICAgIGlmICh0aGlzLnhoclR5cGUgPT09IFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLkpTT04gfHwgdGhpcy54aHJUeXBlID09PSBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5ET0NVTUVOVCkge1xuICAgICAgICAgICAgeGhyLnJlc3BvbnNlVHlwZSA9IFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLlRFWFQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB4aHIucmVzcG9uc2VUeXBlID0gdGhpcy54aHJUeXBlO1xuICAgICAgICB9XG5cbiAgICAgICAgeGhyLmFkZEV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgdGhpcy5fYm91bmRYaHJPbkVycm9yLCBmYWxzZSk7XG4gICAgICAgIHhoci5hZGRFdmVudExpc3RlbmVyKCdhYm9ydCcsIHRoaXMuX2JvdW5kWGhyT25BYm9ydCwgZmFsc2UpO1xuICAgICAgICB4aHIuYWRkRXZlbnRMaXN0ZW5lcigncHJvZ3Jlc3MnLCB0aGlzLl9ib3VuZE9uUHJvZ3Jlc3MsIGZhbHNlKTtcbiAgICAgICAgeGhyLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCB0aGlzLl9ib3VuZFhock9uTG9hZCwgZmFsc2UpO1xuXG4gICAgICAgIHhoci5zZW5kKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIExvYWRzIHRoaXMgcmVzb3VyY2VzIHVzaW5nIGFuIFhEb21haW5SZXF1ZXN0LiBUaGlzIGlzIGhlcmUgYmVjYXVzZSB3ZSBuZWVkIHRvIHN1cHBvcnQgSUU5IChncm9zcykuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuXG5cbiAgICBSZXNvdXJjZS5wcm90b3R5cGUuX2xvYWRYZHIgPSBmdW5jdGlvbiBfbG9hZFhkcigpIHtcbiAgICAgICAgLy8gaWYgdW5zZXQsIGRldGVybWluZSB0aGUgdmFsdWVcbiAgICAgICAgaWYgKHR5cGVvZiB0aGlzLnhoclR5cGUgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICB0aGlzLnhoclR5cGUgPSB0aGlzLl9kZXRlcm1pbmVYaHJUeXBlKCk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgeGRyID0gdGhpcy54aHIgPSBuZXcgWERvbWFpblJlcXVlc3QoKTtcblxuICAgICAgICAvLyBYRG9tYWluUmVxdWVzdCBoYXMgYSBmZXcgcXVpcmtzLiBPY2Nhc2lvbmFsbHkgaXQgd2lsbCBhYm9ydCByZXF1ZXN0c1xuICAgICAgICAvLyBBIHdheSB0byBhdm9pZCB0aGlzIGlzIHRvIG1ha2Ugc3VyZSBBTEwgY2FsbGJhY2tzIGFyZSBzZXQgZXZlbiBpZiBub3QgdXNlZFxuICAgICAgICAvLyBNb3JlIGluZm8gaGVyZTogaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xNTc4Njk2Ni94ZG9tYWlucmVxdWVzdC1hYm9ydHMtcG9zdC1vbi1pZS05XG4gICAgICAgIHhkci50aW1lb3V0ID0gNTAwMDtcblxuICAgICAgICB4ZHIub25lcnJvciA9IHRoaXMuX2JvdW5kWGhyT25FcnJvcjtcbiAgICAgICAgeGRyLm9udGltZW91dCA9IHRoaXMuX2JvdW5kWGRyT25UaW1lb3V0O1xuICAgICAgICB4ZHIub25wcm9ncmVzcyA9IHRoaXMuX2JvdW5kT25Qcm9ncmVzcztcbiAgICAgICAgeGRyLm9ubG9hZCA9IHRoaXMuX2JvdW5kWGhyT25Mb2FkO1xuXG4gICAgICAgIHhkci5vcGVuKCdHRVQnLCB0aGlzLnVybCwgdHJ1ZSk7XG5cbiAgICAgICAgLy8gTm90ZTogVGhlIHhkci5zZW5kKCkgY2FsbCBpcyB3cmFwcGVkIGluIGEgdGltZW91dCB0byBwcmV2ZW50IGFuXG4gICAgICAgIC8vIGlzc3VlIHdpdGggdGhlIGludGVyZmFjZSB3aGVyZSBzb21lIHJlcXVlc3RzIGFyZSBsb3N0IGlmIG11bHRpcGxlXG4gICAgICAgIC8vIFhEb21haW5SZXF1ZXN0cyBhcmUgYmVpbmcgc2VudCBhdCB0aGUgc2FtZSB0aW1lLlxuICAgICAgICAvLyBTb21lIGluZm8gaGVyZTogaHR0cHM6Ly9naXRodWIuY29tL3Bob3RvbnN0b3JtL3BoYXNlci9pc3N1ZXMvMTI0OFxuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB4ZHIuc2VuZCgpO1xuICAgICAgICB9LCAxKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIHNvdXJjZSB1c2VkIGluIGxvYWRpbmcgdmlhIGFuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIGVsZW1lbnQgdHlwZSAodmlkZW8gb3IgYXVkaW8pLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgc291cmNlIFVSTCB0byBsb2FkIGZyb20uXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IFttaW1lXSAtIFRoZSBtaW1lIHR5cGUgb2YgdGhlIHZpZGVvXG4gICAgICogQHJldHVybiB7SFRNTFNvdXJjZUVsZW1lbnR9IFRoZSBzb3VyY2UgZWxlbWVudC5cbiAgICAgKi9cblxuXG4gICAgUmVzb3VyY2UucHJvdG90eXBlLl9jcmVhdGVTb3VyY2UgPSBmdW5jdGlvbiBfY3JlYXRlU291cmNlKHR5cGUsIHVybCwgbWltZSkge1xuICAgICAgICBpZiAoIW1pbWUpIHtcbiAgICAgICAgICAgIG1pbWUgPSB0eXBlICsgJy8nICsgdGhpcy5fZ2V0RXh0ZW5zaW9uKHVybCk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc291cmNlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc291cmNlJyk7XG5cbiAgICAgICAgc291cmNlLnNyYyA9IHVybDtcbiAgICAgICAgc291cmNlLnR5cGUgPSBtaW1lO1xuXG4gICAgICAgIHJldHVybiBzb3VyY2U7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENhbGxlZCBpZiBhIGxvYWQgZXJyb3JzIG91dC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7RXZlbnR9IGV2ZW50IC0gVGhlIGVycm9yIGV2ZW50IGZyb20gdGhlIGVsZW1lbnQgdGhhdCBlbWl0cyBpdC5cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuXG5cbiAgICBSZXNvdXJjZS5wcm90b3R5cGUuX29uRXJyb3IgPSBmdW5jdGlvbiBfb25FcnJvcihldmVudCkge1xuICAgICAgICB0aGlzLmFib3J0KCdGYWlsZWQgdG8gbG9hZCBlbGVtZW50IHVzaW5nOiAnICsgZXZlbnQudGFyZ2V0Lm5vZGVOYW1lKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2FsbGVkIGlmIGEgbG9hZCBwcm9ncmVzcyBldmVudCBmaXJlcyBmb3IgeGhyL3hkci5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtYTUxIdHRwUmVxdWVzdFByb2dyZXNzRXZlbnR8RXZlbnR9IGV2ZW50IC0gUHJvZ3Jlc3MgZXZlbnQuXG4gICAgICovXG5cblxuICAgIFJlc291cmNlLnByb3RvdHlwZS5fb25Qcm9ncmVzcyA9IGZ1bmN0aW9uIF9vblByb2dyZXNzKGV2ZW50KSB7XG4gICAgICAgIGlmIChldmVudCAmJiBldmVudC5sZW5ndGhDb21wdXRhYmxlKSB7XG4gICAgICAgICAgICB0aGlzLm9uUHJvZ3Jlc3MuZGlzcGF0Y2godGhpcywgZXZlbnQubG9hZGVkIC8gZXZlbnQudG90YWwpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENhbGxlZCBpZiBhbiBlcnJvciBldmVudCBmaXJlcyBmb3IgeGhyL3hkci5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtYTUxIdHRwUmVxdWVzdEVycm9yRXZlbnR8RXZlbnR9IGV2ZW50IC0gRXJyb3IgZXZlbnQuXG4gICAgICovXG5cblxuICAgIFJlc291cmNlLnByb3RvdHlwZS5feGhyT25FcnJvciA9IGZ1bmN0aW9uIF94aHJPbkVycm9yKCkge1xuICAgICAgICB2YXIgeGhyID0gdGhpcy54aHI7XG5cbiAgICAgICAgdGhpcy5hYm9ydChyZXFUeXBlKHhocikgKyAnIFJlcXVlc3QgZmFpbGVkLiBTdGF0dXM6ICcgKyB4aHIuc3RhdHVzICsgJywgdGV4dDogXCInICsgeGhyLnN0YXR1c1RleHQgKyAnXCInKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2FsbGVkIGlmIGFuIGFib3J0IGV2ZW50IGZpcmVzIGZvciB4aHIuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7WE1MSHR0cFJlcXVlc3RBYm9ydEV2ZW50fSBldmVudCAtIEFib3J0IEV2ZW50XG4gICAgICovXG5cblxuICAgIFJlc291cmNlLnByb3RvdHlwZS5feGhyT25BYm9ydCA9IGZ1bmN0aW9uIF94aHJPbkFib3J0KCkge1xuICAgICAgICB0aGlzLmFib3J0KHJlcVR5cGUodGhpcy54aHIpICsgJyBSZXF1ZXN0IHdhcyBhYm9ydGVkIGJ5IHRoZSB1c2VyLicpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBDYWxsZWQgaWYgYSB0aW1lb3V0IGV2ZW50IGZpcmVzIGZvciB4ZHIuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7RXZlbnR9IGV2ZW50IC0gVGltZW91dCBldmVudC5cbiAgICAgKi9cblxuXG4gICAgUmVzb3VyY2UucHJvdG90eXBlLl94ZHJPblRpbWVvdXQgPSBmdW5jdGlvbiBfeGRyT25UaW1lb3V0KCkge1xuICAgICAgICB0aGlzLmFib3J0KHJlcVR5cGUodGhpcy54aHIpICsgJyBSZXF1ZXN0IHRpbWVkIG91dC4nKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2FsbGVkIHdoZW4gZGF0YSBzdWNjZXNzZnVsbHkgbG9hZHMgZnJvbSBhbiB4aHIveGRyIHJlcXVlc3QuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7WE1MSHR0cFJlcXVlc3RMb2FkRXZlbnR8RXZlbnR9IGV2ZW50IC0gTG9hZCBldmVudFxuICAgICAqL1xuXG5cbiAgICBSZXNvdXJjZS5wcm90b3R5cGUuX3hock9uTG9hZCA9IGZ1bmN0aW9uIF94aHJPbkxvYWQoKSB7XG4gICAgICAgIHZhciB4aHIgPSB0aGlzLnhocjtcbiAgICAgICAgdmFyIHRleHQgPSAnJztcbiAgICAgICAgdmFyIHN0YXR1cyA9IHR5cGVvZiB4aHIuc3RhdHVzID09PSAndW5kZWZpbmVkJyA/IFNUQVRVU19PSyA6IHhoci5zdGF0dXM7IC8vIFhEUiBoYXMgbm8gYC5zdGF0dXNgLCBhc3N1bWUgMjAwLlxuXG4gICAgICAgIC8vIHJlc3BvbnNlVGV4dCBpcyBhY2Nlc3NpYmxlIG9ubHkgaWYgcmVzcG9uc2VUeXBlIGlzICcnIG9yICd0ZXh0JyBhbmQgb24gb2xkZXIgYnJvd3NlcnNcbiAgICAgICAgaWYgKHhoci5yZXNwb25zZVR5cGUgPT09ICcnIHx8IHhoci5yZXNwb25zZVR5cGUgPT09ICd0ZXh0JyB8fCB0eXBlb2YgeGhyLnJlc3BvbnNlVHlwZSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIHRleHQgPSB4aHIucmVzcG9uc2VUZXh0O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gc3RhdHVzIGNhbiBiZSAwIHdoZW4gdXNpbmcgdGhlIGBmaWxlOi8vYCBwcm90b2NvbCBzbyB3ZSBhbHNvIGNoZWNrIGlmIGEgcmVzcG9uc2UgaXMgc2V0LlxuICAgICAgICAvLyBJZiBpdCBoYXMgYSByZXNwb25zZSwgd2UgYXNzdW1lIDIwMDsgb3RoZXJ3aXNlIGEgMCBzdGF0dXMgY29kZSB3aXRoIG5vIGNvbnRlbnRzIGlzIGFuIGFib3J0ZWQgcmVxdWVzdC5cbiAgICAgICAgaWYgKHN0YXR1cyA9PT0gU1RBVFVTX05PTkUgJiYgKHRleHQubGVuZ3RoID4gMCB8fCB4aHIucmVzcG9uc2VUeXBlID09PSBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5CVUZGRVIpKSB7XG4gICAgICAgICAgICBzdGF0dXMgPSBTVEFUVVNfT0s7XG4gICAgICAgIH1cbiAgICAgICAgLy8gaGFuZGxlIElFOSBidWc6IGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTAwNDY5NzIvbXNpZS1yZXR1cm5zLXN0YXR1cy1jb2RlLW9mLTEyMjMtZm9yLWFqYXgtcmVxdWVzdFxuICAgICAgICBlbHNlIGlmIChzdGF0dXMgPT09IFNUQVRVU19JRV9CVUdfRU1QVFkpIHtcbiAgICAgICAgICAgICAgICBzdGF0dXMgPSBTVEFUVVNfRU1QVFk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgdmFyIHN0YXR1c1R5cGUgPSBzdGF0dXMgLyAxMDAgfCAwO1xuXG4gICAgICAgIGlmIChzdGF0dXNUeXBlID09PSBTVEFUVVNfVFlQRV9PSykge1xuICAgICAgICAgICAgLy8gaWYgdGV4dCwganVzdCByZXR1cm4gaXRcbiAgICAgICAgICAgIGlmICh0aGlzLnhoclR5cGUgPT09IFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLlRFWFQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRhdGEgPSB0ZXh0O1xuICAgICAgICAgICAgICAgIHRoaXMudHlwZSA9IFJlc291cmNlLlRZUEUuVEVYVDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIGlmIGpzb24sIHBhcnNlIGludG8ganNvbiBvYmplY3RcbiAgICAgICAgICAgIGVsc2UgaWYgKHRoaXMueGhyVHlwZSA9PT0gUmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEUuSlNPTikge1xuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kYXRhID0gSlNPTi5wYXJzZSh0ZXh0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudHlwZSA9IFJlc291cmNlLlRZUEUuSlNPTjtcbiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hYm9ydCgnRXJyb3IgdHJ5aW5nIHRvIHBhcnNlIGxvYWRlZCBqc29uOiAnICsgZSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBpZiB4bWwsIHBhcnNlIGludG8gYW4geG1sIGRvY3VtZW50IG9yIGRpdiBlbGVtZW50XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAodGhpcy54aHJUeXBlID09PSBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5ET0NVTUVOVCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAod2luZG93LkRPTVBhcnNlcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgZG9tcGFyc2VyID0gbmV3IERPTVBhcnNlcigpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGF0YSA9IGRvbXBhcnNlci5wYXJzZUZyb21TdHJpbmcodGV4dCwgJ3RleHQveG1sJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGRpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpdi5pbm5lckhUTUwgPSB0ZXh0O1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGF0YSA9IGRpdjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnR5cGUgPSBSZXNvdXJjZS5UWVBFLlhNTDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmFib3J0KCdFcnJvciB0cnlpbmcgdG8gcGFyc2UgbG9hZGVkIHhtbDogJyArIGUpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8vIG90aGVyIHR5cGVzIGp1c3QgcmV0dXJuIHRoZSByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRhdGEgPSB4aHIucmVzcG9uc2UgfHwgdGV4dDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYWJvcnQoJ1snICsgeGhyLnN0YXR1cyArICddICcgKyB4aHIuc3RhdHVzVGV4dCArICc6ICcgKyB4aHIucmVzcG9uc2VVUkwpO1xuXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmNvbXBsZXRlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIGBjcm9zc09yaWdpbmAgcHJvcGVydHkgZm9yIHRoaXMgcmVzb3VyY2UgYmFzZWQgb24gaWYgdGhlIHVybFxuICAgICAqIGZvciB0aGlzIHJlc291cmNlIGlzIGNyb3NzLW9yaWdpbi4gSWYgY3Jvc3NPcmlnaW4gd2FzIG1hbnVhbGx5IHNldCwgdGhpc1xuICAgICAqIGZ1bmN0aW9uIGRvZXMgbm90aGluZy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSB1cmwgdG8gdGVzdC5cbiAgICAgKiBAcGFyYW0ge29iamVjdH0gW2xvYz13aW5kb3cubG9jYXRpb25dIC0gVGhlIGxvY2F0aW9uIG9iamVjdCB0byB0ZXN0IGFnYWluc3QuXG4gICAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgY3Jvc3NPcmlnaW4gdmFsdWUgdG8gdXNlIChvciBlbXB0eSBzdHJpbmcgZm9yIG5vbmUpLlxuICAgICAqL1xuXG5cbiAgICBSZXNvdXJjZS5wcm90b3R5cGUuX2RldGVybWluZUNyb3NzT3JpZ2luID0gZnVuY3Rpb24gX2RldGVybWluZUNyb3NzT3JpZ2luKHVybCwgbG9jKSB7XG4gICAgICAgIC8vIGRhdGE6IGFuZCBqYXZhc2NyaXB0OiB1cmxzIGFyZSBjb25zaWRlcmVkIHNhbWUtb3JpZ2luXG4gICAgICAgIGlmICh1cmwuaW5kZXhPZignZGF0YTonKSA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZGVmYXVsdCBpcyB3aW5kb3cubG9jYXRpb25cbiAgICAgICAgbG9jID0gbG9jIHx8IHdpbmRvdy5sb2NhdGlvbjtcblxuICAgICAgICBpZiAoIXRlbXBBbmNob3IpIHtcbiAgICAgICAgICAgIHRlbXBBbmNob3IgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBsZXQgdGhlIGJyb3dzZXIgZGV0ZXJtaW5lIHRoZSBmdWxsIGhyZWYgZm9yIHRoZSB1cmwgb2YgdGhpcyByZXNvdXJjZSBhbmQgdGhlblxuICAgICAgICAvLyBwYXJzZSB3aXRoIHRoZSBub2RlIHVybCBsaWIsIHdlIGNhbid0IHVzZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgYW5jaG9yIGVsZW1lbnRcbiAgICAgICAgLy8gYmVjYXVzZSB0aGV5IGRvbid0IHdvcmsgaW4gSUU5IDooXG4gICAgICAgIHRlbXBBbmNob3IuaHJlZiA9IHVybDtcbiAgICAgICAgdXJsID0gKDAsIF9wYXJzZVVyaTIuZGVmYXVsdCkodGVtcEFuY2hvci5ocmVmLCB7IHN0cmljdE1vZGU6IHRydWUgfSk7XG5cbiAgICAgICAgdmFyIHNhbWVQb3J0ID0gIXVybC5wb3J0ICYmIGxvYy5wb3J0ID09PSAnJyB8fCB1cmwucG9ydCA9PT0gbG9jLnBvcnQ7XG4gICAgICAgIHZhciBwcm90b2NvbCA9IHVybC5wcm90b2NvbCA/IHVybC5wcm90b2NvbCArICc6JyA6ICcnO1xuXG4gICAgICAgIC8vIGlmIGNyb3NzIG9yaWdpblxuICAgICAgICBpZiAodXJsLmhvc3QgIT09IGxvYy5ob3N0bmFtZSB8fCAhc2FtZVBvcnQgfHwgcHJvdG9jb2wgIT09IGxvYy5wcm90b2NvbCkge1xuICAgICAgICAgICAgcmV0dXJuICdhbm9ueW1vdXMnO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBEZXRlcm1pbmVzIHRoZSByZXNwb25zZVR5cGUgb2YgYW4gWEhSIHJlcXVlc3QgYmFzZWQgb24gdGhlIGV4dGVuc2lvbiBvZiB0aGVcbiAgICAgKiByZXNvdXJjZSBiZWluZyBsb2FkZWQuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEByZXR1cm4ge1Jlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFfSBUaGUgcmVzcG9uc2VUeXBlIHRvIHVzZS5cbiAgICAgKi9cblxuXG4gICAgUmVzb3VyY2UucHJvdG90eXBlLl9kZXRlcm1pbmVYaHJUeXBlID0gZnVuY3Rpb24gX2RldGVybWluZVhoclR5cGUoKSB7XG4gICAgICAgIHJldHVybiBSZXNvdXJjZS5feGhyVHlwZU1hcFt0aGlzLmV4dGVuc2lvbl0gfHwgUmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEUuVEVYVDtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogRGV0ZXJtaW5lcyB0aGUgbG9hZFR5cGUgb2YgYSByZXNvdXJjZSBiYXNlZCBvbiB0aGUgZXh0ZW5zaW9uIG9mIHRoZVxuICAgICAqIHJlc291cmNlIGJlaW5nIGxvYWRlZC5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHJldHVybiB7UmVzb3VyY2UuTE9BRF9UWVBFfSBUaGUgbG9hZFR5cGUgdG8gdXNlLlxuICAgICAqL1xuXG5cbiAgICBSZXNvdXJjZS5wcm90b3R5cGUuX2RldGVybWluZUxvYWRUeXBlID0gZnVuY3Rpb24gX2RldGVybWluZUxvYWRUeXBlKCkge1xuICAgICAgICByZXR1cm4gUmVzb3VyY2UuX2xvYWRUeXBlTWFwW3RoaXMuZXh0ZW5zaW9uXSB8fCBSZXNvdXJjZS5MT0FEX1RZUEUuWEhSO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBFeHRyYWN0cyB0aGUgZXh0ZW5zaW9uIChzYW5zICcuJykgb2YgdGhlIGZpbGUgYmVpbmcgbG9hZGVkIGJ5IHRoZSByZXNvdXJjZS5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgZXh0ZW5zaW9uLlxuICAgICAqL1xuXG5cbiAgICBSZXNvdXJjZS5wcm90b3R5cGUuX2dldEV4dGVuc2lvbiA9IGZ1bmN0aW9uIF9nZXRFeHRlbnNpb24oKSB7XG4gICAgICAgIHZhciB1cmwgPSB0aGlzLnVybDtcbiAgICAgICAgdmFyIGV4dCA9ICcnO1xuXG4gICAgICAgIGlmICh0aGlzLmlzRGF0YVVybCkge1xuICAgICAgICAgICAgdmFyIHNsYXNoSW5kZXggPSB1cmwuaW5kZXhPZignLycpO1xuXG4gICAgICAgICAgICBleHQgPSB1cmwuc3Vic3RyaW5nKHNsYXNoSW5kZXggKyAxLCB1cmwuaW5kZXhPZignOycsIHNsYXNoSW5kZXgpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHZhciBxdWVyeVN0YXJ0ID0gdXJsLmluZGV4T2YoJz8nKTtcbiAgICAgICAgICAgIHZhciBoYXNoU3RhcnQgPSB1cmwuaW5kZXhPZignIycpO1xuICAgICAgICAgICAgdmFyIGluZGV4ID0gTWF0aC5taW4ocXVlcnlTdGFydCA+IC0xID8gcXVlcnlTdGFydCA6IHVybC5sZW5ndGgsIGhhc2hTdGFydCA+IC0xID8gaGFzaFN0YXJ0IDogdXJsLmxlbmd0aCk7XG5cbiAgICAgICAgICAgIHVybCA9IHVybC5zdWJzdHJpbmcoMCwgaW5kZXgpO1xuICAgICAgICAgICAgZXh0ID0gdXJsLnN1YnN0cmluZyh1cmwubGFzdEluZGV4T2YoJy4nKSArIDEpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGV4dC50b0xvd2VyQ2FzZSgpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBEZXRlcm1pbmVzIHRoZSBtaW1lIHR5cGUgb2YgYW4gWEhSIHJlcXVlc3QgYmFzZWQgb24gdGhlIHJlc3BvbnNlVHlwZSBvZlxuICAgICAqIHJlc291cmNlIGJlaW5nIGxvYWRlZC5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRX0gdHlwZSAtIFRoZSB0eXBlIHRvIGdldCBhIG1pbWUgdHlwZSBmb3IuXG4gICAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgbWltZSB0eXBlIHRvIHVzZS5cbiAgICAgKi9cblxuXG4gICAgUmVzb3VyY2UucHJvdG90eXBlLl9nZXRNaW1lRnJvbVhoclR5cGUgPSBmdW5jdGlvbiBfZ2V0TWltZUZyb21YaHJUeXBlKHR5cGUpIHtcbiAgICAgICAgc3dpdGNoICh0eXBlKSB7XG4gICAgICAgICAgICBjYXNlIFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLkJVRkZFUjpcbiAgICAgICAgICAgICAgICByZXR1cm4gJ2FwcGxpY2F0aW9uL29jdGV0LWJpbmFyeSc7XG5cbiAgICAgICAgICAgIGNhc2UgUmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEUuQkxPQjpcbiAgICAgICAgICAgICAgICByZXR1cm4gJ2FwcGxpY2F0aW9uL2Jsb2InO1xuXG4gICAgICAgICAgICBjYXNlIFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLkRPQ1VNRU5UOlxuICAgICAgICAgICAgICAgIHJldHVybiAnYXBwbGljYXRpb24veG1sJztcblxuICAgICAgICAgICAgY2FzZSBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5KU09OOlxuICAgICAgICAgICAgICAgIHJldHVybiAnYXBwbGljYXRpb24vanNvbic7XG5cbiAgICAgICAgICAgIGNhc2UgUmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEUuREVGQVVMVDpcbiAgICAgICAgICAgIGNhc2UgUmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEUuVEVYVDpcbiAgICAgICAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgcmV0dXJuICd0ZXh0L3BsYWluJztcblxuICAgICAgICB9XG4gICAgfTtcblxuICAgIF9jcmVhdGVDbGFzcyhSZXNvdXJjZSwgW3tcbiAgICAgICAga2V5OiAnaXNEYXRhVXJsJyxcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5faGFzRmxhZyhSZXNvdXJjZS5TVEFUVVNfRkxBR1MuREFUQV9VUkwpO1xuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIERlc2NyaWJlcyBpZiB0aGlzIHJlc291cmNlIGhhcyBmaW5pc2hlZCBsb2FkaW5nLiBJcyB0cnVlIHdoZW4gdGhlIHJlc291cmNlIGhhcyBjb21wbGV0ZWx5XG4gICAgICAgICAqIGxvYWRlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgICAgICogQHJlYWRvbmx5XG4gICAgICAgICAqL1xuXG4gICAgfSwge1xuICAgICAgICBrZXk6ICdpc0NvbXBsZXRlJyxcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5faGFzRmxhZyhSZXNvdXJjZS5TVEFUVVNfRkxBR1MuQ09NUExFVEUpO1xuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIERlc2NyaWJlcyBpZiB0aGlzIHJlc291cmNlIGlzIGN1cnJlbnRseSBsb2FkaW5nLiBJcyB0cnVlIHdoZW4gdGhlIHJlc291cmNlIHN0YXJ0cyBsb2FkaW5nLFxuICAgICAgICAgKiBhbmQgaXMgZmFsc2UgYWdhaW4gd2hlbiBjb21wbGV0ZS5cbiAgICAgICAgICpcbiAgICAgICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgICAgICogQHJlYWRvbmx5XG4gICAgICAgICAqL1xuXG4gICAgfSwge1xuICAgICAgICBrZXk6ICdpc0xvYWRpbmcnLFxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9oYXNGbGFnKFJlc291cmNlLlNUQVRVU19GTEFHUy5MT0FESU5HKTtcbiAgICAgICAgfVxuICAgIH1dKTtcblxuICAgIHJldHVybiBSZXNvdXJjZTtcbn0oKTtcblxuLyoqXG4gKiBUaGUgdHlwZXMgb2YgcmVzb3VyY2VzIGEgcmVzb3VyY2UgY291bGQgcmVwcmVzZW50LlxuICpcbiAqIEBzdGF0aWNcbiAqIEByZWFkb25seVxuICogQGVudW0ge251bWJlcn1cbiAqL1xuXG5cbmV4cG9ydHMuZGVmYXVsdCA9IFJlc291cmNlO1xuUmVzb3VyY2UuU1RBVFVTX0ZMQUdTID0ge1xuICAgIE5PTkU6IDAsXG4gICAgREFUQV9VUkw6IDEgPDwgMCxcbiAgICBDT01QTEVURTogMSA8PCAxLFxuICAgIExPQURJTkc6IDEgPDwgMlxufTtcblxuLyoqXG4gKiBUaGUgdHlwZXMgb2YgcmVzb3VyY2VzIGEgcmVzb3VyY2UgY291bGQgcmVwcmVzZW50LlxuICpcbiAqIEBzdGF0aWNcbiAqIEByZWFkb25seVxuICogQGVudW0ge251bWJlcn1cbiAqL1xuUmVzb3VyY2UuVFlQRSA9IHtcbiAgICBVTktOT1dOOiAwLFxuICAgIEpTT046IDEsXG4gICAgWE1MOiAyLFxuICAgIElNQUdFOiAzLFxuICAgIEFVRElPOiA0LFxuICAgIFZJREVPOiA1LFxuICAgIFRFWFQ6IDZcbn07XG5cbi8qKlxuICogVGhlIHR5cGVzIG9mIGxvYWRpbmcgYSByZXNvdXJjZSBjYW4gdXNlLlxuICpcbiAqIEBzdGF0aWNcbiAqIEByZWFkb25seVxuICogQGVudW0ge251bWJlcn1cbiAqL1xuUmVzb3VyY2UuTE9BRF9UWVBFID0ge1xuICAgIC8qKiBVc2VzIFhNTEh0dHBSZXF1ZXN0IHRvIGxvYWQgdGhlIHJlc291cmNlLiAqL1xuICAgIFhIUjogMSxcbiAgICAvKiogVXNlcyBhbiBgSW1hZ2VgIG9iamVjdCB0byBsb2FkIHRoZSByZXNvdXJjZS4gKi9cbiAgICBJTUFHRTogMixcbiAgICAvKiogVXNlcyBhbiBgQXVkaW9gIG9iamVjdCB0byBsb2FkIHRoZSByZXNvdXJjZS4gKi9cbiAgICBBVURJTzogMyxcbiAgICAvKiogVXNlcyBhIGBWaWRlb2Agb2JqZWN0IHRvIGxvYWQgdGhlIHJlc291cmNlLiAqL1xuICAgIFZJREVPOiA0XG59O1xuXG4vKipcbiAqIFRoZSBYSFIgcmVhZHkgc3RhdGVzLCB1c2VkIGludGVybmFsbHkuXG4gKlxuICogQHN0YXRpY1xuICogQHJlYWRvbmx5XG4gKiBAZW51bSB7c3RyaW5nfVxuICovXG5SZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRSA9IHtcbiAgICAvKiogc3RyaW5nICovXG4gICAgREVGQVVMVDogJ3RleHQnLFxuICAgIC8qKiBBcnJheUJ1ZmZlciAqL1xuICAgIEJVRkZFUjogJ2FycmF5YnVmZmVyJyxcbiAgICAvKiogQmxvYiAqL1xuICAgIEJMT0I6ICdibG9iJyxcbiAgICAvKiogRG9jdW1lbnQgKi9cbiAgICBET0NVTUVOVDogJ2RvY3VtZW50JyxcbiAgICAvKiogT2JqZWN0ICovXG4gICAgSlNPTjogJ2pzb24nLFxuICAgIC8qKiBTdHJpbmcgKi9cbiAgICBURVhUOiAndGV4dCdcbn07XG5cblJlc291cmNlLl9sb2FkVHlwZU1hcCA9IHtcbiAgICAvLyBpbWFnZXNcbiAgICBnaWY6IFJlc291cmNlLkxPQURfVFlQRS5JTUFHRSxcbiAgICBwbmc6IFJlc291cmNlLkxPQURfVFlQRS5JTUFHRSxcbiAgICBibXA6IFJlc291cmNlLkxPQURfVFlQRS5JTUFHRSxcbiAgICBqcGc6IFJlc291cmNlLkxPQURfVFlQRS5JTUFHRSxcbiAgICBqcGVnOiBSZXNvdXJjZS5MT0FEX1RZUEUuSU1BR0UsXG4gICAgdGlmOiBSZXNvdXJjZS5MT0FEX1RZUEUuSU1BR0UsXG4gICAgdGlmZjogUmVzb3VyY2UuTE9BRF9UWVBFLklNQUdFLFxuICAgIHdlYnA6IFJlc291cmNlLkxPQURfVFlQRS5JTUFHRSxcbiAgICB0Z2E6IFJlc291cmNlLkxPQURfVFlQRS5JTUFHRSxcbiAgICBzdmc6IFJlc291cmNlLkxPQURfVFlQRS5JTUFHRSxcbiAgICAnc3ZnK3htbCc6IFJlc291cmNlLkxPQURfVFlQRS5JTUFHRSwgLy8gZm9yIFNWRyBkYXRhIHVybHNcblxuICAgIC8vIGF1ZGlvXG4gICAgbXAzOiBSZXNvdXJjZS5MT0FEX1RZUEUuQVVESU8sXG4gICAgb2dnOiBSZXNvdXJjZS5MT0FEX1RZUEUuQVVESU8sXG4gICAgd2F2OiBSZXNvdXJjZS5MT0FEX1RZUEUuQVVESU8sXG5cbiAgICAvLyB2aWRlb3NcbiAgICBtcDQ6IFJlc291cmNlLkxPQURfVFlQRS5WSURFTyxcbiAgICB3ZWJtOiBSZXNvdXJjZS5MT0FEX1RZUEUuVklERU9cbn07XG5cblJlc291cmNlLl94aHJUeXBlTWFwID0ge1xuICAgIC8vIHhtbFxuICAgIHhodG1sOiBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5ET0NVTUVOVCxcbiAgICBodG1sOiBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5ET0NVTUVOVCxcbiAgICBodG06IFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLkRPQ1VNRU5ULFxuICAgIHhtbDogUmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEUuRE9DVU1FTlQsXG4gICAgdG14OiBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5ET0NVTUVOVCxcbiAgICBzdmc6IFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLkRPQ1VNRU5ULFxuXG4gICAgLy8gVGhpcyB3YXMgYWRkZWQgdG8gaGFuZGxlIFRpbGVkIFRpbGVzZXQgWE1MLCBidXQgLnRzeCBpcyBhbHNvIGEgVHlwZVNjcmlwdCBSZWFjdCBDb21wb25lbnQuXG4gICAgLy8gU2luY2UgaXQgaXMgd2F5IGxlc3MgbGlrZWx5IGZvciBwZW9wbGUgdG8gYmUgbG9hZGluZyBUeXBlU2NyaXB0IGZpbGVzIGluc3RlYWQgb2YgVGlsZWQgZmlsZXMsXG4gICAgLy8gdGhpcyBzaG91bGQgcHJvYmFibHkgYmUgZmluZS5cbiAgICB0c3g6IFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLkRPQ1VNRU5ULFxuXG4gICAgLy8gaW1hZ2VzXG4gICAgZ2lmOiBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5CTE9CLFxuICAgIHBuZzogUmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEUuQkxPQixcbiAgICBibXA6IFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLkJMT0IsXG4gICAganBnOiBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5CTE9CLFxuICAgIGpwZWc6IFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLkJMT0IsXG4gICAgdGlmOiBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5CTE9CLFxuICAgIHRpZmY6IFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLkJMT0IsXG4gICAgd2VicDogUmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEUuQkxPQixcbiAgICB0Z2E6IFJlc291cmNlLlhIUl9SRVNQT05TRV9UWVBFLkJMT0IsXG5cbiAgICAvLyBqc29uXG4gICAganNvbjogUmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEUuSlNPTixcblxuICAgIC8vIHRleHRcbiAgICB0ZXh0OiBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5URVhULFxuICAgIHR4dDogUmVzb3VyY2UuWEhSX1JFU1BPTlNFX1RZUEUuVEVYVCxcblxuICAgIC8vIGZvbnRzXG4gICAgdHRmOiBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5CVUZGRVIsXG4gICAgb3RmOiBSZXNvdXJjZS5YSFJfUkVTUE9OU0VfVFlQRS5CVUZGRVJcbn07XG5cbi8vIFdlIGNhbid0IHNldCB0aGUgYHNyY2AgYXR0cmlidXRlIHRvIGVtcHR5IHN0cmluZywgc28gb24gYWJvcnQgd2Ugc2V0IGl0IHRvIHRoaXMgMXB4IHRyYW5zcGFyZW50IGdpZlxuUmVzb3VyY2UuRU1QVFlfR0lGID0gJ2RhdGE6aW1hZ2UvZ2lmO2Jhc2U2NCxSMGxHT0RsaEFRQUJBSUFBQVAvLy93QUFBQ0g1QkFFQUFBQUFMQUFBQUFBQkFBRUFBQUlDUkFFQU93PT0nO1xuXG4vKipcbiAqIFF1aWNrIGhlbHBlciB0byBzZXQgYSB2YWx1ZSBvbiBvbmUgb2YgdGhlIGV4dGVuc2lvbiBtYXBzLiBFbnN1cmVzIHRoZXJlIGlzIG5vXG4gKiBkb3QgYXQgdGhlIHN0YXJ0IG9mIHRoZSBleHRlbnNpb24uXG4gKlxuICogQGlnbm9yZVxuICogQHBhcmFtIHtvYmplY3R9IG1hcCAtIFRoZSBtYXAgdG8gc2V0IG9uLlxuICogQHBhcmFtIHtzdHJpbmd9IGV4dG5hbWUgLSBUaGUgZXh0ZW5zaW9uIChvciBrZXkpIHRvIHNldC5cbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWwgLSBUaGUgdmFsdWUgdG8gc2V0LlxuICovXG5mdW5jdGlvbiBzZXRFeHRNYXAobWFwLCBleHRuYW1lLCB2YWwpIHtcbiAgICBpZiAoZXh0bmFtZSAmJiBleHRuYW1lLmluZGV4T2YoJy4nKSA9PT0gMCkge1xuICAgICAgICBleHRuYW1lID0gZXh0bmFtZS5zdWJzdHJpbmcoMSk7XG4gICAgfVxuXG4gICAgaWYgKCFleHRuYW1lKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBtYXBbZXh0bmFtZV0gPSB2YWw7XG59XG5cbi8qKlxuICogUXVpY2sgaGVscGVyIHRvIGdldCBzdHJpbmcgeGhyIHR5cGUuXG4gKlxuICogQGlnbm9yZVxuICogQHBhcmFtIHtYTUxIdHRwUmVxdWVzdHxYRG9tYWluUmVxdWVzdH0geGhyIC0gVGhlIHJlcXVlc3QgdG8gY2hlY2suXG4gKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSB0eXBlLlxuICovXG5mdW5jdGlvbiByZXFUeXBlKHhocikge1xuICAgIHJldHVybiB4aHIudG9TdHJpbmcoKS5yZXBsYWNlKCdvYmplY3QgJywgJycpO1xufVxuLy8jIHNvdXJjZU1hcHBpbmdVUkw9UmVzb3VyY2UuanMubWFwIiwiJ3VzZSBzdHJpY3QnO1xuXG5leHBvcnRzLl9fZXNNb2R1bGUgPSB0cnVlO1xuZXhwb3J0cy5lYWNoU2VyaWVzID0gZWFjaFNlcmllcztcbmV4cG9ydHMucXVldWUgPSBxdWV1ZTtcbi8qKlxuICogU21hbGxlciB2ZXJzaW9uIG9mIHRoZSBhc3luYyBsaWJyYXJ5IGNvbnN0cnVjdHMuXG4gKlxuICovXG5mdW5jdGlvbiBfbm9vcCgpIHt9IC8qIGVtcHR5ICovXG5cbi8qKlxuICogSXRlcmF0ZXMgYW4gYXJyYXkgaW4gc2VyaWVzLlxuICpcbiAqIEBwYXJhbSB7QXJyYXkuPCo+fSBhcnJheSAtIEFycmF5IHRvIGl0ZXJhdGUuXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBpdGVyYXRvciAtIEZ1bmN0aW9uIHRvIGNhbGwgZm9yIGVhY2ggZWxlbWVudC5cbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrIC0gRnVuY3Rpb24gdG8gY2FsbCB3aGVuIGRvbmUsIG9yIG9uIGVycm9yLlxuICogQHBhcmFtIHtib29sZWFufSBbZGVmZXJOZXh0PWZhbHNlXSAtIEJyZWFrIHN5bmNocm9ub3VzIGVhY2ggbG9vcCBieSBjYWxsaW5nIG5leHQgd2l0aCBhIHNldFRpbWVvdXQgb2YgMS5cbiAqL1xuZnVuY3Rpb24gZWFjaFNlcmllcyhhcnJheSwgaXRlcmF0b3IsIGNhbGxiYWNrLCBkZWZlck5leHQpIHtcbiAgICB2YXIgaSA9IDA7XG4gICAgdmFyIGxlbiA9IGFycmF5Lmxlbmd0aDtcblxuICAgIChmdW5jdGlvbiBuZXh0KGVycikge1xuICAgICAgICBpZiAoZXJyIHx8IGkgPT09IGxlbikge1xuICAgICAgICAgICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soZXJyKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGRlZmVyTmV4dCkge1xuICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgaXRlcmF0b3IoYXJyYXlbaSsrXSwgbmV4dCk7XG4gICAgICAgICAgICB9LCAxKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGl0ZXJhdG9yKGFycmF5W2krK10sIG5leHQpO1xuICAgICAgICB9XG4gICAgfSkoKTtcbn1cblxuLyoqXG4gKiBFbnN1cmVzIGEgZnVuY3Rpb24gaXMgb25seSBjYWxsZWQgb25jZS5cbiAqXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byB3cmFwLlxuICogQHJldHVybiB7ZnVuY3Rpb259IFRoZSB3cmFwcGluZyBmdW5jdGlvbi5cbiAqL1xuZnVuY3Rpb24gb25seU9uY2UoZm4pIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gb25jZVdyYXBwZXIoKSB7XG4gICAgICAgIGlmIChmbiA9PT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYWxsYmFjayB3YXMgYWxyZWFkeSBjYWxsZWQuJyk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgY2FsbEZuID0gZm47XG5cbiAgICAgICAgZm4gPSBudWxsO1xuICAgICAgICBjYWxsRm4uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9O1xufVxuXG4vKipcbiAqIEFzeW5jIHF1ZXVlIGltcGxlbWVudGF0aW9uLFxuICpcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IHdvcmtlciAtIFRoZSB3b3JrZXIgZnVuY3Rpb24gdG8gY2FsbCBmb3IgZWFjaCB0YXNrLlxuICogQHBhcmFtIHtudW1iZXJ9IGNvbmN1cnJlbmN5IC0gSG93IG1hbnkgd29ya2VycyB0byBydW4gaW4gcGFycmFsbGVsLlxuICogQHJldHVybiB7Kn0gVGhlIGFzeW5jIHF1ZXVlIG9iamVjdC5cbiAqL1xuZnVuY3Rpb24gcXVldWUod29ya2VyLCBjb25jdXJyZW5jeSkge1xuICAgIGlmIChjb25jdXJyZW5jeSA9PSBudWxsKSB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tZXEtbnVsbCxlcWVxZXFcbiAgICAgICAgY29uY3VycmVuY3kgPSAxO1xuICAgIH0gZWxzZSBpZiAoY29uY3VycmVuY3kgPT09IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25jdXJyZW5jeSBtdXN0IG5vdCBiZSB6ZXJvJyk7XG4gICAgfVxuXG4gICAgdmFyIHdvcmtlcnMgPSAwO1xuICAgIHZhciBxID0ge1xuICAgICAgICBfdGFza3M6IFtdLFxuICAgICAgICBjb25jdXJyZW5jeTogY29uY3VycmVuY3ksXG4gICAgICAgIHNhdHVyYXRlZDogX25vb3AsXG4gICAgICAgIHVuc2F0dXJhdGVkOiBfbm9vcCxcbiAgICAgICAgYnVmZmVyOiBjb25jdXJyZW5jeSAvIDQsXG4gICAgICAgIGVtcHR5OiBfbm9vcCxcbiAgICAgICAgZHJhaW46IF9ub29wLFxuICAgICAgICBlcnJvcjogX25vb3AsXG4gICAgICAgIHN0YXJ0ZWQ6IGZhbHNlLFxuICAgICAgICBwYXVzZWQ6IGZhbHNlLFxuICAgICAgICBwdXNoOiBmdW5jdGlvbiBwdXNoKGRhdGEsIGNhbGxiYWNrKSB7XG4gICAgICAgICAgICBfaW5zZXJ0KGRhdGEsIGZhbHNlLCBjYWxsYmFjayk7XG4gICAgICAgIH0sXG4gICAgICAgIGtpbGw6IGZ1bmN0aW9uIGtpbGwoKSB7XG4gICAgICAgICAgICB3b3JrZXJzID0gMDtcbiAgICAgICAgICAgIHEuZHJhaW4gPSBfbm9vcDtcbiAgICAgICAgICAgIHEuc3RhcnRlZCA9IGZhbHNlO1xuICAgICAgICAgICAgcS5fdGFza3MgPSBbXTtcbiAgICAgICAgfSxcbiAgICAgICAgdW5zaGlmdDogZnVuY3Rpb24gdW5zaGlmdChkYXRhLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgX2luc2VydChkYXRhLCB0cnVlLCBjYWxsYmFjayk7XG4gICAgICAgIH0sXG4gICAgICAgIHByb2Nlc3M6IGZ1bmN0aW9uIHByb2Nlc3MoKSB7XG4gICAgICAgICAgICB3aGlsZSAoIXEucGF1c2VkICYmIHdvcmtlcnMgPCBxLmNvbmN1cnJlbmN5ICYmIHEuX3Rhc2tzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciB0YXNrID0gcS5fdGFza3Muc2hpZnQoKTtcblxuICAgICAgICAgICAgICAgIGlmIChxLl90YXNrcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgcS5lbXB0eSgpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHdvcmtlcnMgKz0gMTtcblxuICAgICAgICAgICAgICAgIGlmICh3b3JrZXJzID09PSBxLmNvbmN1cnJlbmN5KSB7XG4gICAgICAgICAgICAgICAgICAgIHEuc2F0dXJhdGVkKCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgd29ya2VyKHRhc2suZGF0YSwgb25seU9uY2UoX25leHQodGFzaykpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgbGVuZ3RoOiBmdW5jdGlvbiBsZW5ndGgoKSB7XG4gICAgICAgICAgICByZXR1cm4gcS5fdGFza3MubGVuZ3RoO1xuICAgICAgICB9LFxuICAgICAgICBydW5uaW5nOiBmdW5jdGlvbiBydW5uaW5nKCkge1xuICAgICAgICAgICAgcmV0dXJuIHdvcmtlcnM7XG4gICAgICAgIH0sXG4gICAgICAgIGlkbGU6IGZ1bmN0aW9uIGlkbGUoKSB7XG4gICAgICAgICAgICByZXR1cm4gcS5fdGFza3MubGVuZ3RoICsgd29ya2VycyA9PT0gMDtcbiAgICAgICAgfSxcbiAgICAgICAgcGF1c2U6IGZ1bmN0aW9uIHBhdXNlKCkge1xuICAgICAgICAgICAgaWYgKHEucGF1c2VkID09PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBxLnBhdXNlZCA9IHRydWU7XG4gICAgICAgIH0sXG4gICAgICAgIHJlc3VtZTogZnVuY3Rpb24gcmVzdW1lKCkge1xuICAgICAgICAgICAgaWYgKHEucGF1c2VkID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcS5wYXVzZWQgPSBmYWxzZTtcblxuICAgICAgICAgICAgLy8gTmVlZCB0byBjYWxsIHEucHJvY2VzcyBvbmNlIHBlciBjb25jdXJyZW50XG4gICAgICAgICAgICAvLyB3b3JrZXIgdG8gcHJlc2VydmUgZnVsbCBjb25jdXJyZW5jeSBhZnRlciBwYXVzZVxuICAgICAgICAgICAgZm9yICh2YXIgdyA9IDE7IHcgPD0gcS5jb25jdXJyZW5jeTsgdysrKSB7XG4gICAgICAgICAgICAgICAgcS5wcm9jZXNzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gX2luc2VydChkYXRhLCBpbnNlcnRBdEZyb250LCBjYWxsYmFjaykge1xuICAgICAgICBpZiAoY2FsbGJhY2sgIT0gbnVsbCAmJiB0eXBlb2YgY2FsbGJhY2sgIT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tZXEtbnVsbCxlcWVxZXFcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigndGFzayBjYWxsYmFjayBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHEuc3RhcnRlZCA9IHRydWU7XG5cbiAgICAgICAgaWYgKGRhdGEgPT0gbnVsbCAmJiBxLmlkbGUoKSkge1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1lcS1udWxsLGVxZXFlcVxuICAgICAgICAgICAgLy8gY2FsbCBkcmFpbiBpbW1lZGlhdGVseSBpZiB0aGVyZSBhcmUgbm8gdGFza3NcbiAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBxLmRyYWluKCk7XG4gICAgICAgICAgICB9LCAxKTtcblxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGl0ZW0gPSB7XG4gICAgICAgICAgICBkYXRhOiBkYXRhLFxuICAgICAgICAgICAgY2FsbGJhY2s6IHR5cGVvZiBjYWxsYmFjayA9PT0gJ2Z1bmN0aW9uJyA/IGNhbGxiYWNrIDogX25vb3BcbiAgICAgICAgfTtcblxuICAgICAgICBpZiAoaW5zZXJ0QXRGcm9udCkge1xuICAgICAgICAgICAgcS5fdGFza3MudW5zaGlmdChpdGVtKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHEuX3Rhc2tzLnB1c2goaXRlbSk7XG4gICAgICAgIH1cblxuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBxLnByb2Nlc3MoKTtcbiAgICAgICAgfSwgMSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gX25leHQodGFzaykge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gbmV4dCgpIHtcbiAgICAgICAgICAgIHdvcmtlcnMgLT0gMTtcblxuICAgICAgICAgICAgdGFzay5jYWxsYmFjay5hcHBseSh0YXNrLCBhcmd1bWVudHMpO1xuXG4gICAgICAgICAgICBpZiAoYXJndW1lbnRzWzBdICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLWVxLW51bGwsZXFlcWVxXG4gICAgICAgICAgICAgICAgcS5lcnJvcihhcmd1bWVudHNbMF0sIHRhc2suZGF0YSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh3b3JrZXJzIDw9IHEuY29uY3VycmVuY3kgLSBxLmJ1ZmZlcikge1xuICAgICAgICAgICAgICAgIHEudW5zYXR1cmF0ZWQoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHEuaWRsZSgpKSB7XG4gICAgICAgICAgICAgICAgcS5kcmFpbigpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBxLnByb2Nlc3MoKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4gcTtcbn1cbi8vIyBzb3VyY2VNYXBwaW5nVVJMPWFzeW5jLmpzLm1hcCIsIid1c2Ugc3RyaWN0JztcblxuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZTtcbmV4cG9ydHMuZW5jb2RlQmluYXJ5ID0gZW5jb2RlQmluYXJ5O1xudmFyIF9rZXlTdHIgPSAnQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLz0nO1xuXG5mdW5jdGlvbiBlbmNvZGVCaW5hcnkoaW5wdXQpIHtcbiAgICB2YXIgb3V0cHV0ID0gJyc7XG4gICAgdmFyIGlueCA9IDA7XG5cbiAgICB3aGlsZSAoaW54IDwgaW5wdXQubGVuZ3RoKSB7XG4gICAgICAgIC8vIEZpbGwgYnl0ZSBidWZmZXIgYXJyYXlcbiAgICAgICAgdmFyIGJ5dGVidWZmZXIgPSBbMCwgMCwgMF07XG4gICAgICAgIHZhciBlbmNvZGVkQ2hhckluZGV4ZXMgPSBbMCwgMCwgMCwgMF07XG5cbiAgICAgICAgZm9yICh2YXIgam54ID0gMDsgam54IDwgYnl0ZWJ1ZmZlci5sZW5ndGg7ICsram54KSB7XG4gICAgICAgICAgICBpZiAoaW54IDwgaW5wdXQubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhyb3cgYXdheSBoaWdoLW9yZGVyIGJ5dGUsIGFzIGRvY3VtZW50ZWQgYXQ6XG4gICAgICAgICAgICAgICAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvRW4vVXNpbmdfWE1MSHR0cFJlcXVlc3QjSGFuZGxpbmdfYmluYXJ5X2RhdGFcbiAgICAgICAgICAgICAgICBieXRlYnVmZmVyW2pueF0gPSBpbnB1dC5jaGFyQ29kZUF0KGlueCsrKSAmIDB4ZmY7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGJ5dGVidWZmZXJbam54XSA9IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBHZXQgZWFjaCBlbmNvZGVkIGNoYXJhY3RlciwgNiBiaXRzIGF0IGEgdGltZVxuICAgICAgICAvLyBpbmRleCAxOiBmaXJzdCA2IGJpdHNcbiAgICAgICAgZW5jb2RlZENoYXJJbmRleGVzWzBdID0gYnl0ZWJ1ZmZlclswXSA+PiAyO1xuXG4gICAgICAgIC8vIGluZGV4IDI6IHNlY29uZCA2IGJpdHMgKDIgbGVhc3Qgc2lnbmlmaWNhbnQgYml0cyBmcm9tIGlucHV0IGJ5dGUgMSArIDQgbW9zdCBzaWduaWZpY2FudCBiaXRzIGZyb20gYnl0ZSAyKVxuICAgICAgICBlbmNvZGVkQ2hhckluZGV4ZXNbMV0gPSAoYnl0ZWJ1ZmZlclswXSAmIDB4MykgPDwgNCB8IGJ5dGVidWZmZXJbMV0gPj4gNDtcblxuICAgICAgICAvLyBpbmRleCAzOiB0aGlyZCA2IGJpdHMgKDQgbGVhc3Qgc2lnbmlmaWNhbnQgYml0cyBmcm9tIGlucHV0IGJ5dGUgMiArIDIgbW9zdCBzaWduaWZpY2FudCBiaXRzIGZyb20gYnl0ZSAzKVxuICAgICAgICBlbmNvZGVkQ2hhckluZGV4ZXNbMl0gPSAoYnl0ZWJ1ZmZlclsxXSAmIDB4MGYpIDw8IDIgfCBieXRlYnVmZmVyWzJdID4+IDY7XG5cbiAgICAgICAgLy8gaW5kZXggMzogZm9ydGggNiBiaXRzICg2IGxlYXN0IHNpZ25pZmljYW50IGJpdHMgZnJvbSBpbnB1dCBieXRlIDMpXG4gICAgICAgIGVuY29kZWRDaGFySW5kZXhlc1szXSA9IGJ5dGVidWZmZXJbMl0gJiAweDNmO1xuXG4gICAgICAgIC8vIERldGVybWluZSB3aGV0aGVyIHBhZGRpbmcgaGFwcGVuZWQsIGFuZCBhZGp1c3QgYWNjb3JkaW5nbHlcbiAgICAgICAgdmFyIHBhZGRpbmdCeXRlcyA9IGlueCAtIChpbnB1dC5sZW5ndGggLSAxKTtcblxuICAgICAgICBzd2l0Y2ggKHBhZGRpbmdCeXRlcykge1xuICAgICAgICAgICAgY2FzZSAyOlxuICAgICAgICAgICAgICAgIC8vIFNldCBsYXN0IDIgY2hhcmFjdGVycyB0byBwYWRkaW5nIGNoYXJcbiAgICAgICAgICAgICAgICBlbmNvZGVkQ2hhckluZGV4ZXNbM10gPSA2NDtcbiAgICAgICAgICAgICAgICBlbmNvZGVkQ2hhckluZGV4ZXNbMl0gPSA2NDtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSAxOlxuICAgICAgICAgICAgICAgIC8vIFNldCBsYXN0IGNoYXJhY3RlciB0byBwYWRkaW5nIGNoYXJcbiAgICAgICAgICAgICAgICBlbmNvZGVkQ2hhckluZGV4ZXNbM10gPSA2NDtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICBicmVhazsgLy8gTm8gcGFkZGluZyAtIHByb2NlZWRcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdyB3ZSB3aWxsIGdyYWIgZWFjaCBhcHByb3ByaWF0ZSBjaGFyYWN0ZXIgb3V0IG9mIG91ciBrZXlzdHJpbmdcbiAgICAgICAgLy8gYmFzZWQgb24gb3VyIGluZGV4IGFycmF5IGFuZCBhcHBlbmQgaXQgdG8gdGhlIG91dHB1dCBzdHJpbmdcbiAgICAgICAgZm9yICh2YXIgX2pueCA9IDA7IF9qbnggPCBlbmNvZGVkQ2hhckluZGV4ZXMubGVuZ3RoOyArK19qbngpIHtcbiAgICAgICAgICAgIG91dHB1dCArPSBfa2V5U3RyLmNoYXJBdChlbmNvZGVkQ2hhckluZGV4ZXNbX2pueF0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG91dHB1dDtcbn1cbi8vIyBzb3VyY2VNYXBwaW5nVVJMPWI2NC5qcy5tYXAiLCIndXNlIHN0cmljdCc7XG5cbi8vIGltcG9ydCBMb2FkZXIgZnJvbSAnLi9Mb2FkZXInO1xuLy8gaW1wb3J0IFJlc291cmNlIGZyb20gJy4vUmVzb3VyY2UnO1xuLy8gaW1wb3J0ICogYXMgYXN5bmMgZnJvbSAnLi9hc3luYyc7XG4vLyBpbXBvcnQgKiBhcyBiNjQgZnJvbSAnLi9iNjQnO1xuXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xuXG52YXIgTG9hZGVyID0gcmVxdWlyZSgnLi9Mb2FkZXInKS5kZWZhdWx0O1xudmFyIFJlc291cmNlID0gcmVxdWlyZSgnLi9SZXNvdXJjZScpLmRlZmF1bHQ7XG52YXIgYXN5bmMgPSByZXF1aXJlKCcuL2FzeW5jJyk7XG52YXIgYjY0ID0gcmVxdWlyZSgnLi9iNjQnKTtcblxuTG9hZGVyLlJlc291cmNlID0gUmVzb3VyY2U7XG5Mb2FkZXIuYXN5bmMgPSBhc3luYztcbkxvYWRlci5iYXNlNjQgPSBiNjQ7XG5cbi8vIGV4cG9ydCBtYW51YWxseSwgYW5kIGFsc28gYXMgZGVmYXVsdFxubW9kdWxlLmV4cG9ydHMgPSBMb2FkZXI7XG4vLyBleHBvcnQgZGVmYXVsdCBMb2FkZXI7XG5tb2R1bGUuZXhwb3J0cy5kZWZhdWx0ID0gTG9hZGVyO1xuLy8jIHNvdXJjZU1hcHBpbmdVUkw9aW5kZXguanMubWFwIiwiJ3VzZSBzdHJpY3QnO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcblxudmFyIF9jcmVhdGVDbGFzcyA9IChmdW5jdGlvbiAoKSB7IGZ1bmN0aW9uIGRlZmluZVByb3BlcnRpZXModGFyZ2V0LCBwcm9wcykgeyBmb3IgKHZhciBpID0gMDsgaSA8IHByb3BzLmxlbmd0aDsgaSsrKSB7IHZhciBkZXNjcmlwdG9yID0gcHJvcHNbaV07IGRlc2NyaXB0b3IuZW51bWVyYWJsZSA9IGRlc2NyaXB0b3IuZW51bWVyYWJsZSB8fCBmYWxzZTsgZGVzY3JpcHRvci5jb25maWd1cmFibGUgPSB0cnVlOyBpZiAoJ3ZhbHVlJyBpbiBkZXNjcmlwdG9yKSBkZXNjcmlwdG9yLndyaXRhYmxlID0gdHJ1ZTsgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwgZGVzY3JpcHRvci5rZXksIGRlc2NyaXB0b3IpOyB9IH0gcmV0dXJuIGZ1bmN0aW9uIChDb25zdHJ1Y3RvciwgcHJvdG9Qcm9wcywgc3RhdGljUHJvcHMpIHsgaWYgKHByb3RvUHJvcHMpIGRlZmluZVByb3BlcnRpZXMoQ29uc3RydWN0b3IucHJvdG90eXBlLCBwcm90b1Byb3BzKTsgaWYgKHN0YXRpY1Byb3BzKSBkZWZpbmVQcm9wZXJ0aWVzKENvbnN0cnVjdG9yLCBzdGF0aWNQcm9wcyk7IHJldHVybiBDb25zdHJ1Y3RvcjsgfTsgfSkoKTtcblxuZnVuY3Rpb24gX2NsYXNzQ2FsbENoZWNrKGluc3RhbmNlLCBDb25zdHJ1Y3RvcikgeyBpZiAoIShpbnN0YW5jZSBpbnN0YW5jZW9mIENvbnN0cnVjdG9yKSkgeyB0aHJvdyBuZXcgVHlwZUVycm9yKCdDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24nKTsgfSB9XG5cbnZhciBNaW5pU2lnbmFsQmluZGluZyA9IChmdW5jdGlvbiAoKSB7XG4gIGZ1bmN0aW9uIE1pbmlTaWduYWxCaW5kaW5nKGZuLCBvbmNlLCB0aGlzQXJnKSB7XG4gICAgaWYgKG9uY2UgPT09IHVuZGVmaW5lZCkgb25jZSA9IGZhbHNlO1xuXG4gICAgX2NsYXNzQ2FsbENoZWNrKHRoaXMsIE1pbmlTaWduYWxCaW5kaW5nKTtcblxuICAgIHRoaXMuX2ZuID0gZm47XG4gICAgdGhpcy5fb25jZSA9IG9uY2U7XG4gICAgdGhpcy5fdGhpc0FyZyA9IHRoaXNBcmc7XG4gICAgdGhpcy5fbmV4dCA9IHRoaXMuX3ByZXYgPSB0aGlzLl9vd25lciA9IG51bGw7XG4gIH1cblxuICBfY3JlYXRlQ2xhc3MoTWluaVNpZ25hbEJpbmRpbmcsIFt7XG4gICAga2V5OiAnZGV0YWNoJyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gZGV0YWNoKCkge1xuICAgICAgaWYgKHRoaXMuX293bmVyID09PSBudWxsKSByZXR1cm4gZmFsc2U7XG4gICAgICB0aGlzLl9vd25lci5kZXRhY2godGhpcyk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1dKTtcblxuICByZXR1cm4gTWluaVNpZ25hbEJpbmRpbmc7XG59KSgpO1xuXG5mdW5jdGlvbiBfYWRkTWluaVNpZ25hbEJpbmRpbmcoc2VsZiwgbm9kZSkge1xuICBpZiAoIXNlbGYuX2hlYWQpIHtcbiAgICBzZWxmLl9oZWFkID0gbm9kZTtcbiAgICBzZWxmLl90YWlsID0gbm9kZTtcbiAgfSBlbHNlIHtcbiAgICBzZWxmLl90YWlsLl9uZXh0ID0gbm9kZTtcbiAgICBub2RlLl9wcmV2ID0gc2VsZi5fdGFpbDtcbiAgICBzZWxmLl90YWlsID0gbm9kZTtcbiAgfVxuXG4gIG5vZGUuX293bmVyID0gc2VsZjtcblxuICByZXR1cm4gbm9kZTtcbn1cblxudmFyIE1pbmlTaWduYWwgPSAoZnVuY3Rpb24gKCkge1xuICBmdW5jdGlvbiBNaW5pU2lnbmFsKCkge1xuICAgIF9jbGFzc0NhbGxDaGVjayh0aGlzLCBNaW5pU2lnbmFsKTtcblxuICAgIHRoaXMuX2hlYWQgPSB0aGlzLl90YWlsID0gdW5kZWZpbmVkO1xuICB9XG5cbiAgX2NyZWF0ZUNsYXNzKE1pbmlTaWduYWwsIFt7XG4gICAga2V5OiAnaGFuZGxlcnMnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBoYW5kbGVycygpIHtcbiAgICAgIHZhciBleGlzdHMgPSBhcmd1bWVudHMubGVuZ3RoIDw9IDAgfHwgYXJndW1lbnRzWzBdID09PSB1bmRlZmluZWQgPyBmYWxzZSA6IGFyZ3VtZW50c1swXTtcblxuICAgICAgdmFyIG5vZGUgPSB0aGlzLl9oZWFkO1xuXG4gICAgICBpZiAoZXhpc3RzKSByZXR1cm4gISFub2RlO1xuXG4gICAgICB2YXIgZWUgPSBbXTtcblxuICAgICAgd2hpbGUgKG5vZGUpIHtcbiAgICAgICAgZWUucHVzaChub2RlKTtcbiAgICAgICAgbm9kZSA9IG5vZGUuX25leHQ7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBlZTtcbiAgICB9XG4gIH0sIHtcbiAgICBrZXk6ICdoYXMnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBoYXMobm9kZSkge1xuICAgICAgaWYgKCEobm9kZSBpbnN0YW5jZW9mIE1pbmlTaWduYWxCaW5kaW5nKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ01pbmlTaWduYWwjaGFzKCk6IEZpcnN0IGFyZyBtdXN0IGJlIGEgTWluaVNpZ25hbEJpbmRpbmcgb2JqZWN0LicpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gbm9kZS5fb3duZXIgPT09IHRoaXM7XG4gICAgfVxuICB9LCB7XG4gICAga2V5OiAnZGlzcGF0Y2gnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBkaXNwYXRjaCgpIHtcbiAgICAgIHZhciBub2RlID0gdGhpcy5faGVhZDtcblxuICAgICAgaWYgKCFub2RlKSByZXR1cm4gZmFsc2U7XG5cbiAgICAgIHdoaWxlIChub2RlKSB7XG4gICAgICAgIGlmIChub2RlLl9vbmNlKSB0aGlzLmRldGFjaChub2RlKTtcbiAgICAgICAgbm9kZS5fZm4uYXBwbHkobm9kZS5fdGhpc0FyZywgYXJndW1lbnRzKTtcbiAgICAgICAgbm9kZSA9IG5vZGUuX25leHQ7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfSwge1xuICAgIGtleTogJ2FkZCcsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIGFkZChmbikge1xuICAgICAgdmFyIHRoaXNBcmcgPSBhcmd1bWVudHMubGVuZ3RoIDw9IDEgfHwgYXJndW1lbnRzWzFdID09PSB1bmRlZmluZWQgPyBudWxsIDogYXJndW1lbnRzWzFdO1xuXG4gICAgICBpZiAodHlwZW9mIGZuICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTWluaVNpZ25hbCNhZGQoKTogRmlyc3QgYXJnIG11c3QgYmUgYSBGdW5jdGlvbi4nKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBfYWRkTWluaVNpZ25hbEJpbmRpbmcodGhpcywgbmV3IE1pbmlTaWduYWxCaW5kaW5nKGZuLCBmYWxzZSwgdGhpc0FyZykpO1xuICAgIH1cbiAgfSwge1xuICAgIGtleTogJ29uY2UnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBvbmNlKGZuKSB7XG4gICAgICB2YXIgdGhpc0FyZyA9IGFyZ3VtZW50cy5sZW5ndGggPD0gMSB8fCBhcmd1bWVudHNbMV0gPT09IHVuZGVmaW5lZCA/IG51bGwgOiBhcmd1bWVudHNbMV07XG5cbiAgICAgIGlmICh0eXBlb2YgZm4gIT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaW5pU2lnbmFsI29uY2UoKTogRmlyc3QgYXJnIG11c3QgYmUgYSBGdW5jdGlvbi4nKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBfYWRkTWluaVNpZ25hbEJpbmRpbmcodGhpcywgbmV3IE1pbmlTaWduYWxCaW5kaW5nKGZuLCB0cnVlLCB0aGlzQXJnKSk7XG4gICAgfVxuICB9LCB7XG4gICAga2V5OiAnZGV0YWNoJyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gZGV0YWNoKG5vZGUpIHtcbiAgICAgIGlmICghKG5vZGUgaW5zdGFuY2VvZiBNaW5pU2lnbmFsQmluZGluZykpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaW5pU2lnbmFsI2RldGFjaCgpOiBGaXJzdCBhcmcgbXVzdCBiZSBhIE1pbmlTaWduYWxCaW5kaW5nIG9iamVjdC4nKTtcbiAgICAgIH1cbiAgICAgIGlmIChub2RlLl9vd25lciAhPT0gdGhpcykgcmV0dXJuIHRoaXM7XG5cbiAgICAgIGlmIChub2RlLl9wcmV2KSBub2RlLl9wcmV2Ll9uZXh0ID0gbm9kZS5fbmV4dDtcbiAgICAgIGlmIChub2RlLl9uZXh0KSBub2RlLl9uZXh0Ll9wcmV2ID0gbm9kZS5fcHJldjtcblxuICAgICAgaWYgKG5vZGUgPT09IHRoaXMuX2hlYWQpIHtcbiAgICAgICAgdGhpcy5faGVhZCA9IG5vZGUuX25leHQ7XG4gICAgICAgIGlmIChub2RlLl9uZXh0ID09PSBudWxsKSB7XG4gICAgICAgICAgdGhpcy5fdGFpbCA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAobm9kZSA9PT0gdGhpcy5fdGFpbCkge1xuICAgICAgICB0aGlzLl90YWlsID0gbm9kZS5fcHJldjtcbiAgICAgICAgdGhpcy5fdGFpbC5fbmV4dCA9IG51bGw7XG4gICAgICB9XG5cbiAgICAgIG5vZGUuX293bmVyID0gbnVsbDtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgfSwge1xuICAgIGtleTogJ2RldGFjaEFsbCcsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIGRldGFjaEFsbCgpIHtcbiAgICAgIHZhciBub2RlID0gdGhpcy5faGVhZDtcbiAgICAgIGlmICghbm9kZSkgcmV0dXJuIHRoaXM7XG5cbiAgICAgIHRoaXMuX2hlYWQgPSB0aGlzLl90YWlsID0gbnVsbDtcblxuICAgICAgd2hpbGUgKG5vZGUpIHtcbiAgICAgICAgbm9kZS5fb3duZXIgPSBudWxsO1xuICAgICAgICBub2RlID0gbm9kZS5fbmV4dDtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgfV0pO1xuXG4gIHJldHVybiBNaW5pU2lnbmFsO1xufSkoKTtcblxuTWluaVNpZ25hbC5NaW5pU2lnbmFsQmluZGluZyA9IE1pbmlTaWduYWxCaW5kaW5nO1xuXG5leHBvcnRzWydkZWZhdWx0J10gPSBNaW5pU2lnbmFsO1xubW9kdWxlLmV4cG9ydHMgPSBleHBvcnRzWydkZWZhdWx0J107XG4iLCIndXNlIHN0cmljdCdcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBwYXJzZVVSSSAoc3RyLCBvcHRzKSB7XG4gIG9wdHMgPSBvcHRzIHx8IHt9XG5cbiAgdmFyIG8gPSB7XG4gICAga2V5OiBbJ3NvdXJjZScsICdwcm90b2NvbCcsICdhdXRob3JpdHknLCAndXNlckluZm8nLCAndXNlcicsICdwYXNzd29yZCcsICdob3N0JywgJ3BvcnQnLCAncmVsYXRpdmUnLCAncGF0aCcsICdkaXJlY3RvcnknLCAnZmlsZScsICdxdWVyeScsICdhbmNob3InXSxcbiAgICBxOiB7XG4gICAgICBuYW1lOiAncXVlcnlLZXknLFxuICAgICAgcGFyc2VyOiAvKD86XnwmKShbXiY9XSopPT8oW14mXSopL2dcbiAgICB9LFxuICAgIHBhcnNlcjoge1xuICAgICAgc3RyaWN0OiAvXig/OihbXjpcXC8/I10rKTopPyg/OlxcL1xcLygoPzooKFteOkBdKikoPzo6KFteOkBdKikpPyk/QCk/KFteOlxcLz8jXSopKD86OihcXGQqKSk/KSk/KCgoKD86W14/I1xcL10qXFwvKSopKFtePyNdKikpKD86XFw/KFteI10qKSk/KD86IyguKikpPykvLFxuICAgICAgbG9vc2U6IC9eKD86KD8hW146QF0rOlteOkBcXC9dKkApKFteOlxcLz8jLl0rKTopPyg/OlxcL1xcLyk/KCg/OigoW146QF0qKSg/OjooW146QF0qKSk/KT9AKT8oW146XFwvPyNdKikoPzo6KFxcZCopKT8pKCgoXFwvKD86W14/I10oPyFbXj8jXFwvXSpcXC5bXj8jXFwvLl0rKD86Wz8jXXwkKSkpKlxcLz8pPyhbXj8jXFwvXSopKSg/OlxcPyhbXiNdKikpPyg/OiMoLiopKT8pL1xuICAgIH1cbiAgfVxuXG4gIHZhciBtID0gby5wYXJzZXJbb3B0cy5zdHJpY3RNb2RlID8gJ3N0cmljdCcgOiAnbG9vc2UnXS5leGVjKHN0cilcbiAgdmFyIHVyaSA9IHt9XG4gIHZhciBpID0gMTRcblxuICB3aGlsZSAoaS0tKSB1cmlbby5rZXlbaV1dID0gbVtpXSB8fCAnJ1xuXG4gIHVyaVtvLnEubmFtZV0gPSB7fVxuICB1cmlbby5rZXlbMTJdXS5yZXBsYWNlKG8ucS5wYXJzZXIsIGZ1bmN0aW9uICgkMCwgJDEsICQyKSB7XG4gICAgaWYgKCQxKSB1cmlbby5xLm5hbWVdWyQxXSA9ICQyXG4gIH0pXG5cbiAgcmV0dXJuIHVyaVxufVxuIl19