@angular/fire
Version:
The official library for Firebase and Angular
480 lines • 42.5 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core';
import { concat, EMPTY, Observable, of, pipe } from 'rxjs';
import { debounceTime, distinctUntilChanged, filter, groupBy, map, mergeMap, observeOn, scan, shareReplay, startWith, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { FIREBASE_APP_NAME, FIREBASE_OPTIONS, ɵAngularFireSchedulers, ɵfirebaseAppFactory, ɵkeepUnstableUntilFirstFactory, ɵlazySDKProxy } from '@angular/fire';
import { remoteConfig } from 'firebase/app';
import { isPlatformBrowser } from '@angular/common';
import * as i0 from "@angular/core";
import * as i1 from "@angular/fire";
/**
* @record
*/
export function ConfigTemplate() { }
/** @type {?} */
export const SETTINGS = new InjectionToken('angularfire2.remoteConfig.settings');
/** @type {?} */
export const DEFAULTS = new InjectionToken('angularfire2.remoteConfig.defaultConfig');
// WARNING: interface has both a type and a value, skipping emit
/** @type {?} */
const AS_TO_FN = { strings: 'asString', numbers: 'asNumber', booleans: 'asBoolean' };
/** @type {?} */
const STATIC_VALUES = { numbers: 0, booleans: false, strings: undefined };
// TODO look into the types here, I don't like the anys
/** @type {?} */
const proxyAll = (/**
* @param {?} observable
* @param {?} as
* @return {?}
*/
(observable, as) => (/** @type {?} */ (new Proxy(observable.pipe(mapToObject((/** @type {?} */ (as)))), {
get: (/**
* @param {?} self
* @param {?} name
* @return {?}
*/
(self, name) => self[name] || observable.pipe(map((/**
* @param {?} all
* @return {?}
*/
all => all.find((/**
* @param {?} p
* @return {?}
*/
p => p.key === name)))), map((/**
* @param {?} param
* @return {?}
*/
param => param ? param[AS_TO_FN[as]]() : STATIC_VALUES[as])), distinctUntilChanged()))
}))));
const ɵ0 = proxyAll;
// TODO export as implements Partial<...> so minor doesn't break us
export class Value {
// tslint:disable-next-line:variable-name
/**
* @param {?} _source
* @param {?} _value
*/
constructor(_source, _value) {
this._source = _source;
this._value = _value;
}
/**
* @return {?}
*/
asBoolean() {
return ['1', 'true', 't', 'y', 'yes', 'on'].indexOf(this._value.toLowerCase()) > -1;
}
/**
* @return {?}
*/
asString() {
return this._value;
}
/**
* @return {?}
*/
asNumber() {
return Number(this._value) || 0;
}
/**
* @return {?}
*/
getSource() {
return this._source;
}
}
if (false) {
/** @type {?} */
Value.prototype._source;
/** @type {?} */
Value.prototype._value;
}
// SEMVER use ConstructorParameters when we can support Typescript 3.6
export class Parameter extends Value {
/**
* @param {?} key
* @param {?} fetchTimeMillis
* @param {?} source
* @param {?} value
*/
constructor(key, fetchTimeMillis, source, value) {
super(source, value);
this.key = key;
this.fetchTimeMillis = fetchTimeMillis;
}
}
if (false) {
/** @type {?} */
Parameter.prototype.key;
/** @type {?} */
Parameter.prototype.fetchTimeMillis;
}
// If it's a Parameter array, test any, else test the individual Parameter
/** @type {?} */
const filterTest = (/**
* @param {?} fn
* @return {?}
*/
(fn) => filter((/**
* @param {?} it
* @return {?}
*/
it => Array.isArray(it) ? it.some(fn) : fn(it))));
const ɵ1 = filterTest;
// Allow the user to bypass the default values and wait till they get something from the server, even if it's a cached copy;
// if used in conjuntion with first() it will only fetch RC values from the server if they aren't cached locally
/** @type {?} */
export const filterRemote = (/**
* @return {?}
*/
() => filterTest((/**
* @param {?} p
* @return {?}
*/
p => p.getSource() === 'remote')));
// filterFresh allows the developer to effectively set up a maximum cache time
/** @type {?} */
export const filterFresh = (/**
* @param {?} howRecentInMillis
* @return {?}
*/
(howRecentInMillis) => filterTest((/**
* @param {?} p
* @return {?}
*/
p => p.fetchTimeMillis + howRecentInMillis >= new Date().getTime())));
// I ditched loading the defaults into RC and a simple map for scan since we already have our own defaults implementation.
// The idea here being that if they have a default that never loads from the server, they will be able to tell via fetchTimeMillis
// on the Parameter. Also if it doesn't come from the server it won't emit again in .changes, due to the distinctUntilChanged,
// which we can simplify to === rather than deep comparison
/** @type {?} */
const scanToParametersArray = (/**
* @param {?} remoteConfig
* @return {?}
*/
(remoteConfig) => pipe(withLatestFrom(remoteConfig), scan((/**
* @param {?} existing
* @param {?} __1
* @return {?}
*/
(existing, [all, rc]) => {
// SEMVER use "new Set" to unique once we're only targeting es6
// at the scale we expect remote config to be at, we probably won't see a performance hit from this unoptimized uniqueness
// implementation.
// const allKeys = [...new Set([...existing.map(p => p.key), ...Object.keys(all)])];
/** @type {?} */
const allKeys = [...existing.map((/**
* @param {?} p
* @return {?}
*/
p => p.key)), ...Object.keys(all)].filter((/**
* @param {?} v
* @param {?} i
* @param {?} a
* @return {?}
*/
(v, i, a) => a.indexOf(v) === i));
return allKeys.map((/**
* @param {?} key
* @return {?}
*/
key => {
/** @type {?} */
const updatedValue = all[key];
return updatedValue ? new Parameter(key, rc ? rc.fetchTimeMillis : -1, updatedValue.getSource(), updatedValue.asString())
: existing.find((/**
* @param {?} p
* @return {?}
*/
p => p.key === key));
}));
}), (/** @type {?} */ ([])))));
const ɵ2 = scanToParametersArray;
export class AngularFireRemoteConfig {
/**
* @param {?} options
* @param {?} nameOrConfig
* @param {?} settings
* @param {?} defaultConfig
* @param {?} zone
* @param {?} platformId
*/
constructor(options, nameOrConfig, settings, defaultConfig, zone,
// tslint:disable-next-line:ban-types
platformId) {
this.zone = zone;
/** @type {?} */
const schedulers = new ɵAngularFireSchedulers(zone);
/** @type {?} */
const remoteConfig$ = of(undefined).pipe(observeOn(schedulers.outsideAngular), switchMap((/**
* @return {?}
*/
() => isPlatformBrowser(platformId) ? import('firebase/remote-config') : EMPTY)), map((/**
* @return {?}
*/
() => ɵfirebaseAppFactory(options, zone, nameOrConfig))), map((/**
* @param {?} app
* @return {?}
*/
app => app.remoteConfig())), tap((/**
* @param {?} rc
* @return {?}
*/
rc => {
if (settings) {
rc.settings = settings;
}
if (defaultConfig) {
rc.defaultConfig = defaultConfig;
}
})),
// tslint:disable-next-line
startWith(undefined), shareReplay({ bufferSize: 1, refCount: false }));
/** @type {?} */
const loadedRemoteConfig$ = remoteConfig$.pipe(filter((/**
* @param {?} rc
* @return {?}
*/
rc => !!rc)));
/** @type {?} */
const default$ = of(Object.keys(defaultConfig || {}).reduce((/**
* @param {?} c
* @param {?} k
* @return {?}
*/
(c, k) => (Object.assign(Object.assign({}, c), { [k]: new Value('default', defaultConfig[k].toString()) }))), {}));
// we should filter out the defaults we provided to RC, since we have our own implementation
// that gives us a -1 for fetchTimeMillis (so filterFresh can filter them out)
/** @type {?} */
const filterOutDefaults = map((/**
* @param {?} all
* @return {?}
*/
all => Object.keys(all)
.filter((/**
* @param {?} key
* @return {?}
*/
key => all[key].getSource() !== 'default'))
.reduce((/**
* @param {?} acc
* @param {?} key
* @return {?}
*/
(acc, key) => (Object.assign(Object.assign({}, acc), { [key]: all[key] }))), {})));
/** @type {?} */
const existing$ = loadedRemoteConfig$.pipe(switchMap((/**
* @param {?} rc
* @return {?}
*/
rc => rc.activate()
.then((/**
* @return {?}
*/
() => rc.ensureInitialized()))
.then((/**
* @return {?}
*/
() => rc.getAll())))), filterOutDefaults);
/** @type {?} */
const fresh$ = loadedRemoteConfig$.pipe(switchMap((/**
* @param {?} rc
* @return {?}
*/
rc => zone.runOutsideAngular((/**
* @return {?}
*/
() => rc.fetchAndActivate()
.then((/**
* @return {?}
*/
() => rc.ensureInitialized()))
.then((/**
* @return {?}
*/
() => rc.getAll())))))), filterOutDefaults);
this.parameters = concat(default$, existing$, fresh$).pipe(scanToParametersArray(remoteConfig$), ɵkeepUnstableUntilFirstFactory(schedulers), shareReplay({ bufferSize: 1, refCount: true }));
this.changes = this.parameters.pipe(switchMap((/**
* @param {?} params
* @return {?}
*/
params => of(...params))), groupBy((/**
* @param {?} param
* @return {?}
*/
param => param.key)), mergeMap((/**
* @param {?} group
* @return {?}
*/
group => group.pipe(distinctUntilChanged()))));
this.strings = proxyAll(this.parameters, 'strings');
this.booleans = proxyAll(this.parameters, 'booleans');
this.numbers = proxyAll(this.parameters, 'numbers');
return ɵlazySDKProxy(this, loadedRemoteConfig$, zone);
}
}
AngularFireRemoteConfig.decorators = [
{ type: Injectable, args: [{
providedIn: 'any'
},] }
];
/** @nocollapse */
AngularFireRemoteConfig.ctorParameters = () => [
{ type: undefined, decorators: [{ type: Inject, args: [FIREBASE_OPTIONS,] }] },
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [FIREBASE_APP_NAME,] }] },
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [SETTINGS,] }] },
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DEFAULTS,] }] },
{ type: NgZone },
{ type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
];
/** @nocollapse */ AngularFireRemoteConfig.ɵprov = i0.ɵɵdefineInjectable({ factory: function AngularFireRemoteConfig_Factory() { return new AngularFireRemoteConfig(i0.ɵɵinject(i1.FIREBASE_OPTIONS), i0.ɵɵinject(i1.FIREBASE_APP_NAME, 8), i0.ɵɵinject(SETTINGS, 8), i0.ɵɵinject(DEFAULTS, 8), i0.ɵɵinject(i0.NgZone), i0.ɵɵinject(i0.PLATFORM_ID)); }, token: AngularFireRemoteConfig, providedIn: "any" });
if (false) {
/** @type {?} */
AngularFireRemoteConfig.prototype.changes;
/** @type {?} */
AngularFireRemoteConfig.prototype.parameters;
/** @type {?} */
AngularFireRemoteConfig.prototype.numbers;
/** @type {?} */
AngularFireRemoteConfig.prototype.booleans;
/** @type {?} */
AngularFireRemoteConfig.prototype.strings;
/**
* @type {?}
* @private
*/
AngularFireRemoteConfig.prototype.zone;
}
/** @type {?} */
export const budget = (/**
* @template T
* @param {?} interval
* @return {?}
*/
(interval) => (/**
* @param {?} source
* @return {?}
*/
(source) => new Observable((/**
* @param {?} observer
* @return {?}
*/
observer => {
/** @type {?} */
let timedOut = false;
// TODO use scheduler task rather than settimeout
/** @type {?} */
const timeout = setTimeout((/**
* @return {?}
*/
() => {
observer.complete();
timedOut = true;
}), interval);
return source.subscribe({
/**
* @param {?} val
* @return {?}
*/
next(val) {
if (!timedOut) {
observer.next(val);
}
},
/**
* @param {?} err
* @return {?}
*/
error(err) {
if (!timedOut) {
clearTimeout(timeout);
observer.error(err);
}
},
/**
* @return {?}
*/
complete() {
if (!timedOut) {
clearTimeout(timeout);
observer.complete();
}
}
});
}))));
/** @type {?} */
const typedMethod = (/**
* @param {?} it
* @return {?}
*/
(it) => {
switch (typeof it) {
case 'string':
return 'asString';
case 'boolean':
return 'asBoolean';
case 'number':
return 'asNumber';
default:
return 'asString';
}
});
const ɵ3 = typedMethod;
/**
* @template T
* @param {?=} to
* @return {?}
*/
export function scanToObject(to = 'strings') {
return pipe(
// TODO cleanup
scan((/**
* @param {?} c
* @param {?} p
* @return {?}
*/
(c, p) => (Object.assign(Object.assign({}, c), { [p.key]: typeof to === 'object' ?
p[typedMethod(to[p.key])]() :
p[AS_TO_FN[to]]() }))), typeof to === 'object' ?
(/** @type {?} */ (to)) :
(/** @type {?} */ ({}))), debounceTime(1), budget(10), distinctUntilChanged((/**
* @param {?} a
* @param {?} b
* @return {?}
*/
(a, b) => JSON.stringify(a) === JSON.stringify(b))));
}
/**
* @template T
* @param {?=} to
* @return {?}
*/
export function mapToObject(to = 'strings') {
return pipe(
// TODO this is getting a little long, cleanup
map((/**
* @param {?} params
* @return {?}
*/
(params) => params.reduce((/**
* @param {?} c
* @param {?} p
* @return {?}
*/
(c, p) => (Object.assign(Object.assign({}, c), { [p.key]: typeof to === 'object' ?
p[typedMethod(to[p.key])]() :
p[AS_TO_FN[to]]() }))), typeof to === 'object' ?
(/** @type {?} */ (to)) :
(/** @type {?} */ ({}))))), distinctUntilChanged((/**
* @param {?} a
* @param {?} b
* @return {?}
*/
(a, b) => JSON.stringify(a) === JSON.stringify(b))));
}
export { ɵ0, ɵ1, ɵ2, ɵ3 };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVtb3RlLWNvbmZpZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9yZW1vdGUtY29uZmlnL3JlbW90ZS1jb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNsRyxPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBNEIsVUFBVSxFQUFFLEVBQUUsRUFBb0IsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3ZHLE9BQU8sRUFDTCxZQUFZLEVBQ1osb0JBQW9CLEVBQ3BCLE1BQU0sRUFDTixPQUFPLEVBQ1AsR0FBRyxFQUNILFFBQVEsRUFDUixTQUFTLEVBQ1QsSUFBSSxFQUNKLFdBQVcsRUFDWCxTQUFTLEVBQ1QsU0FBUyxFQUNULEdBQUcsRUFDSCxjQUFjLEVBQ2YsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLGdCQUFnQixFQUdoQixzQkFBc0IsRUFDdEIsbUJBQW1CLEVBQ25CLDhCQUE4QixFQUM5QixhQUFhLEVBRWQsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUM1QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7Ozs7O0FBRXBELG9DQUVDOztBQUVELE1BQU0sT0FBTyxRQUFRLEdBQUcsSUFBSSxjQUFjLENBQXdCLG9DQUFvQyxDQUFDOztBQUN2RyxNQUFNLE9BQU8sUUFBUSxHQUFHLElBQUksY0FBYyxDQUFpQix5Q0FBeUMsQ0FBQzs7O01BSy9GLFFBQVEsR0FBRyxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFOztNQUM5RSxhQUFhLEdBQUcs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UyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQ3hFLENBQUM7QUFDSixDQUFDOzs7Ozs7QUFTRCxNQUFNLFVBQVUsV0FBVyxDQUEyQixLQUE2QyxTQUFTO0lBQzFHLE9BQU8sSUFBSTtJQUNULDhDQUE4QztJQUM5QyxHQUFHOzs7O0lBQUMsQ0FBQyxNQUFtQixFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTTs7Ozs7SUFDeEMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxpQ0FDTCxDQUFDLEtBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsT0FBTyxFQUFFLEtBQUssUUFBUSxDQUFDLENBQUM7WUFDckMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDN0IsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLElBQ25CLEdBQ0YsT0FBTyxFQUFFLEtBQUssUUFBUSxDQUFDLENBQUM7UUFDdEIsbUJBQUEsRUFBRSxFQUE2QyxDQUFDLENBQUM7UUFDakQsbUJBQUEsRUFBRSxFQUFnRCxDQUNyRCxFQUFDLEVBQ0Ysb0JBQW9COzs7OztJQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQ3hFLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0LCBJbmplY3RhYmxlLCBJbmplY3Rpb25Ub2tlbiwgTmdab25lLCBPcHRpb25hbCwgUExBVEZPUk1fSUQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IGNvbmNhdCwgRU1QVFksIE1vbm9UeXBlT3BlcmF0b3JGdW5jdGlvbiwgT2JzZXJ2YWJsZSwgb2YsIE9wZXJhdG9yRnVuY3Rpb24sIHBpcGUgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7XG4gIGRlYm91bmNlVGltZSxcbiAgZGlzdGluY3RVbnRpbENoYW5nZWQsXG4gIGZpbHRlcixcbiAgZ3JvdXBCeSxcbiAgbWFwLFxuICBtZXJnZU1hcCxcbiAgb2JzZXJ2ZU9uLFxuICBzY2FuLFxuICBzaGFyZVJlcGxheSxcbiAgc3RhcnRXaXRoLFxuICBzd2l0Y2hNYXAsXG4gIHRhcCxcbiAgd2l0aExhdGVzdEZyb21cbn0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHtcbiAgRklSRUJBU0VfQVBQX05BTUUsXG4gIEZJUkVCQVNFX09QVElPTlMsXG4gIEZpcmViYXNlQXBwQ29uZmlnLFxuICBGaXJlYmFzZU9wdGlvbnMsXG4gIMm1QW5ndWxhckZpcmVTY2hlZHVsZXJzLFxuICDJtWZpcmViYXNlQXBwRmFjdG9yeSxcbiAgybVrZWVwVW5zdGFibGVVbnRpbEZpcnN0RmFjdG9yeSxcbiAgybVsYXp5U0RLUHJveHksXG4gIMm1UHJvbWlzZVByb3h5XG59IGZyb20gJ0Bhbmd1bGFyL2ZpcmUnO1xuaW1wb3J0IHsgcmVtb3RlQ29uZmlnIH0gZnJvbSAnZmlyZWJhc2UvYXBwJztcbmltcG9ydCB7IGlzUGxhdGZvcm1Ccm93c2VyIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcblxuZXhwb3J0IGludGVyZmFjZSBDb25maWdUZW1wbGF0ZSB7XG4gIFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjb25zdCBTRVRUSU5HUyA9IG5ldyBJbmplY3Rpb25Ub2tlbjxyZW1vdGVDb25maWcuU2V0dGluZ3M+KCdhbmd1bGFyZmlyZTIucmVtb3RlQ29uZmlnLnNldHRpbmdzJyk7XG5leHBvcnQgY29uc3QgREVGQVVMVFMgPSBuZXcgSW5qZWN0aW9uVG9rZW48Q29uZmlnVGVtcGxhdGU+KCdhbmd1bGFyZmlyZTIucmVtb3RlQ29uZmlnLmRlZmF1bHRDb25maWcnKTtcblxuZXhwb3J0IGludGVyZmFjZSBBbmd1bGFyRmlyZVJlbW90ZUNvbmZpZyBleHRlbmRzIMm1UHJvbWlzZVByb3h5PHJlbW90ZUNvbmZpZy5SZW1vdGVDb25maWc+IHtcbn1cblxuY29uc3QgQVNfVE9fRk4gPSB7IHN0cmluZ3M6ICdhc1N0cmluZycsIG51bWJlcnM6ICdhc051bWJlcicsIGJvb2xlYW5zOiAnYXNCb29sZWFuJyB9O1xuY29uc3QgU1RBVElDX1ZBTFVFUyA9IHsgbnVtYmVyczogMCwgYm9vbGVhbnM6IGZhbHNlLCBzdHJpbmdzOiB1bmRlZmluZWQgfTtcblxuLy8gVE9ETyBsb29rIGludG8gdGhlIHR5cGVzIGhlcmUsIEkgZG9uJ3QgbGlrZSB0aGUgYW55c1xuY29uc3QgcHJveHlBbGwgPSAob2JzZXJ2YWJsZTogT2JzZXJ2YWJsZTxQYXJhbWV0ZXJbXT4sIGFzOiAnbnVtYmVycycgfCAnYm9vbGVhbnMnIHwgJ3N0cmluZ3MnKSA9PiBuZXcgUHJveHkoXG4gIG9ic2VydmFibGUucGlwZShtYXBUb09iamVjdChhcyBhcyBhbnkpKSwge1xuICAgIGdldDogKHNlbGYsIG5hbWU6IHN0cmluZykgPT4gc2VsZltuYW1lXSB8fCBvYnNlcnZhYmxlLnBpcGUoXG4gICAgICBtYXAoYWxsID0+IGFsbC5maW5kKHAgPT4gcC5rZXkgPT09IG5hbWUpKSxcbiAgICAgIG1hcChwYXJhbSA9PiBwYXJhbSA/IHBhcmFtW0FTX1RPX0ZOW2FzXV0oKSA6IFNUQVRJQ19WQUxVRVNbYXNdKSxcbiAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKClcbiAgICApXG4gIH1cbikgYXMgYW55O1xuXG4vLyBUT0RPIGV4cG9ydCBhcyBpbXBsZW1lbnRzIFBhcnRpYWw8Li4uPiBzbyBtaW5vciBkb2Vzbid0IGJyZWFrIHVzXG5leHBvcnQgY2xhc3MgVmFsdWUgaW1wbGVtZW50cyByZW1vdGVDb25maWcuVmFsdWUge1xuICBhc0Jvb2xlYW4oKSB7XG4gICAgcmV0dXJuIFsnMScsICd0cnVlJywgJ3QnLCAneScsICd5ZXMnLCAnb24nXS5pbmRleE9mKHRoaXMuX3ZhbHVlLnRvTG93ZXJDYXNlKCkpID4gLTE7XG4gIH1cblxuICBhc1N0cmluZygpIHtcbiAgICByZXR1cm4gdGhpcy5fdmFsdWU7XG4gIH1cblxuICBhc051bWJlcigpIHtcbiAgICByZXR1cm4gTnVtYmVyKHRoaXMuX3ZhbHVlKSB8fCAwO1xuICB9XG5cbiAgZ2V0U291cmNlKCkge1xuICAgIHJldHVybiB0aGlzLl9zb3VyY2U7XG4gIH1cblxuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6dmFyaWFibGUtbmFtZVxuICBjb25zdHJ1Y3RvcihwdWJsaWMgX3NvdXJjZTogcmVtb3RlQ29uZmlnLlZhbHVlU291cmNlLCBwdWJsaWMgX3ZhbHVlOiBzdHJpbmcpIHtcbiAgfVxufVxuXG4vLyBTRU1WRVIgdXNlIENvbnN0cnVjdG9yUGFyYW1ldGVycyB3aGVuIHdlIGNhbiBzdXBwb3J0IFR5cGVzY3JpcHQgMy42XG5leHBvcnQgY2xhc3MgUGFyYW1ldGVyIGV4dGVuZHMgVmFsdWUge1xuICBjb25zdHJ1Y3RvcihwdWJsaWMga2V5OiBzdHJpbmcsIHB1YmxpYyBmZXRjaFRpbWVNaWxsaXM6IG51bWJlciwgc291cmNlOiByZW1vdGVDb25maWcuVmFsdWVTb3VyY2UsIHZhbHVlOiBzdHJpbmcpIHtcbiAgICBzdXBlcihzb3VyY2UsIHZhbHVlKTtcbiAgfVxufVxuXG4vLyBJZiBpdCdzIGEgUGFyYW1ldGVyIGFycmF5LCB0ZXN0IGFueSwgZWxzZSB0ZXN0IHRoZSBpbmRpdmlkdWFsIFBhcmFtZXRlclxuY29uc3QgZmlsdGVyVGVzdCA9IChmbjogKHBhcmFtOiBQYXJhbWV0ZXIpID0+IGJvb2xlYW4pID0+IGZpbHRlcjxQYXJhbWV0ZXIgfCBQYXJhbWV0ZXJbXT4oaXQgPT4gQXJyYXkuaXNBcnJheShpdCkgPyBpdC5zb21lKGZuKSA6IGZuKGl0KSk7XG5cbi8vIEFsbG93IHRoZSB1c2VyIHRvIGJ5cGFzcyB0aGUgZGVmYXVsdCB2YWx1ZXMgYW5kIHdhaXQgdGlsbCB0aGV5IGdldCBzb21ldGhpbmcgZnJvbSB0aGUgc2VydmVyLCBldmVuIGlmIGl0J3MgYSBjYWNoZWQgY29weTtcbi8vIGlmIHVzZWQgaW4gY29uanVudGlvbiB3aXRoIGZpcnN0KCkgaXQgd2lsbCBvbmx5IGZldGNoIFJDIHZhbHVlcyBmcm9tIHRoZSBzZXJ2ZXIgaWYgdGhleSBhcmVuJ3QgY2FjaGVkIGxvY2FsbHlcbmV4cG9ydCBjb25zdCBmaWx0ZXJSZW1vdGUgPSAoKSA9PiBmaWx0ZXJUZXN0KHAgPT4gcC5nZXRTb3VyY2UoKSA9PT0gJ3JlbW90ZScpO1xuXG4vLyBmaWx0ZXJGcmVzaCBhbGxvd3MgdGhlIGRldmVsb3BlciB0byBlZmZlY3RpdmVseSBzZXQgdXAgYSBtYXhpbXVtIGNhY2hlIHRpbWVcbmV4cG9ydCBjb25zdCBmaWx0ZXJGcmVzaCA9IChob3dSZWNlbnRJbk1pbGxpczogbnVtYmVyKSA9PiBmaWx0ZXJUZXN0KHAgPT4gcC5mZXRjaFRpbWVNaWxsaXMgKyBob3dSZWNlbnRJbk1pbGxpcyA+PSBuZXcgRGF0ZSgpLmdldFRpbWUoKSk7XG5cblxuLy8gSSBkaXRjaGVkIGxvYWRpbmcgdGhlIGRlZmF1bHRzIGludG8gUkMgYW5kIGEgc2ltcGxlIG1hcCBmb3Igc2NhbiBzaW5jZSB3ZSBhbHJlYWR5IGhhdmUgb3VyIG93biBkZWZhdWx0cyBpbXBsZW1lbnRhdGlvbi5cbi8vIFRoZSBpZGVhIGhlcmUgYmVpbmcgdGhhdCBpZiB0aGV5IGhhdmUgYSBkZWZhdWx0IHRoYXQgbmV2ZXIgbG9hZHMgZnJvbSB0aGUgc2VydmVyLCB0aGV5IHdpbGwgYmUgYWJsZSB0byB0ZWxsIHZpYSBmZXRjaFRpbWVNaWxsaXNcbi8vIG9uIHRoZSBQYXJhbWV0ZXIuIEFsc28gaWYgaXQgZG9lc24ndCBjb21lIGZyb20gdGhlIHNlcnZlciBpdCB3b24ndCBlbWl0IGFnYWluIGluIC5jaGFuZ2VzLCBkdWUgdG8gdGhlIGRpc3RpbmN0VW50aWxDaGFuZ2VkLFxuLy8gd2hpY2ggd2UgY2FuIHNpbXBsaWZ5IHRvID09PSByYXRoZXIgdGhhbiBkZWVwIGNvbXBhcmlzb25cbmNvbnN0IHNjYW5Ub1BhcmFtZXRlcnNBcnJheSA9IChcbiAgcmVtb3RlQ29uZmlnOiBPYnNlcnZhYmxlPHJlbW90ZUNvbmZpZy5SZW1vdGVDb25maWcgfCB1bmRlZmluZWQ+XG4pOiBPcGVyYXRvckZ1bmN0aW9uPHsgW2tleTogc3RyaW5nXTogcmVtb3RlQ29uZmlnLlZhbHVlIH0sIFBhcmFtZXRlcltdPiA9PiBwaXBlKFxuICB3aXRoTGF0ZXN0RnJvbShyZW1vdGVDb25maWcpLFxuICBzY2FuKChleGlzdGluZywgW2FsbCwgcmNdKSA9PiB7XG4gICAgLy8gU0VNVkVSIHVzZSBcIm5ldyBTZXRcIiB0byB1bmlxdWUgb25jZSB3ZSdyZSBvbmx5IHRhcmdldGluZyBlczZcbiAgICAvLyBhdCB0aGUgc2NhbGUgd2UgZXhwZWN0IHJlbW90ZSBjb25maWcgdG8gYmUgYXQsIHdlIHByb2JhYmx5IHdvbid0IHNlZSBhIHBlcmZvcm1hbmNlIGhpdCBmcm9tIHRoaXMgdW5vcHRpbWl6ZWQgdW5pcXVlbmVzc1xuICAgIC8vIGltcGxlbWVudGF0aW9uLlxuICAgIC8vIGNvbnN0IGFsbEtleXMgPSBbLi4ubmV3IFNldChbLi4uZXhpc3RpbmcubWFwKHAgPT4gcC5rZXkpLCAuLi5PYmplY3Qua2V5cyhhbGwpXSldO1xuICAgIGNvbnN0IGFsbEtleXMgPSBbLi4uZXhpc3RpbmcubWFwKHAgPT4gcC5rZXkpLCAuLi5PYmplY3Qua2V5cyhhbGwpXS5maWx0ZXIoKHYsIGksIGEpID0+IGEuaW5kZXhPZih2KSA9PT0gaSk7XG4gICAgcmV0dXJuIGFsbEtleXMubWFwKGtleSA9PiB7XG4gICAgICBjb25zdCB1cGRhdGVkVmFsdWUgPSBhbGxba2V5XTtcbiAgICAgIHJldHVybiB1cGRhdGVkVmFsdWUgPyBuZXcgUGFyYW1ldGVyKGtleSwgcmMgPyByYy5mZXRjaFRpbWVNaWxsaXMgOiAtMSwgdXBkYXRlZFZhbHVlLmdldFNvdXJjZSgpLCB1cGRhdGVkVmFsdWUuYXNTdHJpbmcoKSlcbiAgICAgICAgOiBleGlzdGluZy5maW5kKHAgPT4gcC5rZXkgPT09IGtleSk7XG4gICAgfSk7XG4gIH0sIFtdIGFzIEFycmF5PFBhcmFtZXRlcj4pXG4pO1xuXG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ2FueSdcbn0pXG5leHBvcnQgY2xhc3MgQW5ndWxhckZpcmVSZW1vdGVDb25maWcge1xuXG4gIHJlYWRvbmx5IGNoYW5nZXM6IE9ic2VydmFibGU8UGFyYW1ldGVyPjtcbiAgcmVhZG9ubHkgcGFyYW1ldGVyczogT2JzZXJ2YWJsZTxQYXJhbWV0ZXJbXT47XG4gIHJlYWRvbmx5IG51bWJlcnM6IE9ic2VydmFibGU8eyBba2V5OiBzdHJpbmddOiBudW1iZXIgfCB1bmRlZmluZWQgfT4gJiB7IFtrZXk6IHN0cmluZ106IE9ic2VydmFibGU8bnVtYmVyPiB9O1xuICByZWFkb25seSBib29sZWFuczogT2JzZXJ2YWJsZTx7IFtrZXk6IHN0cmluZ106IGJvb2xlYW4gfCB1bmRlZmluZWQgfT4gJiB7IFtrZXk6IHN0cmluZ106IE9ic2VydmFibGU8Ym9vbGVhbj4gfTtcbiAgcmVhZG9ubHkgc3RyaW5nczogT2JzZXJ2YWJsZTx7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9PiAmIHsgW2tleTogc3RyaW5nXTogT2JzZXJ2YWJsZTxzdHJpbmcgfCB1bmRlZmluZWQ+IH07XG5cbiAgY29uc3RydWN0b3IoXG4gICAgQEluamVjdChGSVJFQkFTRV9PUFRJT05TKSBvcHRpb25zOiBGaXJlYmFzZU9wdGlvbnMsXG4gICAgQE9wdGlvbmFsKCkgQEluamVjdChGSVJFQkFTRV9BUFBfTkFNRSkgbmFtZU9yQ29uZmlnOiBzdHJpbmcgfCBGaXJlYmFzZUFwcENvbmZpZyB8IG51bGwgfCB1bmRlZmluZWQsXG4gICAgQE9wdGlvbmFsKCkgQEluamVjdChTRVRUSU5HUykgc2V0dGluZ3M6IHJlbW90ZUNvbmZpZy5TZXR0aW5ncyB8IG51bGwsXG4gICAgQE9wdGlvbmFsKCkgQEluamVjdChERUZBVUxUUykgZGVmYXVsdENvbmZpZzogQ29uZmlnVGVtcGxhdGUgfCBudWxsLFxuICAgIHByaXZhdGUgem9uZTogTmdab25lLFxuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpiYW4tdHlwZXNcbiAgICBASW5qZWN0KFBMQVRGT1JNX0lEKSBwbGF0Zm9ybUlkOiBPYmplY3RcbiAgKSB7XG5cbiAgICBjb25zdCBzY2hlZHVsZXJzID0gbmV3IMm1QW5ndWxhckZpcmVTY2hlZHVsZXJzKHpvbmUpO1xuXG4gICAgY29uc3QgcmVtb3RlQ29uZmlnJCA9IG9mKHVuZGVmaW5lZCkucGlwZShcbiAgICAgIG9ic2VydmVPbihzY2hlZHVsZXJzLm91dHNpZGVBbmd1bGFyKSxcbiAgICAgIHN3aXRjaE1hcCgoKSA9PiBpc1BsYXRmb3JtQnJvd3NlcihwbGF0Zm9ybUlkKSA/IGltcG9ydCgnZmlyZWJhc2UvcmVtb3RlLWNvbmZpZycpIDogRU1QVFkpLFxuICAgICAgbWFwKCgpID0+IMm1ZmlyZWJhc2VBcHBGYWN0b3J5KG9wdGlvbnMsIHpvbmUsIG5hbWVPckNvbmZpZykpLFxuICAgICAgbWFwKGFwcCA9PiBhcHAucmVtb3RlQ29uZmlnKCkpLFxuICAgICAgdGFwKHJjID0+IHtcbiAgICAgICAgaWYgKHNldHRpbmdzKSB7XG4gICAgICAgICAgcmMuc2V0dGluZ3MgPSBzZXR0aW5ncztcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGVmYXVsdENvbmZpZykge1xuICAgICAgICAgIHJjLmRlZmF1bHRDb25maWcgPSBkZWZhdWx0Q29uZmlnO1xuICAgICAgICB9XG4gICAgICB9KSxcbiAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZVxuICAgICAgc3RhcnRXaXRoKHVuZGVmaW5lZCksXG4gICAgICBzaGFyZVJlcGxheSh7IGJ1ZmZlclNpemU6IDEsIHJlZkNvdW50OiBmYWxzZSB9KVxuICAgICk7XG5cbiAgICBjb25zdCBsb2FkZWRSZW1vdGVDb25maWckID0gcmVtb3RlQ29uZmlnJC5waXBlKFxuICAgICAgZmlsdGVyPHJlbW90ZUNvbmZpZy5SZW1vdGVDb25maWc+KHJjID0+ICEhcmMpXG4gICAgKTtcblxuICAgIGNvbnN0IGRlZmF1bHQkOiBPYnNlcnZhYmxlPHsgW2tleTogc3RyaW5nXTogcmVtb3RlQ29uZmlnLlZhbHVlIH0+ID0gb2YoT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZyB8fCB7fSkucmVkdWNlKFxuICAgICAgKGMsIGspID0+ICh7IC4uLmMsIFtrXTogbmV3IFZhbHVlKCdkZWZhdWx0JywgZGVmYXVsdENvbmZpZ1trXS50b1N0cmluZygpKSB9KSwge31cbiAgICApKTtcblxuICAgIC8vIHdlIHNob3VsZCBmaWx0ZXIgb3V0IHRoZSBkZWZhdWx0cyB3ZSBwcm92aWRlZCB0byBSQywgc2luY2Ugd2UgaGF2ZSBvdXIgb3duIGltcGxlbWVudGF0aW9uXG4gICAgLy8gdGhhdCBnaXZlcyB1cyBhIC0xIGZvciBmZXRjaFRpbWVNaWxsaXMgKHNvIGZpbHRlckZyZXNoIGNhbiBmaWx0ZXIgdGhlbSBvdXQpXG4gICAgY29uc3QgZmlsdGVyT3V0RGVmYXVsdHMgPSBtYXA8eyBba2V5OiBzdHJpbmddOiByZW1vdGVDb25maWcuVmFsdWUgfSwgeyBba2V5OiBzdHJpbmddOiByZW1vdGVDb25maWcuVmFsdWUgfT4oYWxsID0+XG4gICAgICBPYmplY3Qua2V5cyhhbGwpXG4gICAgICAgIC5maWx0ZXIoa2V5ID0+IGFsbFtrZXldLmdldFNvdXJjZSgpICE9PSAnZGVmYXVsdCcpXG4gICAgICAgIC5yZWR1Y2UoKGFjYywga2V5KSA9PiAoeyAuLi5hY2MsIFtrZXldOiBhbGxba2V5XSB9KSwge30pXG4gICAgKTtcblxuICAgIGNvbnN0IGV4aXN0aW5nJCA9IGxvYWRlZFJlbW90ZUNvbmZpZyQucGlwZShcbiAgICAgIHN3aXRjaE1hcChyYyA9PlxuICAgICAgICByYy5hY3RpdmF0ZSgpXG4gICAgICAgICAgLnRoZW4oKCkgPT4gcmMuZW5zdXJlSW5pdGlhbGl6ZWQoKSlcbiAgICAgICAgICAudGhlbigoKSA9PiByYy5nZXRBbGwoKSlcbiAgICAgICksXG4gICAgICBmaWx0ZXJPdXREZWZhdWx0c1xuICAgICk7XG5cbiAgICBjb25zdCBmcmVzaCQgPSBsb2FkZWRSZW1vdGVDb25maWckLnBpcGUoXG4gICAgICBzd2l0Y2hNYXAocmMgPT4gem9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PlxuICAgICAgICByYy5mZXRjaEFuZEFjdGl2YXRlKClcbiAgICAgICAgICAudGhlbigoKSA9PiByYy5lbnN1cmVJbml0aWFsaXplZCgpKVxuICAgICAgICAgIC50aGVuKCgpID0+IHJjLmdldEFsbCgpKVxuICAgICAgKSksXG4gICAgICBmaWx0ZXJPdXREZWZhdWx0c1xuICAgICk7XG5cbiAgICB0aGlzLnBhcmFtZXRlcnMgPSBjb25jYXQoZGVmYXVsdCQsIGV4aXN0aW5nJCwgZnJlc2gkKS5waXBlKFxuICAgICAgc2NhblRvUGFyYW1ldGVyc0FycmF5KHJlbW90ZUNvbmZpZyQpLFxuICAgICAgybVrZWVwVW5zdGFibGVVbnRpbEZpcnN0RmFjdG9yeShzY2hlZHVsZXJzKSxcbiAgICAgIHNoYXJlUmVwbGF5KHsgYnVmZmVyU2l6ZTogMSwgcmVmQ291bnQ6IHRydWUgfSlcbiAgICApO1xuXG4gICAgdGhpcy5jaGFuZ2VzID0gdGhpcy5wYXJhbWV0ZXJzLnBpcGUoXG4gICAgICBzd2l0Y2hNYXAocGFyYW1zID0+IG9mKC4uLnBhcmFtcykpLFxuICAgICAgZ3JvdXBCeShwYXJhbSA9PiBwYXJhbS5rZXkpLFxuICAgICAgbWVyZ2VNYXAoZ3JvdXAgPT4gZ3JvdXAucGlwZShcbiAgICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKVxuICAgICAgKSlcbiAgICApO1xuXG4gICAgdGhpcy5zdHJpbmdzID0gcHJveHlBbGwodGhpcy5wYXJhbWV0ZXJzLCAnc3RyaW5ncycpO1xuICAgIHRoaXMuYm9vbGVhbnMgPSBwcm94eUFsbCh0aGlzLnBhcmFtZXRlcnMsICdib29sZWFucycpO1xuICAgIHRoaXMubnVtYmVycyA9IHByb3h5QWxsKHRoaXMucGFyYW1ldGVycywgJ251bWJlcnMnKTtcblxuICAgIHJldHVybiDJtWxhenlTREtQcm94eSh0aGlzLCBsb2FkZWRSZW1vdGVDb25maWckLCB6b25lKTtcbiAgfVxuXG59XG5cblxuZXhwb3J0IGNvbnN0IGJ1ZGdldCA9IDxUPihpbnRlcnZhbDogbnVtYmVyKTogTW9ub1R5cGVPcGVyYXRvckZ1bmN0aW9uPFQ+ID0+IChzb3VyY2U6IE9ic2VydmFibGU8VD4pID0+IG5ldyBPYnNlcnZhYmxlPFQ+KG9ic2VydmVyID0+IHtcbiAgbGV0IHRpbWVkT3V0ID0gZmFsc2U7XG4gIC8vIFRPRE8gdXNlIHNjaGVkdWxlciB0YXNrIHJhdGhlciB0aGFuIHNldHRpbWVvdXRcbiAgY29uc3QgdGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgIG9ic2VydmVyLmNvbXBsZXRlKCk7XG4gICAgdGltZWRPdXQgPSB0cnVlO1xuICB9LCBpbnRlcnZhbCk7XG4gIHJldHVybiBzb3VyY2Uuc3Vic2NyaWJlKHtcbiAgICBuZXh0KHZhbCkge1xuICAgICAgaWYgKCF0aW1lZE91dCkge1xuICAgICAgICBvYnNlcnZlci5uZXh0KHZhbCk7XG4gICAgICB9XG4gICAgfSxcbiAgICBlcnJvcihlcnIpIHtcbiAgICAgIGlmICghdGltZWRPdXQpIHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICBvYnNlcnZlci5lcnJvcihlcnIpO1xuICAgICAgfVxuICAgIH0sXG4gICAgY29tcGxldGUoKSB7XG4gICAgICBpZiAoIXRpbWVkT3V0KSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgb2JzZXJ2ZXIuY29tcGxldGUoKTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufSk7XG5cbmNvbnN0IHR5cGVkTWV0aG9kID0gKGl0OiBhbnkpID0+IHtcbiAgc3dpdGNoICh0eXBlb2YgaXQpIHtcbiAgICBjYXNlICdzdHJpbmcnOlxuICAgICAgcmV0dXJuICdhc1N0cmluZyc7XG4gICAgY2FzZSAnYm9vbGVhbic6XG4gICAgICByZXR1cm4gJ2FzQm9vbGVhbic7XG4gICAgY2FzZSAnbnVtYmVyJzpcbiAgICAgIHJldHVybiAnYXNOdW1iZXInO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gJ2FzU3RyaW5nJztcbiAgfVxufTtcblxuXG5leHBvcnQgZnVuY3Rpb24gc2NhblRvT2JqZWN0KCk6IE9wZXJhdG9yRnVuY3Rpb248UGFyYW1ldGVyLCB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9PjtcbmV4cG9ydCBmdW5jdGlvbiBzY2FuVG9PYmplY3QodG86ICdudW1iZXJzJyk6IE9wZXJhdG9yRnVuY3Rpb248UGFyYW1ldGVyLCB7IFtrZXk6IHN0cmluZ106IG51bWJlciB8IHVuZGVmaW5lZCB9PjtcbmV4cG9ydCBmdW5jdGlvbiBzY2FuVG9PYmplY3QodG86ICdib29sZWFucycpOiBPcGVyYXRvckZ1bmN0aW9uPFBhcmFtZXRlciwgeyBba2V5OiBzdHJpbmddOiBib29sZWFuIHwgdW5kZWZpbmVkIH0+O1xuLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOnVuaWZpZWQtc2lnbmF0dXJlc1xuZXhwb3J0IGZ1bmN0aW9uIHNjYW5Ub09iamVjdCh0bzogJ3N0cmluZ3MnKTogT3BlcmF0b3JGdW5jdGlvbjxQYXJhbWV0ZXIsIHsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgdW5kZWZpbmVkIH0+O1xuZXhwb3J0IGZ1bmN0aW9uIHNjYW5Ub09iamVjdDxUIGV4dGVuZHMgQ29uZmlnVGVtcGxhdGU+KHRlbXBsYXRlOiBUKTogT3BlcmF0b3JGdW5jdGlvbjxQYXJhbWV0ZXIsIFQgJiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9PjtcbmV4cG9ydCBmdW5jdGlvbiBzY2FuVG9PYmplY3Q8VCBleHRlbmRzIENvbmZpZ1RlbXBsYXRlPih0bzogJ251bWJlcnMnIHwgJ2Jvb2xlYW5zJyB8ICdzdHJpbmdzJyB8IFQgPSAnc3RyaW5ncycpIHtcbiAgcmV0dXJuIHBpcGUoXG4gICAgLy8gVE9ETyBjbGVhbnVwXG4gICAgc2NhbihcbiAgICAgIChjLCBwOiBQYXJhbWV0ZXIpID0+ICh7XG4gICAgICAgIC4uLmMsIFtwLmtleV06IHR5cGVvZiB0byA9PT0gJ29iamVjdCcgP1xuICAgICAgICAgIHBbdHlwZWRNZXRob2QodG9bcC5rZXldKV0oKSA6XG4gICAgICAgICAgcFtBU19UT19GTlt0b11dKClcbiAgICAgIH0pLFxuICAgICAgdHlwZW9mIHRvID09PSAnb2JqZWN0JyA/XG4gICAgICAgIHRvIGFzIFQgJiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9IDpcbiAgICAgICAge30gYXMgeyBba2V5OiBzdHJpbmddOiBudW1iZXIgfCBib29sZWFuIHwgc3RyaW5nIH1cbiAgICApLFxuICAgIGRlYm91bmNlVGltZSgxKSxcbiAgICBidWRnZXQoMTApLFxuICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKChhLCBiKSA9PiBKU09OLnN0cmluZ2lmeShhKSA9PT0gSlNPTi5zdHJpbmdpZnkoYikpXG4gICk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBtYXBUb09iamVjdCgpOiBPcGVyYXRvckZ1bmN0aW9uPFBhcmFtZXRlcltdLCB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9PjtcbmV4cG9ydCBmdW5jdGlvbiBtYXBUb09iamVjdCh0bzogJ251bWJlcnMnKTogT3BlcmF0b3JGdW5jdGlvbjxQYXJhbWV0ZXJbXSwgeyBba2V5OiBzdHJpbmddOiBudW1iZXIgfCB1bmRlZmluZWQgfT47XG5leHBvcnQgZnVuY3Rpb24gbWFwVG9PYmplY3QodG86ICdib29sZWFucycpOiBPcGVyYXRvckZ1bmN0aW9uPFBhcmFtZXRlcltdLCB7IFtrZXk6IHN0cmluZ106IGJvb2xlYW4gfCB1bmRlZmluZWQgfT47XG4vLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6dW5pZmllZC1zaWduYXR1cmVzXG5leHBvcnQgZnVuY3Rpb24gbWFwVG9PYmplY3QodG86ICdzdHJpbmdzJyk6IE9wZXJhdG9yRnVuY3Rpb248UGFyYW1ldGVyW10sIHsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgdW5kZWZpbmVkIH0+O1xuZXhwb3J0IGZ1bmN0aW9uIG1hcFRvT2JqZWN0PFQgZXh0ZW5kcyBDb25maWdUZW1wbGF0ZT4odGVtcGxhdGU6IFQpOlxuICBPcGVyYXRvckZ1bmN0aW9uPFBhcmFtZXRlcltdLCBUICYgeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCB1bmRlZmluZWQgfT47XG5leHBvcnQgZnVuY3Rpb24gbWFwVG9PYmplY3Q8VCBleHRlbmRzIENvbmZpZ1RlbXBsYXRlPih0bzogJ251bWJlcnMnIHwgJ2Jvb2xlYW5zJyB8ICdzdHJpbmdzJyB8IFQgPSAnc3RyaW5ncycpIHtcbiAgcmV0dXJuIHBpcGUoXG4gICAgLy8gVE9ETyB0aGlzIGlzIGdldHRpbmcgYSBsaXR0bGUgbG9uZywgY2xlYW51cFxuICAgIG1hcCgocGFyYW1zOiBQYXJhbWV0ZXJbXSkgPT4gcGFyYW1zLnJlZHVjZShcbiAgICAgIChjLCBwKSA9PiAoe1xuICAgICAgICAuLi5jLCBbcC5rZXldOiB0eXBlb2YgdG8gPT09ICdvYmplY3QnID9cbiAgICAgICAgICBwW3R5cGVkTWV0aG9kKHRvW3Aua2V5XSldKCkgOlxuICAgICAgICAgIHBbQVNfVE9fRk5bdG9dXSgpXG4gICAgICB9KSxcbiAgICAgIHR5cGVvZiB0byA9PT0gJ29iamVjdCcgP1xuICAgICAgICB0byBhcyBUICYgeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCB1bmRlZmluZWQgfSA6XG4gICAgICAgIHt9IGFzIHsgW2tleTogc3RyaW5nXTogbnVtYmVyIHwgYm9vbGVhbiB8IHN0cmluZyB9XG4gICAgKSksXG4gICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKGEsIGIpID0+IEpTT04uc3RyaW5naWZ5KGEpID09PSBKU09OLnN0cmluZ2lmeShiKSlcbiAgKTtcbn1cblxuIl19