tas-uell-sdk 0.0.2 → 0.0.4

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.
@@ -0,0 +1,427 @@
1
+ # TAS-UELL-SDK Library Installation & Testing Guide
2
+
3
+ This guide provides step-by-step instructions for installing and testing the `tas-uell-sdk` Angular library.
4
+
5
+ ---
6
+
7
+ ## Prerequisites
8
+
9
+ - Angular 13+ project
10
+ - Node.js and npm installed
11
+ - A TokBox/Vonage API Key (for video call functionality)
12
+
13
+ ---
14
+
15
+ ## Installation Steps
16
+
17
+ ### Step 1: Install the Library
18
+
19
+ Install from npm:
20
+
21
+ ```bash
22
+ npm install tas-uell-sdk --legacy-peer-deps
23
+ ```
24
+
25
+ ### Step 2: Install Peer Dependencies
26
+
27
+ ```bash
28
+ npm install @ng-bootstrap/ng-bootstrap @opentok/client interactjs --legacy-peer-deps
29
+ ```
30
+
31
+ ### Step 3: Install Style Dependencies (IMPORTANT!)
32
+
33
+ The library uses **Font Awesome icons** and **Bootstrap** for styling:
34
+
35
+ ```bash
36
+ npm install font-awesome bootstrap --legacy-peer-deps
37
+ ```
38
+
39
+ ### Step 4: Add Styles to angular.json
40
+
41
+ Update your `angular.json` file to include the required CSS files in the `styles` array:
42
+
43
+ ```json
44
+ {
45
+ "projects": {
46
+ "your-project-name": {
47
+ "architect": {
48
+ "build": {
49
+ "options": {
50
+ "styles": [
51
+ "node_modules/bootstrap/dist/css/bootstrap.min.css",
52
+ "node_modules/font-awesome/css/font-awesome.min.css",
53
+ "src/styles.scss"
54
+ ]
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ **Important:** Make sure Bootstrap and Font Awesome are added BEFORE your custom styles.
64
+
65
+ ---
66
+
67
+ ## Configuration Steps
68
+
69
+ ### Step 5: Create HTTP Adapter Service
70
+
71
+ Create a new file at `src/app/adapters/tas-http-adapter.service.ts`:
72
+
73
+ ```typescript
74
+ import { Injectable } from '@angular/core';
75
+ import { HttpClient } from '@angular/common/http';
76
+ import { Observable } from 'rxjs';
77
+ import { TasHttpClient } from 'tas-uell-sdk';
78
+
79
+ @Injectable({ providedIn: 'root' })
80
+ export class TasHttpAdapterService implements TasHttpClient {
81
+ // IMPORTANT: Change this to your actual API URL
82
+ private apiUrl = 'https://your-api-url.com';
83
+
84
+ constructor(private http: HttpClient) {}
85
+
86
+ post<T>(url: string, options: { body: any; headers?: Record<string, string> }): Observable<T> {
87
+ return this.http.post<T>(`${this.apiUrl}/${url}`, options.body, {
88
+ headers: options.headers
89
+ });
90
+ }
91
+ }
92
+ ```
93
+
94
+ ### Step 6: Update AppModule
95
+
96
+ Update `src/app/app.module.ts` to import and configure the TAS SDK:
97
+
98
+ ```typescript
99
+ import { NgModule } from '@angular/core';
100
+ import { BrowserModule } from '@angular/platform-browser';
101
+ import { HttpClientModule } from '@angular/common/http';
102
+ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
103
+
104
+ // Import TAS SDK
105
+ import { TasUellSdkModule } from 'tas-uell-sdk';
106
+ import { TasHttpAdapterService } from './adapters/tas-http-adapter.service';
107
+
108
+ // IMPORTANT: Replace with your actual TokBox API Key
109
+ const TOKBOX_API_KEY = 'YOUR_TOKBOX_API_KEY';
110
+
111
+ @NgModule({
112
+ declarations: [
113
+ AppComponent,
114
+ // ... your other components
115
+ ],
116
+ imports: [
117
+ BrowserModule,
118
+ HttpClientModule,
119
+ NgbModule,
120
+
121
+ // TAS SDK configuration
122
+ TasUellSdkModule.forRoot({
123
+ config: { tokBoxApiKey: TOKBOX_API_KEY },
124
+ httpClient: TasHttpAdapterService
125
+ })
126
+ ],
127
+ providers: [],
128
+ bootstrap: [AppComponent]
129
+ })
130
+ export class AppModule { }
131
+ ```
132
+
133
+ ### Step 7: Add Global Modal Styles
134
+
135
+ Add these styles to your `src/styles.scss` (or `src/styles.css`):
136
+
137
+ ```scss
138
+ /* TAS Video Modal - Full screen video call */
139
+ .tas-video-modal {
140
+ .modal-dialog {
141
+ max-width: 100vw;
142
+ margin: 0;
143
+ height: 100vh;
144
+ }
145
+ .modal-content {
146
+ height: 100vh;
147
+ border: none;
148
+ border-radius: 0;
149
+ background: #000;
150
+ }
151
+ .modal-body {
152
+ padding: 0;
153
+ }
154
+ }
155
+
156
+ /* TAS Waiting Room Modal */
157
+ .tas-waiting-room-modal {
158
+ .modal-dialog {
159
+ max-width: 480px;
160
+ }
161
+ .modal-content {
162
+ border: none;
163
+ border-radius: 5px;
164
+ background: #ffffff;
165
+ overflow: hidden;
166
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
167
+ }
168
+ .modal-body {
169
+ padding: 0;
170
+ }
171
+ }
172
+ ```
173
+
174
+ ### Step 8: Add Floating Call Component
175
+
176
+ Update `src/app/app.component.html` to include the floating call component at the end:
177
+
178
+ ```html
179
+ <!-- Your existing content -->
180
+ <router-outlet></router-outlet>
181
+
182
+ <!-- Add this line at the end for Picture-in-Picture support -->
183
+ <tas-floating-call></tas-floating-call>
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Usage - Create a Test Component
189
+
190
+ ### Step 9: Create a Test Component
191
+
192
+ Create `src/app/tas-test/tas-test.component.ts`:
193
+
194
+ ```typescript
195
+ import { Component } from '@angular/core';
196
+ import { TasCurrentUser, TasUserRole } from 'tas-uell-sdk';
197
+
198
+ @Component({
199
+ selector: 'app-tas-test',
200
+ template: `
201
+ <div style="padding: 40px; text-align: center;">
202
+ <h1>TAS SDK Test</h1>
203
+ <p>Click the button below to test the video call functionality:</p>
204
+
205
+ <tas-btn
206
+ [appointmentId]="appointmentId"
207
+ [product]="product"
208
+ [tenantId]="tenantId"
209
+ [currentUser]="currentUser"
210
+ [ownerUserIds]="[userId]"
211
+ [regularUserIds]="[]"
212
+ [moderatorUserIds]="[]"
213
+ ></tas-btn>
214
+
215
+ <hr style="margin: 40px 0;">
216
+
217
+ <h3>Test Configuration:</h3>
218
+ <pre style="text-align: left; background: #f5f5f5; padding: 20px; border-radius: 8px;">
219
+ User ID: {{ userId }}
220
+ Appointment ID: {{ appointmentId }}
221
+ Product: {{ product }}
222
+ Tenant ID: {{ tenantId }}
223
+ Current User: {{ currentUser | json }}
224
+ </pre>
225
+ </div>
226
+ `
227
+ })
228
+ export class TasTestComponent {
229
+ // Test configuration - modify these values as needed
230
+ userId = 12345;
231
+ appointmentId = 1;
232
+ product = 'test-product';
233
+ tenantId = 'test-tenant';
234
+
235
+ currentUser: TasCurrentUser = {
236
+ name: 'Test',
237
+ lastname: 'User',
238
+ role: TasUserRole.OWNER
239
+ };
240
+ }
241
+ ```
242
+
243
+ ### Step 10: Register the Test Component
244
+
245
+ Add the test component to your module declarations in `app.module.ts`:
246
+
247
+ ```typescript
248
+ import { TasTestComponent } from './tas-test/tas-test.component';
249
+
250
+ @NgModule({
251
+ declarations: [
252
+ AppComponent,
253
+ TasTestComponent, // Add this
254
+ // ... other components
255
+ ],
256
+ // ...
257
+ })
258
+ ```
259
+
260
+ ### Step 11: Add Route or Use Directly
261
+
262
+ **Option A - Add a route** in `app-routing.module.ts`:
263
+
264
+ ```typescript
265
+ const routes: Routes = [
266
+ { path: 'tas-test', component: TasTestComponent },
267
+ // ... other routes
268
+ ];
269
+ ```
270
+
271
+ **Option B - Use directly** in `app.component.html`:
272
+
273
+ ```html
274
+ <app-tas-test></app-tas-test>
275
+ <tas-floating-call></tas-floating-call>
276
+ ```
277
+
278
+ ---
279
+
280
+ ## Run and Test
281
+
282
+ ### Step 12: Start the Application
283
+
284
+ ```bash
285
+ ng serve
286
+ ```
287
+
288
+ ### Step 13: Navigate to Test Page
289
+
290
+ Open your browser and go to:
291
+ - `http://localhost:4200/tas-test` (if using route)
292
+ - Or `http://localhost:4200` (if using directly in app.component)
293
+
294
+ ### Step 14: Test the Video Call
295
+
296
+ 1. Click the **"Iniciar TAS"** button
297
+ 2. The waiting room modal should appear
298
+ 3. Click **"Create Room"** to create a video room
299
+ 4. Click **"Join Session"** to enter the video call
300
+ 5. Test the controls: mute, swap views, minimize to PiP
301
+ 6. Test the floating window (PiP mode)
302
+ 7. Click hang up to end the call
303
+
304
+ ---
305
+
306
+ ## Style Dependencies Summary
307
+
308
+ | Dependency | Purpose | Required |
309
+ |------------|---------|----------|
310
+ | `bootstrap` | Button styles, modal layout | ✅ Yes |
311
+ | `font-awesome` | Icons (video, phone, mute, etc.) | ✅ Yes |
312
+ | Global modal styles | Modal positioning | ✅ Yes (add to styles.scss) |
313
+
314
+ ---
315
+
316
+ ## API Endpoints Required
317
+
318
+ Your backend API must provide these endpoints:
319
+
320
+ | Method | Endpoint | Description |
321
+ |--------|----------|-------------|
322
+ | POST | `v2/room` | Creates a new video room |
323
+ | POST | `v2/room/token` | Generates a session token |
324
+
325
+ ### Request/Response Examples
326
+
327
+ **POST v2/room**
328
+ ```json
329
+ // Request
330
+ {
331
+ "roomType": "TAS",
332
+ "type": "SPONTANEOUS",
333
+ "tenant": "tenant-id",
334
+ "appointmentId": 123,
335
+ "users": [{ "userExternalId": 12345, "rol": "OWNER" }],
336
+ "product": "product-name"
337
+ }
338
+
339
+ // Response
340
+ {
341
+ "content": {
342
+ "sessionId": "session-id-from-tokbox",
343
+ "roomId": 456
344
+ }
345
+ }
346
+ ```
347
+
348
+ **POST v2/room/token**
349
+ ```json
350
+ // Request
351
+ {
352
+ "sessionId": "session-id-from-tokbox",
353
+ "name": "John",
354
+ "lastname": "Doe",
355
+ "roleVC": "OWNER"
356
+ }
357
+
358
+ // Response
359
+ {
360
+ "content": {
361
+ "token": "tokbox-token-string"
362
+ }
363
+ }
364
+ ```
365
+
366
+ ---
367
+
368
+ ## Troubleshooting
369
+
370
+ ### Styles not applying
371
+ - ✅ Check that `bootstrap` and `font-awesome` are installed
372
+ - ✅ Check that styles are added to `angular.json` in the correct order
373
+ - ✅ Check that global modal styles are in `styles.scss`
374
+ - ✅ Restart `ng serve` after modifying `angular.json`
375
+
376
+ ### Icons not showing
377
+ - ✅ Verify `font-awesome` is installed: `npm list font-awesome`
378
+ - ✅ Verify the CSS is in `angular.json`: `"node_modules/font-awesome/css/font-awesome.min.css"`
379
+
380
+ ### "Cannot find module 'tas-uell-sdk'"
381
+ - ✅ Verify installation: `npm list tas-uell-sdk`
382
+
383
+ ### "No provider for TAS_CONFIG"
384
+ - ✅ Ensure `TasUellSdkModule.forRoot()` is called in AppModule
385
+
386
+ ### "No provider for TAS_HTTP_CLIENT"
387
+ - ✅ Ensure `httpClient` is passed to `forRoot()`
388
+
389
+ ### NgbModal errors
390
+ - ✅ Ensure `NgbModule` is imported in AppModule
391
+
392
+ ### Video not working
393
+ - ✅ Check browser console for TokBox errors
394
+ - ✅ Verify TokBox API key is correct
395
+ - ✅ Check camera/microphone permissions
396
+
397
+ ---
398
+
399
+ ## Checklist
400
+
401
+ - [ ] Library installed (`npm install tas-uell-sdk`)
402
+ - [ ] Peer dependencies installed (`@ng-bootstrap/ng-bootstrap`, `@opentok/client`, `interactjs`)
403
+ - [ ] Style dependencies installed (`bootstrap`, `font-awesome`)
404
+ - [ ] Styles added to `angular.json`
405
+ - [ ] HTTP Adapter service created
406
+ - [ ] AppModule updated with `TasUellSdkModule.forRoot()`
407
+ - [ ] Global modal styles added to `styles.scss`
408
+ - [ ] `<tas-floating-call>` added to app.component.html
409
+ - [ ] Test component created
410
+ - [ ] TokBox API key configured
411
+ - [ ] Backend API endpoints available
412
+
413
+ ---
414
+
415
+ ## Success Criteria
416
+
417
+ The library is working correctly if:
418
+ 1. ✅ The TAS button renders with proper styling (pink/magenta button with video icon)
419
+ 2. ✅ Clicking the button opens the waiting room modal
420
+ 3. ✅ "Create Room" successfully calls the API
421
+ 4. ✅ "Join Session" opens the full-screen video call
422
+ 5. ✅ Video from camera is displayed
423
+ 6. ✅ Mute/unmute works (icon changes)
424
+ 7. ✅ Minimize to PiP works
425
+ 8. ✅ Expand from PiP works
426
+ 9. ✅ Hang up ends the call properly
427
+
@@ -16,6 +16,10 @@ export class TasButtonComponent {
16
16
  this.tenantId = "";
17
17
  this.regularUserIds = [];
18
18
  this.moderatorUserIds = [];
19
+ /** Optional: If provided, skips room creation and goes directly to getting a token */
20
+ this.existingSessionId = "";
21
+ /** Optional: Custom button text */
22
+ this.buttonText = "Iniciar TAS";
19
23
  this.isLoading = false;
20
24
  this.subscriptions = new Subscription();
21
25
  this.currentModalRef = null;
@@ -69,6 +73,8 @@ export class TasButtonComponent {
69
73
  this.currentModalRef.componentInstance.ownerUserIds = this.ownerUserIds;
70
74
  this.currentModalRef.componentInstance.regularUserIds = this.regularUserIds;
71
75
  this.currentModalRef.componentInstance.moderatorUserIds = this.moderatorUserIds;
76
+ // Pass existing session ID if provided
77
+ this.currentModalRef.componentInstance.existingSessionId = this.existingSessionId;
72
78
  this.currentModalRef.result.then(() => { this.currentModalRef = null; }, () => { this.currentModalRef = null; });
73
79
  }
74
80
  openVideoCallModal(isReturningFromPip = false) {
@@ -85,10 +91,10 @@ export class TasButtonComponent {
85
91
  }
86
92
  }
87
93
  TasButtonComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TasButtonComponent, deps: [{ token: i1.NgbModal }, { token: i2.TasService }], target: i0.ɵɵFactoryTarget.Component });
