UNPKG

@genialis/resolwe

Version:
228 lines (226 loc) 32.1 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); var Rx = require("rx"); var angular = require("angular"); var _ = require("lodash"); require("ng-file-upload"); var error_1 = require("../errors/error"); var lang_1 = require("../utils/lang"); var random = require("../utils/random"); var angularModule = angular.module('resolwe.services.api', [ 'ngFileUpload', ]); var UploadEventType; (function (UploadEventType) { UploadEventType["PROGRESS"] = "progress"; UploadEventType["RETRYING"] = "retrying"; UploadEventType["RESULT"] = "result"; })(UploadEventType = exports.UploadEventType || (exports.UploadEventType = {})); /** * Base API service class providing additional features like file * upload support. It should be used as a mixin together with an * actual API class. */ var APIServiceBase = /** @class */ (function () { // @ngInject APIServiceBase.$inject = ["Upload", "$q", "$http", "maxConsecutiveAutoretryAttempts"]; function APIServiceBase(Upload, $q, $http, maxConsecutiveAutoretryAttempts) { this.CHUNK_SIZE = 1 * 1024 * 1024; // 1MB /** * Max consecutive autoretry attempts are configurable in provider. An autoretry attempt is not * considered consecutive if it happens later than 2 * maxDelay (retry attempts are reset after * that time). */ this.maxConsecutiveAutoretryAttempts = 5; this.RETRY_DELAY_INCREMENT = 500; this.MAX_RETRY_DELAY = 5000; this._upload = Upload; this._q = $q; this._http = $http; if (!_.isUndefined(maxConsecutiveAutoretryAttempts)) { this.maxConsecutiveAutoretryAttempts = maxConsecutiveAutoretryAttempts; } } APIServiceBase.prototype.isTimeToResetAutoretryAttempts = function (timeSincePreviousError) { var maxDelay = Math.max(this.maxConsecutiveAutoretryAttempts * this.RETRY_DELAY_INCREMENT, this.MAX_RETRY_DELAY); return timeSincePreviousError > 2 * maxDelay; }; /** * Performs a data upload. * * Each field including nested objects will be sent as a form data multipart. * Samples: * {pic: file, username: username} * {files: files, otherInfo: {id: id, person: person,...}} multiple files (html5) * {profiles: {[{pic: file1, username: username1}, {pic: file2, username: username2}]} nested array multiple files (html5) * {file: file, info: Upload.json({id: id, name: name, ...})} send fields as json string * {file: file, info: Upload.jsonBlob({id: id, name: name, ...})} send fields as json blob, 'application/json' content_type * {picFile: Upload.rename(file, 'profile.jpg'), title: title} send file with picFile key and profile.jpg file name * * @param {any} data See angular.angularFileUpload.IFileUploadConfigFile. */ APIServiceBase.prototype.upload = function (data, fileUID) { var _this = this; if (fileUID === void 0) { fileUID = ''; } var url = this.connection.createUriFromPath('/upload/'); var headers = { 'Session-Id': this.connection.sessionId(), 'X-File-Uid': fileUID, 'X-CSRFToken': this.connection.csrfCookie(), }; return Rx.Observable.create(function (observer) { observer.onNext({ type: UploadEventType.RETRYING }); // Note: First one of these is skipped below. var rejectableResumeSizePromise = _this._q.defer(); var fileUpload = _this._upload.upload({ url: url, method: 'POST', headers: headers, withCredentials: true, resumeSize: function () { var resumeSizePromise = _this._http.get(url, { headers: headers, withCredentials: true, }).then(function (response) { return response.data.resume_offset; }, function (error) { observer.onError(error); // Handled in observables return _this._q.defer().promise; // Never resolve }); rejectableResumeSizePromise.resolve(resumeSizePromise); return rejectableResumeSizePromise.promise; }, resumeChunkSize: _this.CHUNK_SIZE, data: data, }); fileUpload.then(function (result) { observer.onNext({ result: result.data, type: UploadEventType.RESULT }); observer.onCompleted(); }, function (error) { observer.onError(error); }, function (progress) { observer.onNext({ progress: progress, type: UploadEventType.PROGRESS }); }); return function () { // To differentiate between connections aborted by server or client (when computer // goes to standby/sleep), we emit a custom error. Otherwise we would have to // filter out all `xhrStatus === 'abort'` and couldn't auto-retry after standby. observer.onError({ xhrStatus: 'manual-abort' }); fileUpload.abort(); rejectableResumeSizePromise.reject(); }; }) .retryWhen(function (errors) { return errors .filter(function (error) { return error && error.xhrStatus !== 'manual-abort'; }) .timeInterval() .scan(function (accumulated, value) { var error = value.value; var timeSincePrevious = value.interval; var consecutiveErrors = accumulated.consecutiveErrors + 1; if (_this.isTimeToResetAutoretryAttempts(timeSincePrevious)) consecutiveErrors = 1; var retry = consecutiveErrors <= _this.maxConsecutiveAutoretryAttempts; var delay = Math.min(consecutiveErrors * _this.RETRY_DELAY_INCREMENT, _this.MAX_RETRY_DELAY); return { error: error, consecutiveErrors: consecutiveErrors, timeSincePrevious: timeSincePrevious, retry: retry, delay: delay }; }, { error: null, consecutiveErrors: 0, timeSincePrevious: 0, retry: false, delay: 0 }) .flatMap(function (_a) { var retry = _a.retry, delay = _a.delay, error = _a.error; // This event is probably computer going to standby. Wait a bit longer. if (error && error.xhrStatus === 'abort') delay = 10000; if (!retry) { // Stop retrying after a while and return unwrapped error return Rx.Observable.throw(error); } return Rx.Observable.just(error).delay(delay); }) .do(function (error) { console.info("Retrying upload after an error", error); }); }) .skip(1) // Skip initial 'retrying' event. .filter(function (event) { // If a retry request fails, it would remove the progress bar until it // succeeds again. With this filter we can keep the progress bar anyway. return !(event.type === UploadEventType.PROGRESS && event.progress.loaded === 0 && event.progress.total === 0); }); }; /** * Uploads string content as a file. */ APIServiceBase.prototype.uploadString = function (filename, content) { var file; try { file = new File([content], filename, { type: 'text/plain', lastModified: Date.now() }); } catch (e) { // Simple fallback for Safari 9 and IE/Edge, because they don't // support File constructor. file = _.assign(new Blob([content], { type: 'text/plain' }), { name: filename }); } return this.upload({ file: file }, 'string-' + random.randomUuid()); }; return APIServiceBase; }()); exports.APIServiceBase = APIServiceBase; /** * Service provider for configuring the API service. Before using the * API service, this provider must be configured with an actual API * class, which should derive from [[ResolweApi]]. * * For example, if the API class is called `BaseApi`, we can configure * the API service as follows: * ``` * // Create a type for the service. * export interface APIService extends APIServiceBase, BaseApi { * } * * // Configure the API provider with our API instance. * module.config((apiProvider: APIServiceProvider) => { * apiProvider.setAPI( * BaseApi, * new SimpleConnection(), * REST_URL, * WEBSOCKET_URL * ); * * // Configure upload auto-retries to infinity * apiProvider.setMaxConsecutiveAutoretryAttempts(Infinity); * }); * ``` */ var APIServiceProvider = /** @class */ (function () { function APIServiceProvider() { } APIServiceProvider.prototype.setAPI = function (api, locals) { this._api = api; this._apiLocals = locals; }; APIServiceProvider.prototype.setMaxConsecutiveAutoretryAttempts = function (retries) { this._maxConsecutiveAutoretryAttempts = retries; }; // @ngInject APIServiceProvider.prototype.$get = function ($injector) { // TODO: Use error notification service instead. if (!this._api) throw new error_1.GenError("API not configured."); // Mix together the API and the APIServiceBase. var serviceClass = lang_1.ngCompose([this._api, APIServiceBase]); return $injector.instantiate(serviceClass, __assign({}, this._apiLocals, { maxConsecutiveAutoretryAttempts: this._maxConsecutiveAutoretryAttempts })); }; APIServiceProvider.prototype.$get.$inject = ["$injector"]; return APIServiceProvider; }()); exports.APIServiceProvider = APIServiceProvider; angularModule.provider('api', APIServiceProvider); //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jb3JlL3NlcnZpY2VzL2FwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7O0FBQUEsdUJBQXlCO0FBQ3pCLGlDQUFtQztBQUNuQywwQkFBNEI7QUFDNUIsMEJBQXdCO0FBRXhCLHlDQUF5QztBQUl6QyxzQ0FBd0M7QUFDeEMsd0NBQTBDO0FBRTFDLElBQU0sYUFBYSxHQUFvQixPQUFPLENBQUMsTUFBTSxDQUFDLHNCQUFzQixFQUFFO0lBQzFFLGNBQWM7Q0FDakIsQ0FBQyxDQUFDO0FBRUgsSUFBWSxlQUlYO0FBSkQsV0FBWSxlQUFlO0lBQ3ZCLHdDQUFxQixDQUFBO0lBQ3JCLHdDQUFxQixDQUFBO0lBQ3JCLG9DQUFpQixDQUFBO0FBQ3JCLENBQUMsRUFKVyxlQUFlLEdBQWYsdUJBQWUsS0FBZix1QkFBZSxRQUkxQjtBQU1EOzs7O0dBSUc7QUFDSDtJQXdCSSxZQUFZO0lBQ1osd0JBQVksTUFBZ0QsRUFDaEQsRUFBcUIsRUFDckIsS0FBMkIsRUFDM0IsK0JBQXdDO1FBM0I3QyxlQUFVLEdBQUcsQ0FBQyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQyxNQUFNO1FBRTNDOzs7O1dBSUc7UUFDSSxvQ0FBK0IsR0FBRyxDQUFDLENBQUM7UUFDcEMsMEJBQXFCLEdBQUcsR0FBRyxDQUFDO1FBQzVCLG9CQUFlLEdBQUcsSUFBSSxDQUFDO1FBbUIxQixJQUFJLENBQUMsT0FBTyxHQUFHLE1BQU0sQ0FBQztRQUN0QixJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQztRQUNiLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBRW5CLElBQUksQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLCtCQUErQixDQUFDLEVBQUU7WUFDakQsSUFBSSxDQUFDLCtCQUErQixHQUFHLCtCQUErQixDQUFDO1NBQzFFO0lBQ0wsQ0FBQztJQXpCTSx1REFBOEIsR0FBckMsVUFBc0Msc0JBQThCO1FBQ2hFLElBQU0sUUFBUSxHQUFH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QUFJLENBQUMsVUFBVSxJQUNsQiwrQkFBK0IsRUFBRSxJQUFJLENBQUMsZ0NBQWdDLElBQ3hFLENBQUM7SUFDUCxDQUFDO0lBQ0wseUJBQUM7QUFBRCxDQTdCQSxBQTZCQyxJQUFBO0FBN0JZLGdEQUFrQjtBQStCL0IsYUFBYSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsa0JBQWtCLENBQUMsQ0FBQyIsImZpbGUiOiJjb3JlL3NlcnZpY2VzL2FwaS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIFJ4IGZyb20gJ3J4JztcbmltcG9ydCAqIGFzIGFuZ3VsYXIgZnJvbSAnYW5ndWxhcic7XG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgJ25nLWZpbGUtdXBsb2FkJztcblxuaW1wb3J0IHtHZW5FcnJvcn0gZnJvbSAnLi4vZXJyb3JzL2Vycm9yJztcbmltcG9ydCB7UmVzb2x3ZUFwaX0gZnJvbSAnLi4vLi4vYXBpJztcbmltcG9ydCB7Q29ubmVjdGlvbn0gZnJvbSAnLi4vLi4vYXBpL2Nvbm5lY3Rpb24nO1xuaW1wb3J0IHtGaWxlVXBsb2FkUmVzcG9uc2V9IGZyb20gJy4uLy4uL2FwaS90eXBlcy9tb2R1bGVzJztcbmltcG9ydCB7bmdDb21wb3NlfSBmcm9tICcuLi91dGlscy9sYW5nJztcbmltcG9ydCAqIGFzIHJhbmRvbSBmcm9tICcuLi91dGlscy9yYW5kb20nO1xuXG5jb25zdCBhbmd1bGFyTW9kdWxlOiBhbmd1bGFyLklNb2R1bGUgPSBhbmd1bGFyLm1vZHVsZSgncmVzb2x3ZS5zZXJ2aWNlcy5hcGknLCBbXG4gICAgJ25nRmlsZVVwbG9hZCcsXG5dKTtcblxuZXhwb3J0IGVudW0gVXBsb2FkRXZlbnRUeXBlIHtcbiAgICBQUk9HUkVTUyA9ICdwcm9ncmVzcycsXG4gICAgUkVUUllJTkcgPSAncmV0cnlpbmcnLFxuICAgIFJFU1VMVCA9ICdyZXN1bHQnLFxufVxuXG5leHBvcnQgdHlwZSBVcGxvYWRFdmVudDxUPiA9IHsgcHJvZ3Jlc3M6IFByb2dyZXNzRXZlbnQsIHR5cGU6IFVwbG9hZEV2ZW50VHlwZS5QUk9HUkVTUyB9IHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeyB0eXBlOiBVcGxvYWRFdmVudFR5cGUuUkVUUllJTkcgfSB8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsgcmVzdWx0OiBULCB0eXBlOiBVcGxvYWRFdmVudFR5cGUuUkVTVUxUIH07XG5cbi8qKlxuICogQmFzZSBBUEkgc2VydmljZSBjbGFzcyBwcm92aWRpbmcgYWRkaXRpb25hbCBmZWF0dXJlcyBsaWtlIGZpbGVcbiAqIHVwbG9hZCBzdXBwb3J0LiBJdCBzaG91bGQgYmUgdXNlZCBhcyBhIG1peGluIHRvZ2V0aGVyIHdpdGggYW5cbiAqIGFjdHVhbCBBUEkgY2xhc3MuXG4gKi9cbmV4cG9ydCBjbGFzcyBBUElTZXJ2aWNlQmFzZSB7XG4gICAgcHVibGljIENIVU5LX1NJWkUgPSAxICogMTAyNCAqIDEwMjQ7IC8vIDFNQlxuXG4gICAgLyoqXG4gICAgICogTWF4IGNvbnNlY3V0aXZlIGF1dG9yZXRyeSBhdHRlbXB0cyBhcmUgY29uZmlndXJhYmxlIGluIHByb3ZpZGVyLiBBbiBhdXRvcmV0cnkgYXR0ZW1wdCBpcyBub3RcbiAgICAgKiBjb25zaWRlcmVkIGNvbnNlY3V0aXZlIGlmIGl0IGhhcHBlbnMgbGF0ZXIgdGhhbiAyICogbWF4RGVsYXkgKHJldHJ5IGF0dGVtcHRzIGFyZSByZXNldCBhZnRlclxuICAgICAqIHRoYXQgdGltZSkuXG4gICAgICovXG4gICAgcHVibGljIG1heENvbnNlY3V0aXZlQXV0b3JldHJ5QXR0ZW1wdHMgPSA1O1xuICAgIHB1YmxpYyBSRVRSWV9ERUxBWV9JTkNSRU1FTlQgPSA1MDA7XG4gICAgcHVibGljIE1BWF9SRVRSWV9ERUxBWSA9IDUwMDA7XG4gICAgcHVibGljIGlzVGltZVRvUmVzZXRBdXRvcmV0cnlBdHRlbXB0cyh0aW1lU2luY2VQcmV2aW91c0Vycm9yOiBudW1iZXIpOiBib29sZWFuIHtcbiAgICAgICAgY29uc3QgbWF4RGVsYXkgPSBNYXRoLm1heCh0aGlzLm1heENvbnNlY3V0aXZlQXV0b3JldHJ5QXR0ZW1wdHMgKiB0aGlzLlJFVFJZX0RFTEFZX0lOQ1JFTUVOVCwgdGhpcy5NQVhfUkVUUllfREVMQVkpO1xuICAgICAgICByZXR1cm4gdGltZVNpbmNlUHJldmlvdXNFcnJvciA+IDIgKiBtYXhEZWxheTtcbiAgICB9XG5cbiAgICAvLyBOb3RlIHRoYXQgdGhpcyBjb25uZWN0aW9uIHByb3BlcnR5IGlzIG5vdCBpbml0aWFsaXplZCBhbnl3aGVyZSBhcyBpdCB3aWxsXG4gICAgLy8gYmUgaW5pdGlhbGl6ZWQgYnkgdGhlIGFjdHVhbCBBUEkgd2hpY2ggaXMgbWl4ZWQgaW4gYnkgdGhlIHByb3ZpZGVyLlxuICAgIHB1YmxpYyBjb25uZWN0aW9uOiBDb25uZWN0aW9uO1xuXG4gICAgcHJpdmF0ZSBfdXBsb2FkOiBhbmd1bGFyLmFuZ3VsYXJGaWxlVXBsb2FkLklVcGxvYWRTZXJ2aWNlO1xuICAgIHByaXZhdGUgX3E6IGFuZ3VsYXIuSVFTZXJ2aWNlO1xuICAgIHByaXZhdGUgX2h0dHA6IGFuZ3VsYXIuSUh0dHBTZXJ2aWNlO1xuXG4gICAgLy8gQG5nSW5qZWN0XG4gICAgY29uc3RydWN0b3IoVXBsb2FkOiBhbmd1bGFyLmFuZ3VsYXJGaWxlVXBsb2FkLklVcGxvYWRTZXJ2aWNlLFxuICAgICAgICAgICAgICAgICRxOiBhbmd1bGFyLklRU2VydmljZSxcbiAgICAgICAgICAgICAgICAkaHR0cDogYW5ndWxhci5JSHR0cFNlcnZpY2UsXG4gICAgICAgICAgICAgICAgbWF4Q29uc2VjdXRpdmVBdXRvcmV0cnlBdHRlbXB0cz86IG51bWJlcikge1xuICAgICAgICB0aGlzLl91cGxvYWQgPSBVcGxvYWQ7XG4gICAgICAgIHRoaXMuX3EgPSAkcTtcbiAgICAgICAgdGhpcy5faHR0cCA9ICRodHRwO1xuXG4gICAgICAgIGlmICghXy5pc1VuZGVmaW5lZChtYXhDb25zZWN1dGl2ZUF1dG9yZXRyeUF0dGVtcHRzKSkge1xuICAgICAgICAgICAgdGhpcy5tYXhDb25zZWN1dGl2ZUF1dG9yZXRyeUF0dGVtcHRzID0gbWF4Q29uc2VjdXRpdmVBdXRvcmV0cnlBdHRlbXB0cztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBlcmZvcm1zIGEgZGF0YSB1cGxvYWQuXG4gICAgICpcbiAgICAgKiBFYWNoIGZpZWxkIGluY2x1ZGluZyBuZXN0ZWQgb2JqZWN0cyB3aWxsIGJlIHNlbnQgYXMgYSBmb3JtIGRhdGEgbXVsdGlwYXJ0LlxuICAgICAqIFNhbXBsZXM6XG4gICAgICogICB7cGljOiBmaWxlLCB1c2VybmFtZTogdXNlcm5hbWV9XG4gICAgICogICB7ZmlsZXM6IGZpbGVzLCBvdGhlckluZm86IHtpZDogaWQsIHBlcnNvbjogcGVyc29uLC4uLn19IG11bHRpcGxlIGZpbGVzIChodG1sNSlcbiAgICAgKiAgIHtwcm9maWxlczoge1t7cGljOiBmaWxlMSwgdXNlcm5hbWU6IHVzZXJuYW1lMX0sIHtwaWM6IGZpbGUyLCB1c2VybmFtZTogdXNlcm5hbWUyfV19IG5lc3RlZCBhcnJheSBtdWx0aXBsZSBmaWxlcyAoaHRtbDUpXG4gICAgICogICB7ZmlsZTogZmlsZSwgaW5mbzogVXBsb2FkLmpzb24oe2lkOiBpZCwgbmFtZTogbmFtZSwgLi4ufSl9IHNlbmQgZmllbGRzIGFzIGpzb24gc3RyaW5nXG4gICAgICogICB7ZmlsZTogZmlsZSwgaW5mbzogVXBsb2FkLmpzb25CbG9iKHtpZDogaWQsIG5hbWU6IG5hbWUsIC4uLn0pfSBzZW5kIGZpZWxkcyBhcyBqc29uIGJsb2IsICdhcHBsaWNhdGlvbi9qc29uJyBjb250ZW50X3R5cGVcbiAgICAgKiAgIHtwaWNGaWxlOiBVcGxvYWQucmVuYW1lKGZpbGUsICdwcm9maWxlLmpwZycpLCB0aXRsZTogdGl0bGV9IHNlbmQgZmlsZSB3aXRoIHBpY0ZpbGUga2V5IGFuZCBwcm9maWxlLmpwZyBmaWxlIG5hbWVcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7YW55fSBkYXRhIFNlZSBhbmd1bGFyLmFuZ3VsYXJGaWxlVXBsb2FkLklGaWxlVXBsb2FkQ29uZmlnRmlsZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgdXBsb2FkPFQ+KGRhdGE6IGFueSwgZmlsZVVJRDogc3RyaW5nID0gJycpOiBSeC5PYnNlcnZhYmxlPFVwbG9hZEV2ZW50PFQ+PiB7XG4gICAgICAgIGNvbnN0IHVybCA9IHRoaXMuY29ubmVjdGlvbi5jcmVhdGVVcmlGcm9tUGF0aCgnL3VwbG9hZC8nKTtcbiAgICAgICAgY29uc3QgaGVhZGVyczogYW5ndWxhci5JSHR0cFJlcXVlc3RDb25maWdIZWFkZXJzID0ge1xuICAgICAgICAgICAgJ1Nlc3Npb24tSWQnOiB0aGlzLmNvbm5lY3Rpb24uc2Vzc2lvbklkKCksXG4gICAgICAgICAgICAnWC1GaWxlLVVpZCc6IGZpbGVVSUQsXG4gICAgICAgICAgICAnWC1DU1JGVG9rZW4nOiB0aGlzLmNvbm5lY3Rpb24uY3NyZkNvb2tpZSgpLFxuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiBSeC5PYnNlcnZhYmxlLmNyZWF0ZTxVcGxvYWRFdmVudDxUPj4oKG9ic2VydmVyKSA9PiB7XG4gICAgICAgICAgICBvYnNlcnZlci5vbk5leHQoeyB0eXBlOiBVcGxvYWRFdmVudFR5cGUuUkVUUllJTkcgfSk7IC8vIE5vdGU6IEZpcnN0IG9uZSBvZiB0aGVzZSBpcyBza2lwcGVkIGJlbG93LlxuXG4gICAgICAgICAgICBjb25zdCByZWplY3RhYmxlUmVzdW1lU2l6ZVByb21pc2UgPSB0aGlzLl9xLmRlZmVyPG51bWJlcj4oKTtcbiAgICAgICAgICAgIGNvbnN0IGZpbGVVcGxvYWQgPSB0aGlzLl91cGxvYWQudXBsb2FkPFQ+KHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybCxcbiAgICAgICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiBoZWFkZXJzLFxuICAgICAgICAgICAgICAgIHdpdGhDcmVkZW50aWFsczogdHJ1ZSxcbiAgICAgICAgICAgICAgICByZXN1bWVTaXplOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlc3VtZVNpemVQcm9taXNlID0gdGhpcy5faHR0cC5nZXQodXJsLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXJzOiBoZWFkZXJzLFxuICAgICAgICAgICAgICAgICAgICAgICAgd2l0aENyZWRlbnRpYWxzOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICB9KS50aGVuKChyZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICg8YW55PiByZXNwb25zZS5kYXRhKS5yZXN1bWVfb2Zmc2V0O1xuICAgICAgICAgICAgICAgICAgICB9LCAoZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLm9uRXJyb3IoZXJyb3IpOyAvLyBIYW5kbGVkIGluIG9ic2VydmFibGVzXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcS5kZWZlcigpLnByb21pc2U7IC8vIE5ldmVyIHJlc29sdmVcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0YWJsZVJlc3VtZVNpemVQcm9taXNlLnJlc29sdmUocmVzdW1lU2l6ZVByb21pc2UpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVqZWN0YWJsZVJlc3VtZVNpemVQcm9taXNlLnByb21pc2U7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICByZXN1bWVDaHVua1NpemU6IHRoaXMuQ0hVTktfU0laRSxcbiAgICAgICAgICAgICAgICBkYXRhOiBkYXRhLFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGZpbGVVcGxvYWQudGhlbigocmVzdWx0KSA9PiB7XG4gICAgICAgICAgICAgICAgb2JzZXJ2ZXIub25OZXh0KHsgcmVzdWx0OiByZXN1bHQuZGF0YSwgdHlwZTogVXBsb2FkRXZlbnRUeXBlLlJFU1VMVCB9KTtcbiAgICAgICAgICAgICAgICBvYnNlcnZlci5vbkNvbXBsZXRlZCgpO1xuICAgICAgICAgICAgfSwgKGVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgb2JzZXJ2ZXIub25FcnJvcihlcnJvcik7XG4gICAgICAgICAgICB9LCAocHJvZ3Jlc3MpID0+IHtcbiAgICAgICAgICAgICAgICBvYnNlcnZlci5vbk5leHQoeyBwcm9ncmVzczogcHJvZ3Jlc3MsIHR5cGU6IFVwbG9hZEV2ZW50VHlwZS5QUk9HUkVTUyB9KTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIFRvIGRpZmZlcmVudGlhdGUgYmV0d2VlbiBjb25uZWN0aW9ucyBhYm9ydGVkIGJ5IHNlcnZlciBvciBjbGllbnQgKHdoZW4gY29tcHV0ZXJcbiAgICAgICAgICAgICAgICAvLyBnb2VzIHRvIHN0YW5kYnkvc2xlZXApLCB3ZSBlbWl0IGEgY3VzdG9tIGVycm9yLiBPdGhlcndpc2Ugd2Ugd291bGQgaGF2ZSB0b1xuICAgICAgICAgICAgICAgIC8vIGZpbHRlciBvdXQgYWxsIGB4aHJTdGF0dXMgPT09ICdhYm9ydCdgIGFuZCBjb3VsZG4ndCBhdXRvLXJldHJ5IGFmdGVyIHN0YW5kYnkuXG4gICAgICAgICAgICAgICAgb2JzZXJ2ZXIub25FcnJvcih7eGhyU3RhdHVzOiAnbWFudWFsLWFib3J0J30pO1xuICAgICAgICAgICAgICAgIGZpbGVVcGxvYWQuYWJvcnQoKTtcbiAgICAgICAgICAgICAgICByZWplY3RhYmxlUmVzdW1lU2l6ZVByb21pc2UucmVqZWN0KCk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9KVxuICAgICAgICAucmV0cnlXaGVuKChlcnJvcnMpID0+IHtcbiAgICAgICAgICAgIHJldHVybiBlcnJvcnNcbiAgICAgICAgICAgICAgICAuZmlsdGVyKChlcnJvcikgPT4gZXJyb3IgJiYgZXJyb3IueGhyU3RhdHVzICE9PSAnbWFudWFsLWFib3J0JylcbiAgICAgICAgICAgICAgICAudGltZUludGVydmFsKClcbiAgICAgICAgICAgICAgICAuc2NhbigoYWNjdW11bGF0ZWQsIHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yID0gdmFsdWUudmFsdWU7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRpbWVTaW5jZVByZXZpb3VzID0gdmFsdWUuaW50ZXJ2YWw7XG5cbiAgICAgICAgICAgICAgICAgICAgbGV0IGNvbnNlY3V0aXZlRXJyb3JzID0gYWNjdW11bGF0ZWQuY29uc2VjdXRpdmVFcnJvcnMgKyAxO1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5pc1RpbWVUb1Jlc2V0QXV0b3JldHJ5QXR0ZW1wdHModGltZVNpbmNlUHJldmlvdXMpKSBjb25zZWN1dGl2ZUVycm9ycyA9IDE7XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcmV0cnkgPSBjb25zZWN1dGl2ZUVycm9ycyA8PSB0aGlzLm1heENvbnNlY3V0aXZlQXV0b3JldHJ5QXR0ZW1wdHM7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGRlbGF5ID0gTWF0aC5taW4oY29uc2VjdXRpdmVFcnJvcnMgKiB0aGlzLlJFVFJZX0RFTEFZX0lOQ1JFTUVOVCwgdGhpcy5NQVhfUkVUUllfREVMQVkpO1xuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7IGVycm9yLCBjb25zZWN1dGl2ZUVycm9ycywgdGltZVNpbmNlUHJldmlvdXMsIHJldHJ5LCBkZWxheSB9O1xuICAgICAgICAgICAgICAgIH0sIHsgZXJyb3I6IG51bGwsIGNvbnNlY3V0aXZlRXJyb3JzOiAwLCB0aW1lU2luY2VQcmV2aW91czogMCwgcmV0cnk6IGZhbHNlLCBkZWxheTogMCB9KVxuICAgICAgICAgICAgICAgIC5mbGF0TWFwKCh7cmV0cnksIGRlbGF5LCBlcnJvcn0pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhpcyBldmVudCBpcyBwcm9iYWJseSBjb21wdXRlciBnb2luZyB0byBzdGFuZGJ5LiBXYWl0IGEgYml0IGxvbmdlci5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yICYmIGVycm9yLnhoclN0YXR1cyA9PT0gJ2Fib3J0JykgZGVsYXkgPSAxMDAwMDtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoIXJldHJ5KSB7IC8vIFN0b3AgcmV0cnlpbmcgYWZ0ZXIgYSB3aGlsZSBhbmQgcmV0dXJuIHVud3JhcHBlZCBlcnJvclxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFJ4Lk9ic2VydmFibGUudGhyb3coZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBSeC5PYnNlcnZhYmxlLmp1c3QoZXJyb3IpLmRlbGF5KGRlbGF5KTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5kbygoZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiUmV0cnlpbmcgdXBsb2FkIGFmdGVyIGFuIGVycm9yXCIsIGVycm9yKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnNraXAoMSkgLy8gU2tpcCBpbml0aWFsICdyZXRyeWluZycgZXZlbnQuXG4gICAgICAgIC5maWx0ZXIoKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAvLyBJZiBhIHJldHJ5IHJlcXVlc3QgZmFpbHMsIGl0IHdvdWxkIHJlbW92ZSB0aGUgcHJvZ3Jlc3MgYmFyIHVudGlsIGl0XG4gICAgICAgICAgICAvLyBzdWNjZWVkcyBhZ2Fpbi4gV2l0aCB0aGlzIGZpbHRlciB3ZSBjYW4ga2VlcCB0aGUgcHJvZ3Jlc3MgYmFyIGFueXdheS5cbiAgICAgICAgICAgIHJldHVybiAhKGV2ZW50LnR5cGUgPT09IFVwbG9hZEV2ZW50VHlwZS5QUk9HUkVTUyAmJiBldmVudC5wcm9ncmVzcy5sb2FkZWQgPT09IDAgJiYgZXZlbnQucHJvZ3Jlc3MudG90YWwgPT09IDApO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBVcGxvYWRzIHN0cmluZyBjb250ZW50IGFzIGEgZmlsZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgdXBsb2FkU3RyaW5nKGZpbGVuYW1lOiBzdHJpbmcsIGNvbnRlbnQ6IHN0cmluZyk6IFJ4Lk9ic2VydmFibGU8VXBsb2FkRXZlbnQ8RmlsZVVwbG9hZFJlc3BvbnNlPj4ge1xuICAgICAgICBsZXQgZmlsZTogRmlsZTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGZpbGUgPSBuZXcgRmlsZShbY29udGVudF0sIGZpbGVuYW1lLCB7dHlwZTogJ3RleHQvcGxhaW4nLCBsYXN0TW9kaWZpZWQ6IERhdGUubm93KCl9KTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgLy8gU2ltcGxlIGZhbGxiYWNrIGZvciBTYWZhcmkgOSBhbmQgSUUvRWRnZSwgYmVjYXVzZSB0aGV5IGRvbid0XG4gICAgICAgICAgICAvLyBzdXBwb3J0IEZpbGUgY29uc3RydWN0b3IuXG4gICAgICAgICAgICBmaWxlID0gPEZpbGU+IF8uYXNzaWduKG5ldyBCbG9iKFtjb250ZW50XSwge3R5cGU6ICd0ZXh0L3BsYWluJ30pLCB7bmFtZTogZmlsZW5hbWV9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLnVwbG9hZDxGaWxlVXBsb2FkUmVzcG9uc2U+KHtmaWxlOiBmaWxlfSwgJ3N0cmluZy0nICsgcmFuZG9tLnJhbmRvbVV1aWQoKSk7XG4gICAgfVxufVxuXG4vKipcbiAqIFNlcnZpY2UgcHJvdmlkZXIgZm9yIGNvbmZpZ3VyaW5nIHRoZSBBUEkgc2VydmljZS4gQmVmb3JlIHVzaW5nIHRoZVxuICogQVBJIHNlcnZpY2UsIHRoaXMgcHJvdmlkZXIgbXVzdCBiZSBjb25maWd1cmVkIHdpdGggYW4gYWN0dWFsIEFQSVxuICogY2xhc3MsIHdoaWNoIHNob3VsZCBkZXJpdmUgZnJvbSBbW1Jlc29sd2VBcGldXS5cbiAqXG4gKiBGb3IgZXhhbXBsZSwgaWYgdGhlIEFQSSBjbGFzcyBpcyBjYWxsZWQgYEJhc2VBcGlgLCB3ZSBjYW4gY29uZmlndXJlXG4gKiB0aGUgQVBJIHNlcnZpY2UgYXMgZm9sbG93czpcbiAqIGBgYFxuICogLy8gQ3JlYXRlIGEgdHlwZSBmb3IgdGhlIHNlcnZpY2UuXG4gKiBleHBvcnQgaW50ZXJmYWNlIEFQSVNlcnZpY2UgZXh0ZW5kcyBBUElTZXJ2aWNlQmFzZSwgQmFzZUFwaSB7XG4gKiB9XG4gKlxuICogLy8gQ29uZmlndXJlIHRoZSBBUEkgcHJvdmlkZXIgd2l0aCBvdXIgQVBJIGluc3RhbmNlLlxuICogbW9kdWxlLmNvbmZpZygoYXBpUHJvdmlkZXI6IEFQSVNlcnZpY2VQcm92aWRlcikgPT4ge1xuICogICAgIGFwaVByb3ZpZGVyLnNldEFQSShcbiAqICAgICAgICAgQmFzZUFwaSxcbiAqICAgICAgICAgbmV3IFNpbXBsZUNvbm5lY3Rpb24oKSxcbiAqICAgICAgICAgUkVTVF9VUkwsXG4gKiAgICAgICAgIFdFQlNPQ0tFVF9VUkxcbiAqICAgICApO1xuICpcbiAqICAgICAvLyBDb25maWd1cmUgdXBsb2FkIGF1dG8tcmV0cmllcyB0byBpbmZpbml0eVxuICogICAgIGFwaVByb3ZpZGVyLnNldE1heENvbnNlY3V0aXZlQXV0b3JldHJ5QXR0ZW1wdHMoSW5maW5pdHkpO1xuICogfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIEFQSVNlcnZpY2VQcm92aWRlciB7XG4gICAgLy8gQVBJIGluc3RhbmNlIHRoYXQgc2hvdWxkIGJlIHVzZWQgYnkgdGhlIHNlcnZpY2UuXG4gICAgcHJpdmF0ZSBfYXBpOiB0eXBlb2YgUmVzb2x3ZUFwaTtcbiAgICBwcml2YXRlIF9hcGlMb2NhbHM6IF8uRGljdGlvbmFyeTxzdHJpbmc+O1xuICAgIHByaXZhdGUgX21heENvbnNlY3V0aXZlQXV0b3JldHJ5QXR0ZW1wdHM6IG51bWJlcjtcblxuICAgIHB1YmxpYyBzZXRBUEkoYXBpOiBuZXcgKC4uLmluamVjdGlvbnM6IGFueVtdKSA9PiBSZXNvbHdlQXBpLFxuICAgICAgICAgICAgICAgICAgbG9jYWxzOiB7Y29ubmVjdGlvbjogQ29ubmVjdGlvbiwgcmVzdFVyaTogc3RyaW5nLCB3ZWJzb2NrZXRVcmk6IHN0cmluZywgW2tleTogc3RyaW5nXTogYW55IH0pIHtcbiAgICAgICAgdGhpcy5fYXBpID0gYXBpO1xuICAgICAgICB0aGlzLl9hcGlMb2NhbHMgPSBsb2NhbHM7XG4gICAgfVxuXG4gICAgcHVibGljIHNldE1heENvbnNlY3V0aXZlQXV0b3JldHJ5QXR0ZW1wdHMocmV0cmllczogbnVtYmVyKSB7XG4gICAgICAgIHRoaXMuX21heENvbnNlY3V0aXZlQXV0b3JldHJ5QXR0ZW1wdHMgPSByZXRyaWVzO1xuICAgIH1cblxuICAgIC8vIEBuZ0luamVjdFxuICAgIHB1YmxpYyAkZ2V0KCRpbmplY3RvcjogYW5ndWxhci5hdXRvLklJbmplY3RvclNlcnZpY2UpIHtcbiAgICAgICAgLy8gVE9ETzogVXNlIGVycm9yIG5vdGlmaWNhdGlvbiBzZXJ2aWNlIGluc3RlYWQuXG4gICAgICAgIGlmICghdGhpcy5fYXBpKSB0aHJvdyBuZXcgR2VuRXJyb3IoXCJBUEkgbm90IGNvbmZpZ3VyZWQuXCIpO1xuXG4gICAgICAgIC8vIE1peCB0b2dldGhlciB0aGUgQVBJIGFuZCB0aGUgQVBJU2VydmljZUJhc2UuXG4gICAgICAgIGNvbnN0IHNlcnZpY2VDbGFzcyA9IG5nQ29tcG9zZShbdGhpcy5fYXBpLCBBUElTZXJ2aWNlQmFzZV0pO1xuXG4gICAgICAgIHJldHVybiAkaW5qZWN0b3IuaW5zdGFudGlhdGUoc2VydmljZUNsYXNzLCB7XG4gICAgICAgICAgICAuLi50aGlzLl9hcGlMb2NhbHMsXG4gICAgICAgICAgICBtYXhDb25zZWN1dGl2ZUF1dG9yZXRyeUF0dGVtcHRzOiB0aGlzLl9tYXhDb25zZWN1dGl2ZUF1dG9yZXRyeUF0dGVtcHRzLFxuICAgICAgICB9KTtcbiAgICB9XG59XG5cbmFuZ3VsYXJNb2R1bGUucHJvdmlkZXIoJ2FwaScsIEFQSVNlcnZpY2VQcm92aWRlcik7XG4iXX0=