@savvagent/angular 1.0.1

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +21 -0
  3. package/README.md +484 -0
  4. package/coverage/base.css +224 -0
  5. package/coverage/block-navigation.js +87 -0
  6. package/coverage/favicon.png +0 -0
  7. package/coverage/index.html +131 -0
  8. package/coverage/lcov-report/base.css +224 -0
  9. package/coverage/lcov-report/block-navigation.js +87 -0
  10. package/coverage/lcov-report/favicon.png +0 -0
  11. package/coverage/lcov-report/index.html +131 -0
  12. package/coverage/lcov-report/module.ts.html +289 -0
  13. package/coverage/lcov-report/prettify.css +1 -0
  14. package/coverage/lcov-report/prettify.js +2 -0
  15. package/coverage/lcov-report/service.ts.html +1846 -0
  16. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  17. package/coverage/lcov-report/sorter.js +210 -0
  18. package/coverage/lcov.info +242 -0
  19. package/coverage/module.ts.html +289 -0
  20. package/coverage/prettify.css +1 -0
  21. package/coverage/prettify.js +2 -0
  22. package/coverage/service.ts.html +1846 -0
  23. package/coverage/sort-arrow-sprite.png +0 -0
  24. package/coverage/sorter.js +210 -0
  25. package/dist/README.md +484 -0
  26. package/dist/esm2022/index.mjs +15 -0
  27. package/dist/esm2022/module.mjs +75 -0
  28. package/dist/esm2022/savvagent-angular.mjs +5 -0
  29. package/dist/esm2022/service.mjs +473 -0
  30. package/dist/fesm2022/savvagent-angular.mjs +563 -0
  31. package/dist/fesm2022/savvagent-angular.mjs.map +1 -0
  32. package/dist/index.d.ts +13 -0
  33. package/dist/module.d.ts +57 -0
  34. package/dist/service.d.ts +319 -0
  35. package/jest.config.js +40 -0
  36. package/ng-package.json +8 -0
  37. package/package.json +73 -0
  38. package/setup-jest.ts +2 -0
  39. package/src/index.spec.ts +144 -0
  40. package/src/index.ts +38 -0
  41. package/src/module.spec.ts +283 -0
  42. package/src/module.ts +68 -0
  43. package/src/service.spec.ts +945 -0
  44. package/src/service.ts +587 -0
  45. package/test-utils/angular-core-mock.ts +28 -0
  46. package/test-utils/angular-testing-mock.ts +87 -0
  47. package/tsconfig.json +33 -0
  48. package/tsconfig.spec.json +11 -0