88
- TasButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TasButtonComponent, selector: "tas-btn", inputs: { appointmentId: "appointmentId", product: "product", tenantId: "tenantId", currentUser: "currentUser", ownerUserIds: "ownerUserIds", regularUserIds: "regularUserIds", moderatorUserIds: "moderatorUserIds" }, ngImport: i0, template: "<button\n\ttype=\"button\"\n\tclass=\"btn btn-primary tas-btn\"\n\t(click)=\"onClick()\"\n\t[disabled]=\"isLoading\"\n>\n\t<i class=\"fa fa-video-camera\" aria-hidden=\"true\" *ngIf=\"!isLoading\"></i>\n\t<span *ngIf=\"!isLoading\"> Iniciar TAS</span>\n\t<span *ngIf=\"isLoading\"> Processing...</span>\n</button>\n\n", styles: [":host{display:inline-block}.tas-btn{background-color:#ee316b!important;color:#fff!important;border-color:#ee316b!important;margin-right:24px}.tas-btn:disabled{background-color:#ccc!important;border-color:#ccc!important;cursor:not-allowed}.tas-btn:hover:not(:disabled){background-color:#d62a5f!important;border-color:#d62a5f!important}.tas-btn i{margin-right:5px}\n"], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
94
+ TasButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TasButtonComponent, selector: "tas-btn", inputs: { appointmentId: "appointmentId", product: "product", tenantId: "tenantId", currentUser: "currentUser", ownerUserIds: "ownerUserIds", regularUserIds: "regularUserIds", moderatorUserIds: "moderatorUserIds", existingSessionId: "existingSessionId", buttonText: "buttonText" }, ngImport: i0, template: "<button\n\ttype=\"button\"\n\tclass=\"btn btn-primary tas-btn\"\n\t(click)=\"onClick()\"\n\t[disabled]=\"isLoading\"\n>\n\t<i class=\"fa fa-video-camera\" aria-hidden=\"true\" *ngIf=\"!isLoading\"></i>\n\t<span *ngIf=\"!isLoading\"> {{ buttonText }}</span>\n\t<span *ngIf=\"isLoading\"> Processing...</span>\n</button>\n", styles: [":host{display:inline-block}.tas-btn{background-color:#ee316b!important;color:#fff!important;border-color:#ee316b!important;margin-right:24px}.tas-btn:disabled{background-color:#ccc!important;border-color:#ccc!important;cursor:not-allowed}.tas-btn:hover:not(:disabled){background-color:#d62a5f!important;border-color:#d62a5f!important}.tas-btn i{margin-right:5px}\n"], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
89
95
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TasButtonComponent, decorators: [{
90
96
  type: Component,
91
- args: [{ selector: "tas-btn", template: "<button\n\ttype=\"button\"\n\tclass=\"btn btn-primary tas-btn\"\n\t(click)=\"onClick()\"\n\t[disabled]=\"isLoading\"\n>\n\t<i class=\"fa fa-video-camera\" aria-hidden=\"true\" *ngIf=\"!isLoading\"></i>\n\t<span *ngIf=\"!isLoading\"> Iniciar TAS</span>\n\t<span *ngIf=\"isLoading\"> Processing...</span>\n</button>\n\n", styles: [":host{display:inline-block}.tas-btn{background-color:#ee316b!important;color:#fff!important;border-color:#ee316b!important;margin-right:24px}.tas-btn:disabled{background-color:#ccc!important;border-color:#ccc!important;cursor:not-allowed}.tas-btn:hover:not(:disabled){background-color:#d62a5f!important;border-color:#d62a5f!important}.tas-btn i{margin-right:5px}\n"] }]
97
+ args: [{ selector: "tas-btn", template: "<button\n\ttype=\"button\"\n\tclass=\"btn btn-primary tas-btn\"\n\t(click)=\"onClick()\"\n\t[disabled]=\"isLoading\"\n>\n\t<i class=\"fa fa-video-camera\" aria-hidden=\"true\" *ngIf=\"!isLoading\"></i>\n\t<span *ngIf=\"!isLoading\"> {{ buttonText }}</span>\n\t<span *ngIf=\"isLoading\"> Processing...</span>\n</button>\n", styles: [":host{display:inline-block}.tas-btn{background-color:#ee316b!important;color:#fff!important;border-color:#ee316b!important;margin-right:24px}.tas-btn:disabled{background-color:#ccc!important;border-color:#ccc!important;cursor:not-allowed}.tas-btn:hover:not(:disabled){background-color:#d62a5f!important;border-color:#d62a5f!important}.tas-btn i{margin-right:5px}\n"] }]
92
98
  }], ctorParameters: function () { return [{ type: i1.NgbModal }, { type: i2.TasService }]; }, propDecorators: { appointmentId: [{
93
99
  type: Input
94
100
  }], product: [{
@@ -103,5 +109,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
103
109
  type: Input
104
110
  }], moderatorUserIds: [{
105
111
  type: Input
112
+ }], existingSessionId: [{
113
+ type: Input
114
+ }], buttonText: [{
115
+ type: Input
106
116
  }] } });
