UNPKG

27.3 kBJavaScriptView Raw
1import { Inject, Injectable, InjectionToken } from '@angular/core';
2import { UPDATE } from '@ngrx/store';
3import { EMPTY, Observable, of } from 'rxjs';
4import { catchError, concatMap, debounceTime, filter, map, share, switchMap, take, takeUntil, timeout, } from 'rxjs/operators';
5import { IMPORT_STATE, PERFORM_ACTION } from './actions';
6import { STORE_DEVTOOLS_CONFIG, StoreDevtoolsConfig, } from './config';
7import { DevtoolsDispatcher } from './devtools-dispatcher';
8import { isActionFiltered, sanitizeAction, sanitizeActions, sanitizeState, sanitizeStates, shouldFilterActions, unliftState, } from './utils';
9export const ExtensionActionTypes = {
10 START: 'START',
11 DISPATCH: 'DISPATCH',
12 STOP: 'STOP',
13 ACTION: 'ACTION',
14};
15export const REDUX_DEVTOOLS_EXTENSION = new InjectionToken('@ngrx/store-devtools Redux Devtools Extension');
16export class DevtoolsExtension {
17 constructor(devtoolsExtension, config, dispatcher) {
18 this.config = config;
19 this.dispatcher = dispatcher;
20 this.devtoolsExtension = devtoolsExtension;
21 this.createActionStreams();
22 }
23 notify(action, state) {
24 if (!this.devtoolsExtension) {
25 return;
26 }
27 // Check to see if the action requires a full update of the liftedState.
28 // If it is a simple action generated by the user's app and the recording
29 // is not locked/paused, only send the action and the current state (fast).
30 //
31 // A full liftedState update (slow: serializes the entire liftedState) is
32 // only required when:
33 // a) redux-devtools-extension fires the @@Init action (ignored by
34 // @ngrx/store-devtools)
35 // b) an action is generated by an @ngrx module (e.g. @ngrx/effects/init
36 // or @ngrx/store/update-reducers)
37 // c) the state has been recomputed due to time-traveling
38 // d) any action that is not a PerformAction to err on the side of
39 // caution.
40 if (action.type === PERFORM_ACTION) {
41 if (state.isLocked || state.isPaused) {
42 return;
43 }
44 const currentState = unliftState(state);
45 if (shouldFilterActions(this.config) &&
46 isActionFiltered(currentState, action, this.config.predicate, this.config.actionsSafelist, this.config.actionsBlocklist)) {
47 return;
48 }
49 const sanitizedState = this.config.stateSanitizer
50 ? sanitizeState(this.config.stateSanitizer, currentState, state.currentStateIndex)
51 : currentState;
52 const sanitizedAction = this.config.actionSanitizer
53 ? sanitizeAction(this.config.actionSanitizer, action, state.nextActionId)
54 : action;
55 this.sendToReduxDevtools(() => this.extensionConnection.send(sanitizedAction, sanitizedState));
56 }
57 else {
58 // Requires full state update
59 const sanitizedLiftedState = Object.assign(Object.assign({}, state), { stagedActionIds: state.stagedActionIds, actionsById: this.config.actionSanitizer
60 ? sanitizeActions(this.config.actionSanitizer, state.actionsById)
61 : state.actionsById, computedStates: this.config.stateSanitizer
62 ? sanitizeStates(this.config.stateSanitizer, state.computedStates)
63 : state.computedStates });
64 this.sendToReduxDevtools(() => this.devtoolsExtension.send(null, sanitizedLiftedState, this.getExtensionConfig(this.config)));
65 }
66 }
67 createChangesObservable() {
68 if (!this.devtoolsExtension) {
69 return EMPTY;
70 }
71 return new Observable((subscriber) => {
72 const connection = this.devtoolsExtension.connect(this.getExtensionConfig(this.config));
73 this.extensionConnection = connection;
74 connection.init();
75 connection.subscribe((change) => subscriber.next(change));
76 return connection.unsubscribe;
77 });
78 }
79 createActionStreams() {
80 // Listens to all changes
81 const changes$ = this.createChangesObservable().pipe(share());
82 // Listen for the start action
83 const start$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.START));
84 // Listen for the stop action
85 const stop$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.STOP));
86 // Listen for lifted actions
87 const liftedActions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.DISPATCH), map((change) => this.unwrapAction(change.payload)), concatMap((action) => {
88 if (action.type === IMPORT_STATE) {
89 // State imports may happen in two situations:
90 // 1. Explicitly by user
91 // 2. User activated the "persist state accross reloads" option
92 // and now the state is imported during reload.
93 // Because of option 2, we need to give possible
94 // lazy loaded reducers time to instantiate.
95 // As soon as there is no UPDATE action within 1 second,
96 // it is assumed that all reducers are loaded.
97 return this.dispatcher.pipe(filter((action) => action.type === UPDATE), timeout(1000), debounceTime(1000), map(() => action), catchError(() => of(action)), take(1));
98 }
99 else {
100 return of(action);
101 }
102 }));
103 // Listen for unlifted actions
104 const actions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.ACTION), map((change) => this.unwrapAction(change.payload)));
105 const actionsUntilStop$ = actions$.pipe(takeUntil(stop$));
106 const liftedUntilStop$ = liftedActions$.pipe(takeUntil(stop$));
107 this.start$ = start$.pipe(takeUntil(stop$));
108 // Only take the action sources between the start/stop events
109 this.actions$ = this.start$.pipe(switchMap(() => actionsUntilStop$));
110 this.liftedActions$ = this.start$.pipe(switchMap(() => liftedUntilStop$));
111 }
112 unwrapAction(action) {
113 return typeof action === 'string' ? eval(`(${action})`) : action;
114 }
115 getExtensionConfig(config) {
116 var _a;
117 const extensionOptions = {
118 name: config.name,
119 features: config.features,
120 serialize: config.serialize,
121 autoPause: (_a = config.autoPause) !== null && _a !== void 0 ? _a : false,
122 // The action/state sanitizers are not added to the config
123 // because sanitation is done in this class already.
124 // It is done before sending it to the devtools extension for consistency:
125 // - If we call extensionConnection.send(...),
126 // the extension would call the sanitizers.
127 // - If we call devtoolsExtension.send(...) (aka full state update),
128 // the extension would NOT call the sanitizers, so we have to do it ourselves.
129 };
130 if (config.maxAge !== false /* support === 0 */) {
131 extensionOptions.maxAge = config.maxAge;
132 }
133 return extensionOptions;
134 }
135 sendToReduxDevtools(send) {
136 try {
137 send();
138 }
139 catch (err) {
140 console.warn('@ngrx/store-devtools: something went wrong inside the redux devtools', err);
141 }
142 }
143}
144DevtoolsExtension.decorators = [
145 { type: Injectable }
146];
147/** @nocollapse */
148DevtoolsExtension.ctorParameters = () => [
149 { type: undefined, decorators: [{ type: Inject, args: [REDUX_DEVTOOLS_EXTENSION,] }] },
150 { type: StoreDevtoolsConfig, decorators: [{ type: Inject, args: [STORE_DEVTOOLS_CONFIG,] }] },
151 { type: DevtoolsDispatcher }
152];
153//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXh0ZW5zaW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbW9kdWxlcy9zdG9yZS1kZXZ0b29scy9zcmMvZXh0ZW5zaW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNuRSxPQUFPLEVBQVUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUM3QyxPQUFPLEVBQ0wsVUFBVSxFQUNWLFNBQVMsRUFDVCxZQUFZLEVBQ1osTUFBTSxFQUNOLEdBQUcsRUFDSCxLQUFLLEVBQ0wsU0FBUyxFQUNULElBQUksRUFDSixTQUFTLEVBQ1QsT0FBTyxHQUNSLE1BQU0sZ0JBQWdCLENBQUM7QUFFeEIsT0FBTyxFQUFFLFlBQVksRUFBRSxjQUFjLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDekQsT0FBTyxFQUVMLHFCQUFxQixFQUNyQixtQkFBbUIsR0FDcEIsTUFBTSxVQUFVLENBQUM7QUFDbEIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFFM0QsT0FBTyxFQUNMLGdCQUFnQixFQUNoQixjQUFjLEVBQ2QsZUFBZSxFQUNmLGFBQWEsRUFDYixjQUFjLEVBQ2QsbUJBQW1CLEVBQ25CLFdBQVcsR0FDWixNQUFNLFNBQVMsQ0FBQztBQUVqQixNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRztJQUNsQyxLQUFLLEVBQUUsT0FBTztJQUNkLFFBQVEsRUFBRSxVQUFVO0lBQ3BCLElBQUksRUFBRSxNQUFNO0lBQ1osTUFBTSxFQUFFLFFBQVE7Q0FDakIsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLHdCQUF3QixHQUFHLElBQUksY0FBYyxDQUN4RCwrQ0FBK0MsQ0FDaEQsQ0FBQztBQXlCRixNQUFN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QUFDO1FBQ0YsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLEtBQUssQ0FBQyxtQkFBbUIsRUFBRTtZQUMvQyxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztTQUN6QztRQUNELE9BQU8sZ0JBQWdCLENBQUM7SUFDMUIsQ0FBQztJQUVPLG1CQUFtQixDQUFDLElBQWM7UUFDeEMsSUFBSTtZQUNGLElBQUksRUFBRSxDQUFDO1NBQ1I7UUFBQyxPQUFPLEdBQUcsRUFBRTtZQUNaLE9BQU8sQ0FBQyxJQUFJLENBQ1Ysc0VBQXNFLEVBQ3RFLEdBQUcsQ0FDSixDQUFDO1NBQ0g7SUFDSCxDQUFDOzs7WUF6TUYsVUFBVTs7Ozs0Q0FVTixNQUFNLFNBQUMsd0JBQXdCO1lBekRsQyxtQkFBbUIsdUJBMERoQixNQUFNLFNBQUMscUJBQXFCO1lBeER4QixrQkFBa0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUsIEluamVjdGlvblRva2VuIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBY3Rpb24sIFVQREFURSB9IGZyb20gJ0BuZ3J4L3N0b3JlJztcbmltcG9ydCB7IEVNUFRZLCBPYnNlcnZhYmxlLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHtcbiAgY2F0Y2hFcnJvcixcbiAgY29uY2F0TWFwLFxuICBkZWJvdW5jZVRpbWUsXG4gIGZpbHRlcixcbiAgbWFwLFxuICBzaGFyZSxcbiAgc3dpdGNoTWFwLFxuICB0YWtlLFxuICB0YWtlVW50aWwsXG4gIHRpbWVvdXQsXG59IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgSU1QT1JUX1NUQVRFLCBQRVJGT1JNX0FDVElPTiB9IGZyb20gJy4vYWN0aW9ucyc7XG5pbXBvcnQge1xuICBTZXJpYWxpemF0aW9uT3B0aW9ucyxcbiAgU1RPUkVfREVWVE9PTFNfQ09ORklHLFxuICBTdG9yZURldnRvb2xzQ29uZmlnLFxufSBmcm9tICcuL2NvbmZpZyc7XG5pbXBvcnQgeyBEZXZ0b29sc0Rpc3BhdGNoZXIgfSBmcm9tICcuL2RldnRvb2xzLWRpc3BhdGNoZXInO1xuaW1wb3J0IHsgTGlmdGVkQWN0aW9uLCBMaWZ0ZWRTdGF0ZSB9IGZyb20gJy4vcmVkdWNlcic7XG5pbXBvcnQge1xuICBpc0FjdGlvbkZpbHRlcmVkLFxuICBzYW5pdGl6ZUFjdGlvbixcbiAgc2FuaXRpemVBY3Rpb25zLFxuICBzYW5pdGl6ZVN0YXRlLFxuICBzYW5pdGl6ZVN0YXRlcyxcbiAgc2hvdWxkRmlsdGVyQWN0aW9ucyxcbiAgdW5saWZ0U3RhdGUsXG59IGZyb20gJy4vdXRpbHMnO1xuXG5leHBvcnQgY29uc3QgRXh0ZW5zaW9uQWN0aW9uVHlwZXMgPSB7XG4gIFNUQVJUOiAnU1RBUlQnLFxuICBESVNQQVRDSDogJ0RJU1BBVENIJyxcbiAgU1RPUDogJ1NUT1AnLFxuICBBQ1RJT046ICdBQ1RJT04nLFxufTtcblxuZXhwb3J0IGNvbnN0IFJFRFVYX0RFVlRPT0xTX0VYVEVOU0lPTiA9IG5ldyBJbmplY3Rpb25Ub2tlbjxSZWR1eERldnRvb2xzRXh0ZW5zaW9uPihcbiAgJ0BuZ3J4L3N0b3JlLWRldnRvb2xzIFJlZHV4IERldnRvb2xzIEV4dGVuc2lvbidcbik7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVkdXhEZXZ0b29sc0V4dGVuc2lvbkNvbm5lY3Rpb24ge1xuICBzdWJzY3JpYmUobGlzdGVuZXI6IChjaGFuZ2U6IGFueSkgPT4gdm9pZCk6IHZvaWQ7XG4gIHVuc3Vic2NyaWJlKCk6IHZvaWQ7XG4gIHNlbmQoYWN0aW9uOiBhbnksIHN0YXRlOiBhbnkpOiB2b2lkO1xuICBpbml0KHN0YXRlPzogYW55KTogdm9pZDtcbiAgZXJyb3IoYW55RXJyOiBhbnkpOiB2b2lkO1xufVxuZXhwb3J0IGludGVyZmFjZSBSZWR1eERldnRvb2xzRXh0ZW5zaW9uQ29uZmlnIHtcbiAgZmVhdHVyZXM/OiBvYmplY3QgfCBib29sZWFuO1xuICBuYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIG1heEFnZT86IG51bWJlcjtcbiAgYXV0b1BhdXNlPzogYm9vbGVhbjtcbiAgc2VyaWFsaXplPzogYm9vbGVhbiB8IFNlcmlhbGl6YXRpb25PcHRpb25zO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlZHV4RGV2dG9vbHNFeHRlbnNpb24ge1xuICBjb25uZWN0KFxuICAgIG9wdGlvbnM6IFJlZHV4RGV2dG9vbHNFeHRlbnNpb25Db25maWdcbiAgKTogUmVkdXhEZXZ0b29sc0V4dGVuc2lvbkNvbm5lY3Rpb247XG4gIHNlbmQoYWN0aW9uOiBhbnksIHN0YXRlOiBhbnksIG9wdGlvbnM6IFJlZHV4RGV2dG9vbHNFeHRlbnNpb25Db25maWcpOiB2b2lkO1xufVxuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgRGV2dG9vbHNFeHRlbnNpb24ge1xuICBwcml2YXRlIGRldnRvb2xzRXh0ZW5zaW9uOiBSZWR1eERldnRvb2xzRXh0ZW5zaW9uO1xuICBwcml2YXRlIGV4dGVuc2lvbkNvbm5lY3Rpb24hOiBSZWR1eERldnRvb2xzRXh0ZW5zaW9uQ29ubmVjdGlvbjtcblxuICBsaWZ0ZWRBY3Rpb25zJCE6IE9ic2VydmFibGU8YW55PjtcbiAgYWN0aW9ucyQhOiBPYnNlcnZhYmxlPGFueT47XG4gIHN0YXJ0JCE6IE9ic2VydmFibGU8YW55PjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBASW5qZWN0KFJFRFVYX0RFVlRPT0xTX0VYVEVOU0lPTikgZGV2dG9vbHNFeHRlbnNpb246IFJlZHV4RGV2dG9vbHNFeHRlbnNpb24sXG4gICAgQEluamVjdChTVE9SRV9ERVZUT09MU19DT05GSUcpIHByaXZhdGUgY29uZmlnOiBTdG9yZURldnRvb2xzQ29uZmlnLFxuICAgIHByaXZhdGUgZGlzcGF0Y2hlcjogRGV2dG9vbHNEaXNwYXRjaGVyXG4gICkge1xuICAgIHRoaXMuZGV2dG9vbHNFeHRlbnNpb24gPSBkZXZ0b29sc0V4dGVuc2lvbjtcbiAgICB0aGlzLmNyZWF0ZUFjdGlvblN0cmVhbXMoKTtcbiAgfVxuXG4gIG5vdGlmeShhY3Rpb246IExpZnRlZEFjdGlvbiwgc3RhdGU6IExpZnRlZFN0YXRlKSB7XG4gICAgaWYgKCF0aGlzLmRldnRvb2xzRXh0ZW5zaW9uKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIENoZWNrIHRvIHNlZSBpZiB0aGUgYWN0aW9uIHJlcXVpcmVzIGEgZnVsbCB1cGRhdGUgb2YgdGhlIGxpZnRlZFN0YXRlLlxuICAgIC8vIElmIGl0IGlzIGEgc2ltcGxlIGFjdGlvbiBnZW5lcmF0ZWQgYnkgdGhlIHVzZXIncyBhcHAgYW5kIHRoZSByZWNvcmRpbmdcbiAgICAvLyBpcyBub3QgbG9ja2VkL3BhdXNlZCwgb25seSBzZW5kIHRoZSBhY3Rpb24gYW5kIHRoZSBjdXJyZW50IHN0YXRlIChmYXN0KS5cbiAgICAvL1xuICAgIC8vIEEgZnVsbCBsaWZ0ZWRTdGF0ZSB1cGRhdGUgKHNsb3c6IHNlcmlhbGl6ZXMgdGhlIGVudGlyZSBsaWZ0ZWRTdGF0ZSkgaXNcbiAgICAvLyBvbmx5IHJlcXVpcmVkIHdoZW46XG4gICAgLy8gICBhKSByZWR1eC1kZXZ0b29scy1leHRlbnNpb24gZmlyZXMgdGhlIEBASW5pdCBhY3Rpb24gKGlnbm9yZWQgYnlcbiAgICAvLyAgICAgIEBuZ3J4L3N0b3JlLWRldnRvb2xzKVxuICAgIC8vICAgYikgYW4gYWN0aW9uIGlzIGdlbmVyYXRlZCBieSBhbiBAbmdyeCBtb2R1bGUgKGUuZy4gQG5ncngvZWZmZWN0cy9pbml0XG4gICAgLy8gICAgICBvciBAbmdyeC9zdG9yZS91cGRhdGUtcmVkdWNlcnMpXG4gICAgLy8gICBjKSB0aGUgc3RhdGUgaGFzIGJlZW4gcmVjb21wdXRlZCBkdWUgdG8gdGltZS10cmF2ZWxpbmdcbiAgICAvLyAgIGQpIGFueSBhY3Rpb24gdGhhdCBpcyBub3QgYSBQZXJmb3JtQWN0aW9uIHRvIGVyciBvbiB0aGUgc2lkZSBvZlxuICAgIC8vICAgICAgY2F1dGlvbi5cbiAgICBpZiAoYWN0aW9uLnR5cGUgPT09IFBFUkZPUk1fQUNUSU9OKSB7XG4gICAgICBpZiAoc3RhdGUuaXNMb2NrZWQgfHwgc3RhdGUuaXNQYXVzZWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBjdXJyZW50U3RhdGUgPSB1bmxpZnRTdGF0ZShzdGF0ZSk7XG4gICAgICBpZiAoXG4gICAgICAgIHNob3VsZEZpbHRlckFjdGlvbnModGhpcy5jb25maWcpICYmXG4gICAgICAgIGlzQWN0aW9uRmlsdGVyZWQoXG4gICAgICAgICAgY3VycmVudFN0YXRlLFxuICAgICAgICAgIGFjdGlvbixcbiAgICAgICAgICB0aGlzLmNvbmZpZy5wcmVkaWNhdGUsXG4gICAgICAgICAgdGhpcy5jb25maWcuYWN0aW9uc1NhZmVsaXN0LFxuICAgICAgICAgIHRoaXMuY29uZmlnLmFjdGlvbnNCbG9ja2xpc3RcbiAgICAgICAgKVxuICAgICAgKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNhbml0aXplZFN0YXRlID0gdGhpcy5jb25maWcuc3RhdGVTYW5pdGl6ZXJcbiAgICAgICAgPyBzYW5pdGl6ZVN0YXRlKFxuICAgICAgICAgICAgdGhpcy5jb25maWcuc3RhdGVTYW5pdGl6ZXIsXG4gICAgICAgICAgICBjdXJyZW50U3RhdGUsXG4gICAgICAgICAgICBzdGF0ZS5jdXJyZW50U3RhdGVJbmRleFxuICAgICAgICAgIClcbiAgICAgICAgOiBjdXJyZW50U3RhdGU7XG4gICAgICBjb25zdCBzYW5pdGl6ZWRBY3Rpb24gPSB0aGlzLmNvbmZpZy5hY3Rpb25TYW5pdGl6ZXJcbiAgICAgICAgPyBzYW5pdGl6ZUFjdGlvbihcbiAgICAgICAgICAgIHRoaXMuY29uZmlnLmFjdGlvblNhbml0aXplcixcbiAgICAgICAgICAgIGFjdGlvbixcbiAgICAgICAgICAgIHN0YXRlLm5leHRBY3Rpb25JZFxuICAgICAgICAgIClcbiAgICAgICAgOiBhY3Rpb247XG5cbiAgICAgIHRoaXMuc2VuZFRvUmVkdXhEZXZ0b29scygoKSA9PlxuICAgICAgICB0aGlzLmV4dGVuc2lvbkNvbm5lY3Rpb24uc2VuZChzYW5pdGl6ZWRBY3Rpb24sIHNhbml0aXplZFN0YXRlKVxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gUmVxdWlyZXMgZnVsbCBzdGF0ZSB1cGRhdGVcbiAgICAgIGNvbnN0IHNhbml0aXplZExpZnRlZFN0YXRlID0ge1xuICAgICAgICAuLi5zdGF0ZSxcbiAgICAgICAgc3RhZ2VkQWN0aW9uSWRzOiBzdGF0ZS5zdGFnZWRBY3Rpb25JZHMsXG4gICAgICAgIGFjdGlvbnNCeUlkOiB0aGlzLmNvbmZpZy5hY3Rpb25TYW5pdGl6ZXJcbiAgICAgICAgICA/IHNhbml0aXplQWN0aW9ucyh0aGlzLmNvbmZpZy5hY3Rpb25TYW5pdGl6ZXIsIHN0YXRlLmFjdGlvbnNCeUlkKVxuICAgICAgICAgIDogc3RhdGUuYWN0aW9uc0J5SWQsXG4gICAgICAgIGNvbXB1dGVkU3RhdGVzOiB0aGlzLmNvbmZpZy5zdGF0ZVNhbml0aXplclxuICAgICAgICAgID8gc2FuaXRpemVTdGF0ZXModGhpcy5jb25maWcuc3RhdGVTYW5pdGl6ZXIsIHN0YXRlLmNvbXB1dGVkU3RhdGVzKVxuICAgICAgICAgIDogc3RhdGUuY29tcHV0ZWRTdGF0ZXMsXG4gICAgICB9O1xuXG4gICAgICB0aGlzLnNlbmRUb1JlZHV4RGV2dG9vbHMoKCkgPT5cbiAgICAgICAgdGhpcy5kZXZ0b29sc0V4dGVuc2lvbi5zZW5kKFxuICAgICAgICAgIG51bGwsXG4gICAgICAgICAgc2FuaXRpemVkTGlmdGVkU3RhdGUsXG4gICAgICAgICAgdGhpcy5nZXRFeHRlbnNpb25Db25maWcodGhpcy5jb25maWcpXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVDaGFuZ2VzT2JzZXJ2YWJsZSgpOiBPYnNlcnZhYmxlPGFueT4ge1xuICAgIGlmICghdGhpcy5kZXZ0b29sc0V4dGVuc2lvbikge1xuICAgICAgcmV0dXJuIEVNUFRZO1xuICAgIH1cblxuICAgIHJldHVybiBuZXcgT2JzZXJ2YWJsZSgoc3Vic2NyaWJlcikgPT4ge1xuICAgICAgY29uc3QgY29ubmVjdGlvbiA9IHRoaXMuZGV2dG9vbHNFeHRlbnNpb24uY29ubmVjdChcbiAgICAgICAgdGhpcy5nZXRFeHRlbnNpb25Db25maWcodGhpcy5jb25maWcpXG4gICAgICApO1xuICAgICAgdGhpcy5leHRlbnNpb25Db25uZWN0aW9uID0gY29ubmVjdGlvbjtcbiAgICAgIGNvbm5lY3Rpb24uaW5pdCgpO1xuXG4gICAgICBjb25uZWN0aW9uLnN1YnNjcmliZSgoY2hhbmdlOiBhbnkpID0+IHN1YnNjcmliZXIubmV4dChjaGFuZ2UpKTtcbiAgICAgIHJldHVybiBjb25uZWN0aW9uLnVuc3Vic2NyaWJlO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVBY3Rpb25TdHJlYW1zKCkge1xuICAgIC8vIExpc3RlbnMgdG8gYWxsIGNoYW5nZXNcbiAgICBjb25zdCBjaGFuZ2VzJCA9IHRoaXMuY3JlYXRlQ2hhbmdlc09ic2VydmFibGUoKS5waXBlKHNoYXJlKCkpO1xuXG4gICAgLy8gTGlzdGVuIGZvciB0aGUgc3RhcnQgYWN0aW9uXG4gICAgY29uc3Qgc3RhcnQkID0gY2hhbmdlcyQucGlwZShcbiAgICAgIGZpbHRlcigoY2hhbmdlOiBhbnkpID0+IGNoYW5nZS50eXBlID09PSBFeHRlbnNpb25BY3Rpb25UeXBlcy5TVEFSVClcbiAgICApO1xuXG4gICAgLy8gTGlzdGVuIGZvciB0aGUgc3RvcCBhY3Rpb25cbiAgICBjb25zdCBzdG9wJCA9IGNoYW5nZXMkLnBpcGUoXG4gICAgICBmaWx0ZXIoKGNoYW5nZTogYW55KSA9PiBjaGFuZ2UudHlwZSA9PT0gRXh0ZW5zaW9uQWN0aW9uVHlwZXMuU1RPUClcbiAgICApO1xuXG4gICAgLy8gTGlzdGVuIGZvciBsaWZ0ZWQgYWN0aW9uc1xuICAgIGNvbnN0IGxpZnRlZEFjdGlvbnMkID0gY2hhbmdlcyQucGlwZShcbiAgICAgIGZpbHRlcigoY2hhbmdlKSA9PiBjaGFuZ2UudHlwZSA9PT0gRXh0ZW5zaW9uQWN0aW9uVHlwZXMuRElTUEFUQ0gpLFxuICAgICAgbWFwKChjaGFuZ2UpID0+IHRoaXMudW53cmFwQWN0aW9uKGNoYW5nZS5wYXlsb2FkKSksXG4gICAgICBjb25jYXRNYXAoKGFjdGlvbjogYW55KSA9PiB7XG4gICAgICAgIGlmIChhY3Rpb24udHlwZSA9PT0gSU1QT1JUX1NUQVRFKSB7XG4gICAgICAgICAgLy8gU3RhdGUgaW1wb3J0cyBtYXkgaGFwcGVuIGluIHR3byBzaXR1YXRpb25zOlxuICAgICAgICAgIC8vIDEuIEV4cGxpY2l0bHkgYnkgdXNlclxuICAgICAgICAgIC8vIDIuIFVzZXIgYWN0aXZhdGVkIHRoZSBcInBlcnNpc3Qgc3RhdGUgYWNjcm9zcyByZWxvYWRzXCIgb3B0aW9uXG4gICAgICAgICAgLy8gICAgYW5kIG5vdyB0aGUgc3RhdGUgaXMgaW1wb3J0ZWQgZHVyaW5nIHJlbG9hZC5cbiAgICAgICAgICAvLyBCZWNhdXNlIG9mIG9wdGlvbiAyLCB3ZSBuZWVkIHRvIGdpdmUgcG9zc2libGVcbiAgICAgICAgICAvLyBsYXp5IGxvYWRlZCByZWR1Y2VycyB0aW1lIHRvIGluc3RhbnRpYXRlLlxuICAgICAgICAgIC8vIEFzIHNvb24gYXMgdGhlcmUgaXMgbm8gVVBEQVRFIGFjdGlvbiB3aXRoaW4gMSBzZWNvbmQsXG4gICAgICAgICAgLy8gaXQgaXMgYXNzdW1lZCB0aGF0IGFsbCByZWR1Y2VycyBhcmUgbG9hZGVkLlxuICAgICAgICAgIHJldHVybiB0aGlzLmRpc3BhdGNoZXIucGlwZShcbiAgICAgICAgICAgIGZpbHRlcigoYWN0aW9uKSA9PiBhY3Rpb24udHlwZSA9PT0gVVBEQVRFKSxcbiAgICAgICAgICAgIHRpbWVvdXQoMTAwMCksXG4gICAgICAgICAgICBkZWJvdW5jZVRpbWUoMTAwMCksXG4gICAgICAgICAgICBtYXAoKCkgPT4gYWN0aW9uKSxcbiAgICAgICAgICAgIGNhdGNoRXJyb3IoKCkgPT4gb2YoYWN0aW9uKSksXG4gICAgICAgICAgICB0YWtlKDEpXG4gICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gb2YoYWN0aW9uKTtcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICApO1xuXG4gICAgLy8gTGlzdGVuIGZvciB1bmxpZnRlZCBhY3Rpb25zXG4gICAgY29uc3QgYWN0aW9ucyQgPSBjaGFuZ2VzJC5waXBlKFxuICAgICAgZmlsdGVyKChjaGFuZ2UpID0+IGNoYW5nZS50eXBlID09PSBFeHRlbnNpb25BY3Rpb25UeXBlcy5BQ1RJT04pLFxuICAgICAgbWFwKChjaGFuZ2UpID0+IHRoaXMudW53cmFwQWN0aW9uKGNoYW5nZS5wYXlsb2FkKSlcbiAgICApO1xuXG4gICAgY29uc3QgYWN0aW9uc1VudGlsU3RvcCQgPSBhY3Rpb25zJC5waXBlKHRha2VVbnRpbChzdG9wJCkpO1xuICAgIGNvbnN0IGxpZnRlZFVudGlsU3RvcCQgPSBsaWZ0ZWRBY3Rpb25zJC5waXBlKHRha2VVbnRpbChzdG9wJCkpO1xuICAgIHRoaXMuc3RhcnQkID0gc3RhcnQkLnBpcGUodGFrZVVudGlsKHN0b3AkKSk7XG5cbiAgICAvLyBPbmx5IHRha2UgdGhlIGFjdGlvbiBzb3VyY2VzIGJldHdlZW4gdGhlIHN0YXJ0L3N0b3AgZXZlbnRzXG4gICAgdGhpcy5hY3Rpb25zJCA9IHRoaXMuc3RhcnQkLnBpcGUoc3dpdGNoTWFwKCgpID0+IGFjdGlvbnNVbnRpbFN0b3AkKSk7XG4gICAgdGhpcy5saWZ0ZWRBY3Rpb25zJCA9IHRoaXMuc3RhcnQkLnBpcGUoc3dpdGNoTWFwKCgpID0+IGxpZnRlZFVudGlsU3RvcCQpKTtcbiAgfVxuXG4gIHByaXZhdGUgdW53cmFwQWN0aW9uKGFjdGlvbjogQWN0aW9uKSB7XG4gICAgcmV0dXJuIHR5cGVvZiBhY3Rpb24gPT09ICdzdHJpbmcnID8gZXZhbChgKCR7YWN0aW9ufSlgKSA6IGFjdGlvbjtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0RXh0ZW5zaW9uQ29uZmlnKGNvbmZpZzogU3RvcmVEZXZ0b29sc0NvbmZpZykge1xuICAgIGNvbnN0IGV4dGVuc2lvbk9wdGlvbnM6IFJlZHV4RGV2dG9vbHNFeHRlbnNpb25Db25maWcgPSB7XG4gICAgICBuYW1lOiBjb25maWcubmFtZSxcbiAgICAgIGZlYXR1cmVzOiBjb25maWcuZmVhdHVyZXMsXG4gICAgICBzZXJpYWxpemU6IGNvbmZpZy5zZXJpYWxpemUsXG4gICAgICBhdXRvUGF1c2U6IGNvbmZpZy5hdXRvUGF1c2UgPz8gZmFsc2UsXG4gICAgICAvLyBUaGUgYWN0aW9uL3N0YXRlIHNhbml0aXplcnMgYXJlIG5vdCBhZGRlZCB0byB0aGUgY29uZmlnXG4gICAgICAvLyBiZWNhdXNlIHNhbml0YXRpb24gaXMgZG9uZSBpbiB0aGlzIGNsYXNzIGFscmVhZHkuXG4gICAgICAvLyBJdCBpcyBkb25lIGJlZm9yZSBzZW5kaW5nIGl0IHRvIHRoZSBkZXZ0b29scyBleHRlbnNpb24gZm9yIGNvbnNpc3RlbmN5OlxuICAgICAgLy8gLSBJZiB3ZSBjYWxsIGV4dGVuc2lvbkNvbm5lY3Rpb24uc2VuZCguLi4pLFxuICAgICAgLy8gICB0aGUgZXh0ZW5zaW9uIHdvdWxkIGNhbGwgdGhlIHNhbml0aXplcnMuXG4gICAgICAvLyAtIElmIHdlIGNhbGwgZGV2dG9vbHNFeHRlbnNpb24uc2VuZCguLi4pIChha2EgZnVsbCBzdGF0ZSB1cGRhdGUpLFxuICAgICAgLy8gICB0aGUgZXh0ZW5zaW9uIHdvdWxkIE5PVCBjYWxsIHRoZSBzYW5pdGl6ZXJzLCBzbyB3ZSBoYXZlIHRvIGRvIGl0IG91cnNlbHZlcy5cbiAgICB9O1xuICAgIGlmIChjb25maWcubWF4QWdlICE9PSBmYWxzZSAvKiBzdXBwb3J0ID09PSAwICovKSB7XG4gICAgICBleHRlbnNpb25PcHRpb25zLm1heEFnZSA9IGNvbmZpZy5tYXhBZ2U7XG4gICAgfVxuICAgIHJldHVybiBleHRlbnNpb25PcHRpb25zO1xuICB9XG5cbiAgcHJpdmF0ZSBzZW5kVG9SZWR1eERldnRvb2xzKHNlbmQ6IEZ1bmN0aW9uKSB7XG4gICAgdHJ5IHtcbiAgICAgIHNlbmQoKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgJ0BuZ3J4L3N0b3JlLWRldnRvb2xzOiBzb21ldGhpbmcgd2VudCB3cm9uZyBpbnNpZGUgdGhlIHJlZHV4IGRldnRvb2xzJyxcbiAgICAgICAgZXJyXG4gICAgICApO1xuICAgIH1cbiAgfVxufVxuIl19
\No newline at end of file