@@ -0,0 +1,75 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { SavvagentService, SAVVAGENT_CONFIG } from './service';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Angular module for Savvagent feature flags.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // app.module.ts
10
+ * import { SavvagentModule } from '@savvagent/angular';
11
+ *
12
+ * @NgModule({
13
+ * imports: [
14
+ * SavvagentModule.forRoot({
15
+ * config: {
16
+ * apiKey: 'sdk_your_api_key',
17
+ * baseUrl: 'https://api.savvagent.com'
18
+ * },
19
+ * defaultContext: {
20
+ * applicationId: 'my-app',
21
+ * environment: 'production',
22
+ * userId: 'user-123'
23
+ * }
24
+ * })
25
+ * ]
26
+ * })
27
+ * export class AppModule {}
28
+ * ```
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // For standalone components (Angular 14+)
33
+ * import { SavvagentModule } from '@savvagent/angular';
34
+ *
35
+ * bootstrapApplication(AppComponent, {
36
+ * providers: [
37
+ * importProvidersFrom(
38
+ * SavvagentModule.forRoot({
39
+ * config: { apiKey: 'sdk_...' }
40
+ * })
41
+ * )
42
+ * ]
43
+ * });
44
+ * ```
45
+ */
46
+ export class SavvagentModule {
47
+ /**
48
+ * Configure the Savvagent module with API key and default context.
49
+ *
50
+ * @param savvagentConfig - Configuration including API key and optional default context
51
+ * @returns Module with providers
52
+ */
53
+ static forRoot(savvagentConfig) {
54
+ return {
55
+ ngModule: SavvagentModule,
56
+ providers: [
57
+ {
58
+ provide: SAVVAGENT_CONFIG,
59
+ useValue: savvagentConfig
60
+ },
61
+ SavvagentService
62
+ ]
63
+ };
64
+ }
65
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SavvagentModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
66
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: SavvagentModule });
67
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SavvagentModule, providers: [SavvagentService] });
68
+ }
69
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SavvagentModule, decorators: [{
70
+ type: NgModule,
71
+ args: [{
72
+ providers: [SavvagentService]
73
+ }]
74
+ }] });
75
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL21vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUF1QixNQUFNLGVBQWUsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQW1CLGdCQUFnQixFQUFFLE1BQU0sV0FBVyxDQUFDOztBQUVoRjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Q0c7QUFJSCxNQUFNLE9BQU8sZUFBZTtJQUMxQjs7Ozs7T0FLRztJQUNILE1BQU0sQ0FBQyxPQUFPLENBQUMsZUFBZ0M7UUFDN0MsT0FBTztZQUNMLFFBQVEsRUFBRSxlQUFlO1lBQ3pCLFNBQVMsRUFBRTtnQkFDVDtvQkFDRSxPQUFPLEVBQUUsZ0JBQWdCO29CQUN6QixRQUFRLEVBQUUsZUFBZTtpQkFDMUI7Z0JBQ0QsZ0JBQWdCO2FBQ2pCO1NBQ0YsQ0FBQztJQUNKLENBQUM7d0dBbEJVLGVBQWU7eUdBQWYsZUFBZTt5R0FBZixlQUFlLGFBRmYsQ0FBQyxnQkFBZ0IsQ0FBQzs7NEZBRWxCLGVBQWU7a0JBSDNCLFFBQVE7bUJBQUM7b0JBQ1IsU0FBUyxFQUFFLENBQUMsZ0JBQWdCLENBQUM7aUJBQzlCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTmdNb2R1bGUsIE1vZHVsZVdpdGhQcm92aWRlcnMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFNhdnZhZ2VudFNlcnZpY2UsIFNhdnZhZ2VudENvbmZpZywgU0FWVkFHRU5UX0NPTkZJRyB9IGZyb20gJy4vc2VydmljZSc7XG5cbi8qKlxuICogQW5ndWxhciBtb2R1bGUgZm9yIFNhdnZhZ2VudCBmZWF0dXJlIGZsYWdzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBhcHAubW9kdWxlLnRzXG4gKiBpbXBvcnQgeyBTYXZ2YWdlbnRNb2R1bGUgfSBmcm9tICdAc2F2dmFnZW50L2FuZ3VsYXInO1xuICpcbiAqIEBOZ01vZHVsZSh7XG4gKiAgIGltcG9ydHM6IFtcbiAqICAgICBTYXZ2YWdlbnRNb2R1bGUuZm9yUm9vdCh7XG4gKiAgICAgICBjb25maWc6IHtcbiAqICAgICAgICAgYXBpS2V5OiAnc2RrX3lvdXJfYXBpX2tleScsXG4gKiAgICAgICAgIGJhc2VVcmw6ICdodHRwczovL2FwaS5zYXZ2YWdlbnQuY29tJ1xuICogICAgICAgfSxcbiAqICAgICAgIGRlZmF1bHRDb250ZXh0OiB7XG4gKiAgICAgICAgIGFwcGxpY2F0aW9uSWQ6ICdteS1hcHAnLFxuICogICAgICAgICBlbnZpcm9ubWVudDogJ3Byb2R1Y3Rpb24nLFxuICogICAgICAgICB1c2VySWQ6ICd1c2VyLTEyMydcbiAqICAgICAgIH1cbiAqICAgICB9KVxuICogICBdXG4gKiB9KVxuICogZXhwb3J0IGNsYXNzIEFwcE1vZHVsZSB7fVxuICogYGBgXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIEZvciBzdGFuZGFsb25lIGNvbXBvbmVudHMgKEFuZ3VsYXIgMTQrKVxuICogaW1wb3J0IHsgU2F2dmFnZW50TW9kdWxlIH0gZnJvbSAnQHNhdnZhZ2VudC9hbmd1bGFyJztcbiAqXG4gKiBib290c3RyYXBBcHBsaWNhdGlvbihBcHBDb21wb25lbnQsIHtcbiAqICAgcHJvdmlkZXJzOiBbXG4gKiAgICAgaW1wb3J0UHJvdmlkZXJzRnJvbShcbiAqICAgICAgIFNhdnZhZ2VudE1vZHVsZS5mb3JSb290KHtcbiAqICAgICAgICAgY29uZmlnOiB7IGFwaUtleTogJ3Nka18uLi4nIH1cbiAqICAgICAgIH0pXG4gKiAgICAgKVxuICogICBdXG4gKiB9KTtcbiAqIGBgYFxuICovXG5ATmdNb2R1bGUoe1xuICBwcm92aWRlcnM6IFtTYXZ2YWdlbnRTZXJ2aWNlXVxufSlcbmV4cG9ydCBjbGFzcyBTYXZ2YWdlbnRNb2R1bGUge1xuICAvKipcbiAgICogQ29uZmlndXJlIHRoZSBTYXZ2YWdlbnQgbW9kdWxlIHdpdGggQVBJIGtleSBhbmQgZGVmYXVsdCBjb250ZXh0LlxuICAgKlxuICAgKiBAcGFyYW0gc2F2dmFnZW50Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBpbmNsdWRpbmcgQVBJIGtleSBhbmQgb3B0aW9uYWwgZGVmYXVsdCBjb250ZXh0XG4gICAqIEByZXR1cm5zIE1vZHVsZSB3aXRoIHByb3ZpZGVyc1xuICAgKi9cbiAgc3RhdGljIGZvclJvb3Qoc2F2dmFnZW50Q29uZmlnOiBTYXZ2YWdlbnRDb25maWcpOiBNb2R1bGVXaXRoUHJvdmlkZXJzPFNhdnZhZ2VudE1vZHVsZT4ge1xuICAgIHJldHVybiB7XG4gICAgICBuZ01vZHVsZTogU2F2dmFnZW50TW9kdWxlLFxuICAgICAgcHJvdmlkZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBwcm92aWRlOiBTQVZWQUdFTlRfQ09ORklHLFxuICAgICAgICAgIHVzZVZhbHVlOiBzYXZ2YWdlbnRDb25maWdcbiAgICAgICAgfSxcbiAgICAgICAgU2F2dmFnZW50U2VydmljZVxuICAgICAgXVxuICAgIH07XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './index';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2F2dmFnZW50LWFuZ3VsYXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2F2dmFnZW50LWFuZ3VsYXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLFNBQVMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9pbmRleCc7XG4iXX0=
@@ -0,0 +1,473 @@
1
+ import { Injectable, Inject, InjectionToken, Optional } from '@angular/core';
2
+ import { BehaviorSubject, from, of, Subject } from 'rxjs';
3
+ import { map, takeUntil, catchError, distinctUntilChanged } from 'rxjs/operators';
4
+ import { FlagClient } from '@savvagent/sdk';
5
+ import * as i0 from "@angular/core";
6
+ /**
7
+ * Injection token for Savvagent configuration
8
+ */
9
+ export const SAVVAGENT_CONFIG = new InjectionToken('SAVVAGENT_CONFIG');
10
+ /**
11
+ * Angular service for Savvagent feature flags.
12
+ * Provides reactive flag evaluation using RxJS Observables.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * // In your component
17
+ * @Component({...})
18
+ * export class MyComponent {
19
+ * newFeature$ = this.savvagent.flag$('new-feature');
20
+ *
21
+ * constructor(private savvagent: SavvagentService) {}
22
+ * }
23
+ *
24
+ * // In your template
25
+ * <div *ngIf="(newFeature$ | async)?.value">
26
+ * New feature content!
27
+ * </div>
28
+ * ```
29
+ */
30
+ export class SavvagentService {
31
+ client = null;
32
+ destroy$ = new Subject();
33
+ isReady$ = new BehaviorSubject(false);
34
+ defaultContext = {};
35
+ flagSubjects = new Map();
36
+ constructor(config) {
37
+ if (config) {
38
+ this.initialize(config);
39
+ }
40
+ }
41
+ /**
42
+ * Initialize the Savvagent client with configuration.
43
+ * Call this if not using the SAVVAGENT_CONFIG injection token.
44
+ *
45
+ * @param savvagentConfig - Configuration including API key and default context
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * @Component({...})
50
+ * export class AppComponent implements OnInit {
51
+ * constructor(private savvagent: SavvagentService) {}
52
+ *
53
+ * ngOnInit() {
54
+ * this.savvagent.initialize({
55
+ * config: { apiKey: 'sdk_...' },
56
+ * defaultContext: {
57
+ * applicationId: 'my-app',
58
+ * environment: 'development',
59
+ * userId: 'user-123'
60
+ * }
61
+ * });
62
+ * }
63
+ * }
64
+ * ```
65
+ */
66
+ initialize(savvagentConfig) {
67
+ if (this.client) {
68
+ console.warn('[Savvagent] Client already initialized. Call close() first to reinitialize.');
69
+ return;
70
+ }
71
+ try {
72
+ this.client = new FlagClient(savvagentConfig.config);
73
+ // Convert DefaultFlagContext to FlagContext format (camelCase to snake_case)
74
+ if (savvagentConfig.defaultContext) {
75
+ this.defaultContext = {
76
+ application_id: savvagentConfig.defaultContext.applicationId,
77
+ environment: savvagentConfig.defaultContext.environment,
78
+ organization_id: savvagentConfig.defaultContext.organizationId,
79
+ user_id: savvagentConfig.defaultContext.userId,
80
+ anonymous_id: savvagentConfig.defaultContext.anonymousId,
81
+ session_id: savvagentConfig.defaultContext.sessionId,
82
+ language: savvagentConfig.defaultContext.language,
83
+ attributes: savvagentConfig.defaultContext.attributes,
84
+ };
85
+ }
86
+ this.isReady$.next(true);
87
+ // Subscribe to override changes to re-evaluate all active flags
88
+ this.client.onOverrideChange(() => {
89
+ this.reEvaluateAllFlags();
90
+ });
91
+ }
92
+ catch (error) {
93
+ console.error('[Savvagent] Failed to initialize client:', error);
94
+ savvagentConfig.config.onError?.(error);
95
+ }
96
+ }
97
+ /**
98
+ * Observable that emits true when the client is ready.
99
+ */
100
+ get ready$() {
101
+ return this.isReady$.asObservable();
102
+ }
103
+ /**
104
+ * Check if the client is ready.
105
+ */
106
+ get isReady() {
107
+ return this.isReady$.value;
108
+ }
109
+ /**
110
+ * Get the underlying FlagClient instance for advanced use cases.
111
+ */
112
+ get flagClient() {
113
+ return this.client;
114
+ }
115
+ /**
116
+ * Merge default context with per-call context.
117
+ */
118
+ mergeContext(context) {
119
+ return {
120
+ ...this.defaultContext,
121
+ ...context,
122
+ attributes: {
123
+ ...this.defaultContext.attributes,
124
+ ...context?.attributes,
125
+ },
126
+ };
127
+ }
128
+ /**
129
+ * Get a reactive Observable for a feature flag.
130
+ * Automatically updates when the flag value changes.
131
+ *
132
+ * @param flagKey - The feature flag key to evaluate
133
+ * @param options - Configuration options
134
+ * @returns Observable of flag evaluation state
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * // In your component
139
+ * newFeature$ = this.savvagent.flag$('new-feature', {
140
+ * defaultValue: false,
141
+ * realtime: true,
142
+ * context: { attributes: { plan: 'pro' } }
143
+ * });
144
+ *
145
+ * // In template
146
+ * <ng-container *ngIf="newFeature$ | async as flag">
147
+ * <app-loading *ngIf="flag.loading"></app-loading>
148
+ * <app-new-feature *ngIf="flag.value"></app-new-feature>
149
+ * <app-old-feature *ngIf="!flag.value && !flag.loading"></app-old-feature>
150
+ * </ng-container>
151
+ * ```
152
+ */
153
+ flag$(flagKey, options = {}) {
154
+ const { context, defaultValue = false, realtime = true } = options;
155
+ const mergedContext = this.mergeContext(context);
156
+ const cacheKey = this.getCacheKey(flagKey, mergedContext);
157
+ // Check if we already have a subject for this flag+context
158
+ if (!this.flagSubjects.has(cacheKey)) {
159
+ const subject = new BehaviorSubject({
160
+ value: defaultValue,
161
+ loading: true,
162
+ error: null,
163
+ result: null,
164
+ });
165
+ this.flagSubjects.set(cacheKey, subject);
166
+ // Initial evaluation
167
+ this.evaluateAndEmit(flagKey, mergedContext, defaultValue, subject);
168
+ // Set up real-time subscription if enabled
169
+ if (realtime && this.client) {
170
+ const unsubscribe = this.client.subscribe(flagKey, () => {
171
+ this.evaluateAndEmit(flagKey, mergedContext, defaultValue, subject);
172
+ });
173
+ // Clean up subscription when subject is complete
174
+ subject.pipe(takeUntil(this.destroy$)).subscribe({
175
+ complete: () => unsubscribe(),
176
+ });
177
+ }
178
+ }
179
+ return this.flagSubjects.get(cacheKey).asObservable().pipe(takeUntil(this.destroy$), distinctUntilChanged((a, b) => a.value === b.value &&
180
+ a.loading === b.loading &&
181
+ a.error === b.error));
182
+ }
183
+ /**
184
+ * Generate a cache key for a flag+context combination.
185
+ */
186
+ getCacheKey(flagKey, context) {
187
+ return `${flagKey}:${JSON.stringify(context)}`;
188
+ }
189
+ /**
190
+ * Evaluate a flag and emit the result to a subject.
191
+ */
192
+ async evaluateAndEmit(flagKey, context, defaultValue, subject) {
193
+ if (!this.client) {
194
+ subject.next({
195
+ value: defaultValue,
196
+ loading: false,
197
+ error: new Error('Savvagent client not initialized'),
198
+ result: null,
199
+ });
200
+ return;
201
+ }
202
+ try {
203
+ const result = await this.client.evaluate(flagKey, context);
204
+ subject.next({
205
+ value: result.value,
206
+ loading: false,
207
+ error: null,
208
+ result,
209
+ });
210
+ }
211
+ catch (error) {
212
+ subject.next({
213
+ value: defaultValue,
214
+ loading: false,
215
+ error: error,
216
+ result: null,
217
+ });
218
+ }
219
+ }
220
+ /**
221
+ * Re-evaluate all active flag subscriptions.
222
+ * Called when overrides change.
223
+ */
224
+ reEvaluateAllFlags() {
225
+ this.flagSubjects.forEach((subject, cacheKey) => {
226
+ const [flagKey, contextJson] = cacheKey.split(':', 2);
227
+ const context = JSON.parse(contextJson || '{}');
228
+ const currentValue = subject.value;
229
+ this.evaluateAndEmit(flagKey, context, currentValue.value, subject);
230
+ });
231
+ }
232
+ /**
233
+ * Get a flag value as a simple Observable<boolean>.
234
+ * Useful when you only need the value without loading/error states.
235
+ *
236
+ * @param flagKey - The feature flag key to evaluate
237
+ * @param options - Configuration options
238
+ * @returns Observable of boolean flag value
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * isFeatureEnabled$ = this.savvagent.flagValue$('my-feature');
243
+ *
244
+ * // In template
245
+ * <button *ngIf="isFeatureEnabled$ | async">New Button</button>
246
+ * ```
247
+ */
248
+ flagValue$(flagKey, options = {}) {
249
+ return this.flag$(flagKey, options).pipe(map((result) => result.value), distinctUntilChanged());
250
+ }
251
+ /**
252
+ * Evaluate a feature flag once (non-reactive).
253
+ * For reactive updates, use flag$() instead.
254
+ *
255
+ * @param flagKey - The feature flag key to evaluate
256
+ * @param context - Optional context for targeting
257
+ * @returns Promise with detailed evaluation result
258
+ *
259
+ * @example
260
+ * ```typescript
261
+ * async checkFeature() {
262
+ * const result = await this.savvagent.evaluate('new-feature');
263
+ * if (result.value) {
264
+ * // Feature is enabled
265
+ * }
266
+ * }
267
+ * ```
268
+ */
269
+ async evaluate(flagKey, context) {
270
+ if (!this.client) {
271
+ throw new Error('Savvagent client not initialized');
272
+ }
273
+ return this.client.evaluate(flagKey, this.mergeContext(context));
274
+ }
275
+ /**
276
+ * Check if a feature flag is enabled (non-reactive).
277
+ *
278
+ * @param flagKey - The feature flag key to evaluate
279
+ * @param context - Optional context for targeting
280
+ * @returns Promise<boolean>
281
+ */
282
+ async isEnabled(flagKey, context) {
283
+ if (!this.client) {
284
+ return false;
285
+ }
286
+ return this.client.isEnabled(flagKey, this.mergeContext(context));
287
+ }
288
+ /**
289
+ * Execute code conditionally based on flag value.
290
+ *
291
+ * @param flagKey - The flag key to check
292
+ * @param callback - Function to execute if flag is enabled
293
+ * @param context - Optional context for targeting
294
+ *
295
+ * @example
296
+ * ```typescript
297
+ * await this.savvagent.withFlag('analytics-enabled', async () => {
298
+ * await this.analytics.track('page_view');
299
+ * });
300
+ * ```
301
+ */
302
+ async withFlag(flagKey, callback, context) {
303
+ if (!this.client) {
304
+ return null;
305
+ }
306
+ return this.client.withFlag(flagKey, callback, this.mergeContext(context));
307
+ }
308
+ /**
309
+ * Track an error with flag context.
310
+ *
311
+ * @param flagKey - The flag key associated with the error
312
+ * @param error - The error that occurred
313
+ * @param context - Optional context
314
+ */
315
+ trackError(flagKey, error, context) {
316
+ this.client?.trackError(flagKey, error, this.mergeContext(context));
317
+ }
318
+ /**
319
+ * Set the user ID for logged-in users.
320
+ *
321
+ * @param userId - The user ID (or null to clear)
322
+ */
323
+ setUserId(userId) {
324
+ this.client?.setUserId(userId);
325
+ }
326
+ /**
327
+ * Get the current user ID.
328
+ */
329
+ getUserId() {
330
+ return this.client?.getUserId() || null;
331
+ }
332
+ /**
333
+ * Get the current anonymous ID.
334
+ */
335
+ getAnonymousId() {
336
+ return this.client?.getAnonymousId() || null;
337
+ }
338
+ /**
339
+ * Set a custom anonymous ID.
340
+ */
341
+ setAnonymousId(id) {
342
+ this.client?.setAnonymousId(id);
343
+ }
344
+ // =====================
345
+ // Local Override Methods
346
+ // =====================
347
+ /**
348
+ * Set a local override for a flag.
349
+ * Overrides take precedence over server values.
350
+ *
351
+ * @param flagKey - The flag key to override
352
+ * @param value - The override value
353
+ */
354
+ setOverride(flagKey, value) {
355
+ this.client?.setOverride(flagKey, value);
356
+ }
357
+ /**
358
+ * Clear a local override for a flag.
359
+ */
360
+ clearOverride(flagKey) {
361
+ this.client?.clearOverride(flagKey);
362
+ }
363
+ /**
364
+ * Clear all local overrides.
365
+ */
366
+ clearAllOverrides() {
367
+ this.client?.clearAllOverrides();
368
+ }
369
+ /**
370
+ * Check if a flag has a local override.
371
+ */
372
+ hasOverride(flagKey) {
373
+ return this.client?.hasOverride(flagKey) || false;
374
+ }
375
+ /**
376
+ * Get the override value for a flag.
377
+ */
378
+ getOverride(flagKey) {
379
+ return this.client?.getOverride(flagKey);
380
+ }
381
+ /**
382
+ * Get all current overrides.
383
+ */
384
+ getOverrides() {
385
+ return this.client?.getOverrides() || {};
386
+ }
387
+ /**
388
+ * Set multiple overrides at once.
389
+ */
390
+ setOverrides(overrides) {
391
+ this.client?.setOverrides(overrides);
392
+ }
393
+ // =====================
394
+ // Flag Discovery Methods
395
+ // =====================
396
+ /**
397
+ * Get all flags for the application.
398
+ *
399
+ * @param environment - Environment to evaluate (default: 'development')
400
+ * @returns Observable of flag definitions
401
+ */
402
+ getAllFlags$(environment = 'development') {
403
+ if (!this.client) {
404
+ return of([]);
405
+ }
406
+ return from(this.client.getAllFlags(environment)).pipe(catchError((error) => {
407
+ console.error('[Savvagent] Failed to fetch all flags:', error);
408
+ return of([]);
409
+ }));
410
+ }
411
+ /**
412
+ * Get all flags for the application (Promise-based).
413
+ */
414
+ async getAllFlags(environment = 'development') {
415
+ if (!this.client) {
416
+ return [];
417
+ }
418
+ return this.client.getAllFlags(environment);
419
+ }
420
+ /**
421
+ * Get enterprise-scoped flags only.
422
+ */
423
+ async getEnterpriseFlags(environment = 'development') {
424
+ if (!this.client) {
425
+ return [];
426
+ }
427
+ return this.client.getEnterpriseFlags(environment);
428
+ }
429
+ // =====================
430
+ // Cache & Connection
431
+ // =====================
432
+ /**
433
+ * Clear the flag cache.
434
+ */
435
+ clearCache() {
436
+ this.client?.clearCache();
437
+ }
438
+ /**
439
+ * Check if real-time connection is active.
440
+ */
441
+ isRealtimeConnected() {
442
+ return this.client?.isRealtimeConnected() || false;
443
+ }
444
+ /**
445
+ * Close the client and cleanup resources.
446
+ */
447
+ close() {
448
+ this.client?.close();
449
+ this.client = null;
450
+ this.isReady$.next(false);
451
+ this.flagSubjects.forEach((subject) => subject.complete());
452
+ this.flagSubjects.clear();
453
+ }
454
+ ngOnDestroy() {
455
+ this.destroy$.next();
456
+ this.destroy$.complete();
457
+ this.close();
458
+ }
459
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SavvagentService, deps: [{ token: SAVVAGENT_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
460
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SavvagentService, providedIn: 'root' });
461
+ }
462
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SavvagentService, decorators: [{
463
+ type: Injectable,
464
+ args: [{
465
+ providedIn: 'root'
466
+ }]
467
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
468
+ type: Optional
469
+ }, {
470
+ type: Inject,
471
+ args: [SAVVAGENT_CONFIG]
472
+ }] }] });
473
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQWEsTUFBTSxFQUFFLGNBQWMsRUFBRSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDeEYsT0FBTyxFQUFFLGVBQWUsRUFBYyxJQUFJLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0RSxPQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNsRixPQUFPLEVBQUUsVUFBVSxFQUF1RSxNQUFNLGdCQUFnQixDQUFDOztBQW1Dakg7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLGNBQWMsQ0FBa0Isa0JBQWtCLENBQUMsQ0FBQztBQTRCeEY7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQkc7QUFJSCxNQUFNLE9BQU8sZ0JBQWdCO0lBQ25CLE1BQU0sR0FBc0IsSUFBSSxDQUFDO0lBQ2pDLFFBQVEsR0FBRyxJQUFJLE9BQU8sRUFBUSxDQUFDO0lBQy9CLFFBQVEsR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztJQUMvQyxjQUFjLEdBQWdCLEVBQUUsQ0FBQztJQUNqQyxZQUFZLEdBQUcsSUFBSSxHQUFHLEVBQWlELENBQUM7SUFFaEYsWUFDd0MsTUFBd0I7UUFFOUQsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUNYLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDMUIsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O09Bd0JHO0lBQ0gsVUFBVSxDQUFDLGVBQWdDO1FBQ3pDLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLE9BQU8sQ0FBQyxJQUFJLENBQUMsNkVBQTZF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QUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDNUIsQ0FBQztJQUVELFdBQVc7UUFDVCxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ2YsQ0FBQzt3R0E3ZVUsZ0JBQWdCLGtCQVFMLGdCQUFnQjs0R0FSM0IsZ0JBQWdCLGNBRmYsTUFBTTs7NEZBRVAsZ0JBQWdCO2tCQUg1QixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQjs7MEJBU0ksUUFBUTs7MEJBQUksTUFBTTsyQkFBQyxnQkFBZ0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBPbkRlc3Ryb3ksIEluamVjdCwgSW5qZWN0aW9uVG9rZW4sIE9wdGlvbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUsIGZyb20sIG9mLCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBtYXAsIHRha2VVbnRpbCwgY2F0Y2hFcnJvciwgZGlzdGluY3RVbnRpbENoYW5nZWQgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBGbGFnQ2xpZW50LCBGbGFnQ2xpZW50Q29uZmlnLCBGbGFnQ29udGV4dCwgRmxhZ0V2YWx1YXRpb25SZXN1bHQsIEZsYWdEZWZpbml0aW9uIH0gZnJvbSAnQHNhdnZhZ2VudC9zZGsnO1xuXG4vKipcbiAqIERlZmF1bHQgY29udGV4dCB2YWx1ZXMgdGhhdCBhcHBseSB0byBhbGwgZmxhZyBldmFsdWF0aW9uc1xuICogUGVyIFNESyBEZXZlbG9wZXIgR3VpZGU6IGh0dHBzOi8vZG9jcy5zYXZ2YWdlbnQuY29tL3Nkay1kZXZlbG9wZXItZ3VpZGVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZWZhdWx0RmxhZ0NvbnRleHQge1xuICAvKiogQXBwbGljYXRpb24gSUQgZm9yIGFwcGxpY2F0aW9uLXNjb3BlZCBmbGFncyAqL1xuICBhcHBsaWNhdGlvbklkPzogc3RyaW5nO1xuICAvKiogRW52aXJvbm1lbnQgKGRldmVsb3BtZW50LCBzdGFnaW5nLCBwcm9kdWN0aW9uKSAqL1xuICBlbnZpcm9ubWVudD86IHN0cmluZztcbiAgLyoqIE9yZ2FuaXphdGlvbiBJRCBmb3IgbXVsdGktdGVuYW50IGFwcHMgKi9cbiAgb3JnYW5pemF0aW9uSWQ/OiBzdHJpbmc7XG4gIC8qKiBEZWZhdWx0IHVzZXIgSUQgKHJlcXVpcmVkIGZvciBwZXJjZW50YWdlIHJvbGxvdXRzKSAqL1xuICB1c2VySWQ/OiBzdHJpbmc7XG4gIC8qKiBEZWZhdWx0IGFub255bW91cyBJRCAoYWx0ZXJuYXRpdmUgdG8gdXNlcklkIGZvciBhbm9ueW1vdXMgdXNlcnMpICovXG4gIGFub255bW91c0lkPzogc3RyaW5nO1xuICAvKiogU2Vzc2lvbiBJRCBhcyBmYWxsYmFjayBpZGVudGlmaWVyICovXG4gIHNlc3Npb25JZD86IHN0cmluZztcbiAgLyoqIFVzZXIncyBsYW5ndWFnZSBjb2RlIChlLmcuLCBcImVuXCIsIFwiZXNcIikgKi9cbiAgbGFuZ3VhZ2U/OiBzdHJpbmc7XG4gIC8qKiBEZWZhdWx0IGF0dHJpYnV0ZXMgZm9yIHRhcmdldGluZyAqL1xuICBhdHRyaWJ1dGVzPzogUmVjb3JkPHN0cmluZywgYW55Pjtcbn1cblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIGZvciB0aGUgU2F2dmFnZW50IEFuZ3VsYXIgc2VydmljZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNhdnZhZ2VudENvbmZpZyB7XG4gIC8qKiBTREsgQVBJIGtleSBjb25maWd1cmF0aW9uICovXG4gIGNvbmZpZzogRmxhZ0NsaWVudENvbmZpZztcbiAgLyoqIERlZmF1bHQgY29udGV4dCB2YWx1ZXMgYXBwbGllZCB0byBhbGwgZmxhZyBldmFsdWF0aW9ucyAqL1xuICBkZWZhdWx0Q29udGV4dD86IERlZmF1bHRGbGFnQ29udGV4dDtcbn1cblxuLyoqXG4gKiBJbmplY3Rpb24gdG9rZW4gZm9yIFNhdnZhZ2VudCBjb25maWd1cmF0aW9uXG4gKi9cbmV4cG9ydCBjb25zdCBTQVZWQUdFTlRfQ09ORklHID0gbmV3IEluamVjdGlvblRva2VuPFNhdnZhZ2VudENvbmZpZz4oJ1NBVlZBR0VOVF9DT05GSUcnKTtcblxuLyoqXG4gKiBSZXN1bHQgZnJvbSBmbGFnIGV2YWx1YXRpb24gYXMgYW4gT2JzZXJ2YWJsZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZsYWdPYnNlcnZhYmxlUmVzdWx0IHtcbiAgLyoqIEN1cnJlbnQgZmxhZyB2YWx1ZSAqL1xuICB2YWx1ZTogYm9vbGVhbjtcbiAgLyoqIFdoZXRoZXIgdGhlIGZsYWcgaXMgY3VycmVudGx5IGJlaW5nIGV2YWx1YXRlZCAqL1xuICBsb2FkaW5nOiBib29sZWFuO1xuICAvKiogRXJyb3IgaWYgZXZhbHVhdGlvbiBmYWlsZWQgKi9cbiAgZXJyb3I6IEVycm9yIHwgbnVsbDtcbiAgLyoqIERldGFpbGVkIGV2YWx1YXRpb24gcmVzdWx0ICovXG4gIHJlc3VsdDogRmxhZ0V2YWx1YXRpb25SZXN1bHQgfCBudWxsO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGZsYWcgZXZhbHVhdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZsYWdPcHRpb25zIHtcbiAgLyoqIENvbnRleHQgZm9yIGZsYWcgZXZhbHVhdGlvbiAodXNlcl9pZCwgYXR0cmlidXRlcywgZXRjLikgKi9cbiAgY29udGV4dD86IEZsYWdDb250ZXh0O1xuICAvKiogRGVmYXVsdCB2YWx1ZSB0byB1c2Ugd2hpbGUgbG9hZGluZyBvciBvbiBlcnJvciAqL1xuICBkZWZhdWx0VmFsdWU/OiBib29sZWFuO1xuICAvKiogRW5hYmxlIHJlYWwtdGltZSB1cGRhdGVzIGZvciB0aGlzIGZsYWcgKi9cbiAgcmVhbHRpbWU/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEFuZ3VsYXIgc2VydmljZSBmb3IgU2F2dmFnZW50IGZlYXR1cmUgZmxhZ3MuXG4gKiBQcm92aWRlcyByZWFjdGl2ZSBmbGFnIGV2YWx1YXRpb24gdXNpbmcgUnhKUyBPYnNlcnZhYmxlcy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gSW4geW91ciBjb21wb25lbnRcbiAqIEBDb21wb25lbnQoey4uLn0pXG4gKiBleHBvcnQgY2xhc3MgTXlDb21wb25lbnQge1xuICogICBuZXdGZWF0dXJlJCA9IHRoaXMuc2F2dmFnZW50LmZsYWckKCduZXctZmVhdHVyZScpO1xuICpcbiAqICAgY29uc3RydWN0b3IocHJpdmF0ZSBzYXZ2YWdlbnQ6IFNhdnZhZ2VudFNlcnZpY2UpIHt9XG4gKiB9XG4gKlxuICogLy8gSW4geW91ciB0ZW1wbGF0ZVxuICogPGRpdiAqbmdJZj1cIihuZXdGZWF0dXJlJCB8IGFzeW5jKT8udmFsdWVcIj5cbiAqICAgTmV3IGZlYXR1cmUgY29udGVudCFcbiAqIDwvZGl2PlxuICogYGBgXG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIFNhdnZhZ2VudFNlcnZpY2UgaW1wbGVtZW50cyBPbkRlc3Ryb3kge1xuICBwcml2YXRlIGNsaWVudDogRmxhZ0NsaWVudCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgcHJpdmF0ZSBpc1JlYWR5JCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICBwcml2YXRlIGRlZmF1bHRDb250ZXh0OiBGbGFnQ29udGV4dCA9IHt9O1xuICBwcml2YXRlIGZsYWdTdWJqZWN0cyA9IG5ldyBNYXA8c3RyaW5nLCBCZWhhdmlvclN1YmplY3Q8RmxhZ09ic2VydmFibGVSZXN1bHQ+PigpO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIEBPcHRpb25hbCgpIEBJbmplY3QoU0FWVkFHRU5UX0NPTkZJRykgY29uZmlnPzogU2F2dmFnZW50Q29uZmlnXG4gICkge1xuICAgIGlmIChjb25maWcpIHtcbiAgICAgIHRoaXMuaW5pdGlhbGl6ZShjb25maWcpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJbml0aWFsaXplIHRoZSBTYXZ2YWdlbnQgY2xpZW50IHdpdGggY29uZmlndXJhdGlvbi5cbiAgICogQ2FsbCB0aGlzIGlmIG5vdCB1c2luZyB0aGUgU0FWVkFHRU5UX0NPTkZJRyBpbmplY3Rpb24gdG9rZW4uXG4gICAqXG4gICAqIEBwYXJhbSBzYXZ2YWdlbnRDb25maWcgLSBDb25maWd1cmF0aW9uIGluY2x1ZGluZyBBUEkga2V5IGFuZCBkZWZhdWx0IGNvbnRleHRcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBAQ29tcG9uZW50KHsuLi59KVxuICAgKiBleHBvcnQgY2xhc3MgQXBwQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgICogICBjb25zdHJ1Y3Rvcihwcml2YXRlIHNhdnZhZ2VudDogU2F2dmFnZW50U2VydmljZSkge31cbiAgICpcbiAgICogICBuZ09uSW5pdCgpIHtcbiAgICogICAgIHRoaXMuc2F2dmFnZW50LmluaXRpYWxpemUoe1xuICAgKiAgICAgICBjb25maWc6IHsgYXBpS2V5OiAnc2RrXy4uLicgfSxcbiAgICogICAgICAgZGVmYXVsdENvbnRleHQ6IHtcbiAgICogICAgICAgICBhcHBsaWNhdGlvbklkOiAnbXktYXBwJyxcbiAgICogICAgICAgICBlbnZpcm9ubWVudDogJ2RldmVsb3BtZW50JyxcbiAgICogICAgICAgICB1c2VySWQ6ICd1c2VyLTEyMydcbiAgICogICAgICAgfVxuICAgKiAgICAgfSk7XG4gICAqICAgfVxuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgaW5pdGlhbGl6ZShzYXZ2YWdlbnRDb25maWc6IFNhdnZhZ2VudENvbmZpZyk6IHZvaWQge1xuICAgIGlmICh0aGlzLmNsaWVudCkge1xuICAgICAgY29uc29sZS53YXJuKCdbU2F2dmFnZW50XSBDbGllbnQgYWxyZWFkeSBpbml0aWFsaXplZC4gQ2FsbCBjbG9zZSgpIGZpcnN0IHRvIHJlaW5pdGlhbGl6ZS4nKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgdGhpcy5jbGllbnQgPSBuZXcgRmxhZ0NsaWVudChzYXZ2YWdlbnRDb25maWcuY29uZmlnKTtcblxuICAgICAgLy8gQ29udmVydCBEZWZhdWx0RmxhZ0NvbnRleHQgdG8gRmxhZ0NvbnRleHQgZm9ybWF0IChjYW1lbENhc2UgdG8gc25ha2VfY2FzZSlcbiAgICAgIGlmIChzYXZ2YWdlbnRDb25maWcuZGVmYXVsdENvbnRleHQpIHtcbiAgICAgICAgdGhpcy5kZWZhdWx0Q29udGV4dCA9IHtcbiAgICAgICAgICBhcHBsaWNhdGlvbl9pZDogc2F2dmFnZW50Q29uZmlnLmRlZmF1bHRDb250ZXh0LmFwcGxpY2F0aW9uSWQsXG4gICAgICAgICAgZW52aXJvbm1lbnQ6IHNhdnZhZ2VudENvbmZpZy5kZWZhdWx0Q29udGV4dC5lbnZpcm9ubWVudCxcbiAgICAgICAgICBvcmdhbml6YXRpb25faWQ6IHNhdnZhZ2VudENvbmZpZy5kZWZhdWx0Q29udGV4dC5vcmdhbml6YXRpb25JZCxcbiAgICAgICAgICB1c2VyX2lkOiBzYXZ2YWdlbnRDb25maWcuZGVmYXVsdENvbnRleHQudXNlcklkLFxuICAgICAgICAgIGFub255bW91c19pZDogc2F2dmFnZW50Q29uZmlnLmRlZmF1bHRDb250ZXh0LmFub255bW91c0lkLFxuICAgICAgICAgIHNlc3Npb25faWQ6IHNhdnZhZ2VudENvbmZpZy5kZWZhdWx0Q29udGV4dC5zZXNzaW9uSWQsXG4gICAgICAgICAgbGFuZ3VhZ2U6IHNhdnZhZ2VudENvbmZpZy5kZWZhdWx0Q29udGV4dC5sYW5ndWFnZSxcbiAgICAgICAgICBhdHRyaWJ1dGVzOiBzYXZ2YWdlbnRDb25maWcuZGVmYXVsdENvbnRleHQuYXR0cmlidXRlcyxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5pc1JlYWR5JC5uZXh0KHRydWUpO1xuXG4gICAgICAvLyBTdWJzY3JpYmUgdG8gb3ZlcnJpZGUgY2hhbmdlcyB0byByZS1ldmFsdWF0ZSBhbGwgYWN0aXZlIGZsYWdzXG4gICAgICB0aGlzLmNsaWVudC5vbk92ZXJyaWRlQ2hhbmdlKCgpID0+IHtcbiAgICAgICAgdGhpcy5yZUV2YWx1YXRlQWxsRmxhZ3MoKTtcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdbU2F2dmFnZW50XSBGYWlsZWQgdG8gaW5pdGlhbGl6ZSBjbGllbnQ6JywgZXJyb3IpO1xuICAgICAgc2F2dmFnZW50Q29uZmlnLmNvbmZpZy5vbkVycm9yPy4oZXJyb3IgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBPYnNlcnZhYmxlIHRoYXQgZW1pdHMgdHJ1ZSB3aGVuIHRoZSBjbGllbnQgaXMgcmVhZHkuXG4gICAqL1xuICBnZXQgcmVhZHkkKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLmlzUmVhZHkkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIHRoZSBjbGllbnQgaXMgcmVhZHkuXG4gICAqL1xuICBnZXQgaXNSZWFkeSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc1JlYWR5JC52YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIHVuZGVybHlpbmcgRmxhZ0NsaWVudCBpbnN0YW5jZSBmb3IgYWR2YW5jZWQgdXNlIGNhc2VzLlxuICAgKi9cbiAgZ2V0IGZsYWdDbGllbnQoKTogRmxhZ0NsaWVudCB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmNsaWVudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXJnZSBkZWZhdWx0IGNvbnRleHQgd2l0aCBwZXItY2FsbCBjb250ZXh0LlxuICAgKi9cbiAgcHJpdmF0ZSBtZXJnZUNvbnRleHQoY29udGV4dD86IEZsYWdDb250ZXh0KTogRmxhZ0NvbnRleHQge1xuICAgIHJldHVybiB7XG4gICAgICAuLi50aGlzLmRlZmF1bHRDb250ZXh0LFxuICAgICAgLi4uY29udGV4dCxcbiAgICAgIGF0dHJpYnV0ZXM6IHtcbiAgICAgICAgLi4udGhpcy5kZWZhdWx0Q29udGV4dC5hdHRyaWJ1dGVzLFxuICAgICAgICAuLi5jb250ZXh0Py5hdHRyaWJ1dGVzLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIHJlYWN0aXZlIE9ic2VydmFibGUgZm9yIGEgZmVhdHVyZSBmbGFnLlxuICAgKiBBdXRvbWF0aWNhbGx5IHVwZGF0ZXMgd2hlbiB0aGUgZmxhZyB2YWx1ZSBjaGFuZ2VzLlxuICAgKlxuICAgKiBAcGFyYW0gZmxhZ0tleSAtIFRoZSBmZWF0dXJlIGZsYWcga2V5IHRvIGV2YWx1YXRlXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAqIEByZXR1cm5zIE9ic2VydmFibGUgb2YgZmxhZyBldmFsdWF0aW9uIHN0YXRlXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gSW4geW91ciBjb21wb25lbnRcbiAgICogbmV3RmVhdHVyZSQgPSB0aGlzLnNhdnZhZ2VudC5mbGFnJCgnbmV3LWZlYXR1cmUnLCB7XG4gICAqICAgZGVmYXVsdFZhbHVlOiBmYWxzZSxcbiAgICogICByZWFsdGltZTogdHJ1ZSxcbiAgICogICBjb250ZXh0OiB7IGF0dHJpYnV0ZXM6IHsgcGxhbjogJ3BybycgfSB9XG4gICAqIH0pO1xuICAgKlxuICAgKiAvLyBJbiB0ZW1wbGF0ZVxuICAgKiA8bmctY29udGFpbmVyICpuZ0lmPVwibmV3RmVhdHVyZSQgfCBhc3luYyBhcyBmbGFnXCI+XG4gICAqICAgPGFwcC1sb2FkaW5nICpuZ0lmPVwiZmxhZy5sb2FkaW5nXCI+PC9hcHAtbG9hZGluZz5cbiAgICogICA8YXBwLW5ldy1mZWF0dXJlICpuZ0lmPVwiZmxhZy52YWx1ZVwiPjwvYXBwLW5ldy1mZWF0dXJlPlxuICAgKiAgIDxhcHAtb2xkLWZlYXR1cmUgKm5nSWY9XCIhZmxhZy52YWx1ZSAmJiAhZmxhZy5sb2FkaW5nXCI+PC9hcHAtb2xkLWZlYXR1cmU+XG4gICAqIDwvbmctY29udGFpbmVyPlxuICAgKiBgYGBcbiAgICovXG4gIGZsYWckKGZsYWdLZXk6IHN0cmluZywgb3B0aW9uczogRmxhZ09wdGlvbnMgPSB7fSk6IE9ic2VydmFibGU8RmxhZ09ic2VydmFibGVSZXN1bHQ+IHtcbiAgICBjb25zdCB7IGNvbnRleHQsIGRlZmF1bHRWYWx1ZSA9IGZhbHNlLCByZWFsdGltZSA9IHRydWUgfSA9IG9wdGlvbnM7XG4gICAgY29uc3QgbWVyZ2VkQ29udGV4dCA9IHRoaXMubWVyZ2VDb250ZXh0KGNvbnRleHQpO1xuICAgIGNvbnN0IGNhY2hlS2V5ID0gdGhpcy5nZXRDYWNoZUtleShmbGFnS2V5LCBtZXJnZWRDb250ZXh0KTtcblxuICAgIC8vIENoZWNrIGlmIHdlIGFscmVhZHkgaGF2ZSBhIHN1YmplY3QgZm9yIHRoaXMgZmxhZytjb250ZXh0XG4gICAgaWYgKCF0aGlzLmZsYWdTdWJqZWN0cy5oYXMoY2FjaGVLZXkpKSB7XG4gICAgICBjb25zdCBzdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxGbGFnT2JzZXJ2YWJsZVJlc3VsdD4oe1xuICAgICAgICB2YWx1ZTogZGVmYXVsdFZhbHVlLFxuICAgICAgICBsb2FkaW5nOiB0cnVlLFxuICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgcmVzdWx0OiBudWxsLFxuICAgICAgfSk7XG4gICAgICB0aGlzLmZsYWdTdWJqZWN0cy5zZXQoY2FjaGVLZXksIHN1YmplY3QpO1xuXG4gICAgICAvLyBJbml0aWFsIGV2YWx1YXRpb25cbiAgICAgIHRoaXMuZXZhbHVhdGVBbmRFbWl0KGZsYWdLZXksIG1lcmdlZENvbnRleHQsIGRlZmF1bHRWYWx1ZSwgc3ViamVjdCk7XG5cbiAgICAgIC8vIFNldCB1cCByZWFsLXRpbWUgc3Vic2NyaXB0aW9uIGlmIGVuYWJsZWRcbiAgICAgIGlmIChyZWFsdGltZSAmJiB0aGlzLmNsaWVudCkge1xuICAgICAgICBjb25zdCB1bnN1YnNjcmliZSA9IHRoaXMuY2xpZW50LnN1YnNjcmliZShmbGFnS2V5LCAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5ldmFsdWF0ZUFuZEVtaXQoZmxhZ0tleSwgbWVyZ2VkQ29udGV4dCwgZGVmYXVsdFZhbHVlLCBzdWJqZWN0KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQ2xlYW4gdXAgc3Vic2NyaXB0aW9uIHdoZW4gc3ViamVjdCBpcyBjb21wbGV0ZVxuICAgICAgICBzdWJqZWN0LnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKS5zdWJzY3JpYmUoe1xuICAgICAgICAgIGNvbXBsZXRlOiAoKSA9PiB1bnN1YnNjcmliZSgpLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5mbGFnU3ViamVjdHMuZ2V0KGNhY2hlS2V5KSEuYXNPYnNlcnZhYmxlKCkucGlwZShcbiAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSxcbiAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKChhLCBiKSA9PlxuICAgICAgICBhLnZhbHVlID09PSBiLnZhbHVlICYmXG4gICAgICAgIGEubG9hZGluZyA9PT0gYi5sb2FkaW5nICYmXG4gICAgICAgIGEuZXJyb3IgPT09IGIuZXJyb3JcbiAgICAgIClcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGEgY2FjaGUga2V5IGZvciBhIGZsYWcrY29udGV4dCBjb21iaW5hdGlvbi5cbiAgICovXG4gIHByaXZhdGUgZ2V0Q2FjaGVLZXkoZmxhZ0tleTogc3RyaW5nLCBjb250ZXh0OiBGbGFnQ29udGV4dCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGAke2ZsYWdLZXl9OiR7SlNPTi5zdHJpbmdpZnkoY29udGV4dCl9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmFsdWF0ZSBhIGZsYWcgYW5kIGVtaXQgdGhlIHJlc3VsdCB0byBhIHN1YmplY3QuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGV2YWx1YXRlQW5kRW1pdChcbiAgICBmbGFnS2V5OiBzdHJpbmcsXG4gICAgY29udGV4dDogRmxhZ0NvbnRleHQsXG4gICAgZGVmYXVsdFZhbHVlOiBib29sZWFuLFxuICAgIHN1YmplY3Q6IEJlaGF2aW9yU3ViamVjdDxGbGFnT2JzZXJ2YWJsZVJlc3VsdD5cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCF0aGlzLmNsaWVudCkge1xuICAgICAgc3ViamVjdC5uZXh0KHtcbiAgICAgICAgdmFsdWU6IGRlZmF1bHRWYWx1ZSxcbiAgICAgICAgbG9hZGluZzogZmFsc2UsXG4gICAgICAgIGVycm9yOiBuZXcgRXJyb3IoJ1NhdnZhZ2VudCBjbGllbnQgbm90IGluaXRpYWxpemVkJyksXG4gICAgICAgIHJlc3VsdDogbnVsbCxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmNsaWVudC5ldmFsdWF0ZShmbGFnS2V5LCBjb250ZXh0KTtcbiAgICAgIHN1YmplY3QubmV4dCh7XG4gICAgICAgIHZhbHVlOiByZXN1bHQudmFsdWUsXG4gICAgICAgIGxvYWRpbmc6IGZhbHNlLFxuICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgcmVzdWx0LFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHN1YmplY3QubmV4dCh7XG4gICAgICAgIHZhbHVlOiBkZWZhdWx0VmFsdWUsXG4gICAgICAgIGxvYWRpbmc6IGZhbHNlLFxuICAgICAgICBlcnJvcjogZXJyb3IgYXMgRXJyb3IsXG4gICAgICAgIHJlc3VsdDogbnVsbCxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZS1ldmFsdWF0ZSBhbGwgYWN0aXZlIGZsYWcgc3Vic2NyaXB0aW9ucy5cbiAgICogQ2FsbGVkIHdoZW4gb3ZlcnJpZGVzIGNoYW5nZS5cbiAgICovXG4gIHByaXZhdGUgcmVFdmFsdWF0ZUFsbEZsYWdzKCk6IHZvaWQge1xuICAgIHRoaXMuZmxhZ1N1YmplY3RzLmZvckVhY2goKHN1YmplY3QsIGNhY2hlS2V5KSA9PiB7XG4gICAgICBjb25zdCBbZmxhZ0tleSwgY29udGV4dEpzb25dID0gY2FjaGVLZXkuc3BsaXQoJzonLCAyKTtcbiAgICAgIGNvbnN0IGNvbnRleHQgPSBKU09OLnBhcnNlKGNvbnRleHRKc29uIHx8ICd7fScpO1xuICAgICAgY29uc3QgY3VycmVudFZhbHVlID0gc3ViamVjdC52YWx1ZTtcbiAgICAgIHRoaXMuZXZhbHVhdGVBbmRFbWl0KGZsYWdLZXksIGNvbnRleHQsIGN1cnJlbnRWYWx1ZS52YWx1ZSwgc3ViamVjdCk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGEgZmxhZyB2YWx1ZSBhcyBhIHNpbXBsZSBPYnNlcnZhYmxlPGJvb2xlYW4+LlxuICAgKiBVc2VmdWwgd2hlbiB5b3Ugb25seSBuZWVkIHRoZSB2YWx1ZSB3aXRob3V0IGxvYWRpbmcvZXJyb3Igc3RhdGVzLlxuICAgKlxuICAgKiBAcGFyYW0gZmxhZ0tleSAtIFRoZSBmZWF0dXJlIGZsYWcga2V5IHRvIGV2YWx1YXRlXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAqIEByZXR1cm5zIE9ic2VydmFibGUgb2YgYm9vbGVhbiBmbGFnIHZhbHVlXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogaXNGZWF0dXJlRW5hYmxlZCQgPSB0aGlzLnNhdnZhZ2VudC5mbGFnVmFsdWUkKCdteS1mZWF0dXJlJyk7XG4gICAqXG4gICAqIC8vIEluIHRlbXBsYXRlXG4gICAqIDxidXR0b24gKm5nSWY9XCJpc0ZlYXR1cmVFbmFibGVkJCB8IGFzeW5jXCI+TmV3IEJ1dHRvbjwvYnV0dG9uPlxuICAgKiBgYGBcbiAgICovXG4gIGZsYWdWYWx1ZSQoZmxhZ0tleTogc3RyaW5nLCBvcHRpb25zOiBGbGFnT3B0aW9ucyA9IHt9KTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMuZmxhZyQoZmxhZ0tleSwgb3B0aW9ucykucGlwZShcbiAgICAgIG1hcCgocmVzdWx0KSA9PiByZXN1bHQudmFsdWUpLFxuICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogRXZhbHVhdGUgYSBmZWF0dXJlIGZsYWcgb25jZSAobm9uLXJlYWN0aXZlKS5cbiAgICogRm9yIHJlYWN0aXZlIHVwZGF0ZXMsIHVzZSBmbGFnJCgpIGluc3RlYWQuXG4gICAqXG4gICAqIEBwYXJhbSBmbGFnS2V5IC0gVGhlIGZlYXR1cmUgZmxhZyBrZXkgdG8gZXZhbHVhdGVcbiAgICogQHBhcmFtIGNvbnRleHQgLSBPcHRpb25hbCBjb250ZXh0IGZvciB0YXJnZXRpbmdcbiAgICogQHJldHVybnMgUHJvbWlzZSB3aXRoIGRldGFpbGVkIGV2YWx1YXRpb24gcmVzdWx0XG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogYXN5bmMgY2hlY2tGZWF0dXJlKCkge1xuICAgKiAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuc2F2dmFnZW50LmV2YWx1YXRlKCduZXctZmVhdHVyZScpO1xuICAgKiAgIGlmIChyZXN1bHQudmFsdWUpIHtcbiAgICogICAgIC8vIEZlYXR1cmUgaXMgZW5hYmxlZFxuICAgKiAgIH1cbiAgICogfVxuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGV2YWx1YXRlKGZsYWdLZXk6IHN0cmluZywgY29udGV4dD86IEZsYWdDb250ZXh0KTogUHJvbWlzZTxGbGFnRXZhbHVhdGlvblJlc3VsdD4ge1xuICAgIGlmICghdGhpcy5jbGllbnQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignU2F2dmFnZW50IGNsaWVudCBub3QgaW5pdGlhbGl6ZWQnKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY2xpZW50LmV2YWx1YXRlKGZsYWdLZXksIHRoaXMubWVyZ2VDb250ZXh0KGNvbnRleHQpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBhIGZlYXR1cmUgZmxhZyBpcyBlbmFibGVkIChub24tcmVhY3RpdmUpLlxuICAgKlxuICAgKiBAcGFyYW0gZmxhZ0tleSAtIFRoZSBmZWF0dXJlIGZsYWcga2V5IHRvIGV2YWx1YXRlXG4gICAqIEBwYXJhbSBjb250ZXh0IC0gT3B0aW9uYWwgY29udGV4dCBmb3IgdGFyZ2V0aW5nXG4gICAqIEByZXR1cm5zIFByb21pc2U8Ym9vbGVhbj5cbiAgICovXG4gIGFzeW5jIGlzRW5hYmxlZChmbGFnS2V5OiBzdHJpbmcsIGNvbnRleHQ/OiBGbGFnQ29udGV4dCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICghdGhpcy5jbGllbnQpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY2xpZW50LmlzRW5hYmxlZChmbGFnS2V5LCB0aGlzLm1lcmdlQ29udGV4dChjb250ZXh0KSk7XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSBjb2RlIGNvbmRpdGlvbmFsbHkgYmFzZWQgb24gZmxhZyB2YWx1ZS5cbiAgICpcbiAgICogQHBhcmFtIGZsYWdLZXkgLSBUaGUgZmxhZyBrZXkgdG8gY2hlY2tcbiAgICogQHBhcmFtIGNhbGxiYWNrIC0gRnVuY3Rpb24gdG8gZXhlY3V0ZSBpZiBmbGFnIGlzIGVuYWJsZWRcbiAgICogQHBhcmFtIGNvbnRleHQgLSBPcHRpb25hbCBjb250ZXh0IGZvciB0YXJnZXRpbmdcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBhd2FpdCB0aGlzLnNhdnZhZ2VudC53aXRoRmxhZygnYW5hbHl0aWNzLWVuYWJsZWQnLCBhc3luYyAoKSA9PiB7XG4gICAqICAgYXdhaXQgdGhpcy5hbmFseXRpY3MudHJhY2soJ3BhZ2VfdmlldycpO1xuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyB3aXRoRmxhZzxUPihcbiAgICBmbGFnS2V5OiBzdHJpbmcsXG4gICAgY2FsbGJhY2s6ICgpID0+IFQgfCBQcm9taXNlPFQ+LFxuICAgIGNvbnRleHQ/OiBGbGFnQ29udGV4dFxuICApOiBQcm9taXNlPFQgfCBudWxsPiB7XG4gICAgaWYgKCF0aGlzLmNsaWVudCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmNsaWVudC53aXRoRmxhZyhmbGFnS2V5LCBjYWxsYmFjaywgdGhpcy5tZXJnZUNvbnRleHQoY29udGV4dCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYWNrIGFuIGVycm9yIHdpdGggZmxhZyBjb250ZXh0LlxuICAgKlxuICAgKiBAcGFyYW0gZmxhZ0tleSAtIFRoZSBmbGFnIGtleSBhc3NvY2lhdGVkIHdpdGggdGhlIGVycm9yXG4gICAqIEBwYXJhbSBlcnJvciAtIFRoZSBlcnJvciB0aGF0IG9jY3VycmVkXG4gICAqIEBwYXJhbSBjb250ZXh0IC0gT3B0aW9uYWwgY29udGV4dFxuICAgKi9cbiAgdHJhY2tFcnJvcihmbGFnS2V5OiBzdHJpbmcsIGVycm9yOiBFcnJvciwgY29udGV4dD86IEZsYWdDb250ZXh0KTogdm9pZCB7XG4gICAgdGhpcy5jbGllbnQ/LnRyYWNrRXJyb3IoZmxhZ0tleSwgZXJyb3IsIHRoaXMubWVyZ2VDb250ZXh0KGNvbnRleHQpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgdGhlIHVzZXIgSUQgZm9yIGxvZ2dlZC1pbiB1c2Vycy5cbiAgICpcbiAgICogQHBhcmFtIHVzZXJJZCAtIFRoZSB1c2VyIElEIChvciBudWxsIHRvIGNsZWFyKVxuICAgKi9cbiAgc2V0VXNlcklkKHVzZXJJZDogc3RyaW5nIHwgbnVsbCk6IHZvaWQge1xuICAgIHRoaXMuY2xpZW50Py5zZXRVc2VySWQodXNlcklkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGN1cnJlbnQgdXNlciBJRC5cbiAgICovXG4gIGdldFVzZXJJZCgpOiBzdHJpbmcgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5jbGllbnQ/LmdldFVzZXJJZCgpIHx8IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBjdXJyZW50IGFub255bW91cyBJRC5cbiAgICovXG4gIGdldEFub255bW91c0lkKCk6IHN0cmluZyB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmNsaWVudD8uZ2V0QW5vbnltb3VzSWQoKSB8fCBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCBhIGN1c3RvbSBhbm9ueW1vdXMgSUQuXG4gICAqL1xuICBzZXRBbm9ueW1vdXNJZChpZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5jbGllbnQ/LnNldEFub255bW91c0lkKGlkKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PVxuICAvLyBMb2NhbCBPdmVycmlkZSBNZXRob2RzXG4gIC8vID09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBTZXQgYSBsb2NhbCBvdmVycmlkZSBmb3IgYSBmbGFnLlxuICAgKiBPdmVycmlkZXMgdGFrZSBwcmVjZWRlbmNlIG92ZXIgc2VydmVyIHZhbHVlcy5cbiAgICpcbiAgICogQHBhcmFtIGZsYWdLZXkgLSBUaGUgZmxhZyBrZXkgdG8gb3ZlcnJpZGVcbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIG92ZXJyaWRlIHZhbHVlXG4gICAqL1xuICBzZXRPdmVycmlkZShmbGFnS2V5OiBzdHJpbmcsIHZhbHVlOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5jbGllbnQ/LnNldE92ZXJyaWRlKGZsYWdLZXksIHZhbHVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbGVhciBhIGxvY2FsIG92ZXJyaWRlIGZvciBhIGZsYWcuXG4gICAqL1xuICBjbGVhck92ZXJyaWRlKGZsYWdLZXk6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuY2xpZW50Py5jbGVhck92ZXJyaWRlKGZsYWdLZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIENsZWFyIGFsbCBsb2NhbCBvdmVycmlkZXMuXG4gICAqL1xuICBjbGVhckFsbE92ZXJyaWRlcygpOiB2b2lkIHtcbiAgICB0aGlzLmNsaWVudD8uY2xlYXJBbGxPdmVycmlkZXMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBhIGZsYWcgaGFzIGEgbG9jYWwgb3ZlcnJpZGUuXG4gICAqL1xuICBoYXNPdmVycmlkZShmbGFnS2V5OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5jbGllbnQ/Lmhhc092ZXJyaWRlKGZsYWdLZXkpIHx8IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgb3ZlcnJpZGUgdmFsdWUgZm9yIGEgZmxhZy5cbiAgICovXG4gIGdldE92ZXJyaWRlKGZsYWdLZXk6IHN0cmluZyk6IGJvb2xlYW4gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmNsaWVudD8uZ2V0T3ZlcnJpZGUoZmxhZ0tleSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFsbCBjdXJyZW50IG92ZXJyaWRlcy5cbiAgICovXG4gIGdldE92ZXJyaWRlcygpOiBSZWNvcmQ8c3RyaW5nLCBib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMuY2xpZW50Py5nZXRPdmVycmlkZXMoKSB8fCB7fTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgbXVsdGlwbGUgb3ZlcnJpZGVzIGF0IG9uY2UuXG4gICAqL1xuICBzZXRPdmVycmlkZXMob3ZlcnJpZGVzOiBSZWNvcmQ8c3RyaW5nLCBib29sZWFuPik6IHZvaWQge1xuICAgIHRoaXMuY2xpZW50Py5zZXRPdmVycmlkZXMob3ZlcnJpZGVzKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PVxuICAvLyBGbGFnIERpc2NvdmVyeSBNZXRob2RzXG4gIC8vID09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBHZXQgYWxsIGZsYWdzIGZvciB0aGUgYXBwbGljYXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSBlbnZpcm9ubWVudCAtIEVudmlyb25tZW50IHRvIGV2YWx1YXRlIChkZWZhdWx0OiAnZGV2ZWxvcG1lbnQnKVxuICAgKiBAcmV0dXJucyBPYnNlcnZhYmxlIG9mIGZsYWcgZGVmaW5pdGlvbnNcbiAgICovXG4gIGdldEFsbEZsYWdzJChlbnZpcm9ubWVudDogc3RyaW5nID0gJ2RldmVsb3BtZW50Jyk6IE9ic2VydmFibGU8RmxhZ0RlZmluaXRpb25bXT4ge1xuICAgIGlmICghdGhpcy5jbGllbnQpIHtcbiAgICAgIHJldHVybiBvZihbXSk7XG4gICAgfVxuICAgIHJldHVybiBmcm9tKHRoaXMuY2xpZW50LmdldEFsbEZsYWdzKGVudmlyb25tZW50KSkucGlwZShcbiAgICAgIGNhdGNoRXJyb3IoKGVycm9yKSA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ1tTYXZ2YWdlbnRdIEZhaWxlZCB0byBmZXRjaCBhbGwgZmxhZ3M6JywgZXJyb3IpO1xuICAgICAgICByZXR1cm4gb2YoW10pO1xuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhbGwgZmxhZ3MgZm9yIHRoZSBhcHBsaWNhdGlvbiAoUHJvbWlzZS1iYXNlZCkuXG4gICAqL1xuICBhc3luYyBnZXRBbGxGbGFncyhlbnZpcm9ubWVudDogc3RyaW5nID0gJ2RldmVsb3BtZW50Jyk6IFByb21pc2U8RmxhZ0RlZmluaXRpb25bXT4ge1xuICAgIGlmICghdGhpcy5jbGllbnQpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY2xpZW50LmdldEFsbEZsYWdzKGVudmlyb25tZW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZW50ZXJwcmlzZS1zY29wZWQgZmxhZ3Mgb25seS5cbiAgICovXG4gIGFzeW5jIGdldEVudGVycHJpc2VGbGFncyhlbnZpcm9ubWVudDogc3RyaW5nID0gJ2RldmVsb3BtZW50Jyk6IFByb21pc2U8RmxhZ0RlZmluaXRpb25bXT4ge1xuICAgIGlmICghdGhpcy5jbGllbnQpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY2xpZW50LmdldEVudGVycHJpc2VGbGFncyhlbnZpcm9ubWVudCk7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gQ2FjaGUgJiBDb25uZWN0aW9uXG4gIC8vID09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBDbGVhciB0aGUgZmxhZyBjYWNoZS5cbiAgICovXG4gIGNsZWFyQ2FjaGUoKTogdm9pZCB7XG4gICAgdGhpcy5jbGllbnQ/LmNsZWFyQ2FjaGUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiByZWFsLXRpbWUgY29ubmVjdGlvbiBpcyBhY3RpdmUuXG4gICAqL1xuICBpc1JlYWx0aW1lQ29ubmVjdGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNsaWVudD8uaXNSZWFsdGltZUNvbm5lY3RlZCgpIHx8IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIENsb3NlIHRoZSBjbGllbnQgYW5kIGNsZWFudXAgcmVzb3VyY2VzLlxuICAgKi9cbiAgY2xvc2UoKTogdm9pZCB7XG4gICAgdGhpcy5jbGllbnQ/LmNsb3NlKCk7XG4gICAgdGhpcy5jbGllbnQgPSBudWxsO1xuICAgIHRoaXMuaXNSZWFkeSQubmV4dChmYWxzZSk7XG4gICAgdGhpcy5mbGFnU3ViamVjdHMuZm9yRWFjaCgoc3ViamVjdCkgPT4gc3ViamVjdC5jb21wbGV0ZSgpKTtcbiAgICB0aGlzLmZsYWdTdWJqZWN0cy5jbGVhcigpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5kZXN0cm95JC5uZXh0KCk7XG4gICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xuICAgIHRoaXMuY2xvc2UoKTtcbiAgfVxufVxuIl19