@akanass/ng-universal-transfer-http
Version:
TransferHttpCacheModule installs a Http interceptor that avoids duplicate HttpClient requests on the client
797 lines • 74.9 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { isPlatformServer } from '@angular/common';
import { HttpErrorResponse, HttpHeaders, HttpResponse } from '@angular/common/http';
import { ApplicationRef, Inject, Injectable, PLATFORM_ID } from '@angular/core';
import { makeStateKey, TransferState } from '@angular/platform-browser';
import createHash from 'create-hash';
import { stringify } from 'flatted/esm';
import { from, merge, of, throwError } from 'rxjs';
import { defaultIfEmpty, filter, first, flatMap, map, tap, toArray } from 'rxjs/operators';
import { TransferHttpCacheConfigService } from '../transfer-http-cache-config/transfer-http-cache-config.service';
/**
* Response interface
* @record
*/
function TransferHttpResponse() { }
if (false) {
/** @type {?|undefined} */
TransferHttpResponse.prototype.body;
/** @type {?|undefined} */
TransferHttpResponse.prototype.error;
/** @type {?|undefined} */
TransferHttpResponse.prototype.headers;
/** @type {?|undefined} */
TransferHttpResponse.prototype.status;
/** @type {?|undefined} */
TransferHttpResponse.prototype.statusText;
/** @type {?|undefined} */
TransferHttpResponse.prototype.url;
}
/**
* Server state interface
* @record
*/
function ServerStateData() { }
if (false) {
/** @type {?} */
ServerStateData.prototype.id;
/** @type {?} */
ServerStateData.prototype.reqKey;
}
export class TransferHttpCacheInterceptor {
/**
* Class constructor
* @param {?} _appRef
* @param {?} _transferState
* @param {?} _platformId
* @param {?} _configService
*/
constructor(_appRef, _transferState, _platformId, _configService) {
this._appRef = _appRef;
this._transferState = _transferState;
this._platformId = _platformId;
this._configService = _configService;
this._id = 0;
this._serverStateDataStoreKey = makeStateKey('server_state_data');
this._lastIdStoreKey = makeStateKey('server_state_last_id');
this._isCacheActivatedStoreKey = makeStateKey('is_cache_activated');
this._initCacheProcess();
}
/**
* Initialize cache process
* @private
* @return {?}
*/
_initCacheProcess() {
// initialize cache flag for the current platform
of(of(isPlatformServer(this._platformId)))
.pipe(flatMap((/**
* @param {?} isServer
* @return {?}
*/
(isServer) => merge(isServer
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !!_)), tap((/**
* @param {?} _
* @return {?}
*/
_ => this._isCacheActivated = _)), tap((/**
* @param {?} _
* @return {?}
*/
_ => this._transferState.set(this._isCacheActivatedStoreKey, _)))), isServer
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !_)), tap((/**
* @param {?} _
* @return {?}
*/
_ => this._transferState.hasKey(this._isCacheActivatedStoreKey) ?
this._isCacheActivated = this._transferState.get(this._isCacheActivatedStoreKey, true) :
this._isCacheActivated = _)))))), flatMap((/**
* @return {?}
*/
() =>
// Stop using the cache if the application has stabilized, indicating initial rendering is complete
// or if we are in development mode.
merge(of(this._configService.config.prodMode)
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !_)), tap((/**
* @return {?}
*/
() => console.log('TransferHttpCacheModule is in the development mode. ' +
'Enable the production mode with Server Side Rendering.')))), this._appRef.isStable
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !!_))))
.pipe(first())))).subscribe((/**
* @return {?}
*/
() => this._isCacheActivated = false));
}
/**
* Interceptor process
* @param {?} req
* @param {?} next
* @return {?}
*/
intercept(req, next) {
return of(of(this._isCacheActivated))
.pipe(flatMap((/**
* @param {?} isCacheActivated
* @return {?}
*/
(isCacheActivated) => merge(isCacheActivated
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !_)), flatMap((/**
* @return {?}
*/
() => next.handle(req)
.pipe(tap((/**
* @return {?}
*/
() => this._cleanServerState())))))), isCacheActivated
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !!_)), flatMap((/**
* @return {?}
*/
() => this._transferStateProcess(req, next))))))));
}
/**
* Function to clean all data in server state
* @private
* @return {?}
*/
_cleanServerState() {
merge(this._getLastId(false)
.pipe(tap((/**
* @return {?}
*/
() => this._transferState.remove(this._lastIdStoreKey)))), this._getServerStateData(false)
.pipe(tap((/**
* @param {?} _
* @return {?}
*/
_ => _.forEach((/**
* @param {?} __
* @return {?}
*/
__ => this._transferState.remove(makeStateKey(this._createHash(`${__.reqKey}_${__.id}`))))))), tap((/**
* @return {?}
*/
() => this._transferState.remove(this._serverStateDataStoreKey)))), of(of(this._transferState.hasKey(this._isCacheActivatedStoreKey)))
.pipe(flatMap((/**
* @param {?} hasKey
* @return {?}
*/
(hasKey) => hasKey
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !!_)), tap((/**
* @return {?}
*/
() => this._transferState.remove(this._isCacheActivatedStoreKey))))))))
.subscribe((/**
* @return {?}
*/
() => undefined), (/**
* @param {?} e
* @return {?}
*/
e => {
throw (e);
}));
}
/**
* Transfer state process
* @private
* @param {?} req
* @param {?} next
* @return {?}
*/
_transferStateProcess(req, next) {
return this._createKey(req)
.pipe(flatMap((/**
* @param {?} storeKey
* @return {?}
*/
storeKey => of(of(this._transferState.hasKey(storeKey)))
.pipe(flatMap((/**
* @param {?} hasKey
* @return {?}
*/
hasKey => merge(this._hasKeyProcess(hasKey, storeKey), this._hasNotKeyProcess(req, next, hasKey, storeKey))))))));
}
/**
* Creates transfer state key's store
* @private
* @param {?} req
* @return {?}
*/
_createKey(req) {
this._id++;
return of(of(isPlatformServer(this._platformId)))
.pipe(flatMap((/**
* @param {?} isServer
* @return {?}
*/
(isServer) => merge(isServer
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !!_)), flatMap((/**
* @return {?}
*/
() => this._serverKey(req)))), isServer
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !_)), flatMap((/**
* @return {?}
*/
() => this._clientKey(req))))))));
}
/**
* Function to get state data and create client key for current request
* @private
* @param {?} req
* @return {?}
*/
_clientKey(req) {
return this._requestFormatted(req)
.pipe(map((/**
* @param {?} _
* @return {?}
*/
(_) => this._createHash(stringify(_)))), flatMap((/**
* @param {?} reqKey
* @return {?}
*/
reqKey => this._getServerStateData()
.pipe(flatMap((/**
* @param {?} _
* @return {?}
*/
_ => from(_))), filter((/**
* @param {?} _
* @return {?}
*/
_ => _.reqKey === reqKey)), defaultIfEmpty(undefined), flatMap((/**
* @param {?} _
* @return {?}
*/
_ => !!_ ?
of(_) :
throwError(new Error('Request missing in server state data')))), flatMap((/**
* @param {?} serverState
* @return {?}
*/
serverState => this._getLastId()
.pipe(flatMap((/**
* @param {?} _
* @return {?}
*/
_ => !_ || this._id > _ ?
throwError(new Error('Wrong id for server state data')) :
of(this._id))), map((/**
* @param {?} _
* @return {?}
*/
_ => _ === serverState.id ? _ : serverState.id)), map((/**
* @param {?} id
* @return {?}
*/
id => this._createHash(`${reqKey}_${id}`))), map((/**
* @param {?} key
* @return {?}
*/
key => makeStateKey(key))))))))));
}
/**
* Function to get last id from server
* @private
* @param {?=} _throwError
* @return {?}
*/
_getLastId(_throwError = true) {
return of(this._lastIdStoreKey)
.pipe(flatMap((/**
* @param {?} storeKey
* @return {?}
*/
storeKey => of(of(this._transferState.hasKey(storeKey)))
.pipe(flatMap((/**
* @param {?} hasKey
* @return {?}
*/
hasKey => merge(hasKey
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !_)), flatMap((/**
* @return {?}
*/
() => of(_throwError)
.pipe(filter((/**
* @param {?} __
* @return {?}
*/
__ => !!__)), flatMap((/**
* @return {?}
*/
() => throwError(new Error('Missing server state last id')))))))), hasKey
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !!_)), map((/**
* @return {?}
*/
() => this._transferState.get(storeKey, 0)))))))))));
}
/**
* Function to get server state data
* @private
* @param {?=} _throwError
* @return {?}
*/
_getServerStateData(_throwError = true) {
return of(this._serverStateDataStoreKey)
.pipe(flatMap((/**
* @param {?} storeKey
* @return {?}
*/
storeKey => of(of(this._transferState.hasKey(storeKey)))
.pipe(flatMap((/**
* @param {?} hasKey
* @return {?}
*/
hasKey => merge(hasKey
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !_)), flatMap((/**
* @return {?}
*/
() => of(_throwError)
.pipe(filter((/**
* @param {?} __
* @return {?}
*/
__ => !!__)), flatMap((/**
* @return {?}
*/
() => throwError(new Error('Missing server state data')))))))), hasKey
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !!_)), map((/**
* @return {?}
*/
() => this._transferState.get(storeKey, (/** @type {?} */ ([])))))))))))));
}
/**
* Function to create server key and store state data for current request
* @private
* @param {?} req
* @return {?}
*/
_serverKey(req) {
return this._requestFormatted(req)
.pipe(map((/**
* @param {?} _
* @return {?}
*/
(_) => this._createHash(stringify(_)))), tap((/**
* @param {?} reqKey
* @return {?}
*/
reqKey => this._storeServerStateData(reqKey))), map((/**
* @param {?} reqKey
* @return {?}
*/
reqKey => this._createHash(`${reqKey}_${this._id}`))), map((/**
* @param {?} key
* @return {?}
*/
key => makeStateKey(key))));
}
/**
* Function to store server state data
* @private
* @param {?} reqKey
* @return {?}
*/
_storeServerStateData(reqKey) {
of(this._serverStateDataStoreKey)
.pipe(flatMap((/**
* @param {?} storeKey
* @return {?}
*/
storeKey => of(of(this._transferState.hasKey(storeKey)))
.pipe(flatMap((/**
* @param {?} hasKey
* @return {?}
*/
hasKey => merge(hasKey
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !_)), map((/**
* @return {?}
*/
() => (/** @type {?} */ ([]))))), hasKey
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !!_)), map((/**
* @return {?}
*/
() => this._transferState.get(storeKey, (/** @type {?} */ ([]))))), flatMap((/**
* @param {?} serverStateData
* @return {?}
*/
serverStateData => !!serverStateData.find((/**
* @param {?} _
* @return {?}
*/
_ => _.reqKey === reqKey)) ?
throwError(new Error('Request already stored in server state data')) :
of(serverStateData))))))), tap((/**
* @return {?}
*/
() => this._transferState.set(this._lastIdStoreKey, this._id)))))))
.subscribe((/**
* @param {?} serverStateData
* @return {?}
*/
serverStateData => this._transferState.set(this._serverStateDataStoreKey, serverStateData.concat({
id: this._id,
reqKey
}))), (/**
* @param {?} e
* @return {?}
*/
e => {
throw (e);
}));
}
/**
* Process when key exists in transfer state
* @private
* @param {?} hasKey
* @param {?} storeKey
* @return {?}
*/
_hasKeyProcess(hasKey, storeKey) {
return hasKey
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !!_)), map((/**
* @return {?}
*/
() => of(this._transferState.get(storeKey, (/** @type {?} */ ({})))))), flatMap((/**
* @param {?} obs
* @return {?}
*/
(obs) => merge(obs
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => _.status < 400)), map((/**
* @param {?} response
* @return {?}
*/
(response) => new HttpResponse({
body: response.body,
headers: new HttpHeaders(response.headers),
status: response.status,
statusText: response.statusText,
url: response.url,
})))), obs
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => _.status >= 400)), flatMap((/**
* @param {?} response
* @return {?}
*/
(response) => throwError(new HttpErrorResponse({
error: response.error,
headers: new HttpHeaders(response.headers),
status: response.status,
statusText: response.statusText,
url: response.url,
})))))))));
}
/**
* Process when key doesn't exist in transfer state
* @private
* @param {?} req
* @param {?} next
* @param {?} hasKey
* @param {?} storeKey
* @return {?}
*/
_hasNotKeyProcess(req, next, hasKey, storeKey) {
return hasKey
.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !_)), flatMap((/**
* @return {?}
*/
() => next.handle(req)
.pipe(tap((/**
* @param {?} event
* @return {?}
*/
(event) => of(event)
.pipe(filter((/**
* @param {?} evt
* @return {?}
*/
evt => evt instanceof HttpResponse)))
.subscribe((/**
* @param {?} evt
* @return {?}
*/
(evt) => this._transferState.set(storeKey, {
body: evt.body,
headers: this._getHeadersMap(evt.headers),
status: evt.status,
statusText: evt.statusText,
// tslint:disable-next-line:no-non-null-assertion
url: (/** @type {?} */ (evt.url)),
})))), (/**
* @param {?} error
* @return {?}
*/
(error) => of(error)
.pipe(filter((/**
* @param {?} err
* @return {?}
*/
err => err instanceof HttpErrorResponse)))
.subscribe((/**
* @param {?} err
* @return {?}
*/
(err) => this._transferState.set(storeKey, {
error: err.error,
headers: this._getHeadersMap(err.headers),
status: err.status,
statusText: err.statusText,
// tslint:disable-next-line:no-non-null-assertion
url: (/** @type {?} */ (err.url)),
})))))))));
}
/**
* Creates Headers Map
* @private
* @param {?} headers
* @return {?}
*/
_getHeadersMap(headers) {
// tslint:disable-next-line:no-non-null-assertion
return headers.keys().reduce((/**
* @param {?} acc
* @param {?} curr
* @return {?}
*/
(acc, curr) => Object.assign(acc, { [curr]: (/** @type {?} */ (headers.getAll(curr))) })), {});
}
/**
* Function to create sha256 hash
* @private
* @param {?} data
* @return {?}
*/
_createHash(data) {
return createHash('sha256').update(data).digest('hex');
}
/**
* Returns HttpRequest with value of header inside url & urlWithParams
* @private
* @param {?} req
* @param {?} headerName
* @return {?}
*/
_replaceWithHeader(req, headerName) {
return of(of(this._getHeadersMap(req.headers)[headerName]))
.pipe(flatMap((/**
* @param {?} obs
* @return {?}
*/
(obs) => merge(obs.pipe(filter((/**
* @param {?} _
* @return {?}
*/
(_) => !!_ && !!_.length)), map((/**
* @param {?} _
* @return {?}
*/
(_) => of(_[_.length - 1]))), flatMap((/**
* @param {?} o
* @return {?}
*/
(o) => merge(o.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !!_)), flatMap((/**
* @param {?} headerValue
* @return {?}
*/
(headerValue) => merge(this._formatUrlWithHeaderValue(req.url, headerValue), this._formatUrlWithHeaderValue(req.urlWithParams, headerValue)).pipe(toArray(), map((/**
* @param {?} _
* @return {?}
*/
_ => (/** @type {?} */ (Object.assign({}, req, {
url: _[0],
urlWithParams: _[1]
}))))))))), o.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !_)), flatMap((/**
* @return {?}
*/
() => throwError(new Error(`Missing header '${headerName}' value inside request to generate state key`))))))))), obs.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !_ || !_.length)), flatMap((/**
* @return {?}
*/
() => throwError(new Error(`Missing header '${headerName}' value inside request to generate state key`)))))))));
}
/**
* Replace url with header value
* @private
* @param {?} url
* @param {?} headerValue
* @return {?}
*/
_formatUrlWithHeaderValue(url, headerValue) {
return of(url)
.pipe(map((/**
* @param {?} _
* @return {?}
*/
(_) => _.split('://')[1].split('/'))), map((/**
* @param {?} _
* @return {?}
*/
(_) => _.map((/**
* @param {?} s
* @param {?} i
* @return {?}
*/
(s, i) => i === 0 ? headerValue : s)))), map((/**
* @param {?} _
* @return {?}
*/
(_) => _.join('/'))));
}
/**
* Returns the good request object to create hash
* @private
* @param {?} req
* @return {?}
*/
_requestFormatted(req) {
return of(of(this._configService.config.headerNameToOverrideUrlInKeyCachingGeneration))
.pipe(flatMap((/**
* @param {?} obs
* @return {?}
*/
(obs) => merge(obs.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !!_)), flatMap((/**
* @param {?} _
* @return {?}
*/
_ => this._replaceWithHeader(req, _)))), obs.pipe(filter((/**
* @param {?} _
* @return {?}
*/
_ => !_)), map((/**
* @return {?}
*/
() => req)))))));
}
}
TransferHttpCacheInterceptor.decorators = [
{ type: Injectable }
];
/** @nocollapse */
TransferHttpCacheInterceptor.ctorParameters = () => [
{ type: ApplicationRef },
{ type: TransferState },
{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] },
{ type: TransferHttpCacheConfigService }
];
if (false) {
/**
* @type {?}
* @private
*/
TransferHttpCacheInterceptor.prototype._isCacheActivated;
/**
* @type {?}
* @private
*/
TransferHttpCacheInterceptor.prototype._id;
/**
* @type {?}
* @private
*/
TransferHttpCacheInterceptor.prototype._serverStateDataStoreKey;
/**
* @type {?}
* @private
*/
TransferHttpCacheInterceptor.prototype._lastIdStoreKey;
/**
* @type {?}
* @private
*/
TransferHttpCacheInterceptor.prototype._isCacheActivatedStoreKey;
/**
* @type {?}
* @private
*/
TransferHttpCacheInterceptor.prototype._appRef;
/**
* @type {?}
* @private
*/
TransferHttpCacheInterceptor.prototype._transferState;
/**
* @type {?}
* @private
*/
TransferHttpCacheInterceptor.prototype._platformId;
/**
* @type {?}
* @private
*/
TransferHttpCacheInterceptor.prototype._configService;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNmZXItaHR0cC1jYWNoZS5pbnRlcmNlcHRvci5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0Bha2FuYXNzL25nLXVuaXZlcnNhbC10cmFuc2Zlci1odHRwLyIsInNvdXJjZXMiOlsibGliL3NoYXJlZC9zZXJ2aWNlcy90cmFuc2Zlci1odHRwLWNhY2hlLWludGVyY2VwdG9yL3RyYW5zZmVyLWh0dHAtY2FjaGUuaW50ZXJjZXB0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sRUFDSCxpQkFBaUIsRUFHakIsV0FBVyxFQUdYLFlBQVksRUFDZixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDaEYsT0FBTyxFQUFFLFlBQVksRUFBWSxhQUFhLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUVsRixPQUFPLFVBQVUsTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUV4QyxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBYyxFQUFFLEVBQUUsVUFBVSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQy9ELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUzRixPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSxrRUFBa0UsQ0FBQzs7Ozs7QUFLbEgsbUNBT0M7OztJQU5HLG9DQUFrQjs7SUFDbEIscUNBQW1COztJQUNuQix1Q0FBc0M7O0lBQ3RDLHNDQUFnQjs7SUFDaEIsMENBQW9COztJQUNwQixtQ0FBYTs7Ozs7O0FBTWpCLDhCQUdDOzs7SUFGRyw2QkFBVzs7SUFD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fSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgICBIdHRwRXJyb3JSZXNwb25zZSxcbiAgICBIdHRwRXZlbnQsXG4gICAgSHR0cEhhbmRsZXIsXG4gICAgSHR0cEhlYWRlcnMsXG4gICAgSHR0cEludGVyY2VwdG9yLFxuICAgIEh0dHBSZXF1ZXN0LFxuICAgIEh0dHBSZXNwb25zZVxufSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBBcHBsaWNhdGlvblJlZiwgSW5qZWN0LCBJbmplY3RhYmxlLCBQTEFURk9STV9JRCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgbWFrZVN0YXRlS2V5LCBTdGF0ZUtleSwgVHJhbnNmZXJTdGF0ZSB9IGZyb20gJ0Bhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXInO1xuXG5pbXBvcnQgY3JlYXRlSGFzaCBmcm9tICdjcmVhdGUtaGFzaCc7XG5pbXBvcnQgeyBzdHJpbmdpZnkgfSBmcm9tICdmbGF0dGVkL2VzbSc7XG5cbmltcG9ydCB7IGZyb20sIG1lcmdlLCBPYnNlcnZhYmxlLCBvZiwgdGhyb3dFcnJvciB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZGVmYXVsdElmRW1wdHksIGZpbHRlciwgZmlyc3QsIGZsYXRNYXAsIG1hcCwgdGFwLCB0b0FycmF5IH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBUcmFuc2Zlckh0dHBDYWNoZUNvbmZpZ1NlcnZpY2UgfSBmcm9tICcuLi90cmFuc2Zlci1odHRwLWNhY2hlLWNvbmZpZy90cmFuc2Zlci1odHRwLWNhY2hlLWNvbmZpZy5zZXJ2aWNlJztcblxuLyoqXG4gKiBSZXNwb25zZSBpbnRlcmZhY2VcbiAqL1xuaW50ZXJmYWNlIFRyYW5zZmVySHR0cFJlc3BvbnNlIHtcbiAgICBib2R5PzogYW55IHwgbnVsbDtcbiAgICBlcnJvcj86IGFueSB8IG51bGw7XG4gICAgaGVhZGVycz86IHsgWyBrOiBzdHJpbmcgXTogc3RyaW5nW10gfTtcbiAgICBzdGF0dXM/OiBudW1iZXI7XG4gICAgc3RhdHVzVGV4dD86IHN0cmluZztcbiAgICB1cmw/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogU2VydmVyIHN0YXRlIGludGVyZmFjZVxuICovXG5pbnRlcmZhY2UgU2VydmVyU3RhdGVEYXRhIHtcbiAgICBpZDogbnVtYmVyO1xuICAgIHJlcUtleTogc3RyaW5nO1xufVxuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgVHJhbnNmZXJIdHRwQ2FjaGVJbnRlcmNlcHRvciBpbXBsZW1lbnRzIEh0dHBJbnRlcmNlcHRvciB7XG4gICAgLy8gcHJpdmF0ZSBwcm9wZXJ0eSB0byBzdG9yZSBjYWNoZSBhY3RpdmF0aW9uIHN0YXR1c1xuICAgIHByaXZhdGUgX2lzQ2FjaGVBY3RpdmF0ZWQ6IGJvb2xlYW47XG4gICAgLy8gcHJpdmF0ZSBwcm9wZXJ0eSB0byBzdG9yZSB1bmlxdWUgaWQgb2YgdGhlIGtleVxuICAgIHByaXZhdGUgX2lkOiBudW1iZXI7XG4gICAgLy8gcHJpdmF0ZSBwcm9wZXJ0eSB0byBzdG9yZSBzZXJ2ZSBzdGF0ZSBkYXRhIHN0b3JlIGtleVxuICAgIHByaXZhdGUgcmVhZG9ubHkgX3NlcnZlclN0YXRlRGF0YVN0b3JlS2V5OiBTdGF0ZUtleTxTZXJ2ZXJTdGF0ZURhdGFbXT47XG4gICAgLy8gcHJpdmF0ZSBwcm9wZXJ0eSB0byBzdG9yZSBsYXN0IGlkIHN0b3JlIGtleVxuICAgIHByaXZhdGUgcmVhZG9ubHkgX2xhc3RJZFN0b3JlS2V5OiBTdGF0ZUtleTxudW1iZXI+O1xuICAgIC8vIHByaXZhdGUgcHJvcGVydHkgdG8gc3RvcmUgZmxhZyB0byBrbm93IGlmIGNhY2hlIGlzIGFjdGl2YXRlZCBpbiBzZXJ2ZXJcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9pc0NhY2hlQWN0aXZhdGVkU3RvcmVLZXk6IFN0YXRlS2V5PGJvb2xlYW4+O1xuXG4gICAgLyoqXG4gICAgICogQ2xhc3MgY29uc3RydWN0b3JcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIF9hcHBSZWY6IEFwcGxpY2F0aW9uUmVmLCBwcml2YXRlIF90cmFuc2ZlclN0YXRlOiBUcmFuc2ZlclN0YXRlLFxuICAgICAgICAgICAgICAgIEBJbmplY3QoUExBVEZPUk1fSUQpIHByaXZhdGUgX3BsYXRmb3JtSWQ6IGFueSxcbiAgICAgICAgICAgICAgICBwcml2YXRlIF9jb25maWdTZXJ2aWNlOiBUcmFuc2Zlckh0dHBDYWNoZUNvbmZpZ1NlcnZpY2UpIHtcbiAgICAgICAgdGhpcy5faWQgPSAwO1xuICAgICAgICB0aGlzLl9zZXJ2ZXJTdGF0ZURhdGFTdG9yZUtleSA9IG1ha2VTdGF0ZUtleTxTZXJ2ZXJTdGF0ZURhdGFbXT4oJ3NlcnZlcl9zdGF0ZV9kYXRhJyk7XG4gICAgICAgIHRoaXMuX2xhc3RJZFN0b3JlS2V5ID0gbWFrZVN0YXRlS2V5PG51bWJlcj4oJ3NlcnZlcl9zdGF0ZV9sYXN0X2lkJyk7XG4gICAgICAgIHRoaXMuX2lzQ2FjaGVBY3RpdmF0ZWRTdG9yZUtleSA9IG1ha2VTdGF0ZUtleTxib29sZWFuPignaXNfY2FjaGVfYWN0aXZhdGVkJyk7XG5cbiAgICAgICAgdGhpcy5faW5pdENhY2hlUHJvY2VzcygpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemUgY2FjaGUgcHJvY2Vzc1xuICAgICAqL1xuICAgIHByaXZhdGUgX2luaXRDYWNoZVByb2Nlc3MoKTogdm9pZCB7XG4gICAgICAgIC8vIGluaXRpYWxpemUgY2FjaGUgZmxhZyBmb3IgdGhlIGN1cnJlbnQgcGxhdGZvcm1cbiAgICAgICAgb2Yob2YoaXNQbGF0Zm9ybVNlcnZlcih0aGlzLl9wbGF0Zm9ybUlkKSkpXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICBmbGF0TWFwKChpc1NlcnZlcjogT2JzZXJ2YWJsZTxib29sZWFuPikgPT5cbiAgICAgICAgICAgICAgICAgICAgbWVyZ2UoXG4gICAgICAgICAgICAgICAgICAgICAgICBpc1NlcnZlclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoXyA9PiAhIV8pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXAoXyA9PiB0aGlzLl9pc0NhY2hlQWN0aXZhdGVkID0gXyksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcChfID0+IHRoaXMuX3RyYW5zZmVyU3RhdGUuc2V0KHRoaXMuX2lzQ2FjaGVBY3RpdmF0ZWRTdG9yZUtleSwgXykpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzU2VydmVyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihfID0+ICFfKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFwKF8gPT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX3RyYW5zZmVyU3RhdGUuaGFzS2V5KHRoaXMuX2lzQ2FjaGVBY3RpdmF0ZWRTdG9yZUtleSkgP1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX2lzQ2FjaGVBY3RpdmF0ZWQgPSB0aGlzLl90cmFuc2ZlclN0YXRlLmdldDxib29sZWFuPih0aGlzLl9pc0NhY2hlQWN0aXZhdGVkU3RvcmVLZXksIHRydWUpIDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl9pc0NhY2hlQWN0aXZhdGVkID0gX1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICBmbGF0TWFwKCgpID0+XG4gICAgICAgICAgICAgICAgICAgIC8vIFN0b3AgdXNpbmcgdGhlIGNhY2hlIGlmIHRoZSBhcHBsaWNhdGlvbiBoYXMgc3RhYmlsaXplZCwgaW5kaWNhdGluZyBpbml0aWFsIHJlbmRlcmluZyBpcyBjb21wbGV0ZVxuICAgICAgICAgICAgICAgICAgICAvLyBvciBpZiB3ZSBhcmUgaW4gZGV2ZWxvcG1lbnQgbW9kZS5cbiAgICAgICAgICAgICAgICAgICAgbWVyZ2UoXG4gICAgICAgICAgICAgICAgICAgICAgICBvZih0aGlzLl9jb25maWdTZXJ2aWNlLmNvbmZpZy5wcm9kTW9kZSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKF8gPT4gIV8pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXAoKCkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdUcmFuc2Zlckh0dHBDYWNoZU1vZHVsZSBpcyBpbiB0aGUgZGV2ZWxvcG1lbnQgbW9kZS4gJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0VuYWJsZSB0aGUgcHJvZHVjdGlvbiBtb2RlIHdpdGggU2VydmVyIFNpZGUgUmVuZGVyaW5nLicpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fYXBwUmVmLmlzU3RhYmxlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihfID0+ICEhXylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpcnN0KClcbiAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICApLnN1YnNjcmliZSgoKSA9PiB0aGlzLl9pc0NhY2hlQWN0aXZhdGVkID0gZmFsc2UpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEludGVyY2VwdG9yIHByb2Nlc3NcbiAgICAgKi9cbiAgICBpbnRlcmNlcHQocmVxOiBIdHRwUmVxdWVzdDxhbnk+LCBuZXh0OiBIdHRwSGFuZGxlcik6IE9ic2VydmFibGU8SHR0cEV2ZW50PGFueT4+IHtcbiAgICAgICAgcmV0dXJuIG9mKFxuICAgICAgICAgICAgb2YodGhpcy5faXNDYWNoZUFjdGl2YXRlZClcbiAgICAgICAgKVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgZmxhdE1hcCgoaXNDYWNoZUFjdGl2YXRlZDogT2JzZXJ2YWJsZTxib29sZWFuPikgPT5cbiAgICAgICAgICAgICAgICAgICAgbWVyZ2UoXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0NhY2hlQWN0aXZhdGVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihfID0+ICFfKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxhdE1hcCgoKSA9PiBuZXh0LmhhbmRsZShyZXEpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXAoKCkgPT4gdGhpcy5fY2xlYW5TZXJ2ZXJTdGF0ZSgpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzQ2FjaGVBY3RpdmF0ZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKF8gPT4gISFfKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxhdE1hcCgoKSA9PiB0aGlzLl90cmFuc2ZlclN0YXRlUHJvY2VzcyhyZXEsIG5leHQpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRnVuY3Rpb24gdG8gY2xlYW4gYWxsIGRhdGEgaW4gc2VydmVyIHN0YXRlXG4gICAgICovXG4gICAgcHJpdmF0ZSBfY2xlYW5TZXJ2ZXJTdGF0ZSgpOiB2b2lkIHtcbiAgICAgICAgbWVyZ2UoXG4gICAgICAgICAgICB0aGlzLl9nZXRMYXN0SWQoZmFsc2UpXG4gICAgICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgIHRhcCgoKSA9PiB0aGlzLl90cmFuc2ZlclN0YXRlLnJlbW92ZSh0aGlzLl9sYXN0SWRTdG9yZUtleSkpXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAg