@nauth-toolkit/client-angular 0.1.58 → 0.1.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,83 +0,0 @@
1
- import { inject } from '@angular/core';
2
- import { Router } from '@angular/router';
3
- import { AuthService } from './auth.service';
4
- /**
5
- * Functional route guard for authentication (Angular 17+).
6
- *
7
- * Protects routes by checking if user is authenticated.
8
- * Redirects to login page if not authenticated.
9
- *
10
- * @param redirectTo - Path to redirect to if not authenticated (default: '/login')
11
- * @returns CanActivateFn guard function
12
- *
13
- * @example
14
- * ```typescript
15
- * // In route configuration
16
- * const routes: Routes = [
17
- * {
18
- * path: 'home',
19
- * component: HomeComponent,
20
- * canActivate: [authGuard()]
21
- * },
22
- * {
23
- * path: 'admin',
24
- * component: AdminComponent,
25
- * canActivate: [authGuard('/admin/login')]
26
- * }
27
- * ];
28
- * ```
29
- */
30
- export function authGuard(redirectTo = '/login') {
31
- return () => {
32
- const auth = inject(AuthService);
33
- const router = inject(Router);
34
- if (auth.isAuthenticated()) {
35
- return true;
36
- }
37
- return router.createUrlTree([redirectTo]);
38
- };
39
- }
40
- /**
41
- * Class-based authentication guard for NgModule compatibility.
42
- *
43
- * @example
44
- * ```typescript
45
- * // In route configuration (NgModule)
46
- * const routes: Routes = [
47
- * {
48
- * path: 'home',
49
- * component: HomeComponent,
50
- * canActivate: [AuthGuard]
51
- * }
52
- * ];
53
- *
54
- * // In module providers
55
- * @NgModule({
56
- * providers: [AuthGuard]
57
- * })
58
- * ```
59
- */
60
- export class AuthGuard {
61
- auth;
62
- router;
63
- /**
64
- * @param auth - Authentication service
65
- * @param router - Angular router
66
- */
67
- constructor(auth, router) {
68
- this.auth = auth;
69
- this.router = router;
70
- }
71
- /**
72
- * Check if route can be activated.
73
- *
74
- * @returns True if authenticated, otherwise redirects to login
75
- */
76
- canActivate() {
77
- if (this.auth.isAuthenticated()) {
78
- return true;
79
- }
80
- return this.router.createUrlTree(['/login']);
81
- }
82
- }
83
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5ndWFyZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3N0YW5kYWxvbmUvYXV0aC5ndWFyZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3ZDLE9BQU8sRUFBaUIsTUFBTSxFQUFXLE1BQU0saUJBQWlCLENBQUM7QUFDakUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTdDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBeUJHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBQyxVQUFVLEdBQUcsUUFBUTtJQUM3QyxPQUFPLEdBQXNCLEVBQUU7UUFDN0IsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ2pDLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUU5QixJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDO1lBQzNCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELE9BQU8sTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFDNUMsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUFNVjtJQUNBO0lBTlY7OztPQUdHO0lBQ0gsWUFDVSxJQUFpQixFQUNqQixNQUFjO1FBRGQsU0FBSSxHQUFKLElBQUksQ0FBYTtRQUNqQixXQUFNLEdBQU4sTUFBTSxDQUFRO0lBQ3JCLENBQUM7SUFFSjs7OztPQUlHO0lBQ0gsV0FBVztRQUNULElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDO1lBQ2hDLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQy9DLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ2FuQWN0aXZhdGVGbiwgUm91dGVyLCBVcmxUcmVlIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IEF1dGhTZXJ2aWNlIH0gZnJvbSAnLi9hdXRoLnNlcnZpY2UnO1xuXG4vKipcbiAqIEZ1bmN0aW9uYWwgcm91dGUgZ3VhcmQgZm9yIGF1dGhlbnRpY2F0aW9uIChBbmd1bGFyIDE3KykuXG4gKlxuICogUHJvdGVjdHMgcm91dGVzIGJ5IGNoZWNraW5nIGlmIHVzZXIgaXMgYXV0aGVudGljYXRlZC5cbiAqIFJlZGlyZWN0cyB0byBsb2dpbiBwYWdlIGlmIG5vdCBhdXRoZW50aWNhdGVkLlxuICpcbiAqIEBwYXJhbSByZWRpcmVjdFRvIC0gUGF0aCB0byByZWRpcmVjdCB0byBpZiBub3QgYXV0aGVudGljYXRlZCAoZGVmYXVsdDogJy9sb2dpbicpXG4gKiBAcmV0dXJucyBDYW5BY3RpdmF0ZUZuIGd1YXJkIGZ1bmN0aW9uXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIEluIHJvdXRlIGNvbmZpZ3VyYXRpb25cbiAqIGNvbnN0IHJvdXRlczogUm91dGVzID0gW1xuICogICB7XG4gKiAgICAgcGF0aDogJ2hvbWUnLFxuICogICAgIGNvbXBvbmVudDogSG9tZUNvbXBvbmVudCxcbiAqICAgICBjYW5BY3RpdmF0ZTogW2F1dGhHdWFyZCgpXVxuICogICB9LFxuICogICB7XG4gKiAgICAgcGF0aDogJ2FkbWluJyxcbiAqICAgICBjb21wb25lbnQ6IEFkbWluQ29tcG9uZW50LFxuICogICAgIGNhbkFjdGl2YXRlOiBbYXV0aEd1YXJkKCcvYWRtaW4vbG9naW4nKV1cbiAqICAgfVxuICogXTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gYXV0aEd1YXJkKHJlZGlyZWN0VG8gPSAnL2xvZ2luJyk6IENhbkFjdGl2YXRlRm4ge1xuICByZXR1cm4gKCk6IGJvb2xlYW4gfCBVcmxUcmVlID0+IHtcbiAgICBjb25zdCBhdXRoID0gaW5qZWN0KEF1dGhTZXJ2aWNlKTtcbiAgICBjb25zdCByb3V0ZXIgPSBpbmplY3QoUm91dGVyKTtcblxuICAgIGlmIChhdXRoLmlzQXV0aGVudGljYXRlZCgpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gcm91dGVyLmNyZWF0ZVVybFRyZWUoW3JlZGlyZWN0VG9dKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBDbGFzcy1iYXNlZCBhdXRoZW50aWNhdGlvbiBndWFyZCBmb3IgTmdNb2R1bGUgY29tcGF0aWJpbGl0eS5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gSW4gcm91dGUgY29uZmlndXJhdGlvbiAoTmdNb2R1bGUpXG4gKiBjb25zdCByb3V0ZXM6IFJvdXRlcyA9IFtcbiAqICAge1xuICogICAgIHBhdGg6ICdob21lJyxcbiAqICAgICBjb21wb25lbnQ6IEhvbWVDb21wb25lbnQsXG4gKiAgICAgY2FuQWN0aXZhdGU6IFtBdXRoR3VhcmRdXG4gKiAgIH1cbiAqIF07XG4gKlxuICogLy8gSW4gbW9kdWxlIHByb3ZpZGVyc1xuICogQE5nTW9kdWxlKHtcbiAqICAgcHJvdmlkZXJzOiBbQXV0aEd1YXJkXVxuICogfSlcbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgQXV0aEd1YXJkIHtcbiAgLyoqXG4gICAqIEBwYXJhbSBhdXRoIC0gQXV0aGVudGljYXRpb24gc2VydmljZVxuICAgKiBAcGFyYW0gcm91dGVyIC0gQW5ndWxhciByb3V0ZXJcbiAgICovXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgYXV0aDogQXV0aFNlcnZpY2UsXG4gICAgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlcixcbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiByb3V0ZSBjYW4gYmUgYWN0aXZhdGVkLlxuICAgKlxuICAgKiBAcmV0dXJucyBUcnVlIGlmIGF1dGhlbnRpY2F0ZWQsIG90aGVyd2lzZSByZWRpcmVjdHMgdG8gbG9naW5cbiAgICovXG4gIGNhbkFjdGl2YXRlKCk6IGJvb2xlYW4gfCBVcmxUcmVlIHtcbiAgICBpZiAodGhpcy5hdXRoLmlzQXV0aGVudGljYXRlZCgpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5yb3V0ZXIuY3JlYXRlVXJsVHJlZShbJy9sb2dpbiddKTtcbiAgfVxufVxuIl19
@@ -1,158 +0,0 @@
1
- import { inject, PLATFORM_ID } from '@angular/core';
2
- import { isPlatformBrowser } from '@angular/common';
3
- import { HttpClient, HttpErrorResponse } from '@angular/common/http';
4
- import { Router } from '@angular/router';
5
- import { catchError, switchMap, throwError, filter, take, BehaviorSubject, from } from 'rxjs';
6
- import { NAUTH_CLIENT_CONFIG } from './tokens';
7
- import { AuthService } from './auth.service';
8
- /**
9
- * Refresh state management.
10
- * BehaviorSubject pattern is the industry-standard for token refresh.
11
- */
12
- let isRefreshing = false;
13
- const refreshTokenSubject = new BehaviorSubject(null);
14
- /**
15
- * Track retried requests to prevent infinite loops.
16
- */
17
- const retriedRequests = new WeakSet();
18
- /**
19
- * Get CSRF token from cookie.
20
- */
21
- function getCsrfToken(cookieName) {
22
- if (typeof document === 'undefined')
23
- return null;
24
- const match = document.cookie.match(new RegExp(`(^| )${cookieName}=([^;]+)`));
25
- return match ? decodeURIComponent(match[2]) : null;
26
- }
27
- /**
28
- * Angular HTTP interceptor for nauth-toolkit.
29
- *
30
- * Handles:
31
- * - Cookies mode: withCredentials + CSRF tokens + refresh via POST
32
- * - JSON mode: refresh via SDK, retry with new token
33
- */
34
- export const authInterceptor = (req, next) => {
35
- const config = inject(NAUTH_CLIENT_CONFIG);
36
- const http = inject(HttpClient);
37
- const authService = inject(AuthService);
38
- const platformId = inject(PLATFORM_ID);
39
- const router = inject(Router);
40
- const isBrowser = isPlatformBrowser(platformId);
41
- if (!isBrowser) {
42
- return next(req);
43
- }
44
- const tokenDelivery = config.tokenDelivery;
45
- const baseUrl = config.baseUrl;
46
- const endpoints = config.endpoints ?? {};
47
- const refreshPath = endpoints.refresh ?? '/refresh';
48
- const loginPath = endpoints.login ?? '/login';
49
- const signupPath = endpoints.signup ?? '/signup';
50
- const socialExchangePath = endpoints.socialExchange ?? '/social/exchange';
51
- const refreshUrl = `${baseUrl}${refreshPath}`;
52
- const isAuthApiRequest = req.url.includes(baseUrl);
53
- const isRefreshEndpoint = req.url.includes(refreshPath);
54
- const isPublicEndpoint = req.url.includes(loginPath) || req.url.includes(signupPath) || req.url.includes(socialExchangePath);
55
- // Build request with credentials (cookies mode only)
56
- let authReq = req;
57
- if (tokenDelivery === 'cookies') {
58
- authReq = authReq.clone({ withCredentials: true });
59
- if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
60
- const csrfCookieName = config.csrf?.cookieName ?? 'nauth_csrf_token';
61
- const csrfHeaderName = config.csrf?.headerName ?? 'x-csrf-token';
62
- const csrfToken = getCsrfToken(csrfCookieName);
63
- if (csrfToken) {
64
- authReq = authReq.clone({ setHeaders: { [csrfHeaderName]: csrfToken } });
65
- }
66
- }
67
- }
68
- return next(authReq).pipe(catchError((error) => {
69
- const shouldHandle = error instanceof HttpErrorResponse &&
70
- error.status === 401 &&
71
- isAuthApiRequest &&
72
- !isRefreshEndpoint &&
73
- !isPublicEndpoint &&
74
- !retriedRequests.has(req);
75
- if (!shouldHandle) {
76
- return throwError(() => error);
77
- }
78
- if (config.debug) {
79
- console.warn('[nauth-interceptor] 401 detected:', req.url);
80
- }
81
- if (!isRefreshing) {
82
- isRefreshing = true;
83
- refreshTokenSubject.next(null);
84
- if (config.debug) {
85
- console.warn('[nauth-interceptor] Starting refresh...');
86
- }
87
- // Refresh based on mode
88
- const refresh$ = tokenDelivery === 'cookies'
89
- ? http.post(refreshUrl, {}, { withCredentials: true })
90
- : from(authService.refresh());
91
- return refresh$.pipe(switchMap((response) => {
92
- if (config.debug) {
93
- console.warn('[nauth-interceptor] Refresh successful');
94
- }
95
- isRefreshing = false;
96
- // Get new token (JSON mode) or signal success (cookies mode)
97
- const newToken = 'accessToken' in response ? response.accessToken : 'success';
98
- refreshTokenSubject.next(newToken ?? 'success');
99
- // Build retry request
100
- const retryReq = buildRetryRequest(authReq, tokenDelivery, newToken);
101
- retriedRequests.add(retryReq);
102
- if (config.debug) {
103
- console.warn('[nauth-interceptor] Retrying:', req.url);
104
- }
105
- return next(retryReq);
106
- }), catchError((err) => {
107
- if (config.debug) {
108
- console.error('[nauth-interceptor] Refresh failed:', err);
109
- }
110
- isRefreshing = false;
111
- refreshTokenSubject.next(null);
112
- // Handle session expiration - redirect to configured URL
113
- if (config.redirects?.sessionExpired) {
114
- router.navigateByUrl(config.redirects.sessionExpired).catch((navError) => {
115
- if (config.debug) {
116
- console.error('[nauth-interceptor] Navigation failed:', navError);
117
- }
118
- });
119
- }
120
- return throwError(() => err);
121
- }));
122
- }
123
- else {
124
- // Wait for ongoing refresh
125
- if (config.debug) {
126
- console.warn('[nauth-interceptor] Waiting for refresh...');
127
- }
128
- return refreshTokenSubject.pipe(filter((token) => token !== null), take(1), switchMap((token) => {
129
- if (config.debug) {
130
- console.warn('[nauth-interceptor] Refresh done, retrying:', req.url);
131
- }
132
- const retryReq = buildRetryRequest(authReq, tokenDelivery, token);
133
- retriedRequests.add(retryReq);
134
- return next(retryReq);
135
- }));
136
- }
137
- }));
138
- };
139
- /**
140
- * Build retry request with appropriate auth.
141
- */
142
- function buildRetryRequest(originalReq, tokenDelivery, newToken) {
143
- if (tokenDelivery === 'json' && newToken && newToken !== 'success') {
144
- return originalReq.clone({
145
- setHeaders: { Authorization: `Bearer ${newToken}` },
146
- });
147
- }
148
- return originalReq.clone();
149
- }
150
- /**
151
- * Class-based interceptor for NgModule compatibility.
152
- */
153
- export class AuthInterceptor {
154
- intercept(req, next) {
155
- return authInterceptor(req, next);
156
- }
157
- }
158
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5pbnRlcmNlcHRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3N0YW5kYWxvbmUvYXV0aC5pbnRlcmNlcHRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNwRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNwRCxPQUFPLEVBQWlELFVBQVUsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3BILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlGLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMvQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFN0M7OztHQUdHO0FBQ0gsSUFBSSxZQUFZLEdBQUcsS0FBSyxDQUFDO0FBQ3pCLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxlQUFlLENBQWdCLElBQUksQ0FBQyxDQUFDO0FBRXJFOztHQUVHO0FBQ0gsTUFBTSxlQUFlLEdBQUcsSUFBSSxPQUFPLEVBQXdCLENBQUM7QUFFNUQ7O0dBRUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxVQUFrQjtJQUN0QyxJQUFJLE9BQU8sUUFBUSxLQUFLLFdBQVc7UUFBRSxPQUFPLElBQUksQ0FBQztJQUNqRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxRQUFRLFVBQVUsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUM5RSxPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsa0JBQWtCLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztBQUNyRCxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sZUFBZSxHQUFzQixDQUFDLEdBQXlCLEVBQUUsSUFBbUIsRUFBRSxFQUFFO0lBQ25HLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0lBQzNDLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNoQyxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDeEMsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3ZDLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUM5QixNQUFNLFNBQVMsR0FBRyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUVoRCxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDZixPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuQixDQUFDO0lBRUQsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLGFBQWEsQ0FBQztJQUMzQyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDO0lBQy9CLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxTQUFTLElBQUksRUFBRSxDQUFDO0lBQ3pDLE1BQU0sV0FBVyxHQUFHLFNBQVMsQ0FBQyxPQUFPLElBQUksVUFBVSxDQUFDO0lBQ3BELE1BQU0sU0FBUyxHQUFHLFNBQVMsQ0FBQyxLQUFLLElBQUksUUFBUSxDQUFDO0lBQzlDLE1BQU0sVUFBVSxHQUFHLFNBQVMsQ0FBQyxNQUFNLElBQUksU0FBUyxDQUFDO0lBQ2pELE1BQU0sa0JBQWtCLEdBQUcsU0FBUyxDQUFDLGNBQWMsSUFBSSxrQkFBa0IsQ0FBQztJQUMxRSxNQUFNLFVBQVUsR0FBRyxHQUFHLE9BQU8sR0FBRyxXQUFXLEVBQUUsQ0FBQztJQUU5QyxNQUFNLGdCQUFnQixHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ25ELE1BQU0saUJBQWlCLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDeEQsTUFBTSxnQkFBZ0IsR0FDcEIsR0FBRyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQUMsQ0FBQztJQUV0RyxxREFBcUQ7SUFDckQsSUFBSSxPQUFPLEdBQUcsR0FBRyxDQUFDO0lBQ2xCLElBQUksYUFBYSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ2hDLE9BQU8sR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsZUFBZSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFFbkQsSUFBSSxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUM1RCxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLFVBQVUsSUFBSSxrQkFBa0IsQ0FBQztZQUNyRSxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLFVBQVUsSUFBSSxjQUFjLENBQUM7WUFDakUsTUFBTSxTQUFTLEdBQUcsWUFBWSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQy9DLElBQUksU0FBUyxFQUFFLENBQUM7Z0JBQ2QsT0FBTyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxVQUFVLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUMzRSxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQ3ZCLFVBQVUsQ0FBQyxDQUFDLEtBQWMsRUFBRSxFQUFFO1FBQzVCLE1BQU0sWUFBWSxHQUNoQixLQUFLLFlBQVksaUJBQWlCO1lBQ2xDLEtBQUssQ0FBQyxNQUFNLEtBQUssR0FBRztZQUNwQixnQkFBZ0I7WUFDaEIsQ0FBQyxpQkFBaUI7WUFDbEIsQ0FBQyxnQkFBZ0I7WUFDakIsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRTVCLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNsQixPQUFPLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNqQyxDQUFDO1FBRUQsSUFBSSxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDakIsT0FBTyxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDN0QsQ0FBQztRQUVELElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNsQixZQUFZLEdBQUcsSUFBSSxDQUFDO1lBQ3BCLG1CQUFtQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUUvQixJQUFJLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDakIsT0FBTyxDQUFDLElBQUksQ0FBQyx5Q0FBeUMsQ0FBQyxDQUFDO1lBQzFELENBQUM7WUFFRCx3QkFBd0I7WUFDeEIsTUFBTSxRQUFRLEdBQ1osYUFBYSxLQUFLLFNBQVM7Z0JBQ3pCLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUEyQixVQUFVLEVBQUUsRUFBRSxFQUFFLEVBQUUsZUFBZSxFQUFFLElBQUksRUFBRSxDQUFDO2dCQUNoRixDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBRWxDLE9BQU8sUUFBUSxDQUFDLElBQUksQ0FDbEIsU0FBUyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUU7Z0JBQ3JCLElBQUksTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUNqQixPQUFPLENBQUMsSUFBSSxDQUFDLHdDQUF3QyxDQUFDLENBQUM7Z0JBQ3pELENBQUM7Z0JBQ0QsWUFBWSxHQUFHLEtBQUssQ0FBQztnQkFFckIsNkRBQTZEO2dCQUM3RCxNQUFNLFFBQVEsR0FBRyxhQUFhLElBQUksUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7Z0JBQzlFLG1CQUFtQixDQUFDLElBQUksQ0FBQyxRQUFRLElBQUksU0FBUyxDQUFDLENBQUM7Z0JBRWhELHNCQUFzQjtnQkFDdEIsTUFBTSxRQUFRLEdBQUcsaUJBQWlCLENBQUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxRQUFRLENBQUMsQ0FBQztnQkFDckUsZUFBZSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFFOUIsSUFBSSxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7b0JBQ2pCLE9BQU8sQ0FBQyxJQUFJLENBQUMsK0JBQStCLEVBQUUsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUN6RCxDQUFDO2dCQUNELE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3hCLENBQUMsQ0FBQyxFQUNGLFVBQVUsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO2dCQUNqQixJQUFJLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztvQkFDakIsT0FBTyxDQUFDLEtBQUssQ0FBQyxxQ0FBcUMsRUFBRSxHQUFHLENBQUMsQ0FBQztnQkFDNUQsQ0FBQztnQkFDRCxZQUFZLEdBQUcsS0FBSyxDQUFDO2dCQUNyQixtQkFBbUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBRS9CLHlEQUF5RDtnQkFDekQsSUFBSSxNQUFNLENBQUMsU0FBUyxFQUFFLGNBQWMsRUFBRSxDQUFDO29CQUNyQyxNQUFNLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUU7d0JBQ3ZFLElBQUksTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDOzRCQUNqQixPQUFPLENBQUMsS0FBSyxDQUFDLHdDQUF3QyxFQUFFLFFBQVEsQ0FBQyxDQUFDO3dCQUNwRSxDQUFDO29CQUNILENBQUMsQ0FBQyxDQUFDO2dCQUNMLENBQUM7Z0JBRUQsT0FBTyxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDL0IsQ0FBQyxDQUFDLENBQ0gsQ0FBQztRQUNKLENBQUM7YUFBTSxDQUFDO1lBQ04sMkJBQTJCO1lBQzNCLElBQUksTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUNqQixPQUFPLENBQUMsSUFBSSxDQUFDLDRDQUE0QyxDQUFDLENBQUM7WUFDN0QsQ0FBQztZQUNELE9BQU8sbUJBQW1CLENBQUMsSUFBSSxDQUM3QixNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQW1CLEVBQUUsQ0FBQyxLQUFLLEtBQUssSUFBSSxDQUFDLEVBQ2xELElBQUksQ0FBQyxDQUFDLENBQUMsRUFDUCxTQUFTLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtnQkFDbEIsSUFBSSxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7b0JBQ2pCLE9BQU8sQ0FBQyxJQUFJLENBQUMsNkNBQTZDLEVBQUUsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUN2RSxDQUFDO2dCQUNELE1BQU0sUUFBUSxHQUFHLGlCQUFpQixDQUFDLE9BQU8sRUFBRSxhQUFhLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQ2xFLGVBQWUsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzlCLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3hCLENBQUMsQ0FBQyxDQUNILENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQyxDQUFDLENBQ0gsQ0FBQztBQUNKLENBQUMsQ0FBQztBQUVGOztHQUVHO0FBQ0gsU0FBUyxpQkFBaUIsQ0FDeEIsV0FBaUMsRUFDakMsYUFBcUIsRUFDckIsUUFBaUI7SUFFakIsSUFBSSxhQUFhLEtBQUssTUFBTSxJQUFJLFFBQVEsSUFBSSxRQUFRLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDbkUsT0FBTyxXQUFXLENBQUMsS0FBSyxDQUFDO1lBQ3ZCLFVBQVUsRUFBRSxFQUFFLGFBQWEsRUFBRSxVQUFVLFFBQVEsRUFBRSxFQUFFO1NBQ3BELENBQUMsQ0FBQztJQUNMLENBQUM7SUFDRCxPQUFPLFdBQVcsQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUM3QixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sZUFBZTtJQUMxQixTQUFTLENBQUMsR0FBeUIsRUFBRSxJQUFtQjtRQUN0RCxPQUFPLGVBQWUsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDcEMsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaW5qZWN0LCBQTEFURk9STV9JRCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgSHR0cEhhbmRsZXJGbiwgSHR0cEludGVyY2VwdG9yRm4sIEh0dHBSZXF1ZXN0LCBIdHRwQ2xpZW50LCBIdHRwRXJyb3JSZXNwb25zZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBjYXRjaEVycm9yLCBzd2l0Y2hNYXAsIHRocm93RXJyb3IsIGZpbHRlciwgdGFrZSwgQmVoYXZpb3JTdWJqZWN0LCBmcm9tIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBOQVVUSF9DTElFTlRfQ09ORklHIH0gZnJvbSAnLi90b2tlbnMnO1xuaW1wb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICcuL2F1dGguc2VydmljZSc7XG5cbi8qKlxuICogUmVmcmVzaCBzdGF0ZSBtYW5hZ2VtZW50LlxuICogQmVoYXZpb3JTdWJqZWN0IHBhdHRlcm4gaXMgdGhlIGluZHVzdHJ5LXN0YW5kYXJkIGZvciB0b2tlbiByZWZyZXNoLlxuICovXG5sZXQgaXNSZWZyZXNoaW5nID0gZmFsc2U7XG5jb25zdCByZWZyZXNoVG9rZW5TdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxzdHJpbmcgfCBudWxsPihudWxsKTtcblxuLyoqXG4gKiBUcmFjayByZXRyaWVkIHJlcXVlc3RzIHRvIHByZXZlbnQgaW5maW5pdGUgbG9vcHMuXG4gKi9cbmNvbnN0IHJldHJpZWRSZXF1ZXN0cyA9IG5ldyBXZWFrU2V0PEh0dHBSZXF1ZXN0PHVua25vd24+PigpO1xuXG4vKipcbiAqIEdldCBDU1JGIHRva2VuIGZyb20gY29va2llLlxuICovXG5mdW5jdGlvbiBnZXRDc3JmVG9rZW4oY29va2llTmFtZTogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gIGlmICh0eXBlb2YgZG9jdW1lbnQgPT09ICd1bmRlZmluZWQnKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgbWF0Y2ggPSBkb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cChgKF58ICkke2Nvb2tpZU5hbWV9PShbXjtdKylgKSk7XG4gIHJldHVybiBtYXRjaCA/IGRlY29kZVVSSUNvbXBvbmVudChtYXRjaFsyXSkgOiBudWxsO1xufVxuXG4vKipcbiAqIEFuZ3VsYXIgSFRUUCBpbnRlcmNlcHRvciBmb3IgbmF1dGgtdG9vbGtpdC5cbiAqXG4gKiBIYW5kbGVzOlxuICogLSBDb29raWVzIG1vZGU6IHdpdGhDcmVkZW50aWFscyArIENTUkYgdG9rZW5zICsgcmVmcmVzaCB2aWEgUE9TVFxuICogLSBKU09OIG1vZGU6IHJlZnJlc2ggdmlhIFNESywgcmV0cnkgd2l0aCBuZXcgdG9rZW5cbiAqL1xuZXhwb3J0IGNvbnN0IGF1dGhJbnRlcmNlcHRvcjogSHR0cEludGVyY2VwdG9yRm4gPSAocmVxOiBIdHRwUmVxdWVzdDx1bmtub3duPiwgbmV4dDogSHR0cEhhbmRsZXJGbikgPT4ge1xuICBjb25zdCBjb25maWcgPSBpbmplY3QoTkFVVEhfQ0xJRU5UX0NPTkZJRyk7XG4gIGNvbnN0IGh0dHAgPSBpbmplY3QoSHR0cENsaWVudCk7XG4gIGNvbnN0IGF1dGhTZXJ2aWNlID0gaW5qZWN0KEF1dGhTZXJ2aWNlKTtcbiAgY29uc3QgcGxhdGZvcm1JZCA9IGluamVjdChQTEFURk9STV9JRCk7XG4gIGNvbnN0IHJvdXRlciA9IGluamVjdChSb3V0ZXIpO1xuICBjb25zdCBpc0Jyb3dzZXIgPSBpc1BsYXRmb3JtQnJvd3NlcihwbGF0Zm9ybUlkKTtcblxuICBpZiAoIWlzQnJvd3Nlcikge1xuICAgIHJldHVybiBuZXh0KHJlcSk7XG4gIH1cblxuICBjb25zdCB0b2tlbkRlbGl2ZXJ5ID0gY29uZmlnLnRva2VuRGVsaXZlcnk7XG4gIGNvbnN0IGJhc2VVcmwgPSBjb25maWcuYmFzZVVybDtcbiAgY29uc3QgZW5kcG9pbnRzID0gY29uZmlnLmVuZHBvaW50cyA/PyB7fTtcbiAgY29uc3QgcmVmcmVzaFBhdGggPSBlbmRwb2ludHMucmVmcmVzaCA/PyAnL3JlZnJlc2gnO1xuICBjb25zdCBsb2dpblBhdGggPSBlbmRwb2ludHMubG9naW4gPz8gJy9sb2dpbic7XG4gIGNvbnN0IHNpZ251cFBhdGggPSBlbmRwb2ludHMuc2lnbnVwID8/ICcvc2lnbnVwJztcbiAgY29uc3Qgc29jaWFsRXhjaGFuZ2VQYXRoID0gZW5kcG9pbnRzLnNvY2lhbEV4Y2hhbmdlID8/ICcvc29jaWFsL2V4Y2hhbmdlJztcbiAgY29uc3QgcmVmcmVzaFVybCA9IGAke2Jhc2VVcmx9JHtyZWZyZXNoUGF0aH1gO1xuXG4gIGNvbnN0IGlzQXV0aEFwaVJlcXVlc3QgPSByZXEudXJsLmluY2x1ZGVzKGJhc2VVcmwpO1xuICBjb25zdCBpc1JlZnJlc2hFbmRwb2ludCA9IHJlcS51cmwuaW5jbHVkZXMocmVmcmVzaFBhdGgpO1xuICBjb25zdCBpc1B1YmxpY0VuZHBvaW50ID1cbiAgICByZXEudXJsLmluY2x1ZGVzKGxvZ2luUGF0aCkgfHwgcmVxLnVybC5pbmNsdWRlcyhzaWdudXBQYXRoKSB8fCByZXEudXJsLmluY2x1ZGVzKHNvY2lhbEV4Y2hhbmdlUGF0aCk7XG5cbiAgLy8gQnVpbGQgcmVxdWVzdCB3aXRoIGNyZWRlbnRpYWxzIChjb29raWVzIG1vZGUgb25seSlcbiAgbGV0IGF1dGhSZXEgPSByZXE7XG4gIGlmICh0b2tlbkRlbGl2ZXJ5ID09PSAnY29va2llcycpIHtcbiAgICBhdXRoUmVxID0gYXV0aFJlcS5jbG9uZSh7IHdpdGhDcmVkZW50aWFsczogdHJ1ZSB9KTtcblxuICAgIGlmIChbJ1BPU1QnLCAnUFVUJywgJ1BBVENIJywgJ0RFTEVURSddLmluY2x1ZGVzKHJlcS5tZXRob2QpKSB7XG4gICAgICBjb25zdCBjc3JmQ29va2llTmFtZSA9IGNvbmZpZy5jc3JmPy5jb29raWVOYW1lID8/ICduYXV0aF9jc3JmX3Rva2VuJztcbiAgICAgIGNvbnN0IGNzcmZIZWFkZXJOYW1lID0gY29uZmlnLmNzcmY/LmhlYWRlck5hbWUgPz8gJ3gtY3NyZi10b2tlbic7XG4gICAgICBjb25zdCBjc3JmVG9rZW4gPSBnZXRDc3JmVG9rZW4oY3NyZkNvb2tpZU5hbWUpO1xuICAgICAgaWYgKGNzcmZUb2tlbikge1xuICAgICAgICBhdXRoUmVxID0gYXV0aFJlcS5jbG9uZSh7IHNldEhlYWRlcnM6IHsgW2NzcmZIZWFkZXJOYW1lXTogY3NyZlRva2VuIH0gfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG5leHQoYXV0aFJlcSkucGlwZShcbiAgICBjYXRjaEVycm9yKChlcnJvcjogdW5rbm93bikgPT4ge1xuICAgICAgY29uc3Qgc2hvdWxkSGFuZGxlID1cbiAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBIdHRwRXJyb3JSZXNwb25zZSAmJlxuICAgICAgICBlcnJvci5zdGF0dXMgPT09IDQwMSAmJlxuICAgICAgICBpc0F1dGhBcGlSZXF1ZXN0ICYmXG4gICAgICAgICFpc1JlZnJlc2hFbmRwb2ludCAmJlxuICAgICAgICAhaXNQdWJsaWNFbmRwb2ludCAmJlxuICAgICAgICAhcmV0cmllZFJlcXVlc3RzLmhhcyhyZXEpO1xuXG4gICAgICBpZiAoIXNob3VsZEhhbmRsZSkge1xuICAgICAgICByZXR1cm4gdGhyb3dFcnJvcigoKSA9PiBlcnJvcik7XG4gICAgICB9XG5cbiAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdbbmF1dGgtaW50ZXJjZXB0b3JdIDQwMSBkZXRlY3RlZDonLCByZXEudXJsKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc1JlZnJlc2hpbmcpIHtcbiAgICAgICAgaXNSZWZyZXNoaW5nID0gdHJ1ZTtcbiAgICAgICAgcmVmcmVzaFRva2VuU3ViamVjdC5uZXh0KG51bGwpO1xuXG4gICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oJ1tuYXV0aC1pbnRlcmNlcHRvcl0gU3RhcnRpbmcgcmVmcmVzaC4uLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVmcmVzaCBiYXNlZCBvbiBtb2RlXG4gICAgICAgIGNvbnN0IHJlZnJlc2gkID1cbiAgICAgICAgICB0b2tlbkRlbGl2ZXJ5ID09PSAnY29va2llcydcbiAgICAgICAgICAgID8gaHR0cC5wb3N0PHsgYWNjZXNzVG9rZW4/OiBzdHJpbmcgfT4ocmVmcmVzaFVybCwge30sIHsgd2l0aENyZWRlbnRpYWxzOiB0cnVlIH0pXG4gICAgICAgICAgICA6IGZyb20oYXV0aFNlcnZpY2UucmVmcmVzaCgpKTtcblxuICAgICAgICByZXR1cm4gcmVmcmVzaCQucGlwZShcbiAgICAgICAgICBzd2l0Y2hNYXAoKHJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgICBpZiAoY29uZmlnLmRlYnVnKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBSZWZyZXNoIHN1Y2Nlc3NmdWwnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlzUmVmcmVzaGluZyA9IGZhbHNlO1xuXG4gICAgICAgICAgICAvLyBHZXQgbmV3IHRva2VuIChKU09OIG1vZGUpIG9yIHNpZ25hbCBzdWNjZXNzIChjb29raWVzIG1vZGUpXG4gICAgICAgICAgICBjb25zdCBuZXdUb2tlbiA9ICdhY2Nlc3NUb2tlbicgaW4gcmVzcG9uc2UgPyByZXNwb25zZS5hY2Nlc3NUb2tlbiA6ICdzdWNjZXNzJztcbiAgICAgICAgICAgIHJlZnJlc2hUb2tlblN1YmplY3QubmV4dChuZXdUb2tlbiA/PyAnc3VjY2VzcycpO1xuXG4gICAgICAgICAgICAvLyBCdWlsZCByZXRyeSByZXF1ZXN0XG4gICAgICAgICAgICBjb25zdCByZXRyeVJlcSA9IGJ1aWxkUmV0cnlSZXF1ZXN0KGF1dGhSZXEsIHRva2VuRGVsaXZlcnksIG5ld1Rva2VuKTtcbiAgICAgICAgICAgIHJldHJpZWRSZXF1ZXN0cy5hZGQocmV0cnlSZXEpO1xuXG4gICAgICAgICAgICBpZiAoY29uZmlnLmRlYnVnKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBSZXRyeWluZzonLCByZXEudXJsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBuZXh0KHJldHJ5UmVxKTtcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBjYXRjaEVycm9yKChlcnIpID0+IHtcbiAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignW25hdXRoLWludGVyY2VwdG9yXSBSZWZyZXNoIGZhaWxlZDonLCBlcnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaXNSZWZyZXNoaW5nID0gZmFsc2U7XG4gICAgICAgICAgICByZWZyZXNoVG9rZW5TdWJqZWN0Lm5leHQobnVsbCk7XG5cbiAgICAgICAgICAgIC8vIEhhbmRsZSBzZXNzaW9uIGV4cGlyYXRpb24gLSByZWRpcmVjdCB0byBjb25maWd1cmVkIFVSTFxuICAgICAgICAgICAgaWYgKGNvbmZpZy5yZWRpcmVjdHM/LnNlc3Npb25FeHBpcmVkKSB7XG4gICAgICAgICAgICAgIHJvdXRlci5uYXZpZ2F0ZUJ5VXJsKGNvbmZpZy5yZWRpcmVjdHMuc2Vzc2lvbkV4cGlyZWQpLmNhdGNoKChuYXZFcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1tuYXV0aC1pbnRlcmNlcHRvcl0gTmF2aWdhdGlvbiBmYWlsZWQ6JywgbmF2RXJyb3IpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IGVycik7XG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBXYWl0IGZvciBvbmdvaW5nIHJlZnJlc2hcbiAgICAgICAgaWYgKGNvbmZpZy5kZWJ1Zykge1xuICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBXYWl0aW5nIGZvciByZWZyZXNoLi4uJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlZnJlc2hUb2tlblN1YmplY3QucGlwZShcbiAgICAgICAgICBmaWx0ZXIoKHRva2VuKTogdG9rZW4gaXMgc3RyaW5nID0+IHRva2VuICE9PSBudWxsKSxcbiAgICAgICAgICB0YWtlKDEpLFxuICAgICAgICAgIHN3aXRjaE1hcCgodG9rZW4pID0+IHtcbiAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdbbmF1dGgtaW50ZXJjZXB0b3JdIFJlZnJlc2ggZG9uZSwgcmV0cnlpbmc6JywgcmVxLnVybCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCByZXRyeVJlcSA9IGJ1aWxkUmV0cnlSZXF1ZXN0KGF1dGhSZXEsIHRva2VuRGVsaXZlcnksIHRva2VuKTtcbiAgICAgICAgICAgIHJldHJpZWRSZXF1ZXN0cy5hZGQocmV0cnlSZXEpO1xuICAgICAgICAgICAgcmV0dXJuIG5leHQocmV0cnlSZXEpO1xuICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0pLFxuICApO1xufTtcblxuLyoqXG4gKiBCdWlsZCByZXRyeSByZXF1ZXN0IHdpdGggYXBwcm9wcmlhdGUgYXV0aC5cbiAqL1xuZnVuY3Rpb24gYnVpbGRSZXRyeVJlcXVlc3QoXG4gIG9yaWdpbmFsUmVxOiBIdHRwUmVxdWVzdDx1bmtub3duPixcbiAgdG9rZW5EZWxpdmVyeTogc3RyaW5nLFxuICBuZXdUb2tlbj86IHN0cmluZyxcbik6IEh0dHBSZXF1ZXN0PHVua25vd24+IHtcbiAgaWYgKHRva2VuRGVsaXZlcnkgPT09ICdqc29uJyAmJiBuZXdUb2tlbiAmJiBuZXdUb2tlbiAhPT0gJ3N1Y2Nlc3MnKSB7XG4gICAgcmV0dXJuIG9yaWdpbmFsUmVxLmNsb25lKHtcbiAgICAgIHNldEhlYWRlcnM6IHsgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke25ld1Rva2VufWAgfSxcbiAgICB9KTtcbiAgfVxuICByZXR1cm4gb3JpZ2luYWxSZXEuY2xvbmUoKTtcbn1cblxuLyoqXG4gKiBDbGFzcy1iYXNlZCBpbnRlcmNlcHRvciBmb3IgTmdNb2R1bGUgY29tcGF0aWJpbGl0eS5cbiAqL1xuZXhwb3J0IGNsYXNzIEF1dGhJbnRlcmNlcHRvciB7XG4gIGludGVyY2VwdChyZXE6IEh0dHBSZXF1ZXN0PHVua25vd24+LCBuZXh0OiBIdHRwSGFuZGxlckZuKSB7XG4gICAgcmV0dXJuIGF1dGhJbnRlcmNlcHRvcihyZXEsIG5leHQpO1xuICB9XG59XG4iXX0=