UNPKG

@akanass/ng-universal-transfer-http

Version:

TransferHttpCacheModule installs a Http interceptor that avoids duplicate HttpClient requests on the client

797 lines 74.9 kB
/** * @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