@isaiahiroko/ng-interceptors
Version:
Angular interceptors for token authorization, local and remote store synchronization and global notification
271 lines (258 loc) • 35.4 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@isaiahiroko/ng-utils'), require('rxjs/operators'), require('rxjs'), require('@angular/common/http')) :
typeof define === 'function' && define.amd ? define('@isaiahiroko/ng-interceptors', ['exports', '@angular/core', '@isaiahiroko/ng-utils', 'rxjs/operators', 'rxjs', '@angular/common/http'], factory) :
(factory((global.isaiahiroko = global.isaiahiroko || {}, global.isaiahiroko['ng-interceptors'] = {}),global.ng.core,null,global.rxjs.operators,global.rxjs,global.ng.common.http));
}(this, (function (exports,core,ngUtils,operators,rxjs,http) { 'use strict';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var AuthInterceptor = (function () {
function AuthInterceptor(auth) {
this.auth = auth;
}
/**
* @param {?} req
* @param {?} next
* @return {?}
*/
AuthInterceptor.prototype.intercept = /**
* @param {?} req
* @param {?} next
* @return {?}
*/
function (req, next) {
/** @type {?} */
var authReq = req.clone({
headers: req.headers.set('Authorization', this.auth.token()),
});
// send cloned request with header to the next handler.
return next.handle(authReq);
};
AuthInterceptor.decorators = [
{ type: core.Injectable },
];
/** @nocollapse */
AuthInterceptor.ctorParameters = function () {
return [
{ type: ngUtils.AuthService }
];
};
return AuthInterceptor;
}());
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m)
return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done)
ar.push(r.value);
}
catch (error) {
e = { error: error };
}
finally {
try {
if (r && !r.done && (m = i["return"]))
m.call(i);
}
finally {
if (e)
throw e.error;
}
}
return ar;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var LoaderServiceContract = (function () {
function LoaderServiceContract() {
}
/**
* @param {?=} type
* @return {?}
*/
LoaderServiceContract.prototype.start = /**
* @param {?=} type
* @return {?}
*/
function (type) { };
/**
* @return {?}
*/
LoaderServiceContract.prototype.stop = /**
* @return {?}
*/
function () { };
/**
* @param {?} message
* @param {?=} title
* @return {?}
*/
LoaderServiceContract.prototype.notify = /**
* @param {?} message
* @param {?=} title
* @return {?}
*/
function (message, title) { };
/**
* @param {?} message
* @param {?=} title
* @return {?}
*/
LoaderServiceContract.prototype.toast = /**
* @param {?} message
* @param {?=} title
* @return {?}
*/
function (message, title) { };
return LoaderServiceContract;
}());
var NotifInterceptor = (function () {
function NotifInterceptor(notif) {
this.notif = notif;
}
/**
* @param {?} req
* @param {?} next
* @return {?}
*/
NotifInterceptor.prototype.intercept = /**
* @param {?} req
* @param {?} next
* @return {?}
*/
function (req, next) {
var _this = this;
this.notif.start();
// extend server response observable with logging
return next.handle(req).pipe(
// things don't always work as planned
// if things go wrong, try again three times
// however, delay trial in an incremental manner (multipl of 1 second)
operators.retryWhen(function (attempts) {
return attempts.pipe(operators.zip(rxjs.range(1, 4)), operators.mergeMap(function (_a) {
var _b = __read(_a, 2), error = _b[0], i = _b[1];
_this.notif.start('query');
if (i > 2) {
return rxjs.throwError(error);
}
return rxjs.timer(i * 1000);
}));
}),
// catchError http errors and turn to observable of undefined
operators.catchError(function (e) {
/** @type {?} */
var title;
/** @type {?} */
var message;
_this.notif.start('buffer');
if (e.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
title = 'Client Error';
message = e.error.message;
}
else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
title = 'Network Info';
message = e.statusText + " (" + e.status + ")";
// message = e.message
}
if (e.status === 401) ;
console.error({ title: title, message: message });
// catche //re throw
// throw {title, message}
// return of({ e: {title, message} })
// return empty()
return rxjs.throwError({ title: title, message: message });
}), operators.finalize(function () {
_this.notif.stop();
}));
};
NotifInterceptor.decorators = [
{ type: core.Injectable },
];
/** @nocollapse */
NotifInterceptor.ctorParameters = function () {
return [
{ type: LoaderServiceContract }
];
};
return NotifInterceptor;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var StoreSyncInterceptor = (function () {
function StoreSyncInterceptor() {
}
// constructor(private cache: RequestCache) {}
/**
* @param {?} req
* @param {?} next
* @return {?}
*/
StoreSyncInterceptor.prototype.intercept = /**
* @param {?} req
* @param {?} next
* @return {?}
*/
function (req, next) {
// continue if not cachable.
// if (!isCachable(req)) { return next.handle(req); }
{
return next.handle(req);
}
// cache-or-fetch
// const cachedResponse = this.cache.get(req);
// return cachedResponse ?
// of(cachedResponse) : sendRequest(req, next, this.cache);
};
StoreSyncInterceptor.decorators = [
{ type: core.Injectable },
];
return StoreSyncInterceptor;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/** @type {?} */
var INTERCEPTORS = [
{ provide: http.HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
// { provide: HTTP_INTERCEPTORS, useClass: StoreSyncInterceptor, multi: true },
{ provide: http.HTTP_INTERCEPTORS, useClass: NotifInterceptor, multi: true }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
exports.INTERCEPTORS = INTERCEPTORS;
exports.StoreSyncInterceptor = StoreSyncInterceptor;
exports.AuthInterceptor = AuthInterceptor;
exports.LoaderServiceContract = LoaderServiceContract;
exports.NotifInterceptor = NotifInterceptor;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXNhaWFoaXJva28tbmctaW50ZXJjZXB0b3JzLnVtZC5qcy5tYXAiLCJzb3VyY2VzIjpbIm5nOi8vQGlzYWlhaGlyb2tvL25nLWludGVyY2VwdG9ycy9saWIvYXV0aC5pbnRlcmNlcHRvci50cyIsbnVsbCwibmc6Ly9AaXNhaWFoaXJva28vbmctaW50ZXJjZXB0b3JzL2xpYi9ub3RpZi5pbnRlcmNlcHRvci50cyIsIm5nOi8vQGlzYWlhaGlyb2tvL25nLWludGVyY2VwdG9ycy9saWIvc3RvcmUtc3luYy5pbnRlcmNlcHRvci50cyIsIm5nOi8vQGlzYWlhaGlyb2tvL25nLWludGVyY2VwdG9ycy9saWIvaW5kZXgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnXHJcbmltcG9ydCB7IEh0dHBJbnRlcmNlcHRvciwgSHR0cFJlcXVlc3QsIEh0dHBIYW5kbGVyLCBIdHRwRXZlbnQgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCdcclxuXHJcbmltcG9ydCB7IEF1dGhTZXJ2aWNlIH0gZnJvbSAnQGlzYWlhaGlyb2tvL25nLXV0aWxzJ1xyXG5pbXBvcnQgeyBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XHJcblxyXG5ASW5qZWN0YWJsZSgpXHJcbmV4cG9ydCBjbGFzcyBBdXRoSW50ZXJjZXB0b3IgaW1wbGVtZW50cyBIdHRwSW50ZXJjZXB0b3Ige1xyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgYXV0aDogQXV0aFNlcnZpY2UpIHt9XHJcblxyXG4gIGludGVyY2VwdChyZXE6IEh0dHBSZXF1ZXN0PGFueT4sIG5leHQ6IEh0dHBIYW5kbGVyKTogT2JzZXJ2YWJsZTxIdHRwRXZlbnQ8YW55Pj4ge1xyXG4gICAgLy8gR2V0IHRoZSBhdXRoIHRva2VuIGZyb20gdGhlIHNlcnZpY2UuXHJcbiAgICAvLyBDbG9uZSB0aGUgcmVxdWVzdCBhbmQgcmVwbGFjZSB0aGUgb3JpZ2luYWwgaGVhZGVycyB3aXRoXHJcbiAgICAvLyBjbG9uZWQgaGVhZGVycywgdXBkYXRlZCB3aXRoIHRoZSBhdXRob3JpemF0aW9uLlxyXG4gICAgY29uc3QgYXV0aFJlcSA9IHJlcS5jbG9uZSh7XHJcbiAgICAgIGhlYWRlcnM6IHJlcS5oZWFkZXJzLnNldCgnQXV0aG9yaXphdGlvbicsIHRoaXMuYXV0aC50b2tlbigpKSxcclxuICAgIH0pXHJcblxyXG4gICAgLy8gc2VuZCBjbG9uZWQgcmVxdWVzdCB3aXRoIGhlYWRlciB0byB0aGUgbmV4dCBoYW5kbGVyLlxyXG4gICAgcmV0dXJuIG5leHQuaGFuZGxlKGF1dGhSZXEpXHJcbiAgfVxyXG59XHJcbiIsIi8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTsgeW91IG1heSBub3QgdXNlXHJcbnRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlXHJcbkxpY2Vuc2UgYXQgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXHJcblxyXG5USElTIENPREUgSVMgUFJPVklERUQgT04gQU4gKkFTIElTKiBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZXHJcbktJTkQsIEVJVEhFUiBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBXSVRIT1VUIExJTUlUQVRJT04gQU5ZIElNUExJRURcclxuV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIFRJVExFLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSxcclxuTUVSQ0hBTlRBQkxJVFkgT1IgTk9OLUlORlJJTkdFTUVOVC5cclxuXHJcblNlZSB0aGUgQXBhY2hlIFZlcnNpb24gMi4wIExpY2Vuc2UgZm9yIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9uc1xyXG5hbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MgPSBPYmplY3Quc2V0UHJvdG90eXBlT2YgfHxcclxuICAgICAgICAoeyBfX3Byb3RvX186IFtdIH0gaW5zdGFuY2VvZiBBcnJheSAmJiBmdW5jdGlvbiAoZCwgYikgeyBkLl9fcHJvdG9fXyA9IGI7IH0pIHx8XHJcbiAgICAgICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoYi5oYXNPd25Qcm9wZXJ0eShwKSkgZFtwXSA9IGJbcF07IH07XHJcbiAgICByZXR1cm4gZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2V4dGVuZHMoZCwgYikge1xyXG4gICAgZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxuICAgIGZ1bmN0aW9uIF9fKCkgeyB0aGlzLmNvbnN0cnVjdG9yID0gZDsgfVxyXG4gICAgZC5wcm90b3R5cGUgPSBiID09PSBudWxsID8gT2JqZWN0LmNyZWF0ZShiKSA6IChfXy5wcm90b3R5cGUgPSBiLnByb3RvdHlwZSwgbmV3IF9fKCkpO1xyXG59XHJcblxyXG5leHBvcnQgdmFyIF9fYXNzaWduID0gZnVuY3Rpb24oKSB7XHJcbiAgICBfX2Fzc2lnbiA9IE9iamVjdC5hc3NpZ24gfHwgZnVuY3Rpb24gX19hc3NpZ24odCkge1xyXG4gICAgICAgIGZvciAodmFyIHMsIGkgPSAxLCBuID0gYXJndW1lbnRzLmxlbmd0aDsgaSA8IG47IGkrKykge1xyXG4gICAgICAgICAgICBzID0gYXJndW1lbnRzW2ldO1xyXG4gICAgICAgICAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkpIHRbcF0gPSBzW3BdO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdDtcclxuICAgIH1cclxuICAgIHJldHVybiBfX2Fzc2lnbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19yZXN0KHMsIGUpIHtcclxuICAgIHZhciB0ID0ge307XHJcbiAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkgJiYgZS5pbmRleE9mKHApIDwgMClcclxuICAgICAgICB0W3BdID0gc1twXTtcclxuICAgIGlmIChzICE9IG51bGwgJiYgdHlwZW9mIE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMgPT09IFwiZnVuY3Rpb25cIilcclxuICAgICAgICBmb3IgKHZhciBpID0gMCwgcCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMocyk7IGkgPCBwLmxlbmd0aDsgaSsrKSBpZiAoZS5pbmRleE9mKHBbaV0pIDwgMClcclxuICAgICAgICAgICAgdFtwW2ldXSA9IHNbcFtpXV07XHJcbiAgICByZXR1cm4gdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpIHtcclxuICAgIHZhciBjID0gYXJndW1lbnRzLmxlbmd0aCwgciA9IGMgPCAzID8gdGFyZ2V0IDogZGVzYyA9PT0gbnVsbCA/IGRlc2MgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwga2V5KSA6IGRlc2MsIGQ7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUgPT09IFwiZnVuY3Rpb25cIikgciA9IFJlZmxlY3QuZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpO1xyXG4gICAgZWxzZSBmb3IgKHZhciBpID0gZGVjb3JhdG9ycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkgaWYgKGQgPSBkZWNvcmF0b3JzW2ldKSByID0gKGMgPCAzID8gZChyKSA6IGMgPiAzID8gZCh0YXJnZXQsIGtleSwgcikgOiBkKHRhcmdldCwga2V5KSkgfHwgcjtcclxuICAgIHJldHVybiBjID4gMyAmJiByICYmIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGtleSwgciksIHI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3BhcmFtKHBhcmFtSW5kZXgsIGRlY29yYXRvcikge1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uICh0YXJnZXQsIGtleSkgeyBkZWNvcmF0b3IodGFyZ2V0LCBrZXksIHBhcmFtSW5kZXgpOyB9XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX21ldGFkYXRhKG1ldGFkYXRhS2V5LCBtZXRhZGF0YVZhbHVlKSB7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QubWV0YWRhdGEgPT09IFwiZnVuY3Rpb25cIikgcmV0dXJuIFJlZmxlY3QubWV0YWRhdGEobWV0YWRhdGFLZXksIG1ldGFkYXRhVmFsdWUpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hd2FpdGVyKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xyXG4gICAgcmV0dXJuIG5ldyAoUCB8fCAoUCA9IFByb21pc2UpKShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XHJcbiAgICAgICAgZnVuY3Rpb24gZnVsZmlsbGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7IHJlc3VsdC5kb25lID8gcmVzb2x2ZShyZXN1bHQudmFsdWUpIDogbmV3IFAoZnVuY3Rpb24gKHJlc29sdmUpIHsgcmVzb2x2ZShyZXN1bHQudmFsdWUpOyB9KS50aGVuKGZ1bGZpbGxlZCwgcmVqZWN0ZWQpOyB9XHJcbiAgICAgICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xyXG4gICAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2dlbmVyYXRvcih0aGlzQXJnLCBib2R5KSB7XHJcbiAgICB2YXIgXyA9IHsgbGFiZWw6IDAsIHNlbnQ6IGZ1bmN0aW9uKCkgeyBpZiAodFswXSAmIDEpIHRocm93IHRbMV07IHJldHVybiB0WzFdOyB9LCB0cnlzOiBbXSwgb3BzOiBbXSB9LCBmLCB5LCB0LCBnO1xyXG4gICAgcmV0dXJuIGcgPSB7IG5leHQ6IHZlcmIoMCksIFwidGhyb3dcIjogdmVyYigxKSwgXCJyZXR1cm5cIjogdmVyYigyKSB9LCB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgKGdbU3ltYm9sLml0ZXJhdG9yXSA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpczsgfSksIGc7XHJcbiAgICBmdW5jdGlvbiB2ZXJiKG4pIHsgcmV0dXJuIGZ1bmN0aW9uICh2KSB7IHJldHVybiBzdGVwKFtuLCB2XSk7IH07IH1cclxuICAgIGZ1bmN0aW9uIHN0ZXAob3ApIHtcclxuICAgICAgICBpZiAoZikgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkdlbmVyYXRvciBpcyBhbHJlYWR5IGV4ZWN1dGluZy5cIik7XHJcbiAgICAgICAgd2hpbGUgKF8pIHRyeSB7XHJcbiAgICAgICAgICAgIGlmIChmID0gMSwgeSAmJiAodCA9IG9wWzBdICYgMiA/IHlbXCJyZXR1cm5cIl0gOiBvcFswXSA/IHlbXCJ0aHJvd1wiXSB8fCAoKHQgPSB5W1wicmV0dXJuXCJdKSAmJiB0LmNhbGwoeSksIDApIDogeS5uZXh0KSAmJiAhKHQgPSB0LmNhbGwoeSwgb3BbMV0pKS5kb25lKSByZXR1cm4gdDtcclxuICAgICAgICAgICAgaWYgKHkgPSAwLCB0KSBvcCA9IFtvcFswXSAmIDIsIHQudmFsdWVdO1xyXG4gICAgICAgICAgICBzd2l0Y2ggKG9wWzBdKSB7XHJcbiAgICAgICAgICAgICAgICBjYXNlIDA6IGNhc2UgMTogdCA9IG9wOyBicmVhaztcclxuICAgICAgICAgICAgICAgIGNhc2UgNDogXy5sYWJlbCsrOyByZXR1cm4geyB2YWx1ZTogb3BbMV0sIGRvbmU6IGZhbHNlIH07XHJcbiAgICAgICAgICAgICAgICBjYXNlIDU6IF8ubGFiZWwrKzsgeSA9IG9wWzFdOyBvcCA9IFswXTsgY29udGludWU7XHJcbiAgICAgICAgICAgICAgICBjYXNlIDc6IG9wID0gXy5vcHMucG9wKCk7IF8udHJ5cy5wb3AoKTsgY29udGludWU7XHJcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICAgICAgICAgIGlmICghKHQgPSBfLnRyeXMsIHQgPSB0Lmxlbmd0aCA+IDAgJiYgdFt0Lmxlbmd0aCAtIDFdKSAmJiAob3BbMF0gPT09IDYgfHwgb3BbMF0gPT09IDIpKSB7IF8gPSAwOyBjb250aW51ZTsgfVxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChvcFswXSA9PT0gMyAmJiAoIXQgfHwgKG9wWzFdID4gdFswXSAmJiBvcFsxXSA8IHRbM10pKSkgeyBfLmxhYmVsID0gb3BbMV07IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wWzBdID09PSA2ICYmIF8ubGFiZWwgPCB0WzFdKSB7IF8ubGFiZWwgPSB0WzFdOyB0ID0gb3A7IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHQgJiYgXy5sYWJlbCA8IHRbMl0pIHsgXy5sYWJlbCA9IHRbMl07IF8ub3BzLnB1c2gob3ApOyBicmVhazsgfVxyXG4gICAgICAgICAgICAgICAgICAgIGlmICh0WzJdKSBfLm9wcy5wb3AoKTtcclxuICAgICAgICAgICAgICAgICAgICBfLnRyeXMucG9wKCk7IGNvbnRpbnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIG9wID0gYm9keS5jYWxsKHRoaXNBcmcsIF8pO1xyXG4gICAgICAgIH0gY2F0Y2ggKGUpIHsgb3AgPSBbNiwgZV07IHkgPSAwOyB9IGZpbmFsbHkgeyBmID0gdCA9IDA7IH1cclxuICAgICAgICBpZiAob3BbMF0gJiA1KSB0aHJvdyBvcFsxXTsgcmV0dXJuIHsgdmFsdWU6IG9wWzBdID8gb3BbMV0gOiB2b2lkIDAsIGRvbmU6IHRydWUgfTtcclxuICAgIH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXhwb3J0U3RhcihtLCBleHBvcnRzKSB7XHJcbiAgICBmb3IgKHZhciBwIGluIG0pIGlmICghZXhwb3J0cy5oYXNPd25Qcm9wZXJ0eShwKSkgZXhwb3J0c1twXSA9IG1bcF07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3ZhbHVlcyhvKSB7XHJcbiAgICB2YXIgbSA9IHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl0sIGkgPSAwO1xyXG4gICAgaWYgKG0pIHJldHVybiBtLmNhbGwobyk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAgIG5leHQ6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKG8gJiYgaSA+PSBvLmxlbmd0aCkgbyA9IHZvaWQgMDtcclxuICAgICAgICAgICAgcmV0dXJuIHsgdmFsdWU6IG8gJiYgb1tpKytdLCBkb25lOiAhbyB9O1xyXG4gICAgICAgIH1cclxuICAgIH07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3JlYWQobywgbikge1xyXG4gICAgdmFyIG0gPSB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgb1tTeW1ib2wuaXRlcmF0b3JdO1xyXG4gICAgaWYgKCFtKSByZXR1cm4gbztcclxuICAgIHZhciBpID0gbS5jYWxsKG8pLCByLCBhciA9IFtdLCBlO1xyXG4gICAgdHJ5IHtcclxuICAgICAgICB3aGlsZSAoKG4gPT09IHZvaWQgMCB8fCBuLS0gPiAwKSAmJiAhKHIgPSBpLm5leHQoKSkuZG9uZSkgYXIucHVzaChyLnZhbHVlKTtcclxuICAgIH1cclxuICAgIGNhdGNoIChlcnJvcikgeyBlID0geyBlcnJvcjogZXJyb3IgfTsgfVxyXG4gICAgZmluYWxseSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgaWYgKHIgJiYgIXIuZG9uZSAmJiAobSA9IGlbXCJyZXR1cm5cIl0pKSBtLmNhbGwoaSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGZpbmFsbHkgeyBpZiAoZSkgdGhyb3cgZS5lcnJvcjsgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIGFyO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19zcHJlYWQoKSB7XHJcbiAgICBmb3IgKHZhciBhciA9IFtdLCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKylcclxuICAgICAgICBhciA9IGFyLmNvbmNhdChfX3JlYWQoYXJndW1lbnRzW2ldKSk7XHJcbiAgICByZXR1cm4gYXI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2F3YWl0KHYpIHtcclxuICAgIHJldHVybiB0aGlzIGluc3RhbmNlb2YgX19hd2FpdCA/ICh0aGlzLnYgPSB2LCB0aGlzKSA6IG5ldyBfX2F3YWl0KHYpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hc3luY0dlbmVyYXRvcih0aGlzQXJnLCBfYXJndW1lbnRzLCBnZW5lcmF0b3IpIHtcclxuICAgIGlmICghU3ltYm9sLmFzeW5jSXRlcmF0b3IpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC5cIik7XHJcbiAgICB2YXIgZyA9IGdlbmVyYXRvci5hcHBseSh0aGlzQXJnLCBfYXJndW1lbnRzIHx8IFtdKSwgaSwgcSA9IFtdO1xyXG4gICAgcmV0dXJuIGkgPSB7fSwgdmVyYihcIm5leHRcIiksIHZlcmIoXCJ0aHJvd1wiKSwgdmVyYihcInJldHVyblwiKSwgaVtTeW1ib2wuYXN5bmNJdGVyYXRvcl0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzOyB9LCBpO1xyXG4gICAgZnVuY3Rpb24gdmVyYihuKSB7IGlmIChnW25dKSBpW25dID0gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChhLCBiKSB7IHEucHVzaChbbiwgdiwgYSwgYl0pID4gMSB8fCByZXN1bWUobiwgdik7IH0pOyB9OyB9XHJcbiAgICBmdW5jdGlvbiByZXN1bWUobiwgdikgeyB0cnkgeyBzdGVwKGdbbl0odikpOyB9IGNhdGNoIChlKSB7IHNldHRsZShxWzBdWzNdLCBlKTsgfSB9XHJcbiAgICBmdW5jdGlvbiBzdGVwKHIpIHsgci52YWx1ZSBpbnN0YW5jZW9mIF9fYXdhaXQgPyBQcm9taXNlLnJlc29sdmUoci52YWx1ZS52KS50aGVuKGZ1bGZpbGwsIHJlamVjdCkgOiBzZXR0bGUocVswXVsyXSwgcik7IH1cclxuICAgIGZ1bmN0aW9uIGZ1bGZpbGwodmFsdWUpIHsgcmVzdW1lKFwibmV4dFwiLCB2YWx1ZSk7IH1cclxuICAgIGZ1bmN0aW9uIHJlamVjdCh2YWx1ZSkgeyByZXN1bWUoXCJ0aHJvd1wiLCB2YWx1ZSk7IH1cclxuICAgIGZ1bmN0aW9uIHNldHRsZShmLCB2KSB7IGlmIChmKHYpLCBxLnNoaWZ0KCksIHEubGVuZ3RoKSByZXN1bWUocVswXVswXSwgcVswXVsxXSk7IH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fYXN5bmNEZWxlZ2F0b3Iobykge1xyXG4gICAgdmFyIGksIHA7XHJcbiAgICByZXR1cm4gaSA9IHt9LCB2ZXJiKFwibmV4dFwiKSwgdmVyYihcInRocm93XCIsIGZ1bmN0aW9uIChlKSB7IHRocm93IGU7IH0pLCB2ZXJiKFwicmV0dXJuXCIpLCBpW1N5bWJvbC5pdGVyYXRvcl0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzOyB9LCBpO1xyXG4gICAgZnVuY3Rpb24gdmVyYihuLCBmKSB7IGlbbl0gPSBvW25dID8gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIChwID0gIXApID8geyB2YWx1ZTogX19hd2FpdChvW25dKHYpKSwgZG9uZTogbiA9PT0gXCJyZXR1cm5cIiB9IDogZiA/IGYodikgOiB2OyB9IDogZjsgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hc3luY1ZhbHVlcyhvKSB7XHJcbiAgICBpZiAoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuXCIpO1xyXG4gICAgdmFyIG0gPSBvW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSwgaTtcclxuICAgIHJldHVybiBtID8gbS5jYWxsKG8pIDogKG8gPSB0eXBlb2YgX192YWx1ZXMgPT09IFwiZnVuY3Rpb25cIiA/IF9fdmFsdWVzKG8pIDogb1tTeW1ib2wuaXRlcmF0b3JdKCksIGkgPSB7fSwgdmVyYihcIm5leHRcIiksIHZlcmIoXCJ0aHJvd1wiKSwgdmVyYihcInJldHVyblwiKSwgaVtTeW1ib2wuYXN5bmNJdGVyYXRvcl0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzOyB9LCBpKTtcclxuICAgIGZ1bmN0aW9uIHZlcmIobikgeyBpW25dID0gb1tuXSAmJiBmdW5jdGlvbiAodikgeyByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkgeyB2ID0gb1tuXSh2KSwgc2V0dGxlKHJlc29sdmUsIHJlamVjdCwgdi5kb25lLCB2LnZhbHVlKTsgfSk7IH07IH1cclxuICAgIGZ1bmN0aW9uIHNldHRsZShyZXNvbHZlLCByZWplY3QsIGQsIHYpIHsgUHJvbWlzZS5yZXNvbHZlKHYpLnRoZW4oZnVuY3Rpb24odikgeyByZXNvbHZlKHsgdmFsdWU6IHYsIGRvbmU6IGQgfSk7IH0sIHJlamVjdCk7IH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fbWFrZVRlbXBsYXRlT2JqZWN0KGNvb2tlZCwgcmF3KSB7XHJcbiAgICBpZiAoT2JqZWN0LmRlZmluZVByb3BlcnR5KSB7IE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjb29rZWQsIFwicmF3XCIsIHsgdmFsdWU6IHJhdyB9KTsgfSBlbHNlIHsgY29va2VkLnJhdyA9IHJhdzsgfVxyXG4gICAgcmV0dXJuIGNvb2tlZDtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2ltcG9ydFN0YXIobW9kKSB7XHJcbiAgICBpZiAobW9kICYmIG1vZC5fX2VzTW9kdWxlKSByZXR1cm4gbW9kO1xyXG4gICAgdmFyIHJlc3VsdCA9IHt9O1xyXG4gICAgaWYgKG1vZCAhPSBudWxsKSBmb3IgKHZhciBrIGluIG1vZCkgaWYgKE9iamVjdC5oYXNPd25Qcm9wZXJ0eS5jYWxsKG1vZCwgaykpIHJlc3VsdFtrXSA9IG1vZFtrXTtcclxuICAgIHJlc3VsdC5kZWZhdWx0ID0gbW9kO1xyXG4gICAgcmV0dXJuIHJlc3VsdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9faW1wb3J0RGVmYXVsdChtb2QpIHtcclxuICAgIHJldHVybiAobW9kICYmIG1vZC5fX2VzTW9kdWxlKSA/IG1vZCA6IHsgZGVmYXVsdDogbW9kIH07XHJcbn1cclxuIiwiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnXHJcbmltcG9ydCB7IEh0dHBSZXF1ZXN0LCBIdHRwSGFuZGxlciwgSHR0cEludGVyY2VwdG9yLCBIdHRwRXZlbnQgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCdcclxuXHJcbmltcG9ydCB7IGZpbmFsaXplLCByZXRyeVdoZW4sIHppcCwgbWVyZ2VNYXAsIGNhdGNoRXJyb3IgfSBmcm9tICdyeGpzL29wZXJhdG9ycydcclxuaW1wb3J0IHsgcmFuZ2UsICB0aW1lciwgIHRocm93RXJyb3IsIE9ic2VydmFibGUgfSBmcm9tICdyeGpzJ1xyXG5cclxuZXhwb3J0IGNsYXNzIExvYWRlclNlcnZpY2VDb250cmFjdCB7XHJcbiAgc3RhcnQgKHR5cGU/OiBzdHJpbmcpIHt9XHJcbiAgc3RvcCAoKSB7fVxyXG4gIG5vdGlmeSAobWVzc2FnZTogc3RyaW5nLCB0aXRsZT86IHN0cmluZykge31cclxuICB0b2FzdCAobWVzc2FnZTogc3RyaW5nLCB0aXRsZT86IHN0cmluZykge31cclxufVxyXG5cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgTm90aWZJbnRlcmNlcHRvciBpbXBsZW1lbnRzIEh0dHBJbnRlcmNlcHRvciB7XHJcbiAgY29uc3RydWN0b3IgKFxyXG4gICAgcHJpdmF0ZSBub3RpZjogTG9hZGVyU2VydmljZUNvbnRyYWN0LFxyXG4gICkge31cclxuXHJcbiAgaW50ZXJjZXB0IChyZXE6IEh0dHBSZXF1ZXN0PGFueT4sIG5leHQ6IEh0dHBIYW5kbGVyKTogT2JzZXJ2YWJsZTxIdHRwRXZlbnQ8YW55Pj4ge1xyXG4gICAgdGhpcy5ub3RpZi5zdGFydCgpXHJcblxyXG4gICAgLy8gZXh0ZW5kIHNlcnZlciByZXNwb25zZSBvYnNlcnZhYmxlIHdpdGggbG9nZ2luZ1xyXG4gICAgcmV0dXJuIG5leHQuaGFuZGxlKHJlcSkucGlwZShcclxuICAgICAgLy8gdGhpbmdzIGRvbid0IGFsd2F5cyB3b3JrIGFzIHBsYW5uZWRcclxuICAgICAgLy8gaWYgdGhpbmdzIGdvIHdyb25nLCB0cnkgYWdhaW4gdGhyZWUgdGltZXNcclxuICAgICAgLy8gaG93ZXZlciwgZGVsYXkgdHJpYWwgaW4gYW4gaW5jcmVtZW50YWwgbWFubmVyIChtdWx0aXBsIG9mIDEgc2Vjb25kKVxyXG4gICAgICByZXRyeVdoZW4oKGF0dGVtcHRzKSA9PiB7XHJcbiAgICAgICAgcmV0dXJuIGF0dGVtcHRzLnBpcGUoXHJcbiAgICAgICAgICB6aXAocmFuZ2UoMSwgNCkpLFxyXG4gICAgICAgICAgbWVyZ2VNYXAoKFtlcnJvciwgaV0pID0+IHtcclxuICAgICAgICAgICAgdGhpcy5ub3RpZi5zdGFydCgncXVlcnknKVxyXG4gICAgICAgICAgICBpZiAoaSA+IDIpIHtcclxuICAgICAgICAgICAgICByZXR1cm4gdGhyb3dFcnJvcihlcnJvcilcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICByZXR1cm4gdGltZXIoaSAqIDEwMDApXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgIClcclxuICAgICAgfSksXHJcblxyXG4gICAgICAvLyBjYXRjaEVycm9yIGh0dHAgZXJyb3JzIGFuZCB0dXJuIHRvIG9ic2VydmFibGUgb2YgdW5kZWZpbmVkXHJcbiAgICAgIGNhdGNoRXJyb3IoKGUpID0+IHtcclxuICAgICAgICBsZXQgdGl0bGUsIG1lc3NhZ2VcclxuXHJcbiAgICAgICAgdGhpcy5ub3RpZi5zdGFydCgnYnVmZmVyJylcclxuXHJcbiAgICAgICAgaWYgKGUuZXJyb3IgaW5zdGFuY2VvZiBFcnJvckV2ZW50KSB7XHJcbiAgICAgICAgICAvLyBBIGNsaWVudC1zaWRlIG9yIG5ldHdvcmsgZXJyb3Igb2NjdXJyZWQuIEhhbmRsZSBpdCBhY2NvcmRpbmdseS5cclxuICAgICAgICAgIHRpdGxlID0gJ0NsaWVudCBFcnJvcidcclxuICAgICAgICAgIG1lc3NhZ2UgPSBlLmVycm9yLm1lc3NhZ2VcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gVGhlIGJhY2tlbmQgcmV0dXJuZWQgYW4gdW5zdWNjZXNzZnVsIHJlc3BvbnNlIGNvZGUuXHJcbiAgICAgICAgICAvLyBUaGUgcmVzcG9uc2UgYm9keSBtYXkgY29udGFpbiBjbHVlcyBhcyB0byB3aGF0IHdlbnQgd3JvbmcsXHJcbiAgICAgICAgICB0aXRsZSA9ICdOZXR3b3JrIEluZm8nXHJcbiAgICAgICAgICBtZXNzYWdlID0gYCR7ZS5zdGF0dXNUZXh0fSAoJHtlLnN0YXR1c30pYFxyXG4gICAgICAgICAgLy8gbWVzc2FnZSA9IGUubWVzc2FnZVxyXG4gICAgICAgIH1cclxuICAgICAgICBcclxuICAgICAgICBpZihlLnN0YXR1cyA9PT0gNDAxKXtcclxuICAgICAgICAgIC8vIHRoaXMubm90aWYubm90aWZ5KCdUaGUgdXNlcm5hbWUvcGFzc3dvcmQgaXMgd3JvbmcnLCAnVW5hdXRob3JpemVkJylcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZXtcclxuICAgICAgICAgIC8vIHRoaXMubm90aWYudG9hc3QobWVzc2FnZSwgdGl0bGUpXHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25zb2xlLmVycm9yKHsgdGl0bGUsIG1lc3NhZ2UgfSk7XHJcbiAgICAgICAgXHJcbiAgICAgICAgLy8gY2F0Y2hlIC8vcmUgdGhyb3dcclxuICAgICAgICAvLyB0aHJvdyB7dGl0bGUsIG1lc3NhZ2V9XHJcbiAgICAgICAgLy8gcmV0dXJuIG9mKHsgZToge3RpdGxlLCBtZXNzYWdlfSB9KVxyXG4gICAgICAgIC8vIHJldHVybiBlbXB0eSgpXHJcbiAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoeyB0aXRsZSwgbWVzc2FnZX0pXHJcbiAgICAgIH0pLFxyXG4gICAgICBmaW5hbGl6ZSgoKSA9PiB7XHJcbiAgICAgICAgdGhpcy5ub3RpZi5zdG9wKClcclxuICAgICAgfSksXHJcbiAgICApXHJcbiAgfVxyXG59XHJcbiIsImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJ1xyXG5pbXBvcnQge1xyXG4gIEh0dHBJbnRlcmNlcHRvcixcclxuICBIdHRwUmVxdWVzdCxcclxuICBIdHRwSGFuZGxlcixcclxuICBIdHRwRXZlbnQsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnXHJcbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcclxuXHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIFN0b3JlU3luY0ludGVyY2VwdG9yIGltcGxlbWVudHMgSHR0cEludGVyY2VwdG9yIHtcclxuICAvLyBjb25zdHJ1Y3Rvcihwcml2YXRlIGNhY2hlOiBSZXF1ZXN0Q2FjaGUpIHt9XHJcblxyXG4gIGludGVyY2VwdChyZXE6IEh0dHBSZXF1ZXN0PGFueT4sIG5leHQ6IEh0dHBIYW5kbGVyKTogT2JzZXJ2YWJsZTxIdHRwRXZlbnQ8YW55Pj4gIHtcclxuICAgIC8vIGNvbnRpbnVlIGlmIG5vdCBjYWNoYWJsZS5cclxuICAgIC8vIGlmICghaXNDYWNoYWJsZShyZXEpKSB7IHJldHVybiBuZXh0LmhhbmRsZShyZXEpOyB9XHJcbiAgICBpZiAodHJ1ZSkge1xyXG4gICAgICByZXR1cm4gbmV4dC5oYW5kbGUocmVxKVxyXG4gICAgfVxyXG5cclxuICAgIC8vIGNhY2hlLW9yLWZldGNoXHJcbiAgICAvLyBjb25zdCBjYWNoZWRSZXNwb25zZSA9IHRoaXMuY2FjaGUuZ2V0KHJlcSk7XHJcbiAgICAvLyByZXR1cm4gY2FjaGVkUmVzcG9uc2UgP1xyXG4gICAgLy8gICBvZihjYWNoZWRSZXNwb25zZSkgOiBzZW5kUmVxdWVzdChyZXEsIG5leHQsIHRoaXMuY2FjaGUpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogR2V0IHNlcnZlciByZXNwb25zZSBvYnNlcnZhYmxlIGJ5IHNlbmRpbmcgcmVxdWVzdCB0byBgbmV4dCgpYC5cclxuICAgKiBXaWxsIGFkZCB0aGUgcmVzcG9uc2UgdG8gdGhlIGNhY2hlIG9uIHRoZSB3YXkgb3V0LlxyXG4gICAqL1xyXG4gIC8vICBzZW5kUmVxdWVzdChcclxuICAvLyAgICAgcmVxOiBIdHRwUmVxdWVzdDxhbnk+LFxyXG4gIC8vICAgICBuZXh0OiBIdHRwSGFuZGxlcixcclxuICAvLyAgICAgY2FjaGU6IFJlcXVlc3RDYWNoZSk6IE9ic2VydmFibGU8SHR0cEV2ZW50PGFueT4+IHtcclxuXHJcbiAgLy8gICAgIC8vIE5vIGhlYWRlcnMgYWxsb3dlZCBpbiBucG0gc2VhcmNoIHJlcXVlc3RcclxuICAvLyAgICAgY29uc3Qgbm9IZWFkZXJSZXEgPSByZXEuY2xvbmUoeyBoZWFkZXJzOiBuZXcgSHR0cEhlYWRlcnMoKSB9KTtcclxuXHJcbiAgLy8gICAgIHJldHVybiBuZXh0LmhhbmRsZShub0hlYWRlclJlcSkucGlwZShcclxuICAvLyAgICAgICB0YXAoZXZlbnQgPT4ge1xyXG4gIC8vICAgICAgICAgLy8gVGhlcmUgbWF5IGJlIG90aGVyIGV2ZW50cyBiZXNpZGVzIHRoZSByZXNwb25zZS5cclxuICAvLyAgICAgICAgIGlmIChldmVudCBpbnN0YW5jZW9mIEh0dHBSZXNwb25zZSkge1xyXG4gIC8vICAgICAgICAgICBjYWNoZS5wdXQocmVxLCBldmVudCk7IC8vIFVwZGF0ZSB0aGUgY2FjaGUuXHJcbiAgLy8gICAgICAgICB9XHJcbiAgLy8gICAgICAgfSlcclxuICAvLyAgICAgKTtcclxuICAvLyAgIH1cclxuXHJcbiAgLy8gY2FjaGUtdGhlbi1yZWZyZXNoXHJcbiAgLy8gaWYgKHJlcS5oZWFkZXJzLmdldCgneC1yZWZyZXNoJykpIHtcclxuICAvLyAgICAgY29uc3QgcmVzdWx0cyQgPSBzZW5kUmVxdWVzdChyZXEsIG5leHQsIHRoaXMuY2FjaGUpO1xyXG4gIC8vICAgICByZXR1cm4gY2FjaGVkUmVzcG9uc2UgP1xyXG4gIC8vICAgICAgIHJlc3VsdHMkLnBpcGUoIHN0YXJ0V2l0aChjYWNoZWRSZXNwb25zZSkgKSA6XHJcbiAgLy8gICAgICAgcmVzdWx0cyQ7XHJcbiAgLy8gICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgU3RvcmVTeW5jSW50ZXJjZXB0b3IgfSBmcm9tICcuL3N0b3JlLXN5bmMuaW50ZXJjZXB0b3InXHJcbmltcG9ydCB7IEF1dGhJbnRlcmNlcHRvciB9IGZyb20gJy4vYXV0aC5pbnRlcmNlcHRvcidcclxuaW1wb3J0IHsgTm90aWZJbnRlcmNlcHRvciB9IGZyb20gJy4vbm90aWYuaW50ZXJjZXB0b3InXHJcbmltcG9ydCB7IEhUVFBfSU5URVJDRVBUT1JTIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnXHJcblxyXG5leHBvcnQgY29uc3QgSU5URVJDRVBUT1JTOiBhbnlbXSA9IFtcclxuICB7IHByb3ZpZGU6IEhUVFBfSU5URVJDRVBUT1JTLCB1c2VDbGFzczogQXV0aEludGVyY2VwdG9yLCBtdWx0aTogdHJ1ZSB9LFxyXG4gIC8vIHsgcHJvdmlkZTogSFRUUF9JTlRFUkNFUFRPUlMsIHVzZUNsYXNzOiBTdG9yZVN5bmNJbnRlcmNlcHRvciwgbXVsdGk6IHRydWUgfSxcclxuICB7IHByb3ZpZGU6IEhUVFBfSU5URVJDRVBUT1JTLCB1c2VDbGFzczogTm90aWZJbnRlcmNlcHRvciwgbXVsdGk6IHRydWUgfVxyXG5dXHJcblxyXG5leHBvcnQgKiBmcm9tICcuL3N0b3JlLXN5bmMuaW50ZXJjZXB0b3InXHJcbmV4cG9ydCAqIGZyb20gJy4vYXV0aC5pbnRlcmNlcHRvcidcclxuZXhwb3J0ICogZnJvbSAnLi9ub3RpZi5pbnRlcmNlcHRvcidcclxuIl0sIm5hbWVzIjpbIkluamVjdGFibGUiLCJBdXRoU2VydmljZSIsInJldHJ5V2hlbiIsInppcCIsInJhbmdlIiwibWVyZ2VNYXAiLCJ0aHJvd0Vycm9yIiwidGltZXIiLCJjYXRjaEVycm9yIiwiZmluYWxpemUiLCJIVFRQX0lOVEVSQ0VQVE9SUyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztBQUFBO1FBUUUseUJBQW9CLElBQWlCO1lBQWpCLFNBQUksR0FBSixJQUFJLENBQWE7U0FBSTs7Ozs7O1FBRXpDLG1DQUFTOzs7OztZQUFULFVBQVUsR0FBcUIsRUFBRSxJQUFpQjs7Z0JBSWhELElBQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUM7b0JBQ3hCLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLEVBQUUsSUFBSSxDQUFDLElB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