@genialis/resolwe
Version:
Resolwe frontend libraries
228 lines (226 loc) • 32.1 kB
JavaScript
;
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=