UNPKG

36.5 kBJavaScriptView Raw
1import { Inject, InjectionToken, NgModule, isDevMode, } from '@angular/core';
2import { NavigationCancel, NavigationError, NavigationEnd, RoutesRecognized, NavigationStart, } from '@angular/router';
3import { isNgrxMockEnvironment, select, ACTIVE_RUNTIME_CHECKS, } from '@ngrx/store';
4import { withLatestFrom } from 'rxjs/operators';
5import { ROUTER_CANCEL, ROUTER_ERROR, ROUTER_NAVIGATED, ROUTER_NAVIGATION, ROUTER_REQUEST, } from './actions';
6import { RouterStateSerializer, } from './serializers/base';
7import { FullRouterStateSerializer, } from './serializers/full_serializer';
8import { MinimalRouterStateSerializer } from './serializers/minimal_serializer';
9import * as i0 from "@angular/core";
10import * as i1 from "@ngrx/store";
11import * as i2 from "@angular/router";
12import * as i3 from "./serializers/base";
13export var NavigationActionTiming;
14(function (NavigationActionTiming) {
15 NavigationActionTiming[NavigationActionTiming["PreActivation"] = 1] = "PreActivation";
16 NavigationActionTiming[NavigationActionTiming["PostActivation"] = 2] = "PostActivation";
17})(NavigationActionTiming || (NavigationActionTiming = {}));
18export const _ROUTER_CONFIG = new InjectionToken('@ngrx/router-store Internal Configuration');
19export const ROUTER_CONFIG = new InjectionToken('@ngrx/router-store Configuration');
20export const DEFAULT_ROUTER_FEATURENAME = 'router';
21export function _createRouterConfig(config) {
22 return {
23 stateKey: DEFAULT_ROUTER_FEATURENAME,
24 serializer: MinimalRouterStateSerializer,
25 navigationActionTiming: NavigationActionTiming.PreActivation,
26 ...config,
27 };
28}
29var RouterTrigger;
30(function (RouterTrigger) {
31 RouterTrigger[RouterTrigger["NONE"] = 1] = "NONE";
32 RouterTrigger[RouterTrigger["ROUTER"] = 2] = "ROUTER";
33 RouterTrigger[RouterTrigger["STORE"] = 3] = "STORE";
34})(RouterTrigger || (RouterTrigger = {}));
35/**
36 * Connects RouterModule with StoreModule.
37 *
38 * During the navigation, before any guards or resolvers run, the router will dispatch
39 * a ROUTER_NAVIGATION action, which has the following signature:
40 *
41 * ```
42 * export type RouterNavigationPayload = {
43 * routerState: SerializedRouterStateSnapshot,
44 * event: RoutesRecognized
45 * }
46 * ```
47 *
48 * Either a reducer or an effect can be invoked in response to this action.
49 * If the invoked reducer throws, the navigation will be canceled.
50 *
51 * If navigation gets canceled because of a guard, a ROUTER_CANCEL action will be
52 * dispatched. If navigation results in an error, a ROUTER_ERROR action will be dispatched.
53 *
54 * Both ROUTER_CANCEL and ROUTER_ERROR contain the store state before the navigation
55 * which can be used to restore the consistency of the store.
56 *
57 * Usage:
58 *
59 * ```typescript
60 * @NgModule({
61 * declarations: [AppCmp, SimpleCmp],
62 * imports: [
63 * BrowserModule,
64 * StoreModule.forRoot(mapOfReducers),
65 * RouterModule.forRoot([
66 * { path: '', component: SimpleCmp },
67 * { path: 'next', component: SimpleCmp }
68 * ]),
69 * StoreRouterConnectingModule.forRoot()
70 * ],
71 * bootstrap: [AppCmp]
72 * })
73 * export class AppModule {
74 * }
75 * ```
76 */
77export class StoreRouterConnectingModule {
78 constructor(store, router, serializer, errorHandler, config, activeRuntimeChecks) {
79 this.store = store;
80 this.router = router;
81 this.serializer = serializer;
82 this.errorHandler = errorHandler;
83 this.config = config;
84 this.activeRuntimeChecks = activeRuntimeChecks;
85 this.lastEvent = null;
86 this.routerState = null;
87 this.trigger = RouterTrigger.NONE;
88 this.stateKey = this.config.stateKey;
89 if (!isNgrxMockEnvironment() &&
90 isDevMode() &&
91 (activeRuntimeChecks?.strictActionSerializability ||
92 activeRuntimeChecks?.strictStateSerializability) &&
93 this.serializer instanceof FullRouterStateSerializer) {
94 console.warn('@ngrx/router-store: The serializability runtime checks cannot be enabled ' +
95 'with the FullRouterStateSerializer. The FullRouterStateSerializer ' +
96 'has an unserializable router state and actions that are not serializable. ' +
97 'To use the serializability runtime checks either use ' +
98 'the MinimalRouterStateSerializer or implement a custom router state serializer.');
99 }
100 this.setUpStoreStateListener();
101 this.setUpRouterEventsListener();
102 }
103 static forRoot(config = {}) {
104 return {
105 ngModule: StoreRouterConnectingModule,
106 providers: [
107 { provide: _ROUTER_CONFIG, useValue: config },
108 {
109 provide: ROUTER_CONFIG,
110 useFactory: _createRouterConfig,
111 deps: [_ROUTER_CONFIG],
112 },
113 {
114 provide: RouterStateSerializer,
115 useClass: config.serializer
116 ? config.serializer
117 : config.routerState === 0 /* Full */
118 ? FullRouterStateSerializer
119 : MinimalRouterStateSerializer,
120 },
121 ],
122 };
123 }
124 setUpStoreStateListener() {
125 this.store
126 .pipe(select(this.stateKey), withLatestFrom(this.store))
127 .subscribe(([routerStoreState, storeState]) => {
128 this.navigateIfNeeded(routerStoreState, storeState);
129 });
130 }
131 navigateIfNeeded(routerStoreState, storeState) {
132 if (!routerStoreState || !routerStoreState.state) {
133 return;
134 }
135 if (this.trigger === RouterTrigger.ROUTER) {
136 return;
137 }
138 if (this.lastEvent instanceof NavigationStart) {
139 return;
140 }
141 const url = routerStoreState.state.url;
142 if (!isSameUrl(this.router.url, url)) {
143 this.storeState = storeState;
144 this.trigger = RouterTrigger.STORE;
145 this.router.navigateByUrl(url).catch((error) => {
146 this.errorHandler.handleError(error);
147 });
148 }
149 }
150 setUpRouterEventsListener() {
151 const dispatchNavLate = this.config.navigationActionTiming ===
152 NavigationActionTiming.PostActivation;
153 let routesRecognized;
154 this.router.events
155 .pipe(withLatestFrom(this.store))
156 .subscribe(([event, storeState]) => {
157 this.lastEvent = event;
158 if (event instanceof NavigationStart) {
159 this.routerState = this.serializer.serialize(this.router.routerState.snapshot);
160 if (this.trigger !== RouterTrigger.STORE) {
161 this.storeState = storeState;
162 this.dispatchRouterRequest(event);
163 }
164 }
165 else if (event instanceof RoutesRecognized) {
166 routesRecognized = event;
167 if (!dispatchNavLate && this.trigger !== RouterTrigger.STORE) {
168 this.dispatchRouterNavigation(event);
169 }
170 }
171 else if (event instanceof NavigationCancel) {
172 this.dispatchRouterCancel(event);
173 this.reset();
174 }
175 else if (event instanceof NavigationError) {
176 this.dispatchRouterError(event);
177 this.reset();
178 }
179 else if (event instanceof NavigationEnd) {
180 if (this.trigger !== RouterTrigger.STORE) {
181 if (dispatchNavLate) {
182 this.dispatchRouterNavigation(routesRecognized);
183 }
184 this.dispatchRouterNavigated(event);
185 }
186 this.reset();
187 }
188 });
189 }
190 dispatchRouterRequest(event) {
191 this.dispatchRouterAction(ROUTER_REQUEST, { event });
192 }
193 dispatchRouterNavigation(lastRoutesRecognized) {
194 const nextRouterState = this.serializer.serialize(lastRoutesRecognized.state);
195 this.dispatchRouterAction(ROUTER_NAVIGATION, {
196 routerState: nextRouterState,
197 event: new RoutesRecognized(lastRoutesRecognized.id, lastRoutesRecognized.url, lastRoutesRecognized.urlAfterRedirects, nextRouterState),
198 });
199 }
200 dispatchRouterCancel(event) {
201 this.dispatchRouterAction(ROUTER_CANCEL, {
202 storeState: this.storeState,
203 event,
204 });
205 }
206 dispatchRouterError(event) {
207 this.dispatchRouterAction(ROUTER_ERROR, {
208 storeState: this.storeState,
209 event: new NavigationError(event.id, event.url, `${event}`),
210 });
211 }
212 dispatchRouterNavigated(event) {
213 const routerState = this.serializer.serialize(this.router.routerState.snapshot);
214 this.dispatchRouterAction(ROUTER_NAVIGATED, { event, routerState });
215 }
216 dispatchRouterAction(type, payload) {
217 this.trigger = RouterTrigger.ROUTER;
218 try {
219 this.store.dispatch({
220 type,
221 payload: {
222 routerState: this.routerState,
223 ...payload,
224 event: this.config.routerState === 0 /* Full */
225 ? payload.event
226 : {
227 id: payload.event.id,
228 url: payload.event.url,
229 // safe, as it will just be `undefined` for non-NavigationEnd router events
230 urlAfterRedirects: payload.event
231 .urlAfterRedirects,
232 },
233 },
234 });
235 }
236 finally {
237 this.trigger = RouterTrigger.NONE;
238 }
239 }
240 reset() {
241 this.trigger = RouterTrigger.NONE;
242 this.storeState = null;
243 this.routerState = null;
244 }
245}
246/** @nocollapse */ StoreRouterConnectingModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: StoreRouterConnectingModule, deps: [{ token: i1.Store }, { token: i2.Router }, { token: i3.RouterStateSerializer }, { token: i0.ErrorHandler }, { token: ROUTER_CONFIG }, { token: ACTIVE_RUNTIME_CHECKS }], target: i0.ɵɵFactoryTarget.NgModule });
247/** @nocollapse */ StoreRouterConnectingModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.0-rc.1", ngImport: i0, type: StoreRouterConnectingModule });
248/** @nocollapse */ StoreRouterConnectingModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: StoreRouterConnectingModule });
249i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: StoreRouterConnectingModule, decorators: [{
250 type: NgModule,
251 args: [{}]
252 }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.Router }, { type: i3.RouterStateSerializer }, { type: i0.ErrorHandler }, { type: undefined, decorators: [{
253 type: Inject,
254 args: [ROUTER_CONFIG]
255 }] }, { type: undefined, decorators: [{
256 type: Inject,
257 args: [ACTIVE_RUNTIME_CHECKS]
258 }] }]; } });
259/**
260 * Check if the URLs are matching. Accounts for the possibility of trailing "/" in url.
261 */
262function isSameUrl(first, second) {
263 return stripTrailingSlash(first) === stripTrailingSlash(second);
264}
265function stripTrailingSlash(text) {
266 if (text?.length > 0 && text[text.length - 1] === '/') {
267 return text.substring(0, text.length - 1);
268 }
269 return text;
270}
271//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyX3N0b3JlX21vZHVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL21vZHVsZXMvcm91dGVyLXN0b3JlL3NyYy9yb3V0ZXJfc3RvcmVfbW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxNQUFNLEVBQ04sY0FBYyxFQUVkLFFBQVEsRUFFUixTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUNMLGdCQUFnQixFQUNoQixlQUFlLEVBQ2YsYUFBYSxFQUViLGdCQUFnQixFQUNoQixlQUFlLEdBR2hCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUNMLHFCQUFxQixFQUVyQixNQUFNLEVBR04scUJBQXFCLEdBQ3RCLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVoRCxPQUFPLEVBQ0wsYUFBYSxFQUNiLFlBQVksRUFDWixnQkFBZ0IsRUFDaEIsaUJBQWlCLEVBQ2pCLGNBQWMsR0FDZixNQUFNLFdBQVcsQ0FBQztBQUVuQixPQUFPLEVBQ0wscUJBQXFCLEdBRXRCLE1BQU0sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUNMLHlCQUF5QixHQUUxQixNQUFNLCtCQUErQixDQUFDO0FBQ3ZDLE9BQU8sRUFBRSw0QkFBNEIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDOzs7OztBQTBDaEYsTUFBTSxDQUFOLElBQVksc0JBR1g7QUFIRCxXQUFZLHNCQUFzQjtJQUNoQyxxRkFBaUIsQ0FBQTtJQUNqQix1RkFBa0IsQ0FBQTtBQUNwQixDQUFDLEVBSFcsc0JBQXNCLEtBQXRCLHNCQUFzQixRQUdqQztBQUVELE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxJQUFJLGNBQWMsQ0FDOUMsMkNBQTJDLENBQzVDLENBQUM7QUFDRixNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUcsSUFBSSxjQUFjLENBQzdDLGtDQUFrQyxD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OzswQkF1Q1AsTUFBTTsyQkFBQyxhQUFhOzswQkFDcEIsTUFBTTsyQkFBQyxxQkFBcUI7O0FBaUxqQzs7R0FFRztBQUNILFNBQVMsU0FBUyxDQUFDLEtBQWEsRUFBRSxNQUFjO0lBQzlDLE9BQU8sa0JBQWtCLENBQUMsS0FBSyxDQUFDLEtBQUssa0JBQWtCLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDbEUsQ0FBQztBQUVELFNBQVMsa0JBQWtCLENBQUMsSUFBWTtJQUN0QyxJQUFJLElBQUksRUFBRSxNQUFNLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxLQUFLLEdBQUcsRUFBRTtRQUNyRCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7S0FDM0M7SUFDRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBJbmplY3QsXG4gIEluamVjdGlvblRva2VuLFxuICBNb2R1bGVXaXRoUHJvdmlkZXJzLFxuICBOZ01vZHVsZSxcbiAgRXJyb3JIYW5kbGVyLFxuICBpc0Rldk1vZGUsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgTmF2aWdhdGlvbkNhbmNlbCxcbiAgTmF2aWdhdGlvbkVycm9yLFxuICBOYXZpZ2F0aW9uRW5kLFxuICBSb3V0ZXIsXG4gIFJvdXRlc1JlY29nbml6ZWQsXG4gIE5hdmlnYXRpb25TdGFydCxcbiAgRXZlbnQsXG4gIFJvdXRlckV2ZW50LFxufSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHtcbiAgaXNOZ3J4TW9ja0Vudmlyb25tZW50LFxuICBSdW50aW1lQ2hlY2tzLFxuICBzZWxlY3QsXG4gIFNlbGVjdG9yLFxuICBTdG9yZSxcbiAgQUNUSVZFX1JVTlRJTUVfQ0hFQ0tTLFxufSBmcm9tICdAbmdyeC9zdG9yZSc7XG5pbXBvcnQgeyB3aXRoTGF0ZXN0RnJvbSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHtcbiAgUk9VVEVSX0NBTkNFTCxcbiAgUk9VVEVSX0VSUk9SLFxuICBST1VURVJfTkFWSUdBVEVELFxuICBST1VURVJfTkFWSUdBVElPTixcbiAgUk9VVEVSX1JFUVVFU1QsXG59IGZyb20gJy4vYWN0aW9ucyc7XG5pbXBvcnQgeyBSb3V0ZXJSZWR1Y2VyU3RhdGUgfSBmcm9tICcuL3JlZHVjZXInO1xuaW1wb3J0IHtcbiAgUm91dGVyU3RhdGVTZXJpYWxpemVyLFxuICBCYXNlUm91dGVyU3RvcmVTdGF0ZSxcbn0gZnJvbSAnLi9zZXJpYWxpemVycy9iYXNlJztcbmltcG9ydCB7XG4gIEZ1bGxSb3V0ZXJTdGF0ZVNlcmlhbGl6ZXIsXG4gIFNlcmlhbGl6ZWRSb3V0ZXJTdGF0ZVNuYXBzaG90LFxufSBmcm9tICcuL3NlcmlhbGl6ZXJzL2Z1bGxfc2VyaWFsaXplcic7XG5pbXBvcnQgeyBNaW5pbWFsUm91dGVyU3RhdGVTZXJpYWxpemVyIH0gZnJvbSAnLi9zZXJpYWxpemVycy9taW5pbWFsX3NlcmlhbGl6ZXInO1xuXG5leHBvcnQgdHlwZSBTdGF0ZUtleU9yU2VsZWN0b3I8XG4gIFQgZXh0ZW5kcyBCYXNlUm91dGVyU3RvcmVTdGF0ZSA9IFNlcmlhbGl6ZWRSb3V0ZXJTdGF0ZVNuYXBzaG90XG4+ID0gc3RyaW5nIHwgU2VsZWN0b3I8YW55LCBSb3V0ZXJSZWR1Y2VyU3RhdGU8VD4+O1xuXG4vKipcbiAqIE1pbmltYWwgPSBTZXJpYWxpemVzIHRoZSByb3V0ZXIgZXZlbnQgd2l0aCBNaW5pbWFsUm91dGVyU3RhdGVTZXJpYWxpemVyXG4gKiBGdWxsID0gU2VyaWFsaXplcyB0aGUgcm91dGVyIGV2ZW50IHdpdGggRnVsbFJvdXRlclN0YXRlU2VyaWFsaXplclxuICovXG5leHBvcnQgY29uc3QgZW51bSBSb3V0ZXJTdGF0ZSB7XG4gIEZ1bGwsXG4gIE1pbmltYWwsXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3RvcmVSb3V0ZXJDb25maWc8XG4gIFQgZXh0ZW5kcyBCYXNlUm91dGVyU3RvcmVTdGF0ZSA9IFNlcmlhbGl6ZWRSb3V0ZXJTdGF0ZVNuYXBzaG90XG4+IHtcbiAgc3RhdGVLZXk/OiBTdGF0ZUtleU9yU2VsZWN0b3I8VD47XG4gIHNlcmlhbGl6ZXI/OiBuZXcgKC4uLmFyZ3M6IGFueVtdKSA9PiBSb3V0ZXJTdGF0ZVNlcmlhbGl6ZXI7XG4gIC8qKlxuICAgKiBCeSBkZWZhdWx0LCBST1VURVJfTkFWSUdBVElPTiBpcyBkaXNwYXRjaGVkIGJlZm9yZSBndWFyZHMgYW5kIHJlc29sdmVycyBydW4uXG4gICAqIFRoZXJlZm9yZSwgdGhlIGFjdGlvbiBjb3VsZCBydW4gdG9vIHNvb24sIGZvciBleGFtcGxlXG4gICAqIHRoZXJlIG1heSBiZSBhIG5hdmlnYXRpb24gY2FuY2VsIGR1ZSB0byBhIGd1YXJkIHNheWluZyB0aGUgbmF2aWdhdGlvbiBpcyBub3QgYWxsb3dlZC5cbiAgICogVG8gcnVuIFJPVVRFUl9OQVZJR0FUSU9OIGFmdGVyIGd1YXJkcyBhbmQgcmVzb2x2ZXJzLFxuICAgKiBzZXQgdGhpcyBwcm9wZXJ0eSB0byBOYXZpZ2F0aW9uQWN0aW9uVGltaW5nLlBvc3RBY3RpdmF0aW9uLlxuICAgKi9cbiAgbmF2aWdhdGlvbkFjdGlvblRpbWluZz86IE5hdmlnYXRpb25BY3Rpb25UaW1pbmc7XG4gIC8qKlxuICAgKiBEZWNpZGVzIHdoaWNoIHJvdXRlciBzZXJpYWxpemVyIHNob3VsZCBiZSB1c2VkLCBpZiB0aGVyZSBpcyBub25lIHByb3ZpZGVkLCBhbmQgdGhlIG1ldGFkYXRhIG9uIHRoZSBkaXNwYXRjaGVkIEBuZ3J4L3JvdXRlci1zdG9yZSBhY3Rpb24gcGF5bG9hZC5cbiAgICogU2V0IHRvIGBNaW5pbWFsYCB0byB1c2UgdGhlIGBNaW5pbWFsUm91dGVyU3RhdGVTZXJpYWxpemVyYCBhbmQgdG8gc2V0IGEgbWluaW1hbCByb3V0ZXIgZXZlbnQgd2l0aCB0aGUgbmF2aWdhdGlvbiBpZCBhbmQgdXJsIGFzIHBheWxvYWQuXG4gICAqIFNldCB0byBgRnVsbGAgdG8gdXNlIHRoZSBgRnVsbFJvdXRlclN0YXRlU2VyaWFsaXplcmAgYW5kIHRvIHNldCB0aGUgYW5ndWxhciByb3V0ZXIgZXZlbnRzIGFzIHBheWxvYWQuXG4gICAqL1xuICByb3V0ZXJTdGF0ZT86IFJvdXRlclN0YXRlO1xufVxuXG5pbnRlcmZhY2UgU3RvcmVSb3V0ZXJBY3Rpb25QYXlsb2FkIHtcbiAgZXZlbnQ6IFJvdXRlckV2ZW50O1xuICByb3V0ZXJTdGF0ZT86IFNlcmlhbGl6ZWRSb3V0ZXJTdGF0ZVNuYXBzaG90O1xuICBzdG9yZVN0YXRlPzogYW55O1xufVxuXG5leHBvcnQgZW51bSBOYXZpZ2F0aW9uQWN0aW9uVGltaW5nIHtcbiAgUHJlQWN0aXZhdGlvbiA9IDEsXG4gIFBvc3RBY3RpdmF0aW9uID0gMixcbn1cblxuZXhwb3J0IGNvbnN0IF9ST1VURVJfQ09ORklHID0gbmV3IEluamVjdGlvblRva2VuKFxuICAnQG5ncngvcm91dGVyLXN0b3JlIEludGVybmFsIENvbmZpZ3VyYXRpb24nXG4pO1xuZXhwb3J0IGNvbnN0IFJPVVRFUl9DT05GSUcgPSBuZXcgSW5qZWN0aW9uVG9rZW4oXG4gICdAbmdyeC9yb3V0ZXItc3RvcmUgQ29uZmlndXJhdGlvbidcbik7XG5leHBvcnQgY29uc3QgREVGQVVMVF9ST1VURVJfRkVBVFVSRU5BTUUgPSAncm91dGVyJztcblxuZXhwb3J0IGZ1bmN0aW9uIF9jcmVhdGVSb3V0ZXJDb25maWcoXG4gIGNvbmZpZzogU3RvcmVSb3V0ZXJDb25maWdcbik6IFN0b3JlUm91dGVyQ29uZmlnIHtcbiAgcmV0dXJuIHtcbiAgICBzdGF0ZUtleTogREVGQVVMVF9ST1VURVJfRkVBVFVSRU5BTUUsXG4gICAgc2VyaWFsaXplcjogTWluaW1hbFJvdXRlclN0YXRlU2VyaWFsaXplcixcbiAgICBuYXZpZ2F0aW9uQWN0aW9uVGltaW5nOiBOYXZpZ2F0aW9uQWN0aW9uVGltaW5nLlByZUFjdGl2YXRpb24sXG4gICAgLi4uY29uZmlnLFxuICB9O1xufVxuXG5lbnVtIFJvdXRlclRyaWdnZXIge1xuICBOT05FID0gMSxcbiAgUk9VVEVSID0gMixcbiAgU1RPUkUgPSAzLFxufVxuXG4vKipcbiAqIENvbm5lY3RzIFJvdXRlck1vZHVsZSB3aXRoIFN0b3JlTW9kdWxlLlxuICpcbiAqIER1cmluZyB0aGUgbmF2aWdhdGlvbiwgYmVmb3JlIGFueSBndWFyZHMgb3IgcmVzb2x2ZXJzIHJ1biwgdGhlIHJvdXRlciB3aWxsIGRpc3BhdGNoXG4gKiBhIFJPVVRFUl9OQVZJR0FUSU9OIGFjdGlvbiwgd2hpY2ggaGFzIHRoZSBmb2xsb3dpbmcgc2lnbmF0dXJlOlxuICpcbiAqIGBgYFxuICogZXhwb3J0IHR5cGUgUm91dGVyTmF2aWdhdGlvblBheWxvYWQgPSB7XG4gKiAgIHJvdXRlclN0YXRlOiBTZXJpYWxpemVkUm91dGVyU3RhdGVTbmFwc2hvdCxcbiAqICAgZXZlbnQ6IFJvdXRlc1JlY29nbml6ZWRcbiAqIH1cbiAqIGBgYFxuICpcbiAqIEVpdGhlciBhIHJlZHVjZXIgb3IgYW4gZWZmZWN0IGNhbiBiZSBpbnZva2VkIGluIHJlc3BvbnNlIHRvIHRoaXMgYWN0aW9uLlxuICogSWYgdGhlIGludm9rZWQgcmVkdWNlciB0aHJvd3MsIHRoZSBuYXZpZ2F0aW9uIHdpbGwgYmUgY2FuY2VsZWQuXG4gKlxuICogSWYgbmF2aWdhdGlvbiBnZXRzIGNhbmNlbGVkIGJlY2F1c2Ugb2YgYSBndWFyZCwgYSBST1VURVJfQ0FOQ0VMIGFjdGlvbiB3aWxsIGJlXG4gKiBkaXNwYXRjaGVkLiBJZiBuYXZpZ2F0aW9uIHJlc3VsdHMgaW4gYW4gZXJyb3IsIGEgUk9VVEVSX0VSUk9SIGFjdGlvbiB3aWxsIGJlIGRpc3BhdGNoZWQuXG4gKlxuICogQm90aCBST1VURVJfQ0FOQ0VMIGFuZCBST1VURVJfRVJST1IgY29udGFpbiB0aGUgc3RvcmUgc3RhdGUgYmVmb3JlIHRoZSBuYXZpZ2F0aW9uXG4gKiB3aGljaCBjYW4gYmUgdXNlZCB0byByZXN0b3JlIHRoZSBjb25zaXN0ZW5jeSBvZiB0aGUgc3RvcmUuXG4gKlxuICogVXNhZ2U6XG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogQE5nTW9kdWxlKHtcbiAqICAgZGVjbGFyYXRpb25zOiBbQXBwQ21wLCBTaW1wbGVDbXBdLFxuICogICBpbXBvcnRzOiBbXG4gKiAgICAgQnJvd3Nlck1vZHVsZSxcbiAqICAgICBTdG9yZU1vZHVsZS5mb3JSb290KG1hcE9mUmVkdWNlcnMpLFxuICogICAgIFJvdXRlck1vZHVsZS5mb3JSb290KFtcbiAqICAgICAgIHsgcGF0aDogJycsIGNvbXBvbmVudDogU2ltcGxlQ21wIH0sXG4gKiAgICAgICB7IHBhdGg6ICduZXh0JywgY29tcG9uZW50OiBTaW1wbGVDbXAgfVxuICogICAgIF0pLFxuICogICAgIFN0b3JlUm91dGVyQ29ubmVjdGluZ01vZHVsZS5mb3JSb290KClcbiAqICAgXSxcbiAqICAgYm9vdHN0cmFwOiBbQXBwQ21wXVxuICogfSlcbiAqIGV4cG9ydCBjbGFzcyBBcHBNb2R1bGUge1xuICogfVxuICogYGBgXG4gKi9cbkBOZ01vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBTdG9yZVJvdXRlckNvbm5lY3RpbmdNb2R1bGUge1xuICBwcml2YXRlIGxhc3RFdmVudDogRXZlbnQgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSByb3V0ZXJTdGF0ZTogU2VyaWFsaXplZFJvdXRlclN0YXRlU25hcHNob3QgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBzdG9yZVN0YXRlOiBhbnk7XG4gIHByaXZhdGUgdHJpZ2dlciA9IFJvdXRlclRyaWdnZXIuTk9ORTtcbiAgcHJpdmF0ZSByZWFkb25seSBzdGF0ZUtleTogU3RhdGVLZXlPclNlbGVjdG9yO1xuXG4gIHN0YXRpYyBmb3JSb290PFxuICAgIFQgZXh0ZW5kcyBCYXNlUm91dGVyU3RvcmVTdGF0ZSA9IFNlcmlhbGl6ZWRSb3V0ZXJTdGF0ZVNuYXBzaG90XG4gID4oXG4gICAgY29uZmlnOiBTdG9yZVJvdXRlckNvbmZpZzxUPiA9IHt9XG4gICk6IE1vZHVsZVdpdGhQcm92aWRlcnM8U3RvcmVSb3V0ZXJDb25uZWN0aW5nTW9kdWxlPiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5nTW9kdWxlOiBTdG9yZVJvdXRlckNvbm5lY3RpbmdNb2R1bGUsXG4gICAgICBwcm92aWRlcnM6IFtcbiAgICAgICAgeyBwcm92aWRlOiBfUk9VVEVSX0NPTkZJRywgdXNlVmFsdWU6IGNvbmZpZyB9LFxuICAgICAgICB7XG4gICAgICAgICAgcHJvdmlkZTogUk9VVEVSX0NPTkZJRyxcbiAgICAgICAgICB1c2VGYWN0b3J5OiBfY3JlYXRlUm91dGVyQ29uZmlnLFxuICAgICAgICAgIGRlcHM6IFtfUk9VVEVSX0NPTkZJR10sXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBwcm92aWRlOiBSb3V0ZXJTdGF0ZVNlcmlhbGl6ZXIsXG4gICAgICAgICAgdXNlQ2xhc3M6IGNvbmZpZy5zZXJpYWxpemVyXG4gICAgICAgICAgICA/IGNvbmZpZy5zZXJpYWxpemVyXG4gICAgICAgICAgICA6IGNvbmZpZy5yb3V0ZXJTdGF0ZSA9PT0gUm91dGVyU3RhdGUuRnVsbFxuICAgICAgICAgICAgPyBGdWxsUm91dGVyU3RhdGVTZXJpYWxpemVyXG4gICAgICAgICAgICA6IE1pbmltYWxSb3V0ZXJTdGF0ZVNlcmlhbGl6ZXIsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH07XG4gIH1cblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHN0b3JlOiBTdG9yZTxhbnk+LFxuICAgIHByaXZhdGUgcm91dGVyOiBSb3V0ZXIsXG4gICAgcHJpdmF0ZSBzZXJpYWxpemVyOiBSb3V0ZXJTdGF0ZVNlcmlhbGl6ZXI8U2VyaWFsaXplZFJvdXRlclN0YXRlU25hcHNob3Q+LFxuICAgIHByaXZhdGUgZXJyb3JIYW5kbGVyOiBFcnJvckhhbmRsZXIsXG4gICAgQEluamVjdChST1VURVJfQ09ORklHKSBwcml2YXRlIHJlYWRvbmx5IGNvbmZpZzogU3RvcmVSb3V0ZXJDb25maWcsXG4gICAgQEluamVjdChBQ1RJVkVfUlVOVElNRV9DSEVDS1MpXG4gICAgcHJpdmF0ZSByZWFkb25seSBhY3RpdmVSdW50aW1lQ2hlY2tzOiBSdW50aW1lQ2hlY2tzXG4gICkge1xuICAgIHRoaXMuc3RhdGVLZXkgPSB0aGlzLmNvbmZpZy5zdGF0ZUtleSBhcyBTdGF0ZUtleU9yU2VsZWN0b3I7XG5cbiAgICBpZiAoXG4gICAgICAhaXNOZ3J4TW9ja0Vudmlyb25tZW50KCkgJiZcbiAgICAgIGlzRGV2TW9kZSgpICYmXG4gICAgICAoYWN0aXZlUnVudGltZUNoZWNrcz8uc3RyaWN0QWN0aW9uU2VyaWFsaXphYmlsaXR5IHx8XG4gICAgICAgIGFjdGl2ZVJ1bnRpbWVDaGVja3M/LnN0cmljdFN0YXRlU2VyaWFsaXphYmlsaXR5KSAmJlxuICAgICAgdGhpcy5zZXJpYWxpemVyIGluc3RhbmNlb2YgRnVsbFJvdXRlclN0YXRlU2VyaWFsaXplclxuICAgICkge1xuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAnQG5ncngvcm91dGVyLXN0b3JlOiBUaGUgc2VyaWFsaXphYmlsaXR5IHJ1bnRpbWUgY2hlY2tzIGNhbm5vdCBiZSBlbmFibGVkICcgK1xuICAgICAgICAgICd3aXRoIHRoZSBGdWxsUm91dGVyU3RhdGVTZXJpYWxpemVyLiBUaGUgRnVsbFJvdXRlclN0YXRlU2VyaWFsaXplciAnICtcbiAgICAgICAgICAnaGFzIGFuIHVuc2VyaWFsaXphYmxlIHJvdXRlciBzdGF0ZSBhbmQgYWN0aW9ucyB0aGF0IGFyZSBub3Qgc2VyaWFsaXphYmxlLiAnICtcbiAgICAgICAgICAnVG8gdXNlIHRoZSBzZXJpYWxpemFiaWxpdHkgcnVudGltZSBjaGVja3MgZWl0aGVyIHVzZSAnICtcbiAgICAgICAgICAndGhlIE1pbmltYWxSb3V0ZXJTdGF0ZVNlcmlhbGl6ZXIgb3IgaW1wbGVtZW50IGEgY3VzdG9tIHJvdXRlciBzdGF0ZSBzZXJpYWxpemVyLidcbiAgICAgICk7XG4gICAgfVxuXG4gICAgdGhpcy5zZXRVcFN0b3JlU3RhdGVMaXN0ZW5lcigpO1xuICAgIHRoaXMuc2V0VXBSb3V0ZXJFdmVudHNMaXN0ZW5lcigpO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXRVcFN0b3JlU3RhdGVMaXN0ZW5lcigpOiB2b2lkIHtcbiAgICB0aGlzLnN0b3JlXG4gICAgICAucGlwZShzZWxlY3QodGhpcy5zdGF0ZUtleSBhcyBhbnkpLCB3aXRoTGF0ZXN0RnJvbSh0aGlzLnN0b3JlKSlcbiAgICAgIC5zdWJzY3JpYmUoKFtyb3V0ZXJTdG9yZVN0YXRlLCBzdG9yZVN0YXRlXSkgPT4ge1xuICAgICAgICB0aGlzLm5hdmlnYXRlSWZOZWVkZWQocm91dGVyU3RvcmVTdGF0ZSwgc3RvcmVTdGF0ZSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgbmF2aWdhdGVJZk5lZWRlZChcbiAgICByb3V0ZXJTdG9yZVN0YXRlOiBSb3V0ZXJSZWR1Y2VyU3RhdGUsXG4gICAgc3RvcmVTdGF0ZTogYW55XG4gICk6IHZvaWQge1xuICAgIGlmICghcm91dGVyU3RvcmVTdGF0ZSB8fCAhcm91dGVyU3RvcmVTdGF0ZS5zdGF0ZSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAodGhpcy50cmlnZ2VyID09PSBSb3V0ZXJUcmlnZ2VyLlJPVVRFUikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAodGhpcy5sYXN0RXZlbnQgaW5zdGFuY2VvZiBOYXZpZ2F0aW9uU3RhcnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCB1cmwgPSByb3V0ZXJTdG9yZVN0YXRlLnN0YXRlLnVybDtcbiAgICBpZiAoIWlzU2FtZVVybCh0aGlzLnJvdXRlci51cmwsIHVybCkpIHtcbiAgICAgIHRoaXMuc3RvcmVTdGF0ZSA9IHN0b3JlU3RhdGU7XG4gICAgICB0aGlzLnRyaWdnZXIgPSBSb3V0ZXJUcmlnZ2VyLlNUT1JFO1xuICAgICAgdGhpcy5yb3V0ZXIubmF2aWdhdGVCeVVybCh1cmwpLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5oYW5kbGVFcnJvcihlcnJvcik7XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldFVwUm91dGVyRXZlbnRzTGlzdGVuZXIoKTogdm9pZCB7XG4gICAgY29uc3QgZGlzcGF0Y2hOYXZMYXRlID1cbiAgICAgIHRoaXMuY29uZmlnLm5hdmlnYXRpb25BY3Rpb25UaW1pbmcgPT09XG4gICAgICBOYXZpZ2F0aW9uQWN0aW9uVGltaW5nLlBvc3RBY3RpdmF0aW9uO1xuICAgIGxldCByb3V0ZXNSZWNvZ25pemVkOiBSb3V0ZXNSZWNvZ25pemVkO1xuXG4gICAgdGhpcy5yb3V0ZXIuZXZlbnRzXG4gICAgICAucGlwZSh3aXRoTGF0ZXN0RnJvbSh0aGlzLnN0b3JlKSlcbiAgICAgIC5zdWJzY3JpYmUoKFtldmVudCwgc3RvcmVTdGF0ZV0pID0+IHtcbiAgICAgICAgdGhpcy5sYXN0RXZlbnQgPSBldmVudDtcblxuICAgICAgICBpZiAoZXZlbnQgaW5zdGFuY2VvZiBOYXZpZ2F0aW9uU3RhcnQpIHtcbiAgICAgICAgICB0aGlzLnJvdXRlclN0YXRlID0gdGhpcy5zZXJpYWxpemVyLnNlcmlhbGl6ZShcbiAgICAgICAgICAgIHRoaXMucm91dGVyLnJvdXRlclN0YXRlLnNuYXBzaG90XG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAodGhpcy50cmlnZ2VyICE9PSBSb3V0ZXJUcmlnZ2VyLlNUT1JFKSB7XG4gICAgICAgICAgICB0aGlzLnN0b3JlU3RhdGUgPSBzdG9yZVN0YXRlO1xuICAgICAgICAgICAgdGhpcy5kaXNwYXRjaFJvdXRlclJlcXVlc3QoZXZlbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChldmVudCBpbnN0YW5jZW9mIFJvdXRlc1JlY29nbml6ZWQpIHtcbiAgICAgICAgICByb3V0ZXNSZWNvZ25pemVkID0gZXZlbnQ7XG5cbiAgICAgICAgICBpZiAoIWRpc3BhdGNoTmF2TGF0ZSAmJiB0aGlzLnRyaWdnZXIgIT09IFJvdXRlclRyaWdnZXIuU1RPUkUpIHtcbiAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2hSb3V0ZXJOYXZpZ2F0aW9uKGV2ZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQgaW5zdGFuY2VvZiBOYXZpZ2F0aW9uQ2FuY2VsKSB7XG4gICAgICAgICAgdGhpcy5kaXNwYXRjaFJvdXRlckNhbmNlbChldmVudCk7XG4gICAgICAgICAgdGhpcy5yZXNldCgpO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50IGluc3RhbmNlb2YgTmF2aWdhdGlvbkVycm9yKSB7XG4gICAgICAgICAgdGhpcy5kaXNwYXRjaFJvdXRlckVycm9yKGV2ZW50KTtcbiAgICAgICAgICB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQgaW5zdGFuY2VvZiBOYXZpZ2F0aW9uRW5kKSB7XG4gICAgICAgICAgaWYgKHRoaXMudHJpZ2dlciAhPT0gUm91dGVyVHJpZ2dlci5TVE9SRSkge1xuICAgICAgICAgICAgaWYgKGRpc3BhdGNoTmF2TGF0ZSkge1xuICAgICAgICAgICAgICB0aGlzLmRpc3BhdGNoUm91dGVyTmF2aWdhdGlvbihyb3V0ZXNSZWNvZ25pemVkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2hSb3V0ZXJOYXZpZ2F0ZWQoZXZlbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBkaXNwYXRjaFJvdXRlclJlcXVlc3QoZXZlbnQ6IE5hdmlnYXRpb25TdGFydCk6IHZvaWQge1xuICAgIHRoaXMuZGlzcGF0Y2hSb3V0ZXJBY3Rpb24oUk9VVEVSX1JFUVVFU1QsIHsgZXZlbnQgfSk7XG4gIH1cblxuICBwcml2YXRlIGRpc3BhdGNoUm91dGVyTmF2aWdhdGlvbihcbiAgICBsYXN0Um91dGVzUmVjb2duaXplZDogUm91dGVzUmVjb2duaXplZFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBuZXh0Um91dGVyU3RhdGUgPSB0aGlzLnNlcmlhbGl6ZXIuc2VyaWFsaXplKFxuICAgICAgbGFzdFJvdXRlc1JlY29nbml6ZWQuc3RhdGVcbiAgICApO1xuICAgIHRoaXMuZGlzcGF0Y2hSb3V0ZXJBY3Rpb24oUk9VVEVSX05BVklHQVRJT04sIHtcbiAgICAgIHJvdXRlclN0YXRlOiBuZXh0Um91dGVyU3RhdGUsXG4gICAgICBldmVudDogbmV3IFJvdXRlc1JlY29nbml6ZWQoXG4gICAgICAgIGxhc3RSb3V0ZXNSZWNvZ25pemVkLmlkLFxuICAgICAgICBsYXN0Um91dGVzUmVjb2duaXplZC51cmwsXG4gICAgICAgIGxhc3RSb3V0ZXNSZWNvZ25pemVkLnVybEFmdGVyUmVkaXJlY3RzLFxuICAgICAgICBuZXh0Um91dGVyU3RhdGVcbiAgICAgICksXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGRpc3BhdGNoUm91dGVyQ2FuY2VsKGV2ZW50OiBOYXZpZ2F0aW9uQ2FuY2VsKTogdm9pZCB7XG4gICAgdGhpcy5kaXNwYXRjaFJvdXRlckFjdGlvbihST1VURVJfQ0FOQ0VMLCB7XG4gICAgICBzdG9yZVN0YXRlOiB0aGlzLnN0b3JlU3RhdGUsXG4gICAgICBldmVudCxcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgZGlzcGF0Y2hSb3V0ZXJFcnJvcihldmVudDogTmF2aWdhdGlvbkVycm9yKTogdm9pZCB7XG4gICAgdGhpcy5kaXNwYXRjaFJvdXRlckFjdGlvbihST1VURVJfRVJST1IsIHtcbiAgICAgIHN0b3JlU3RhdGU6IHRoaXMuc3RvcmVTdGF0ZSxcbiAgICAgIGV2ZW50OiBuZXcgTmF2aWdhdGlvbkVycm9yKGV2ZW50LmlkLCBldmVudC51cmwsIGAke2V2ZW50fWApLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBkaXNwYXRjaFJvdXRlck5hdmlnYXRlZChldmVudDogTmF2aWdhdGlvbkVuZCk6IHZvaWQge1xuICAgIGNvbnN0IHJvdXRlclN0YXRlID0gdGhpcy5zZXJpYWxpemVyLnNlcmlhbGl6ZShcbiAgICAgIHRoaXMucm91dGVyLnJvdXRlclN0YXRlLnNuYXBzaG90XG4gICAgKTtcbiAgICB0aGlzLmRpc3BhdGNoUm91dGVyQWN0aW9uKFJPVVRFUl9OQVZJR0FURUQsIHsgZXZlbnQsIHJvdXRlclN0YXRlIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBkaXNwYXRjaFJvdXRlckFjdGlvbihcbiAgICB0eXBlOiBzdHJpbmcsXG4gICAgcGF5bG9hZDogU3RvcmVSb3V0ZXJBY3Rpb25QYXlsb2FkXG4gICk6IHZvaWQge1xuICAgIHRoaXMudHJpZ2dlciA9IFJvdXRlclRyaWdnZXIuUk9VVEVSO1xuICAgIHRyeSB7XG4gICAgICB0aGlzLnN0b3JlLmRpc3BhdGNoKHtcbiAgICAgICAgdHlwZSxcbiAgICAgICAgcGF5bG9hZDoge1xuICAgICAgICAgIHJvdXRlclN0YXRlOiB0aGlzLnJvdXRlclN0YXRlLFxuICAgICAgICAgIC4uLnBheWxvYWQsXG4gICAgICAgICAgZXZlbnQ6XG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5yb3V0ZXJTdGF0ZSA9PT0gUm91dGVyU3RhdGUuRnVsbFxuICAgICAgICAgICAgICA/IHBheWxvYWQuZXZlbnRcbiAgICAgICAgICAgICAgOiB7XG4gICAgICAgICAgICAgICAgICBpZDogcGF5bG9hZC5ldmVudC5pZCxcbiAgICAgICAgICAgICAgICAgIHVybDogcGF5bG9hZC5ldmVudC51cmwsXG4gICAgICAgICAgICAgICAgICAvLyBzYWZlLCBhcyBpdCB3aWxsIGp1c3QgYmUgYHVuZGVmaW5lZGAgZm9yIG5vbi1OYXZpZ2F0aW9uRW5kIHJvdXRlciBldmVudHNcbiAgICAgICAgICAgICAgICAgIHVybEFmdGVyUmVkaXJlY3RzOiAocGF5bG9hZC5ldmVudCBhcyBOYXZpZ2F0aW9uRW5kKVxuICAgICAgICAgICAgICAgICAgICAudXJsQWZ0ZXJSZWRpcmVjdHMsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLnRyaWdnZXIgPSBSb3V0ZXJUcmlnZ2VyLk5PTkU7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZXNldCgpIHtcbiAgICB0aGlzLnRyaWdnZXIgPSBSb3V0ZXJUcmlnZ2VyLk5PTkU7XG4gICAgdGhpcy5zdG9yZVN0YXRlID0gbnVsbDtcbiAgICB0aGlzLnJvdXRlclN0YXRlID0gbnVsbDtcbiAgfVxufVxuXG4vKipcbiAqIENoZWNrIGlmIHRoZSBVUkxzIGFyZSBtYXRjaGluZy4gQWNjb3VudHMgZm9yIHRoZSBwb3NzaWJpbGl0eSBvZiB0cmFpbGluZyBcIi9cIiBpbiB1cmwuXG4gKi9cbmZ1bmN0aW9uIGlzU2FtZVVybChmaXJzdDogc3RyaW5nLCBzZWNvbmQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gc3RyaXBUcmFpbGluZ1NsYXNoKGZpcnN0KSA9PT0gc3RyaXBUcmFpbGluZ1NsYXNoKHNlY29uZCk7XG59XG5cbmZ1bmN0aW9uIHN0cmlwVHJhaWxpbmdTbGFzaCh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAodGV4dD8ubGVuZ3RoID4gMCAmJiB0ZXh0W3RleHQubGVuZ3RoIC0gMV0gPT09ICcvJykge1xuICAgIHJldHVybiB0ZXh0LnN1YnN0cmluZygwLCB0ZXh0Lmxlbmd0aCAtIDEpO1xuICB9XG4gIHJldHVybiB0ZXh0O1xufVxuIl19
\No newline at end of file