107
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFzLWJ0bi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy90YXMtdWVsbC1zZGsvc3JjL2xpYi9jb21wb25lbnRzL3Rhcy1idG4vdGFzLWJ0bi5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy90YXMtdWVsbC1zZGsvc3JjL2xpYi9jb21wb25lbnRzL3Rhcy1idG4vdGFzLWJ0bi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFxQixLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFcEUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNwQyxPQUFPLEVBQWtCLFFBQVEsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzNFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLGdEQUFnRCxDQUFDO0FBQ3pGLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDBDQUEwQyxDQUFDOzs7OztBQVFqRixNQUFNLE9BQU8sa0JBQWtCO0lBZTlCLFlBQ1MsWUFBc0IsRUFDdEIsVUFBc0I7UUFEdEIsaUJBQVksR0FBWixZQUFZLENBQVU7UUFDdEIsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQWhCdEIsa0JBQWEsR0FBVyxDQUFDLENBQUM7UUFDMUIsWUFBTyxHQUFXLE1BQU0sQ0FBQztRQUN6QixhQUFRLEdBQVcsRUFBRSxDQUFDO1FBR3RCLG1CQUFjLEdBQWEsRUFBRSxDQUFDO1FBQzlCLHFCQUFnQixHQUFhLEVBQUUsQ0FBQztRQUVsQyxjQUFTLEdBQUcsS0FBSyxDQUFDO1FBRWpCLGtCQUFhLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNuQyxvQkFBZSxHQUF1QixJQUFJLENBQUM7UUFDM0Msc0JBQWlCLEdBQXVCLElBQUksQ0FBQztJQUtsRCxDQUFDO0lBRUosUUFBUTtRQUNQLElBQUksQ0FB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b20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBOZ2JNb2RhbCwgTmdiTW9kYWxSZWYgfSBmcm9tIFwiQG5nLWJvb3RzdHJhcC9uZy1ib290c3RyYXBcIjtcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQgeyBUYXNDdXJyZW50VXNlciwgVmlld01vZGUgfSBmcm9tIFwiLi4vLi4vaW50ZXJmYWNlcy90YXMuaW50ZXJmYWNlc1wiO1xuaW1wb3J0IHsgVGFzV2FpdGluZ1Jvb21Db21wb25lbnQgfSBmcm9tIFwiLi4vdGFzLXdhaXRpbmctcm9vbS90YXMtd2FpdGluZy1yb29tLmNvbXBvbmVudFwiO1xuaW1wb3J0IHsgVGFzVmlkZW9jYWxsQ29tcG9uZW50IH0gZnJvbSBcIi4uL3Rhcy12aWRlb2NhbGwvdGFzLXZpZGVvY2FsbC5jb21wb25lbnRcIjtcbmltcG9ydCB7IFRhc1NlcnZpY2UgfSBmcm9tIFwiLi4vLi4vc2VydmljZXMvdGFzLnNlcnZpY2VcIjtcblxuQENvbXBvbmVudCh7XG5cdHNlbGVjdG9yOiBcInRhcy1idG5cIixcblx0dGVtcGxhdGVVcmw6IFwiLi90YXMtYnRuLmNvbXBvbmVudC5odG1sXCIsXG5cdHN0eWxlVXJsczogW1wiLi90YXMtYnRuLmNvbXBvbmVudC5zY3NzXCJdLFxufSlcbmV4cG9ydCBjbGFzcyBUYXNCdXR0b25Db21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG5cdEBJbnB1dCgpIGFwcG9pbnRtZW50SWQ6IG51bWJlciA9IDE7XG5cdEBJbnB1dCgpIHByb2R1Y3Q6IHN0cmluZyA9IFwidWVsbFwiO1xuXHRASW5wdXQoKSB0ZW5hbnRJZDogc3RyaW5nID0gXCJcIjtcblx0QElucHV0KCkgY3VycmVudFVzZXIhOiBUYXNDdXJyZW50VXNlcjtcblx0QElucHV0KCkgb3duZXJVc2VySWRzITogbnVtYmVyW107XG5cdEBJbnB1dCgpIHJlZ3VsYXJVc2VySWRzOiBudW1iZXJbXSA9IFtdO1xuXHRASW5wdXQoKSBtb2RlcmF0b3JVc2VySWRzOiBudW1iZXJbXSA9IFtdO1xuXHRcblx0cHVibGljIGlzTG9hZGluZyA9IGZhbHNlO1xuXHRcblx0cHJpdmF0ZSBzdWJzY3JpcHRpb25zID0gbmV3IFN1YnNjcmlwdGlvbigpO1xuXHRwcml2YXRlIGN1cnJlbnRNb2RhbFJlZjogTmdiTW9kYWxSZWYgfCBudWxsID0gbnVsbDtcblx0cHJpdmF0ZSB2aWRlb0NhbGxNb2RhbFJlZjogTmdiTW9kYWxSZWYgfCBudWxsID0gbnVsbDtcblxuXHRjb25zdHJ1Y3Rvcihcblx0XHRwcml2YXRlIG1vZGFsU2VydmljZTogTmdiTW9kYWwsXG5cdFx0cHJpdmF0ZSB0YXNTZXJ2aWNlOiBUYXNTZXJ2aWNlXG5cdCkge31cblxuXHRuZ09uSW5pdCgpOiB2b2lkIHtcblx0XHRpZiAoIXRoaXMub3duZXJVc2VySWRzIHx8IHRoaXMub3duZXJVc2VySWRzLmxlbmd0aCAhPT0gMSkge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCd0YXMtYnRuOiBvd25lclVzZXJJZHMgaW5wdXQgaXMgcmVxdWlyZWQgYW5kIG11c3QgY29udGFpbiBleGFjdGx5IG9uZSB1c2VyJyk7XG5cdFx0fVxuXHRcdFxuXHRcdC8vIFN1YnNjcmliZSB0byB2aWV3TW9kZSB0byBoYW5kbGUgUGlQIHJldHVyblxuXHRcdHRoaXMuc3Vic2NyaXB0aW9ucy5hZGQoXG5cdFx0XHR0aGlzLnRhc1NlcnZpY2Uudmlld01vZGUkLnN1YnNjcmliZShtb2RlID0+IHtcblx0XHRcdFx0Ly8gUmVvcGVuIHZpZGVvIGNhbGwgbW9kYWwgd2hlbiByZXR1cm5pbmcgZnJvbSBQaVBcblx0XHRcdFx0aWYgKG1vZGUgPT09IFZpZXdNb2RlLkZVTExTQ1JFRU4gJiYgXG5cdFx0XHRcdFx0dGhpcy50YXNTZXJ2aWNlLmlzQ2FsbEFjdGl2ZSgpICYmIFxuXHRcdFx0XHRcdCF0aGlzLnZpZGVvQ2FsbE1vZGFsUmVmKSB7XG5cdFx0XHRcdFx0Y29uc3Qgc2Vzc2lvbklkID0gdGhpcy50YXNTZXJ2aWNlLnNlc3Npb25JZDtcblx0XHRcdFx0XHRjb25zdCB0b2tlbiA9IHRoaXMudGFzU2VydmljZS50b2tlbjtcblx0XHRcdFx0XHRpZiAoc2Vzc2lvbklkICYmIHRva2VuKSB7XG5cdFx0XHRcdFx0XHR0aGlzLm9wZW5WaWRlb0NhbGxNb2RhbCh0cnVlKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0XG5cdFx0XHRcdC8vIFdoZW4gZW50ZXJpbmcgUGlQLCBjbGVhciB0aGUgdmlkZW9DYWxsTW9kYWxSZWYgc2luY2UgbW9kYWwgd2lsbCBjbG9zZVxuXHRcdFx0XHRpZiAobW9kZSA9PT0gVmlld01vZGUuUElQKSB7XG5cdFx0XHRcdFx0dGhpcy52aWRlb0NhbGxNb2RhbFJlZiA9IG51bGw7XG5cdFx0XHRcdH1cblx0XHRcdH0pXG5cdFx0KTtcblx0fVxuXG5cdG5nT25EZXN0cm95KCk6IHZvaWQge1xuXHRcdHRoaXMuc3Vic2NyaXB0aW9ucy51bnN1YnNjcmliZSgpO1xuXHR9XG5cblx0b25DbGljaygpOiB2b2lkIHtcblx0XHRpZiAoIXRoaXMudGVuYW50SWQgfHwgIXRoaXMuY3VycmVudFVzZXI/Lm5hbWUpIHtcblx0XHRcdGNvbnNvbGUuZXJyb3IoXCJUZW5hbnQgSUQgb3IgY3VycmVudCB1c2VyIG5vdCBhdmFpbGFibGVcIik7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5vcGVuV2FpdGluZ1Jvb21Nb2RhbCgpO1xuXHR9XG5cblx0cHJpdmF0ZSBvcGVuV2FpdGluZ1Jvb21Nb2RhbCgpOiB2b2lkIHtcblx0XHR0aGlzLmN1cnJlbnRNb2RhbFJlZiA9IHRoaXMubW9kYWxTZXJ2aWNlLm9wZW4oVGFzV2FpdGluZ1Jvb21Db21wb25lbnQsIHtcblx0XHRcdHNpemU6IFwibGdcIixcblx0XHRcdHdpbmRvd0NsYXNzOiBcInRhcy13YWl0aW5nLXJvb20tbW9kYWxcIixcblx0XHRcdGJhY2tkcm9wOiBcInN0YXRpY1wiLFxuXHRcdFx0a2V5Ym9hcmQ6IGZhbHNlLFxuXHRcdFx0Y2VudGVyZWQ6IHRydWVcblx0XHR9KTtcblxuXHRcdC8vIFBhc3MgYWxsIG5lY2Vzc2FyeSBpbnB1dHMgdG8gdGhlIHdhaXRpbmcgcm9vbSBjb21wb25lbnRcblx0XHR0aGlzLmN1cnJlbnRNb2RhbFJlZi5jb21wb25lbnRJbnN0YW5jZS5hcHBvaW50bWVudElkID0gdGhpcy5hcHBvaW50bWVudElkO1xuXHRcdHRoaXMuY3VycmVudE1vZGFsUmVmLmNvbXBvbmVudEluc3RhbmNlLnByb2R1Y3QgPSB0aGlzLnByb2R1Y3Q7XG5cdFx0dGhpcy5jdXJyZW50TW9kYWxSZWYuY29tcG9uZW50SW5zdGFuY2UudGVuYW50SWQgPSB0aGlzLnRlbmFudElkO1xuXHRcdHRoaXMuY3VycmVudE1vZGFsUmVmLmNvbXBvbmVudEluc3RhbmNlLmN1cnJlbnRVc2VyID0gdGhpcy5jdXJyZW50VXNlcjtcblx0XHR0aGlzLmN1cnJlbnRNb2RhbFJlZi5jb21wb25lbnRJbnN0YW5jZS5vd25lclVzZXJJZHMgPSB0aGlzLm93bmVyVXNlcklkcztcblx0XHR0aGlzLmN1cnJlbnRNb2RhbFJlZi5jb21wb25lbnRJbnN0YW5jZS5yZWd1bGFyVXNlcklkcyA9IHRoaXMucmVndWxhclVzZXJJZHM7XG5cdFx0dGhpcy5jdXJyZW50TW9kYWxSZWYuY29tcG9uZW50SW5zdGFuY2UubW9kZXJhdG9yVXNlcklkcyA9IHRoaXMubW9kZXJhdG9yVXNlcklkcztcblxuXHRcdHRoaXMuY3VycmVudE1vZGFsUmVmLnJlc3VsdC50aGVuKFxuXHRcdFx0KCkgPT4geyB0aGlzLmN1cnJlbnRNb2RhbFJlZiA9IG51bGw7IH0sXG5cdFx0XHQoKSA9PiB7IHRoaXMuY3VycmVudE1vZGFsUmVmID0gbnVsbDsgfVxuXHRcdCk7XG5cdH1cblxuXHRwcml2YXRlIG9wZW5WaWRlb0NhbGxNb2RhbChpc1JldHVybmluZ0Zyb21QaXA6IGJvb2xlYW4gPSBmYWxzZSk6IHZvaWQge1xuXHRcdHRoaXMudmlkZW9DYWxsTW9kYWxSZWYgPSB0aGlzLm1vZGFsU2VydmljZS5vcGVuKFRhc1ZpZGVvY2FsbENvbXBvbmVudCwge1xuXHRcdFx0c2l6ZTogJ3hsJyxcblx0XHRcdHdpbmRvd0NsYXNzOiAndGFzLXZpZGVvLW1vZGFsJyxcblx0XHRcdGJhY2tkcm9wOiAnc3RhdGljJyxcblx0XHRcdGtleWJvYXJkOiBmYWxzZVxuXHRcdH0pO1xuXG5cdFx0dGhpcy52aWRlb0NhbGxNb2RhbFJlZi5jb21wb25lbnRJbnN0YW5jZS5zZXNzaW9uSWQgPSB0aGlzLnRhc1NlcnZpY2Uuc2Vzc2lvbklkO1xuXHRcdHRoaXMudmlkZW9DYWxsTW9kYWxSZWYuY29tcG9uZW50SW5zdGFuY2UudG9rZW4gPSB0aGlzLnRhc1NlcnZpY2UudG9rZW47XG5cdFx0dGhpcy52aWRlb0NhbGxNb2RhbFJlZi5jb21wb25lbnRJbnN0YW5jZS5pc1JldHVybmluZ0Zyb21QaXAgPSBpc1JldHVybmluZ0Zyb21QaXA7XG5cblx0XHR0aGlzLnZpZGVvQ2FsbE1vZGFsUmVmLnJlc3VsdC50aGVuKFxuXHRcdFx0KCkgPT4geyB0aGlzLnZpZGVvQ2FsbE1vZGFsUmVmID0gbnVsbDsgfSxcblx0XHRcdCgpID0+IHsgdGhpcy52aWRlb0NhbGxNb2RhbFJlZiA9IG51bGw7IH1cblx0XHQpO1xuXHR9XG59XG5cbiIsIjxidXR0b25cblx0dHlwZT1cImJ1dHRvblwiXG5cdGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IHRhcy1idG5cIlxuXHQoY2xpY2spPVwib25DbGljaygpXCJcblx0W2Rpc2FibGVkXT1cImlzTG9hZGluZ1wiXG4+XG5cdDxpIGNsYXNzPVwiZmEgZmEtdmlkZW8tY2FtZXJhXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCIgKm5nSWY9XCIhaXNMb2FkaW5nXCI+PC9pPlxuXHQ8c3BhbiAqbmdJZj1cIiFpc0xvYWRpbmdcIj4gSW5pY2lhciBUQVM8L3NwYW4+XG5cdDxzcGFuICpuZ0lmPVwiaXNMb2FkaW5nXCI+IFByb2Nlc3NpbmcuLi48L3NwYW4+XG48L2J1dHRvbj5cblxuIl19
117
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFzLWJ0bi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy90YXMtdWVsbC1zZGsvc3JjL2xpYi9jb21wb25lbnRzL3Rhcy1idG4vdGFzLWJ0bi5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy90YXMtdWVsbC1zZGsvc3JjL2xpYi9jb21wb25lbnRzL3Rhcy1idG4vdGFzLWJ0bi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFxQixLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFcEUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNwQyxPQUFPLEVBQWtCLFFBQVEsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzNFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLGdEQUFnRCxDQUFDO0FBQ3pGLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDBDQUEwQyxDQUFDOzs7OztBQVFqRixNQUFNLE9BQU8sa0JBQWtCO0lBcUI5QixZQUNTLFlBQXNCLEVBQ3RCLFVBQXNCO1FBRHRCLGlCQUFZLEdBQVosWUFBWSxDQUFVO1FBQ3RCLGVBQVUsR0FBVixVQUFVLENBQVk7UUF0QnRCLGtCQUFhLEdBQVcsQ0FBQyxDQUFDO1FBQzFCLFlBQU8sR0FBVyxNQUFNLENBQUM7UUFDekIsYUFBUSxHQUFXLEVBQUUsQ0FBQztRQUd0QixtQkFBYyxHQUFhLEVBQUUsQ0FBQztRQUM5QixxQkFBZ0IsR0FBYSxFQUFFLENBQUM7UUFFekMsc0ZBQXNGO1FBQzdFLHNCQUFpQixHQUFXLEVBQUUsQ0FBQztRQUV4QyxtQ0FBbUM7UUFDMUIsZUFBVSxHQUFXLGFBQWEsQ0FBQztRQUVyQyxjQUFTLEdBQUcsS0FBSyxDQUFDO1FBRWpCLGtCQUFhLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNuQyxvQkFB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QUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSztnQkFDRyxZQUFZO3NCQUFwQixLQUFLO2dCQUNHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBQ0csZ0JBQWdCO3NCQUF4QixLQUFLO2dCQUdHLGlCQUFpQjtzQkFBekIsS0FBSztnQkFHRyxVQUFVO3NCQUFsQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPbkluaXQsIE9uRGVzdHJveSwgSW5wdXQgfSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgTmdiTW9kYWwsIE5nYk1vZGFsUmVmIH0gZnJvbSBcIkBuZy1ib290c3RyYXAvbmctYm9vdHN0cmFwXCI7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHsgVGFzQ3VycmVudFVzZXIsIFZpZXdNb2RlIH0gZnJvbSBcIi4uLy4uL2ludGVyZmFjZXMvdGFzLmludGVyZmFjZXNcIjtcbmltcG9ydCB7IFRhc1dhaXRpbmdSb29tQ29tcG9uZW50IH0gZnJvbSBcIi4uL3Rhcy13YWl0aW5nLXJvb20vdGFzLXdhaXRpbmctcm9vbS5jb21wb25lbnRcIjtcbmltcG9ydCB7IFRhc1ZpZGVvY2FsbENvbXBvbmVudCB9IGZyb20gXCIuLi90YXMtdmlkZW9jYWxsL3Rhcy12aWRlb2NhbGwuY29tcG9uZW50XCI7XG5pbXBvcnQgeyBUYXNTZXJ2aWNlIH0gZnJvbSBcIi4uLy4uL3NlcnZpY2VzL3Rhcy5zZXJ2aWNlXCI7XG5cbkBDb21wb25lbnQoe1xuXHRzZWxlY3RvcjogXCJ0YXMtYnRuXCIsXG5cdHRlbXBsYXRlVXJsOiBcIi4vdGFzLWJ0bi5jb21wb25lbnQuaHRtbFwiLFxuXHRzdHlsZVVybHM6IFtcIi4vdGFzLWJ0bi5jb21wb25lbnQuc2Nzc1wiXSxcbn0pXG5leHBvcnQgY2xhc3MgVGFzQnV0dG9uQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuXHRASW5wdXQoKSBhcHBvaW50bWVudElkOiBudW1iZXIgPSAxO1xuXHRASW5wdXQoKSBwcm9kdWN0OiBzdHJpbmcgPSBcInVlbGxcIjtcblx0QElucHV0KCkgdGVuYW50SWQ6IHN0cmluZyA9IFwiXCI7XG5cdEBJbnB1dCgpIGN1cnJlbnRVc2VyITogVGFzQ3VycmVudFVzZXI7XG5cdEBJbnB1dCgpIG93bmVyVXNlcklkcyE6IG51bWJlcltdO1xuXHRASW5wdXQoKSByZWd1bGFyVXNlcklkczogbnVtYmVyW10gPSBbXTtcblx0QElucHV0KCkgbW9kZXJhdG9yVXNlcklkczogbnVtYmVyW10gPSBbXTtcblx0XG5cdC8qKiBPcHRpb25hbDogSWYgcHJvdmlkZWQsIHNraXBzIHJvb20gY3JlYXRpb24gYW5kIGdvZXMgZGlyZWN0bHkgdG8gZ2V0dGluZyBhIHRva2VuICovXG5cdEBJbnB1dCgpIGV4aXN0aW5nU2Vzc2lvbklkOiBzdHJpbmcgPSBcIlwiO1xuXHRcblx0LyoqIE9wdGlvbmFsOiBDdXN0b20gYnV0dG9uIHRleHQgKi9cblx0QElucHV0KCkgYnV0dG9uVGV4dDogc3RyaW5nID0gXCJJbmljaWFyIFRBU1wiO1xuXHRcblx0cHVibGljIGlzTG9hZGluZyA9IGZhbHNlO1xuXHRcblx0cHJpdmF0ZSBzdWJzY3JpcHRpb25zID0gbmV3IFN1YnNjcmlwdGlvbigpO1xuXHRwcml2YXRlIGN1cnJlbnRNb2RhbFJlZjogTmdiTW9kYWxSZWYgfCBudWxsID0gbnVsbDtcblx0cHJpdmF0ZSB2aWRlb0NhbGxNb2RhbFJlZjogTmdiTW9kYWxSZWYgfCBudWxsID0gbnVsbDtcblxuXHRjb25zdHJ1Y3Rvcihcblx0XHRwcml2YXRlIG1vZGFsU2VydmljZTogTmdiTW9kYWwsXG5cdFx0cHJpdmF0ZSB0YXNTZXJ2aWNlOiBUYXNTZXJ2aWNlXG5cdCkge31cblxuXHRuZ09uSW5pdCgpOiB2b2lkIHtcblx0XHRpZiAoIXRoaXMub3duZXJVc2VySWRzIHx8IHRoaXMub3duZXJVc2VySWRzLmxlbmd0aCAhPT0gMSkge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCd0YXMtYnRuOiBvd25lclVzZXJJZHMgaW5wdXQgaXMgcmVxdWlyZWQgYW5kIG11c3QgY29udGFpbiBleGFjdGx5IG9uZSB1c2VyJyk7XG5cdFx0fVxuXHRcdFxuXHRcdC8vIFN1YnNjcmliZSB0byB2aWV3TW9kZSB0byBoYW5kbGUgUGlQIHJldHVyblxuXHRcdHRoaXMuc3Vic2NyaXB0aW9ucy5hZGQoXG5cdFx0XHR0aGlzLnRhc1NlcnZpY2Uudmlld01vZGUkLnN1YnNjcmliZShtb2RlID0+IHtcblx0XHRcdFx0Ly8gUmVvcGVuIHZpZGVvIGNhbGwgbW9kYWwgd2hlbiByZXR1cm5pbmcgZnJvbSBQaVBcblx0XHRcdFx0aWYgKG1vZGUgPT09IFZpZXdNb2RlLkZVTExTQ1JFRU4gJiYgXG5cdFx0XHRcdFx0dGhpcy50YXNTZXJ2aWNlLmlzQ2FsbEFjdGl2ZSgpICYmIFxuXHRcdFx0XHRcdCF0aGlzLnZpZGVvQ2FsbE1vZGFsUmVmKSB7XG5cdFx0XHRcdFx0Y29uc3Qgc2Vzc2lvbklkID0gdGhpcy50YXNTZXJ2aWNlLnNlc3Npb25JZDtcblx0XHRcdFx0XHRjb25zdCB0b2tlbiA9IHRoaXMudGFzU2VydmljZS50b2tlbjtcblx0XHRcdFx0XHRpZiAoc2Vzc2lvbklkICYmIHRva2VuKSB7XG5cdFx0XHRcdFx0XHR0aGlzLm9wZW5WaWRlb0NhbGxNb2RhbCh0cnVlKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0XG5cdFx0XHRcdC8vIFdoZW4gZW50ZXJpbmcgUGlQLCBjbGVhciB0aGUgdmlkZW9DYWxsTW9kYWxSZWYgc2luY2UgbW9kYWwgd2lsbCBjbG9zZVxuXHRcdFx0XHRpZiAobW9kZSA9PT0gVmlld01vZGUuUElQKSB7XG5cdFx0XHRcdFx0dGhpcy52aWRlb0NhbGxNb2RhbFJlZiA9IG51bGw7XG5cdFx0XHRcdH1cblx0XHRcdH0pXG5cdFx0KTtcblx0fVxuXG5cdG5nT25EZXN0cm95KCk6IHZvaWQge1xuXHRcdHRoaXMuc3Vic2NyaXB0aW9ucy51bnN1YnNjcmliZSgpO1xuXHR9XG5cblx0b25DbGljaygpOiB2b2lkIHtcblx0XHRpZiAoIXRoaXMudGVuYW50SWQgfHwgIXRoaXMuY3VycmVudFVzZXI/Lm5hbWUpIHtcblx0XHRcdGNvbnNvbGUuZXJyb3IoXCJUZW5hbnQgSUQgb3IgY3VycmVudCB1c2VyIG5vdCBhdmFpbGFibGVcIik7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5vcGVuV2FpdGluZ1Jvb21Nb2RhbCgpO1xuXHR9XG5cblx0cHJpdmF0ZSBvcGVuV2FpdGluZ1Jvb21Nb2RhbCgpOiB2b2lkIHtcblx0XHR0aGlzLmN1cnJlbnRNb2RhbFJlZiA9IHRoaXMubW9kYWxTZXJ2aWNlLm9wZW4oVGFzV2FpdGluZ1Jvb21Db21wb25lbnQsIHtcblx0XHRcdHNpemU6IFwibGdcIixcblx0XHRcdHdpbmRvd0NsYXNzOiBcInRhcy13YWl0aW5nLXJvb20tbW9kYWxcIixcblx0XHRcdGJhY2tkcm9wOiBcInN0YXRpY1wiLFxuXHRcdFx0a2V5Ym9hcmQ6IGZhbHNlLFxuXHRcdFx0Y2VudGVyZWQ6IHRydWVcblx0XHR9KTtcblxuXHRcdC8vIFBhc3MgYWxsIG5lY2Vzc2FyeSBpbnB1dHMgdG8gdGhlIHdhaXRpbmcgcm9vbSBjb21wb25lbnRcblx0XHR0aGlzLmN1cnJlbnRNb2RhbFJlZi5jb21wb25lbnRJbnN0YW5jZS5hcHBvaW50bWVudElkID0gdGhpcy5hcHBvaW50bWVudElkO1xuXHRcdHRoaXMuY3VycmVudE1vZGFsUmVmLmNvbXBvbmVudEluc3RhbmNlLnByb2R1Y3QgPSB0aGlzLnByb2R1Y3Q7XG5cdFx0dGhpcy5jdXJyZW50TW9kYWxSZWYuY29tcG9uZW50SW5zdGFuY2UudGVuYW50SWQgPSB0aGlzLnRlbmFudElkO1xuXHRcdHRoaXMuY3VycmVudE1vZGFsUmVmLmNvbXBvbmVudEluc3RhbmNlLmN1cnJlbnRVc2VyID0gdGhpcy5jdXJyZW50VXNlcjtcblx0XHR0aGlzLmN1cnJlbnRNb2RhbFJlZi5jb21wb25lbnRJbnN0YW5jZS5vd25lclVzZXJJZHMgPSB0aGlzLm93bmVyVXNlcklkcztcblx0XHR0aGlzLmN1cnJlbnRNb2RhbFJlZi5jb21wb25lbnRJbnN0YW5jZS5yZWd1bGFyVXNlcklkcyA9IHRoaXMucmVndWxhclVzZXJJZHM7XG5cdFx0dGhpcy5jdXJyZW50TW9kYWxSZWYuY29tcG9uZW50SW5zdGFuY2UubW9kZXJhdG9yVXNlcklkcyA9IHRoaXMubW9kZXJhdG9yVXNlcklkcztcblx0XHRcblx0XHQvLyBQYXNzIGV4aXN0aW5nIHNlc3Npb24gSUQgaWYgcHJvdmlkZWRcblx0XHR0aGlzLmN1cnJlbnRNb2RhbFJlZi5jb21wb25lbnRJbnN0YW5jZS5leGlzdGluZ1Nlc3Npb25JZCA9IHRoaXMuZXhpc3RpbmdTZXNzaW9uSWQ7XG5cblx0XHR0aGlzLmN1cnJlbnRNb2RhbFJlZi5yZXN1bHQudGhlbihcblx0XHRcdCgpID0+IHsgdGhpcy5jdXJyZW50TW9kYWxSZWYgPSBudWxsOyB9LFxuXHRcdFx0KCkgPT4geyB0aGlzLmN1cnJlbnRNb2RhbFJlZiA9IG51bGw7IH1cblx0XHQpO1xuXHR9XG5cblx0cHJpdmF0ZSBvcGVuVmlkZW9DYWxsTW9kYWwoaXNSZXR1cm5pbmdGcm9tUGlwOiBib29sZWFuID0gZmFsc2UpOiB2b2lkIHtcblx0XHR0aGlzLnZpZGVvQ2FsbE1vZGFsUmVmID0gdGhpcy5tb2RhbFNlcnZpY2Uub3BlbihUYXNWaWRlb2NhbGxDb21wb25lbnQsIHtcblx0XHRcdHNpemU6ICd4bCcsXG5cdFx0XHR3aW5kb3dDbGFzczogJ3Rhcy12aWRlby1tb2RhbCcsXG5cdFx0XHRiYWNrZHJvcDogJ3N0YXRpYycsXG5cdFx0XHRrZXlib2FyZDogZmFsc2Vcblx0XHR9KTtcblxuXHRcdHRoaXMudmlkZW9DYWxsTW9kYWxSZWYuY29tcG9uZW50SW5zdGFuY2Uuc2Vzc2lvbklkID0gdGhpcy50YXNTZXJ2aWNlLnNlc3Npb25JZDtcblx0XHR0aGlzLnZpZGVvQ2FsbE1vZGFsUmVmLmNvbXBvbmVudEluc3RhbmNlLnRva2VuID0gdGhpcy50YXNTZXJ2aWNlLnRva2VuO1xuXHRcdHRoaXMudmlkZW9DYWxsTW9kYWxSZWYuY29tcG9uZW50SW5zdGFuY2UuaXNSZXR1cm5pbmdGcm9tUGlwID0gaXNSZXR1cm5pbmdGcm9tUGlwO1xuXG5cdFx0dGhpcy52aWRlb0NhbGxNb2RhbFJlZi5yZXN1bHQudGhlbihcblx0XHRcdCgpID0+IHsgdGhpcy52aWRlb0NhbGxNb2RhbFJlZiA9IG51bGw7IH0sXG5cdFx0XHQoKSA9PiB7IHRoaXMudmlkZW9DYWxsTW9kYWxSZWYgPSBudWxsOyB9XG5cdFx0KTtcblx0fVxufVxuIiwiPGJ1dHRvblxuXHR0eXBlPVwiYnV0dG9uXCJcblx0Y2xhc3M9XCJidG4gYnRuLXByaW1hcnkgdGFzLWJ0blwiXG5cdChjbGljayk9XCJvbkNsaWNrKClcIlxuXHRbZGlzYWJsZWRdPVwiaXNMb2FkaW5nXCJcbj5cblx0PGkgY2xhc3M9XCJmYSBmYS12aWRlby1jYW1lcmFcIiBhcmlhLWhpZGRlbj1cInRydWVcIiAqbmdJZj1cIiFpc0xvYWRpbmdcIj48L2k+XG5cdDxzcGFuICpuZ0lmPVwiIWlzTG9hZGluZ1wiPiB7eyBidXR0b25UZXh0IH19PC9zcGFuPlxuXHQ8c3BhbiAqbmdJZj1cImlzTG9hZGluZ1wiPiBQcm9jZXNzaW5nLi4uPC9zcGFuPlxuPC9idXR0b24+XG4iXX0=