@hivegpt/hiveai-angular 0.0.588 → 0.0.590

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 (29) hide show
  1. package/bundles/hivegpt-hiveai-angular.umd.js +252 -654
  2. package/bundles/hivegpt-hiveai-angular.umd.js.map +1 -1
  3. package/bundles/hivegpt-hiveai-angular.umd.min.js +1 -1
  4. package/bundles/hivegpt-hiveai-angular.umd.min.js.map +1 -1
  5. package/esm2015/hivegpt-hiveai-angular.js +4 -6
  6. package/esm2015/lib/components/chat-drawer/chat-drawer.component.js +1 -1
  7. package/esm2015/lib/components/voice-agent/components/voice-agent-modal/voice-agent-modal.component.js +17 -24
  8. package/esm2015/lib/components/voice-agent/services/audio-analyzer.service.js +3 -3
  9. package/esm2015/lib/components/voice-agent/services/voice-agent.service.js +189 -155
  10. package/esm2015/lib/components/voice-agent/voice-agent.module.js +3 -7
  11. package/fesm2015/hivegpt-hiveai-angular.js +208 -579
  12. package/fesm2015/hivegpt-hiveai-angular.js.map +1 -1
  13. package/hivegpt-hiveai-angular.d.ts +3 -5
  14. package/hivegpt-hiveai-angular.d.ts.map +1 -1
  15. package/hivegpt-hiveai-angular.metadata.json +1 -1
  16. package/lib/components/voice-agent/components/voice-agent-modal/voice-agent-modal.component.d.ts +7 -4
  17. package/lib/components/voice-agent/components/voice-agent-modal/voice-agent-modal.component.d.ts.map +1 -1
  18. package/lib/components/voice-agent/services/audio-analyzer.service.d.ts +2 -2
  19. package/lib/components/voice-agent/services/voice-agent.service.d.ts +23 -17
  20. package/lib/components/voice-agent/services/voice-agent.service.d.ts.map +1 -1
  21. package/lib/components/voice-agent/voice-agent.module.d.ts +2 -2
  22. package/lib/components/voice-agent/voice-agent.module.d.ts.map +1 -1
  23. package/package.json +1 -1
  24. package/esm2015/lib/components/voice-agent/services/daily-voice-client.service.js +0 -312
  25. package/esm2015/lib/components/voice-agent/services/websocket-voice-client.service.js +0 -95
  26. package/lib/components/voice-agent/services/daily-voice-client.service.d.ts +0 -65
  27. package/lib/components/voice-agent/services/daily-voice-client.service.d.ts.map +0 -1
  28. package/lib/components/voice-agent/services/websocket-voice-client.service.d.ts +0 -49
  29. package/lib/components/voice-agent/services/websocket-voice-client.service.d.ts.map +0 -1
@@ -30,9 +30,12 @@ export declare class VoiceAgentModalComponent implements OnInit, OnDestroy {
30
30
  isMicMuted: boolean;
31
31
  isUserSpeaking: boolean;
32
32
  audioLevels: number[];
33
- isSpeaking: boolean;
34
- /** Track whether call has transitioned out of initial connected state. */
35
- private hasLeftConnectedOnce;
33
+ /** True while the bot is speaking — drives avatar pulse animation and voice visualizer. */
34
+ get isBotTalking(): boolean;
35
+ /** True while the user is actively speaking — drives waveform active color. */
36
+ get isUserActive(): boolean;
37
+ /** True during the brief processing pause between user speech and bot response. */
38
+ get isProcessing(): boolean;
36
39
  private subscriptions;
37
40
  ngOnInit(): void;
38
41
  ngOnDestroy(): void;
@@ -46,7 +49,7 @@ export declare class VoiceAgentModalComponent implements OnInit, OnDestroy {
46
49
  * as tiny dots — matching the audio-waveform reference design.
47
50
  */
48
51
  getWaveformHeight(level: number, index: number): number;
49
- /** Status label for active call. */
52
+ /** Status label for active call — driven by callState + service statusText. */
50
53
  get statusLabel(): string;
51
54
  /** Call Again: reset to idle then start a new call. */
52
55
  callAgain(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"voice-agent-modal.component.d.ts","sourceRoot":"/Users/rohitthakur/hive-gpt/HiveAI-Packages/Angular/projects/hivegpt/eventsgpt-angular/src/","sources":["lib/components/voice-agent/components/voice-agent-modal/voice-agent-modal.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,MAAM,EAAE,SAAS,EAAU,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEpG,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAG7E,qBAKa,wBAAyB,YAAW,MAAM,EAAE,SAAS;IAoBvD,iBAAiB,EAAE,iBAAiB;IACpC,aAAa,EAAE,oBAAoB;IAC1C,OAAO,CAAC,QAAQ;IArBR,KAAK,qBAA4B;IAClC,MAAM,EAAG,MAAM,CAAC;IAChB,KAAK,EAAG,MAAM,CAAC;IACf,KAAK,EAAG,MAAM,CAAC;IACf,cAAc,EAAG,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAM;IACpB,UAAU,EAAE,MAAM,CAAM;IACxB,OAAO,EAAE,MAAM,CAAM;IACrB,QAAQ,EAAE,MAAM,CAAM;IACtB,eAAe,EAAE,MAAM,CAAe;IACtC,SAAS,EAAE,MAAM,CAAkB;IACnC,SAAS,EAAE,MAAM,CAAyB;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAM;IAElC,OAAO,CAAC,cAAc,CAAiC;IACvD,OAAO,CAAC,eAAe,CAA6B;gBAG3C,iBAAiB,EAAE,iBAAiB,EACpC,aAAa,EAAE,oBAAoB,EAClC,QAAQ,EAAE,QAAQ;IAG5B,0CAA0C;IAC1C,QAAQ,CAAC,gBAAgB,2GAA2G;IAEpI,SAAS,EAAE,SAAS,CAAU;IAC9B,UAAU,EAAE,MAAM,CAAM;IACxB,QAAQ,EAAE,MAAM,CAAW;IAC3B,UAAU,EAAE,OAAO,CAAS;IAC5B,cAAc,EAAE,OAAO,CAAS;IAChC,WAAW,EAAE,MAAM,EAAE,CAAM;IAC3B,UAAU,EAAE,OAAO,CAAS;IAE5B,0EAA0E;IAC1E,OAAO,CAAC,oBAAoB,CAAkB;IAE9C,OAAO,CAAC,aAAa,CAAsB;IAE3C,QAAQ,IAAI,IAAI;IAqEhB,WAAW,IAAI,IAAI;IAKnB,YAAY,EAAE,OAAO,CAAS;IAExB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB1B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC,SAAS,IAAI,IAAI;IAIjB;;;;OAIG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAYvD,oCAAoC;IACpC,IAAI,WAAW,IAAI,MAAM,CAQxB;IAED,uDAAuD;IACvD,SAAS,IAAI,IAAI;IAKjB,gDAAgD;IAChD,UAAU,IAAI,IAAI;IAIlB,mFAAmF;IACnF,MAAM,IAAI,IAAI;IAId,OAAO,IAAI,IAAI;CAKhB"}
1
+ {"version":3,"file":"voice-agent-modal.component.d.ts","sourceRoot":"/Users/rohitthakur/hive-gpt/HiveAI-Packages/Angular/projects/hivegpt/eventsgpt-angular/src/","sources":["lib/components/voice-agent/components/voice-agent-modal/voice-agent-modal.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,MAAM,EAAE,SAAS,EAAU,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEpG,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAG7E,qBAKa,wBAAyB,YAAW,MAAM,EAAE,SAAS;IAoBvD,iBAAiB,EAAE,iBAAiB;IACpC,aAAa,EAAE,oBAAoB;IAC1C,OAAO,CAAC,QAAQ;IArBR,KAAK,qBAA4B;IAClC,MAAM,EAAG,MAAM,CAAC;IAChB,KAAK,EAAG,MAAM,CAAC;IACf,KAAK,EAAG,MAAM,CAAC;IACf,cAAc,EAAG,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAM;IACpB,UAAU,EAAE,MAAM,CAAM;IACxB,OAAO,EAAE,MAAM,CAAM;IACrB,QAAQ,EAAE,MAAM,CAAM;IACtB,eAAe,EAAE,MAAM,CAAe;IACtC,SAAS,EAAE,MAAM,CAAkB;IACnC,SAAS,EAAE,MAAM,CAAyB;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAM;IAElC,OAAO,CAAC,cAAc,CAAiC;IACvD,OAAO,CAAC,eAAe,CAA6B;gBAG3C,iBAAiB,EAAE,iBAAiB,EACpC,aAAa,EAAE,oBAAoB,EAClC,QAAQ,EAAE,QAAQ;IAG5B,0CAA0C;IAC1C,QAAQ,CAAC,gBAAgB,2GAA2G;IAEpI,SAAS,EAAE,SAAS,CAAU;IAC9B,UAAU,EAAE,MAAM,CAAM;IACxB,QAAQ,EAAE,MAAM,CAAW;IAC3B,UAAU,EAAE,OAAO,CAAS;IAC5B,cAAc,EAAE,OAAO,CAAS;IAChC,WAAW,EAAE,MAAM,EAAE,CAAM;IAE3B,2FAA2F;IAC3F,IAAI,YAAY,IAAI,OAAO,CAAyC;IAEpE,+EAA+E;IAC/E,IAAI,YAAY,IAAI,OAAO,CAAsF;IAEjH,mFAAmF;IACnF,IAAI,YAAY,IAAI,OAAO,CAAkF;IAE7G,OAAO,CAAC,aAAa,CAAsB;IAE3C,QAAQ,IAAI,IAAI;IA6DhB,WAAW,IAAI,IAAI;IAKnB,YAAY,EAAE,OAAO,CAAS;IAExB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB1B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC,SAAS,IAAI,IAAI;IAIjB;;;;OAIG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAYvD,+EAA+E;IAC/E,IAAI,WAAW,IAAI,MAAM,CASxB;IAED,uDAAuD;IACvD,SAAS,IAAI,IAAI;IAKjB,gDAAgD;IAChD,UAAU,IAAI,IAAI;IAIlB,mFAAmF;IACnF,MAAM,IAAI,IAAI;IAId,OAAO,IAAI,IAAI;CAKhB"}
@@ -1,7 +1,7 @@
1
1
  import { Observable } from 'rxjs';
2
2
  /**
3
- * Audio analyzer for waveform visualization only.
4
- * Do NOT use isUserSpeaking$ for call state; speaking state must come from Daily.js.
3
+ * Audio analyzer for waveform visualization and local (mic) speaking detection.
4
+ * VoiceAgentService may combine this with WebSocket server events for call state.
5
5
  */
6
6
  export declare class AudioAnalyzerService {
7
7
  private audioContext;
@@ -1,30 +1,27 @@
1
- import { OnDestroy } from '@angular/core';
1
+ import { NgZone, OnDestroy } from '@angular/core';
2
2
  import { Observable } from 'rxjs';
3
3
  import { PlatformTokenRefreshService } from '../../../services/platform-token-refresh.service';
4
4
  import { AudioAnalyzerService } from './audio-analyzer.service';
5
- import { WebSocketVoiceClientService } from './websocket-voice-client.service';
6
- import { DailyVoiceClientService } from './daily-voice-client.service';
7
5
  export declare type CallState = 'idle' | 'connecting' | 'connected' | 'listening' | 'talking' | 'ended';
8
6
  export interface TranscriptData {
9
7
  text: string;
10
8
  final: boolean;
11
9
  }
12
10
  /**
13
- * Voice agent orchestrator. Coordinates WebSocket (signaling) and Daily.js (WebRTC audio).
11
+ * Voice agent orchestrator using the official PipecatClient SDK.
14
12
  *
15
- * CRITICAL: This service must NEVER use Socket.IO or ngx-socket-io. Voice flow uses only:
16
- * - Native WebSocket (WebSocketVoiceClientService) for signaling (room_created, transcripts)
17
- * - Daily.js (DailyVoiceClientService) for WebRTC audio. Audio does NOT flow over WebSocket.
18
- *
19
- * - Maintains callState, statusText, duration, isMicMuted, isUserSpeaking, audioLevels
20
- * - Uses WebSocket for room_created and transcripts only (no audio)
21
- * - Uses Daily.js for all audio, mic, and real-time speaking detection
13
+ * Audio flow (mirrors the React reference implementation):
14
+ * - Local mic: acquired by PipecatClient.initDevices(); local track fed to
15
+ * AudioAnalyzerService for waveform visualisation.
16
+ * - Bot audio: received as a MediaStreamTrack via RTVIEvent.TrackStarted,
17
+ * played through a hidden <audio> element.
18
+ * - All binary protobuf framing / RTVI protocol handled by
19
+ * @pipecat-ai/client-js + @pipecat-ai/websocket-transport.
22
20
  */
23
21
  export declare class VoiceAgentService implements OnDestroy {
24
22
  private audioAnalyzer;
25
- private wsClient;
26
- private dailyClient;
27
23
  private platformTokenRefresh;
24
+ private ngZone;
28
25
  /** `Object` not `object` — ngc metadata collection rejects the `object` type in DI params. */
29
26
  private platformId;
30
27
  private callStateSubject;
@@ -37,9 +34,10 @@ export declare class VoiceAgentService implements OnDestroy {
37
34
  private botTranscriptSubject;
38
35
  private callStartTime;
39
36
  private durationInterval;
37
+ private pcClient;
38
+ private botAudioElement;
40
39
  private subscriptions;
41
40
  private destroy$;
42
- private hasAutoUnmutedAfterFirstAudio;
43
41
  callState$: Observable<CallState>;
44
42
  statusText$: Observable<string>;
45
43
  duration$: Observable<string>;
@@ -48,15 +46,23 @@ export declare class VoiceAgentService implements OnDestroy {
48
46
  audioLevels$: Observable<number[]>;
49
47
  userTranscript$: Observable<TranscriptData>;
50
48
  botTranscript$: Observable<string>;
51
- constructor(audioAnalyzer: AudioAnalyzerService, wsClient: WebSocketVoiceClientService, dailyClient: DailyVoiceClientService, platformTokenRefresh: PlatformTokenRefreshService,
49
+ constructor(audioAnalyzer: AudioAnalyzerService, platformTokenRefresh: PlatformTokenRefreshService, ngZone: NgZone,
52
50
  /** `Object` not `object` — ngc metadata collection rejects the `object` type in DI params. */
53
51
  platformId: Object);
54
52
  ngOnDestroy(): void;
55
- /** Reset to idle state (e.g. when modal opens so user can click Start Call). */
53
+ /** Reset to idle (e.g. when modal re-opens so user can click Start Call). */
56
54
  resetToIdle(): void;
57
55
  connect(apiUrl: string, token: string, botId: string, conversationId: string, apiKey: string, eventToken: string, eventId: string, eventUrl: string, domainAuthority: string, usersApiUrl?: string): Promise<void>;
58
- private onRoomCreated;
56
+ private onPipecatConnected;
57
+ private onPipecatDisconnected;
58
+ private onBotReady;
59
+ private startLocalMicAnalyzer;
60
+ private onBotStartedSpeaking;
61
+ private onBotStoppedSpeaking;
62
+ private setupBotAudioTrack;
63
+ private stopBotAudio;
59
64
  disconnect(): Promise<void>;
65
+ private cleanupPipecatClient;
60
66
  toggleMic(): void;
61
67
  private startDurationTimer;
62
68
  private stopDurationTimer;
@@ -1 +1 @@
1
- {"version":3,"file":"voice-agent.service.d.ts","sourceRoot":"/Users/rohitthakur/hive-gpt/HiveAI-Packages/Angular/projects/hivegpt/eventsgpt-angular/src/","sources":["lib/components/voice-agent/services/voice-agent.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,SAAS,EAAe,MAAM,eAAe,CAAC;AAC3E,OAAO,EAGL,UAAU,EAGX,MAAM,MAAM,CAAC;AAEd,OAAO,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AAC/F,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,oBAAY,SAAS,GACjB,MAAM,GACN,YAAY,GACZ,WAAW,GACX,WAAW,GACX,SAAS,GACT,OAAO,CAAC;AAEZ,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;;GAUG;AACH,qBAGa,iBAAkB,YAAW,SAAS;IA6B/C,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,oBAAoB;IAC5B,8FAA8F;IACzE,OAAO,CAAC,UAAU;IAjCzC,OAAO,CAAC,gBAAgB,CAA0C;IAClE,OAAO,CAAC,iBAAiB,CAAmC;IAC5D,OAAO,CAAC,eAAe,CAAwC;IAC/D,OAAO,CAAC,iBAAiB,CAAuC;IAChE,OAAO,CAAC,qBAAqB,CAAuC;IACpE,OAAO,CAAC,kBAAkB,CAAqC;IAC/D,OAAO,CAAC,qBAAqB,CAAiC;IAC9D,OAAO,CAAC,oBAAoB,CAAyB;IAErD,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,gBAAgB,CAA+C;IAEvE,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,6BAA6B,CAAS;IAE9C,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,CAAwC;IACzE,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,CAAyC;IACxE,SAAS,EAAE,UAAU,CAAC,MAAM,CAAC,CAAuC;IACpE,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,CAAyC;IACzE,eAAe,EAAE,UAAU,CAAC,OAAO,CAAC,CACQ;IAC5C,YAAY,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAA0C;IAC5E,eAAe,EAAE,UAAU,CAAC,cAAc,CAAC,CACC;IAC5C,cAAc,EAAE,UAAU,CAAC,MAAM,CAAC,CAA4C;gBAGpE,aAAa,EAAE,oBAAoB,EACnC,QAAQ,EAAE,2BAA2B,EACrC,WAAW,EAAE,uBAAuB,EACpC,oBAAoB,EAAE,2BAA2B;IACzD,8FAA8F;IACjE,UAAU,EAAE,MAAM;IAUjD,WAAW,IAAI,IAAI;IAMnB,gFAAgF;IAChF,WAAW,IAAI,IAAI;IAab,OAAO,CACX,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EACvB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC;YAyGF,aAAa;IAuErB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAajC,SAAS,IAAI,IAAI;IAKjB,OAAO,CAAC,kBAAkB;IAe1B,OAAO,CAAC,iBAAiB;CAM1B"}
1
+ {"version":3,"file":"voice-agent.service.d.ts","sourceRoot":"/Users/rohitthakur/hive-gpt/HiveAI-Packages/Angular/projects/hivegpt/eventsgpt-angular/src/","sources":["lib/components/voice-agent/services/voice-agent.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,MAAM,EAAE,SAAS,EAAe,MAAM,eAAe,CAAC;AACnF,OAAO,EAAmB,UAAU,EAAyB,MAAM,MAAM,CAAC;AAI1E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AAC/F,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,oBAAY,SAAS,GACjB,MAAM,GACN,YAAY,GACZ,WAAW,GACX,WAAW,GACX,SAAS,GACT,OAAO,CAAC;AAEZ,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;;GAUG;AACH,qBAGa,iBAAkB,YAAW,SAAS;IA6B/C,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,oBAAoB;IAC5B,OAAO,CAAC,MAAM;IACd,8FAA8F;IACzE,OAAO,CAAC,UAAU;IAhCzC,OAAO,CAAC,gBAAgB,CAA0C;IAClE,OAAO,CAAC,iBAAiB,CAAmC;IAC5D,OAAO,CAAC,eAAe,CAAwC;IAC/D,OAAO,CAAC,iBAAiB,CAAuC;IAChE,OAAO,CAAC,qBAAqB,CAAuC;IACpE,OAAO,CAAC,kBAAkB,CAAqC;IAC/D,OAAO,CAAC,qBAAqB,CAAiC;IAC9D,OAAO,CAAC,oBAAoB,CAAyB;IAErD,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,gBAAgB,CAA+C;IAEvE,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,eAAe,CAAiC;IAExD,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,QAAQ,CAAuB;IAEvC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,CAAwC;IACzE,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,CAAyC;IACxE,SAAS,EAAE,UAAU,CAAC,MAAM,CAAC,CAAuC;IACpE,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,CAAyC;IACzE,eAAe,EAAE,UAAU,CAAC,OAAO,CAAC,CAA6C;IACjF,YAAY,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAA0C;IAC5E,eAAe,EAAE,UAAU,CAAC,cAAc,CAAC,CAA6C;IACxF,cAAc,EAAE,UAAU,CAAC,MAAM,CAAC,CAA4C;gBAGpE,aAAa,EAAE,oBAAoB,EACnC,oBAAoB,EAAE,2BAA2B,EACjD,MAAM,EAAE,MAAM;IACtB,8FAA8F;IACjE,UAAU,EAAE,MAAM;IASjD,WAAW,IAAI,IAAI;IAMnB,6EAA6E;IAC7E,WAAW,IAAI,IAAI;IAQb,OAAO,CACX,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EACvB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC;IAuHhB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,kBAAkB;IAe1B,OAAO,CAAC,YAAY;IAed,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAUnB,oBAAoB;IAWlC,SAAS,IAAI,IAAI;IAQjB,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,iBAAiB;CAM1B"}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Voice agent module. Uses native WebSocket + Daily.js only.
3
- * Does NOT use Socket.IO or ngx-socket-io.
2
+ * Voice agent module. Uses @pipecat-ai/client-js + @pipecat-ai/websocket-transport
3
+ * (peer dependencies) for WebSocket transport, RTVI protocol, and audio.
4
4
  */
5
5
  export declare class VoiceAgentModule {
6
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"voice-agent.module.d.ts","sourceRoot":"/Users/rohitthakur/hive-gpt/HiveAI-Packages/Angular/projects/hivegpt/eventsgpt-angular/src/","sources":["lib/components/voice-agent/voice-agent.module.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,qBAiBa,gBAAgB;CAAI"}
1
+ {"version":3,"file":"voice-agent.module.d.ts","sourceRoot":"/Users/rohitthakur/hive-gpt/HiveAI-Packages/Angular/projects/hivegpt/eventsgpt-angular/src/","sources":["lib/components/voice-agent/voice-agent.module.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,qBAea,gBAAgB;CAAI"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hivegpt/hiveai-angular",
3
- "version": "0.0.588",
3
+ "version": "0.0.590",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^10.2.5",
6
6
  "@angular/core": "^10.2.5",
@@ -1,312 +0,0 @@
1
- import { __awaiter } from "tslib";
2
- import { Injectable, NgZone } from '@angular/core';
3
- import { BehaviorSubject } from 'rxjs';
4
- import Daily from '@daily-co/daily-js';
5
- import * as i0 from "@angular/core";
6
- /**
7
- * Daily.js WebRTC client for voice agent audio.
8
- * Responsibilities:
9
- * - Create and manage Daily CallObject
10
- * - Join Daily room using room_url
11
- * - Handle mic capture + speaker playback
12
- * - Bot speaking detection via AnalyserNode on remote track (instant)
13
- * - User speaking detection via active-speaker-change
14
- * - Expose speaking$ (bot speaking), userSpeaking$ (user speaking), micMuted$
15
- * - Expose localStream$ for waveform visualization (AudioAnalyzerService)
16
- */
17
- export class DailyVoiceClientService {
18
- constructor(ngZone) {
19
- this.ngZone = ngZone;
20
- this.callObject = null;
21
- this.localStream = null;
22
- this.localSessionId = null;
23
- /** Explicit playback of remote (bot) audio; required in some browsers. */
24
- this.remoteAudioElement = null;
25
- /** AnalyserNode-based remote audio monitor for instant bot speaking detection. */
26
- this.remoteAudioContext = null;
27
- this.remoteSpeakingRAF = null;
28
- this.speakingSubject = new BehaviorSubject(false);
29
- this.userSpeakingSubject = new BehaviorSubject(false);
30
- this.micMutedSubject = new BehaviorSubject(false);
31
- this.localStreamSubject = new BehaviorSubject(null);
32
- this.firstRemoteAudioFrameSubject = new BehaviorSubject(false);
33
- /** True when bot (remote participant) is the active speaker. */
34
- this.speaking$ = this.speakingSubject.asObservable();
35
- /** True when user (local participant) is the active speaker. */
36
- this.userSpeaking$ = this.userSpeakingSubject.asObservable();
37
- /** True when mic is muted. */
38
- this.micMuted$ = this.micMutedSubject.asObservable();
39
- /** Emits local mic stream for waveform visualization. */
40
- this.localStream$ = this.localStreamSubject.asObservable();
41
- /** Emits true once when first remote audio frame starts playing. */
42
- this.firstRemoteAudioFrame$ = this.firstRemoteAudioFrameSubject.asObservable();
43
- }
44
- /**
45
- * Connect to Daily room. Acquires mic first for waveform, then joins with audio.
46
- * @param roomUrl Daily room URL (from room_created)
47
- * @param token Optional meeting token
48
- */
49
- connect(roomUrl, token) {
50
- return __awaiter(this, void 0, void 0, function* () {
51
- if (this.callObject) {
52
- yield this.disconnect();
53
- }
54
- try {
55
- // Get mic stream for both Daily and waveform (single capture)
56
- const stream = yield navigator.mediaDevices.getUserMedia({ audio: true });
57
- const audioTrack = stream.getAudioTracks()[0];
58
- if (!audioTrack) {
59
- stream.getTracks().forEach((t) => t.stop());
60
- throw new Error('No audio track');
61
- }
62
- this.localStream = stream;
63
- this.localStreamSubject.next(stream);
64
- // Create audio-only call object
65
- // videoSource: false = no camera, audioSource = our mic track
66
- const callObject = Daily.createCallObject({
67
- videoSource: false,
68
- audioSource: audioTrack,
69
- });
70
- this.callObject = callObject;
71
- this.setupEventHandlers(callObject);
72
- // Join room; Daily handles playback of remote (bot) audio automatically.
73
- // Only pass token when it's a non-empty string (Daily rejects undefined/non-string).
74
- const joinOptions = { url: roomUrl };
75
- if (typeof token === 'string' && token.trim() !== '') {
76
- joinOptions.token = token;
77
- }
78
- yield callObject.join(joinOptions);
79
- console.log(`[VoiceDebug] Room connected (Daily join complete) — ${new Date().toISOString()}`);
80
- const participants = callObject.participants();
81
- if (participants === null || participants === void 0 ? void 0 : participants.local) {
82
- this.localSessionId = participants.local.session_id;
83
- }
84
- // Start with mic muted; VoiceAgentService auto-unmutes after first remote audio frame.
85
- callObject.setLocalAudio(false);
86
- this.micMutedSubject.next(true);
87
- }
88
- catch (err) {
89
- this.cleanup();
90
- throw err;
91
- }
92
- });
93
- }
94
- setupEventHandlers(call) {
95
- // active-speaker-change: used ONLY for user speaking detection.
96
- // Bot speaking is detected by our own AnalyserNode (instant, no debounce).
97
- call.on('active-speaker-change', (event) => {
98
- this.ngZone.run(() => {
99
- var _a;
100
- const peerId = (_a = event === null || event === void 0 ? void 0 : event.activeSpeaker) === null || _a === void 0 ? void 0 : _a.peerId;
101
- if (!peerId || !this.localSessionId) {
102
- this.userSpeakingSubject.next(false);
103
- return;
104
- }
105
- const isLocal = peerId === this.localSessionId;
106
- this.userSpeakingSubject.next(isLocal);
107
- });
108
- });
109
- // track-started / track-stopped: set up remote audio playback + AnalyserNode monitor.
110
- call.on('track-started', (event) => {
111
- this.ngZone.run(() => {
112
- var _a, _b, _c, _d;
113
- const p = event === null || event === void 0 ? void 0 : event.participant;
114
- const type = (_a = event === null || event === void 0 ? void 0 : event.type) !== null && _a !== void 0 ? _a : (_b = event === null || event === void 0 ? void 0 : event.track) === null || _b === void 0 ? void 0 : _b.kind;
115
- const track = event === null || event === void 0 ? void 0 : event.track;
116
- if (p && !p.local && type === 'audio') {
117
- console.log(`[VoiceDebug] Got audio track from backend (track-started) — readyState=${track === null || track === void 0 ? void 0 : track.readyState}, muted=${track === null || track === void 0 ? void 0 : track.muted} — ${new Date().toISOString()}`);
118
- const audioTrack = track !== null && track !== void 0 ? track : (_d = (_c = p.tracks) === null || _c === void 0 ? void 0 : _c.audio) === null || _d === void 0 ? void 0 : _d.track;
119
- if (audioTrack && typeof audioTrack === 'object') {
120
- this.playRemoteTrack(audioTrack);
121
- this.monitorRemoteAudio(audioTrack);
122
- }
123
- }
124
- });
125
- });
126
- call.on('track-stopped', (event) => {
127
- this.ngZone.run(() => {
128
- var _a, _b;
129
- const p = event === null || event === void 0 ? void 0 : event.participant;
130
- const type = (_a = event === null || event === void 0 ? void 0 : event.type) !== null && _a !== void 0 ? _a : (_b = event === null || event === void 0 ? void 0 : event.track) === null || _b === void 0 ? void 0 : _b.kind;
131
- if (p && !p.local && type === 'audio') {
132
- this.stopRemoteAudioMonitor();
133
- this.stopRemoteAudio();
134
- }
135
- });
136
- });
137
- call.on('left-meeting', () => {
138
- this.ngZone.run(() => this.cleanup());
139
- });
140
- call.on('error', (event) => {
141
- this.ngZone.run(() => {
142
- var _a;
143
- console.error('DailyVoiceClient: Daily error', (_a = event === null || event === void 0 ? void 0 : event.errorMsg) !== null && _a !== void 0 ? _a : event);
144
- this.cleanup();
145
- });
146
- });
147
- }
148
- /**
149
- * Play remote (bot) audio track via a dedicated audio element.
150
- * Required in many browsers where Daily's internal playback does not output to speakers.
151
- */
152
- playRemoteTrack(track) {
153
- this.stopRemoteAudio();
154
- try {
155
- console.log(`[VoiceDebug] playRemoteTrack called — track.readyState=${track.readyState}, track.muted=${track.muted} — ${new Date().toISOString()}`);
156
- track.onunmute = () => {
157
- console.log(`[VoiceDebug] Remote audio track UNMUTED (audio data arriving) — ${new Date().toISOString()}`);
158
- };
159
- const stream = new MediaStream([track]);
160
- const audio = new Audio();
161
- audio.autoplay = true;
162
- audio.srcObject = stream;
163
- this.remoteAudioElement = audio;
164
- audio.onplaying = () => {
165
- console.log(`[VoiceDebug] Audio element PLAYING (browser started playback) — ${new Date().toISOString()}`);
166
- };
167
- let firstTimeUpdate = true;
168
- audio.ontimeupdate = () => {
169
- if (firstTimeUpdate) {
170
- firstTimeUpdate = false;
171
- console.log(`[VoiceDebug] Audio element first TIMEUPDATE (actual audio output) — ${new Date().toISOString()}`);
172
- this.firstRemoteAudioFrameSubject.next(true);
173
- }
174
- };
175
- const p = audio.play();
176
- if (p && typeof p.then === 'function') {
177
- p.then(() => {
178
- console.log(`[VoiceDebug] audio.play() resolved — ${new Date().toISOString()}`);
179
- this.firstRemoteAudioFrameSubject.next(true);
180
- }).catch((err) => {
181
- console.warn('DailyVoiceClient: remote audio play failed (may need user gesture)', err);
182
- });
183
- }
184
- }
185
- catch (err) {
186
- console.warn('DailyVoiceClient: failed to create remote audio element', err);
187
- }
188
- }
189
- /**
190
- * Monitor remote audio track energy via AnalyserNode.
191
- * Polls at ~60fps and flips speakingSubject based on actual audio energy.
192
- */
193
- monitorRemoteAudio(track) {
194
- this.stopRemoteAudioMonitor();
195
- try {
196
- const ctx = new AudioContext();
197
- const source = ctx.createMediaStreamSource(new MediaStream([track]));
198
- const analyser = ctx.createAnalyser();
199
- analyser.fftSize = 256;
200
- source.connect(analyser);
201
- this.remoteAudioContext = ctx;
202
- const dataArray = new Uint8Array(analyser.frequencyBinCount);
203
- const THRESHOLD = 5;
204
- const SILENCE_MS = 1500;
205
- let lastSoundTime = 0;
206
- let isSpeaking = false;
207
- const poll = () => {
208
- if (!this.remoteAudioContext)
209
- return;
210
- analyser.getByteFrequencyData(dataArray);
211
- let sum = 0;
212
- for (let i = 0; i < dataArray.length; i++) {
213
- sum += dataArray[i];
214
- }
215
- const avg = sum / dataArray.length;
216
- const now = Date.now();
217
- if (avg > THRESHOLD) {
218
- lastSoundTime = now;
219
- if (!isSpeaking) {
220
- isSpeaking = true;
221
- console.log(`[VoiceDebug] Bot audio energy detected (speaking=true) — avg=${avg.toFixed(1)} — ${new Date().toISOString()}`);
222
- this.ngZone.run(() => {
223
- this.userSpeakingSubject.next(false);
224
- this.speakingSubject.next(true);
225
- });
226
- }
227
- }
228
- else if (isSpeaking && now - lastSoundTime > SILENCE_MS) {
229
- isSpeaking = false;
230
- console.log(`[VoiceDebug] Bot audio silence detected (speaking=false) — ${new Date().toISOString()}`);
231
- this.ngZone.run(() => this.speakingSubject.next(false));
232
- }
233
- this.remoteSpeakingRAF = requestAnimationFrame(poll);
234
- };
235
- this.remoteSpeakingRAF = requestAnimationFrame(poll);
236
- }
237
- catch (err) {
238
- console.warn('DailyVoiceClient: failed to create remote audio monitor', err);
239
- }
240
- }
241
- stopRemoteAudioMonitor() {
242
- if (this.remoteSpeakingRAF) {
243
- cancelAnimationFrame(this.remoteSpeakingRAF);
244
- this.remoteSpeakingRAF = null;
245
- }
246
- if (this.remoteAudioContext) {
247
- this.remoteAudioContext.close().catch(() => { });
248
- this.remoteAudioContext = null;
249
- }
250
- }
251
- stopRemoteAudio() {
252
- if (this.remoteAudioElement) {
253
- try {
254
- this.remoteAudioElement.pause();
255
- this.remoteAudioElement.srcObject = null;
256
- }
257
- catch (_) { }
258
- this.remoteAudioElement = null;
259
- }
260
- }
261
- /** Set mic muted state. */
262
- setMuted(muted) {
263
- if (!this.callObject)
264
- return;
265
- this.callObject.setLocalAudio(!muted);
266
- this.micMutedSubject.next(muted);
267
- }
268
- /** Disconnect and cleanup. */
269
- disconnect() {
270
- return __awaiter(this, void 0, void 0, function* () {
271
- if (!this.callObject) {
272
- this.cleanup();
273
- return;
274
- }
275
- try {
276
- yield this.callObject.leave();
277
- }
278
- catch (e) {
279
- // ignore
280
- }
281
- this.cleanup();
282
- });
283
- }
284
- cleanup() {
285
- this.stopRemoteAudioMonitor();
286
- this.stopRemoteAudio();
287
- if (this.callObject) {
288
- this.callObject.destroy().catch(() => { });
289
- this.callObject = null;
290
- }
291
- if (this.localStream) {
292
- this.localStream.getTracks().forEach((t) => t.stop());
293
- this.localStream = null;
294
- }
295
- this.localSessionId = null;
296
- this.speakingSubject.next(false);
297
- this.userSpeakingSubject.next(false);
298
- this.localStreamSubject.next(null);
299
- this.firstRemoteAudioFrameSubject.next(false);
300
- // Keep last micMuted state; will reset on next connect
301
- }
302
- }
303
- DailyVoiceClientService.ɵprov = i0.ɵɵdefineInjectable({ factory: function DailyVoiceClientService_Factory() { return new DailyVoiceClientService(i0.ɵɵinject(i0.NgZone)); }, token: DailyVoiceClientService, providedIn: "root" });
304
- DailyVoiceClientService.decorators = [
305
- { type: Injectable, args: [{
306
- providedIn: 'root',
307
- },] }
308
- ];
309
- DailyVoiceClientService.ctorParameters = () => [
310
- { type: NgZone }
311
- ];
312
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGFpbHktdm9pY2UtY2xpZW50LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiL1VzZXJzL3JvaGl0dGhha3VyL2hpdmUtZ3B0L0hpdmVBSS1QYWNrYWdlcy9Bbmd1bGFyL3Byb2plY3RzL2hpdmVncHQvZXZlbnRzZ3B0LWFuZ3VsYXIvc3JjLyIsInNvdXJjZXMiOlsibGliL2NvbXBvbmVudHMvdm9pY2UtYWdlbnQvc2VydmljZXMvZGFpbHktdm9pY2UtY2xpZW50LnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBRSxlQUFlLEVBQWMsTUFBTSxNQUFNLENBQUM7QUFDbkQsT0FBTyxLQUFLLE1BQU0sb0JBQW9CLENBQUM7O0FBR3ZDOzs7Ozs7Ozs7O0dBVUc7QUFJSCxNQUFNLE9BQU8sdUJBQXVCO0lBa0NsQyxZQUFvQixNQUFjO1FBQWQsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQWpDMUIsZUFBVSxHQUFxQixJQUFJLENBQUM7UUFDcEMsZ0JBQVcsR0FBdUIsSUFBSSxDQUFDO1FBQ3ZDLG1CQUFjLEdBQWtCLElBQUksQ0FBQztRQUM3QywwRUFBMEU7UUFDbEUsdUJBQWtCLEdBQTRCLElBQUksQ0FBQztRQUUzRCxrRkFBa0Y7UUFDMUUsdUJBQWtCLEdBQXdCLElBQUksQ0FBQztRQUMvQyxzQkFBaUIsR0FBa0IsSUFBSSxDQUFDO1FBRXhDLG9CQUFlLEdBQUcsSUFBSSxlQUFlLENBQVUsS0FBSyxDQUFDLENBQUM7UUFDdEQsd0JBQW1CLEdBQUcsSUFBSSxlQUFlLENBQVUsS0FBSyxDQUFDLENBQUM7UUFDMUQsb0JBQWUsR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztRQUN0RCx1QkFBa0IsR0FBRyxJQUFJLGVBQWUsQ0FBcUIsSUFBSSxDQUFDLENBQUM7UUFDbkUsaUNBQTRCLEdBQUcsSUFBSSxlQUFlLENBQVUsS0FBSyxDQUFDLENBQUM7UUFFM0UsZ0VBQWdFO1FBQ2hFLGNBQVMsR0FBd0IsSUFBSSxDQUFDLGVBQWUsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUVyRSxnRUFBZ0U7UUFDaEUsa0JBQWEsR0FBd0IsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFlBQVksRUFBRSxDQUFDO1FBRTdFLDhCQUE4QjtRQUM5QixjQUFTLEdBQXdCLElBQUksQ0FBQyxlQUFlLENBQUMsWUFBWSxFQUFFLENBQUM7UUFFckUseURBQXlEO1FBQ3pELGlCQUFZLEdBQ1YsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFlBQVksRUFBRSxDQUFDO1FBRXpDLG9FQUFvRTtRQUNwRSwyQkFBc0IsR0FDcEIsSUFBSSxDQUFDLDRCQUE0QixDQUFDLFlBQVksRUFBRSxDQUFDO0lBRWQsQ0FBQztJQUV0Qzs7OztPQUlHO0lBQ0csT0FBTyxDQUFDLE9BQWUsRUFBRSxLQUFjOztZQUMzQyxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUU7Z0JBQ25CLE1BQU0sSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO2FBQ3pCO1lBRUQsSUFBSTtnQkFDRiw4REFBOEQ7Z0JBQzlELE1BQU0sTUFBTSxHQUFHLE1BQU0sU0FBUyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDMUUsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUM5QyxJQUFJLENBQUMsVUFBVSxFQUFFO29CQUNmLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUM1QyxNQUFNLElBQUksS0FBSyxDQUFDLGdCQUFnQixDQUFDLENBQUM7aUJBQ25DO2dCQUVELElBQUksQ0FBQyxXQUFXLEdBQUcsTUFBTSxDQUFDO2dCQUMxQixJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUVyQyxnQ0FBZ0M7Z0JBQ2hDLDhEQUE4RDtnQkFDOUQsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLGdCQUFnQixDQUFDO29CQUN4QyxXQUFXLEVBQUUsS0FBSztvQkFDbEIsV0FBVyxFQUFFLFVBQVU7aUJBQ3hCLENBQUMsQ0FBQztnQkFFSCxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztnQkFFN0IsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUVwQyx5RUFBeUU7Z0JBQ3pFLHFGQUFxRjtnQkFDckYsTUFBTSxXQUFXLEdBQW9DLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxDQUFDO2dCQUN0RSxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO29CQUNwRCxXQUFXLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztpQkFDM0I7Z0JBQ0QsTUFBTSxVQUFVLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO2dCQUNuQyxPQUFPLENBQUMsR0FBRyxDQUFDLHVEQUF1RCxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFFL0YsTUFBTSxZQUFZLEdBQUcsVUFBVSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUMvQyxJQUFJLFlBQVksYUFBWixZQUFZLHVCQUFaLFlBQVksQ0FBRSxLQUFLLEVBQUU7b0JBQ3ZCLElBQUksQ0FBQyxjQUFjLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUM7aUJBQ3JEO2dCQUVELHVGQUF1RjtnQkFDdkYsVUFBVSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDaEMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDakM7WUFBQyxPQUFPLEdBQUcsRUFBRTtnQkFDWixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ2YsTUFBTSxHQUFHLENBQUM7YUFDWDtRQUNILENBQUM7S0FBQTtJQUVPLGtCQUFrQixDQUFDLElBQWU7UUFDeEMsZ0VBQWdFO1FBQ2hFLDJFQUEyRTtRQUMzRSxJQUFJLENBQUMsRUFBRSxDQUFDLHVCQUF1QixFQUFFLENBQUMsS0FBOEMsRUFBRSxFQUFFO1lBQ2xGLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRTs7Z0JBQ25CLE1BQU0sTUFBTSxHQUFHLE1BQUEsS0FBSyxhQUFMLEtBQUssdUJBQUwsS0FBSyxDQUFFLGFBQWEsMENBQUUsTUFBTSxDQUFDO2dCQUM1QyxJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRTtvQkFDbkMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztvQkFDckMsT0FBTztpQkFDUjtnQkFDRCxNQUFNLE9BQU8sR0FBRyxNQUFNLEtBQUssSUFBSSxDQUFDLGNBQWMsQ0FBQztnQkFDL0MsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN6QyxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBRUgsc0ZBQXNGO1FBQ3RGLElBQUksQ0FBQyxFQUFFLENBQUMsZUFBZSxFQUFFLENBQUMsS0FBeUYsRUFBRSxFQUFFO1lBQ3JILElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRTs7Z0JBQ25CLE1BQU0sQ0FBQyxHQUFHLEtBQUssYUFBTCxLQUFLLHVCQUFMLEtBQUssQ0FBRSxXQUFXLENBQUM7Z0JBQzdCLE1BQU0sSUFBSSxHQUFHLE1BQUEsS0FBSyxhQUFMLEtBQUssdUJBQUwsS0FBSyxDQUFFLElBQUksbUNBQUksTUFBQSxLQUFLLGFBQUwsS0FBSyx1QkFBTCxLQUFLLENBQUUsS0FBSywwQ0FBRSxJQUFJLENBQUM7Z0JBQy9DLE1BQU0sS0FBSyxHQUFHLEtBQUssYUFBTCxLQUFLLHVCQUFMLEtBQUssQ0FBRSxLQUFLLENBQUM7Z0JBQzNCLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssSUFBSSxJQUFJLEtBQUssT0FBTyxFQUFFO29CQUNyQyxPQUFPLENBQUMsR0FBRyxDQUFDLDBFQUEwRSxLQUFLLGFBQUwsS0FBSyx1QkFBTCxLQUFLLENBQUUsVUFBVSxXQUFXLEtBQUssYUFBTCxLQUFLLHVCQUFMLEtBQUssQ0FBRSxLQUFLLE1BQU0sSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLENBQUM7b0JBQ2hLLE1BQU0sVUFBVSxHQUFHLEtBQUssYUFBTCxLQUFLLGNBQUwsS0FBSyxHQUFJLE1BQUEsTUFBQyxDQUEyRCxDQUFDLE1BQU0sMENBQUUsS0FBSywwQ0FBRSxLQUFLLENBQUM7b0JBQzlHLElBQUksVUFBVSxJQUFJLE9BQU8sVUFBVSxLQUFLLFFBQVEsRUFBRTt3QkFDaEQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxVQUFVLENBQUMsQ0FBQzt3QkFDakMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFVBQVUsQ0FBQyxDQUFDO3FCQUNyQztpQkFDRjtZQUNILENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsRUFBRSxDQUFDLGVBQWUsRUFBRSxDQUFDLEtBQXlGLEVBQUUsRUFBRTtZQUNySCxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUU7O2dCQUNuQixNQUFNLENBQUMsR0FBRyxLQUFLLGFBQUwsS0FBSyx1QkFBTCxLQUFLLENBQUUsV0FBVyxDQUFDO2dCQUM3QixNQUFNLElBQUksR0FBRyxNQUFBLEtBQUssYUFBTCxLQUFLLHVCQUFMLEtBQUssQ0FBRSxJQUFJLG1DQUFJLE1BQUEsS0FBSyxhQUFMLEtBQUssdUJBQUwsS0FBSyxDQUFFLEtBQUssMENBQUUsSUFBSSxDQUFDO2dCQUMvQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLElBQUksSUFBSSxLQUFLLE9BQU8sRUFBRTtvQkFDckMsSUFBSSxDQUFDLHNCQUFzQixFQUFFLENBQUM7b0JBQzlCLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztpQkFDeEI7WUFDSCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLEVBQUUsQ0FBQyxjQUFjLEVBQUUsR0FBRyxFQUFFO1lBQzNCLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ3hDLENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxLQUE2QixFQUFFLEVBQUU7WUFDakQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFOztnQkFDbkIsT0FBTyxDQUFDLEtBQUssQ0FBQywrQkFBK0IsRUFBRSxNQUFBLEtBQUssYUFBTCxLQUFLLHVCQUFMLEtBQUssQ0FBRSxRQUFRLG1DQUFJLEtBQUssQ0FBQyxDQUFDO2dCQUN6RSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDakIsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7O09BR0c7SUFDSyxlQUFlLENBQUMsS0FBdUI7UUFDN0MsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ3ZCLElBQUk7WUFDRixPQUFPLENBQUMsR0FBRyxDQUFDLDBEQUEwRCxLQUFLLENBQUMsVUFBVSxpQkFBaUIsS0FBSyxDQUFDLEtBQUssTUFBTSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUVwSixLQUFLLENBQUMsUUFBUSxHQUFHLEdBQUcsRUFBRTtnQkFDcEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtRUFBbUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDN0csQ0FBQyxDQUFDO1lBRUYsTUFBTSxNQUFNLEdBQUcsSUFBSSxXQUFXLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQ3hDLE1BQU0sS0FBSyxHQUFHLElBQUksS0FBSyxFQUFFLENBQUM7WUFDMUIsS0FBSyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7WUFDdEIsS0FBSyxDQUFDLFNBQVMsR0FBRyxNQUFNLENBQUM7WUFDekIsSUFBSSxDQUFDLGtCQUFrQixHQUFHLEtBQUssQ0FBQztZQUVoQyxLQUFLLENBQUMsU0FBUyxHQUFHLEdBQUcsRUFBRTtnQkFDckIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtRUFBbUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDN0csQ0FBQyxDQUFDO1lBRUYsSUFBSSxlQUFlLEdBQUcsSUFBSSxDQUFDO1lBQzNCLEtBQUssQ0FBQyxZQUFZLEdBQUcsR0FBRyxFQUFFO2dCQUN4QixJQUFJLGVBQWUsRUFBRTtvQkFDbkIsZUFBZSxHQUFHLEtBQUssQ0FBQztvQkFDeEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyx1RUFBdUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLENBQUM7b0JBQy9HLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7aUJBQzlDO1lBQ0gsQ0FBQyxDQUFDO1lBRUYsTUFBTSxDQUFDLEdBQUcsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ3ZCLElBQUksQ0FBQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLElBQUksS0FBSyxVQUFVLEVBQUU7Z0JBQ3JDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO29CQUNWLE9BQU8sQ0FBQyxHQUFHLENBQUMsd0NBQXdDLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDO29CQUNoRixJQUFJLENBQUMsNEJBQTRCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUMvQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtvQkFDZixPQUFPLENBQUMsSUFBSSxDQUFDLG9FQUFvRSxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dCQUMxRixDQUFDLENBQUMsQ0FBQzthQUNKO1NBQ0Y7UUFBQyxPQUFPLEdBQUcsRUFBRTtZQUNaLE9BQU8sQ0FBQyxJQUFJLENBQUMseURBQXlELEVBQUUsR0FBRyxDQUFDLENBQUM7U0FDOUU7SUFDSCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssa0JBQWtCLENBQUMsS0FBdUI7UUFDaEQsSUFBSSxDQUFDLHNCQUFzQixFQUFFLENBQUM7UUFDOUIsSUFBSTtZQUNGLE1BQU0sR0FBRyxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7WUFDL0IsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLHVCQUF1QixDQUFDLElBQUksV0FBVyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3JFLE1BQU0sUUFBUSxHQUFHLEdBQUcsQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN0QyxRQUFRLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQztZQUN2QixNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3pCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxHQUFHLENBQUM7WUFFOUIsTUFBTSxTQUFTLEdBQUcsSUFBSSxVQUFVLENBQUMsUUFBUSxDQUFDLGlCQUFpQixDQUFDLENBQUM7WUFDN0QsTUFBTSxTQUFTLEdBQUcsQ0FBQyxDQUFDO1lBQ3BCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQztZQUN4QixJQUFJLGFBQWEsR0FBRyxDQUFDLENBQUM7WUFDdEIsSUFBSSxVQUFVLEdBQUcsS0FBSyxDQUFDO1lBRXZCLE1BQU0sSUFBSSxHQUFHLEdBQUcsRUFBRTtnQkFDaEIsSUFBSSxDQUFDLElBQUksQ0FBQyxrQkFBa0I7b0JBQUUsT0FBTztnQkFDckMsUUFBUSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUV6QyxJQUFJLEdBQUcsR0FBRyxDQUFDLENBQUM7Z0JBQ1osS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7b0JBQ3pDLEdBQUcsSUFBSSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7aUJBQ3JCO2dCQUNELE1BQU0sR0FBRyxHQUFHLEdBQUcsR0FBRyxTQUFTLENBQUMsTUFBTSxDQUFDO2dCQUVuQyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ3ZCLElBQUksR0FBRyxHQUFHLFNBQVMsRUFBRTtvQkFDbkIsYUFBYSxHQUFHLEdBQUcsQ0FBQztvQkFDcEIsSUFBSSxDQUFDLFVBQVUsRUFBRTt3QkFDZixVQUFVLEdBQUcsSUFBSSxDQUFDO3dCQUNsQixPQUFPLENBQUMsR0FBRyxDQUFDLGdFQUFnRSxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDO3dCQUM1SCxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUU7NEJBQ25CLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7NEJBQ3JDLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO3dCQUNsQyxDQUFDLENBQUMsQ0FBQztxQkFDSjtpQkFDRjtxQkFBTSxJQUFJLFVBQVUsSUFBSSxHQUFHLEdBQUcsYUFBYSxHQUFHLFVBQVUsRUFBRTtvQkFDekQsVUFBVSxHQUFHLEtBQUssQ0FBQztvQkFDbkIsT0FBTyxDQUFDLEdBQUcsQ0FBQyw4REFBOEQsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLENBQUM7b0JBQ3RHLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7aUJBQ3pEO2dCQUVELElBQUksQ0FBQyxpQkFBaUIsR0FBRyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUN2RCxDQUFDLENBQUM7WUFFRixJQUFJLENBQUMsaUJBQWlCLEdBQUcscUJBQXFCLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDdEQ7UUFBQyxPQUFPLEdBQUcsRUFBRTtZQUNaLE9BQU8sQ0FBQyxJQUFJLENBQUMseURBQXlELEVBQUUsR0FBRyxDQUFDLENBQUM7U0FDOUU7SUFDSCxDQUFDO0lBRU8sc0JBQXNCO1FBQzVCLElBQUksSUFBSSxDQUFDLGlCQUFpQixFQUFFO1lBQzFCLG9CQUFvQixDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1lBQzdDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUM7U0FDL0I7UUFDRCxJQUFJLElBQUksQ0FBQyxrQkFBa0IsRUFBRTtZQUMzQixJQUFJLENBQUMsa0JBQWtCLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ2hELElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUM7U0FDaEM7SUFDSCxDQUFDO0lBRU8sZUFBZTtRQUNyQixJQUFJLElBQUksQ0FBQyxrQkFBa0IsRUFBRTtZQUMzQixJQUFJO2dCQUNGLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDaEMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUM7YUFDMUM7WUFBQyxPQUFPLENBQUMsRUFBRSxHQUFFO1lBQ2QsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQztTQUNoQztJQUNILENBQUM7SUFFRCwyQkFBMkI7SUFDM0IsUUFBUSxDQUFDLEtBQWM7UUFDckIsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVO1lBQUUsT0FBTztRQUM3QixJQUFJLENBQUMsVUFBVSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3RDLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ25DLENBQUM7SUFFRCw4QkFBOEI7SUFDeEIsVUFBVTs7WUFDZCxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRTtnQkFDcEIsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNmLE9BQU87YUFDUjtZQUNELElBQUk7Z0JBQ0YsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO2FBQy9CO1lBQUMsT0FBTyxDQUFDLEVBQUU7Z0JBQ1YsU0FBUzthQUNWO1lBQ0QsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2pCLENBQUM7S0FBQTtJQUVPLE9BQU87UUFDYixJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztRQUM5QixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDdkIsSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFO1lBQ25CLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQyxDQUFDO1lBQzFDLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO1NBQ3hCO1FBQ0QsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFO1lBQ3BCLElBQUksQ0FBQyxXQUFXLENBQUMsU0FBUyxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUN0RCxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztTQUN6QjtRQUNELElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDO1FBQzNCLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2pDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDckMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNuQyxJQUFJLENBQUMsNEJBQTRCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzlDLHVEQUF1RDtJQUN6RCxDQUFDOzs7O1lBdlRGLFVBQVUsU0FBQztnQkFDVixVQUFVLEVBQUUsTUFBTTthQUNuQjs7O1lBbEJvQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgTmdab25lIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcbmltcG9ydCBEYWlseSBmcm9tICdAZGFpbHktY28vZGFpbHktanMnO1xuaW1wb3J0IHR5cGUgeyBEYWlseUNhbGwsIERhaWx5UGFydGljaXBhbnQgfSBmcm9tICdAZGFpbHktY28vZGFpbHktanMnO1xuXG4vKipcbiAqIERhaWx5LmpzIFdlYlJUQyBjbGllbnQgZm9yIHZvaWNlIGFnZW50IGF1ZGlvLlxuICogUmVzcG9uc2liaWxpdGllczpcbiAqIC0gQ3JlYXRlIGFuZCBtYW5hZ2UgRGFpbHkgQ2FsbE9iamVjdFxuICogLSBKb2luIERhaWx5IHJvb20gdXNpbmcgcm9vbV91cmxcbiAqIC0gSGFuZGxlIG1pYyBjYXB0dXJlICsgc3BlYWtlciBwbGF5YmFja1xuICogLSBCb3Qgc3BlYWtpbmcgZGV0ZWN0aW9uIHZpYSBBbmFseXNlck5vZGUgb24gcmVtb3RlIHRyYWNrIChpbnN0YW50KVxuICogLSBVc2VyIHNwZWFraW5nIGRldGVjdGlvbiB2aWEgYWN0aXZlLXNwZWFrZXItY2hhbmdlXG4gKiAtIEV4cG9zZSBzcGVha2luZyQgKGJvdCBzcGVha2luZyksIHVzZXJTcGVha2luZyQgKHVzZXIgc3BlYWtpbmcpLCBtaWNNdXRlZCRcbiAqIC0gRXhwb3NlIGxvY2FsU3RyZWFtJCBmb3Igd2F2ZWZvcm0gdmlzdWFsaXphdGlvbiAoQXVkaW9BbmFseXplclNlcnZpY2UpXG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxufSlcbmV4cG9ydCBjbGFzcyBEYWlseVZvaWNlQ2xpZW50U2VydmljZSB7XG4gIHByaXZhdGUgY2FsbE9iamVjdDogRGFpbHlDYWxsIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgbG9jYWxTdHJlYW06IE1lZGlhU3RyZWFtIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgbG9jYWxTZXNzaW9uSWQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAvKiogRXhwbGljaXQgcGxheWJhY2sgb2YgcmVtb3RlIChib3QpIGF1ZGlvOyByZXF1aXJlZCBpbiBzb21lIGJyb3dzZXJzLiAqL1xuICBwcml2YXRlIHJlbW90ZUF1ZGlvRWxlbWVudDogSFRNTEF1ZGlvRWxlbWVudCB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBBbmFseXNlck5vZGUtYmFzZWQgcmVtb3RlIGF1ZGlvIG1vbml0b3IgZm9yIGluc3RhbnQgYm90IHNwZWFraW5nIGRldGVjdGlvbi4gKi9cbiAgcHJpdmF0ZSByZW1vdGVBdWRpb0NvbnRleHQ6IEF1ZGlvQ29udGV4dCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHJlbW90ZVNwZWFraW5nUkFGOiBudW1iZXIgfCBudWxsID0gbnVsbDtcblxuICBwcml2YXRlIHNwZWFraW5nU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICBwcml2YXRlIHVzZXJTcGVha2luZ1N1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgcHJpdmF0ZSBtaWNNdXRlZFN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgcHJpdmF0ZSBsb2NhbFN0cmVhbVN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PE1lZGlhU3RyZWFtIHwgbnVsbD4obnVsbCk7XG4gIHByaXZhdGUgZmlyc3RSZW1vdGVBdWRpb0ZyYW1lU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuXG4gIC8qKiBUcnVlIHdoZW4gYm90IChyZW1vdGUgcGFydGljaXBhbnQpIGlzIHRoZSBhY3RpdmUgc3BlYWtlci4gKi9cbiAgc3BlYWtpbmckOiBPYnNlcnZhYmxlPGJvb2xlYW4+ID0gdGhpcy5zcGVha2luZ1N1YmplY3QuYXNPYnNlcnZhYmxlKCk7XG5cbiAgLyoqIFRydWUgd2hlbiB1c2VyIChsb2NhbCBwYXJ0aWNpcGFudCkgaXMgdGhlIGFjdGl2ZSBzcGVha2VyLiAqL1xuICB1c2VyU3BlYWtpbmckOiBPYnNlcnZhYmxlPGJvb2xlYW4+ID0gdGhpcy51c2VyU3BlYWtpbmdTdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xuXG4gIC8qKiBUcnVlIHdoZW4gbWljIGlzIG11dGVkLiAqL1xuICBtaWNNdXRlZCQ6IE9ic2VydmFibGU8Ym9vbGVhbj4gPSB0aGlzLm1pY011dGVkU3ViamVjdC5hc09ic2VydmFibGUoKTtcblxuICAvKiogRW1pdHMgbG9jYWwgbWljIHN0cmVhbSBmb3Igd2F2ZWZvcm0gdmlzdWFsaXphdGlvbi4gKi9cbiAgbG9jYWxTdHJlYW0kOiBPYnNlcnZhYmxlPE1lZGlhU3RyZWFtIHwgbnVsbD4gPVxuICAgIHRoaXMubG9jYWxTdHJlYW1TdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xuXG4gIC8qKiBFbWl0cyB0cnVlIG9uY2Ugd2hlbiBmaXJzdCByZW1vdGUgYXVkaW8gZnJhbWUgc3RhcnRzIHBsYXlpbmcuICovXG4gIGZpcnN0UmVtb3RlQXVkaW9GcmFtZSQ6IE9ic2VydmFibGU8Ym9vbGVhbj4gPVxuICAgIHRoaXMuZmlyc3RSZW1vdGVBdWRpb0ZyYW1lU3ViamVjdC5hc09ic2VydmFibGUoKTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIG5nWm9uZTogTmdab25lKSB7fVxuXG4gIC8qKlxuICAgKiBDb25uZWN0IHRvIERhaWx5IHJvb20uIEFjcXVpcmVzIG1pYyBmaXJzdCBmb3Igd2F2ZWZvcm0sIHRoZW4gam9pbnMgd2l0aCBhdWRpby5cbiAgICogQHBhcmFtIHJvb21VcmwgRGFpbHkgcm9vbSBVUkwgKGZyb20gcm9vbV9jcmVhdGVkKVxuICAgKiBAcGFyYW0gdG9rZW4gT3B0aW9uYWwgbWVldGluZyB0b2tlblxuICAgKi9cbiAgYXN5bmMgY29ubmVjdChyb29tVXJsOiBzdHJpbmcsIHRva2VuPzogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuY2FsbE9iamVjdCkge1xuICAgICAgYXdhaXQgdGhpcy5kaXNjb25uZWN0KCk7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIC8vIEdldCBtaWMgc3RyZWFtIGZvciBib3RoIERhaWx5IGFuZCB3YXZlZm9ybSAoc2luZ2xlIGNhcHR1cmUpXG4gICAgICBjb25zdCBzdHJlYW0gPSBhd2FpdCBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYSh7IGF1ZGlvOiB0cnVlIH0pO1xuICAgICAgY29uc3QgYXVkaW9UcmFjayA9IHN0cmVhbS5nZXRBdWRpb1RyYWNrcygpWzBdO1xuICAgICAgaWYgKCFhdWRpb1RyYWNrKSB7XG4gICAgICAgIHN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKCh0KSA9PiB0LnN0b3AoKSk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gYXVkaW8gdHJhY2snKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5sb2NhbFN0cmVhbSA9IHN0cmVhbTtcbiAgICAgIHRoaXMubG9jYWxTdHJlYW1TdWJqZWN0Lm5leHQoc3RyZWFtKTtcblxuICAgICAgLy8gQ3JlYXRlIGF1ZGlvLW9ubHkgY2FsbCBvYmplY3RcbiAgICAgIC8vIHZpZGVvU291cmNlOiBmYWxzZSA9IG5vIGNhbWVyYSwgYXVkaW9Tb3VyY2UgPSBvdXIgbWljIHRyYWNrXG4gICAgICBjb25zdCBjYWxsT2JqZWN0ID0gRGFpbHkuY3JlYXRlQ2FsbE9iamVjdCh7XG4gICAgICAgIHZpZGVvU291cmNlOiBmYWxzZSxcbiAgICAgICAgYXVkaW9Tb3VyY2U6IGF1ZGlvVHJhY2ssXG4gICAgICB9KTtcblxuICAgICAgdGhpcy5jYWxsT2JqZWN0ID0gY2FsbE9iamVjdDtcblxuICAgICAgdGhpcy5zZXR1cEV2ZW50SGFuZGxlcnMoY2FsbE9iamVjdCk7XG5cbiAgICAgIC8vIEpvaW4gcm9vbTsgRGFpbHkgaGFuZGxlcyBwbGF5YmFjayBvZiByZW1vdGUgKGJvdCkgYXVkaW8gYXV0b21hdGljYWxseS5cbiAgICAgIC8vIE9ubHkgcGFzcyB0b2tlbiB3aGVuIGl0J3MgYSBub24tZW1wdHkgc3RyaW5nIChEYWlseSByZWplY3RzIHVuZGVmaW5lZC9ub24tc3RyaW5nKS5cbiAgICAgIGNvbnN0IGpvaW5PcHRpb25zOiB7IHVybDogc3RyaW5nOyB0b2tlbj86IHN0cmluZyB9ID0geyB1cmw6IHJvb21VcmwgfTtcbiAgICAgIGlmICh0eXBlb2YgdG9rZW4gPT09ICdzdHJpbmcnICYmIHRva2VuLnRyaW0oKSAhPT0gJycpIHtcbiAgICAgICAgam9pbk9wdGlvbnMudG9rZW4gPSB0b2tlbjtcbiAgICAgIH1cbiAgICAgIGF3YWl0IGNhbGxPYmplY3Quam9pbihqb2luT3B0aW9ucyk7XG4gICAgICBjb25zb2xlLmxvZyhgW1ZvaWNlRGVidWddIFJvb20gY29ubmVjdGVkIChEYWlseSBqb2luIGNvbXBsZXRlKSDigJQgJHtuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCl9YCk7XG5cbiAgICAgIGNvbnN0IHBhcnRpY2lwYW50cyA9IGNhbGxPYmplY3QucGFydGljaXBhbnRzKCk7XG4gICAgICBpZiAocGFydGljaXBhbnRzPy5sb2NhbCkge1xuICAgICAgICB0aGlzLmxvY2FsU2Vzc2lvbklkID0gcGFydGljaXBhbnRzLmxvY2FsLnNlc3Npb25faWQ7XG4gICAgICB9XG5cbiAgICAgIC8vIFN0YXJ0IHdpdGggbWljIG11dGVkOyBWb2ljZUFnZW50U2VydmljZSBhdXRvLXVubXV0ZXMgYWZ0ZXIgZmlyc3QgcmVtb3RlIGF1ZGlvIGZyYW1lLlxuICAgICAgY2FsbE9iamVjdC5zZXRMb2NhbEF1ZGlvKGZhbHNlKTtcbiAgICAgIHRoaXMubWljTXV0ZWRTdWJqZWN0Lm5leHQodHJ1ZSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aGlzLmNsZWFudXAoKTtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldHVwRXZlbnRIYW5kbGVycyhjYWxsOiBEYWlseUNhbGwpOiB2b2lkIHtcbiAgICAvLyBhY3RpdmUtc3BlYWtlci1jaGFuZ2U6IHVzZWQgT05MWSBmb3IgdXNlciBzcGVha2luZyBkZXRlY3Rpb24uXG4gICAgLy8gQm90IHNwZWFraW5nIGlzIGRldGVjdGVkIGJ5IG91ciBvd24gQW5hbHlzZXJOb2RlIChpbnN0YW50LCBubyBkZWJvdW5jZSkuXG4gICAgY2FsbC5vbignYWN0aXZlLXNwZWFrZXItY2hhbmdlJywgKGV2ZW50OiB7IGFjdGl2ZVNwZWFrZXI/OiB7IHBlZXJJZD86IHN0cmluZyB9IH0pID0+IHtcbiAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgIGNvbnN0IHBlZXJJZCA9IGV2ZW50Py5hY3RpdmVTcGVha2VyPy5wZWVySWQ7XG4gICAgICAgIGlmICghcGVlcklkIHx8ICF0aGlzLmxvY2FsU2Vzc2lvbklkKSB7XG4gICAgICAgICAgdGhpcy51c2VyU3BlYWtpbmdTdWJqZWN0Lm5leHQoZmFsc2UpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBpc0xvY2FsID0gcGVlcklkID09PSB0aGlzLmxvY2FsU2Vzc2lvbklkO1xuICAgICAgICB0aGlzLnVzZXJTcGVha2luZ1N1YmplY3QubmV4dChpc0xvY2FsKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgLy8gdHJhY2stc3RhcnRlZCAvIHRyYWNrLXN0b3BwZWQ6IHNldCB1cCByZW1vdGUgYXVkaW8gcGxheWJhY2sgKyBBbmFseXNlck5vZGUgbW9uaXRvci5cbiAgICBjYWxsLm9uKCd0cmFjay1zdGFydGVkJywgKGV2ZW50OiB7IHBhcnRpY2lwYW50PzogRGFpbHlQYXJ0aWNpcGFudCB8IG51bGw7IHR5cGU/OiBzdHJpbmc7IHRyYWNrPzogTWVkaWFTdHJlYW1UcmFjayB9KSA9PiB7XG4gICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICBjb25zdCBwID0gZXZlbnQ/LnBhcnRpY2lwYW50O1xuICAgICAgICBjb25zdCB0eXBlID0gZXZlbnQ/LnR5cGUgPz8gZXZlbnQ/LnRyYWNrPy5raW5kO1xuICAgICAgICBjb25zdCB0cmFjayA9IGV2ZW50Py50cmFjaztcbiAgICAgICAgaWYgKHAgJiYgIXAubG9jYWwgJiYgdHlwZSA9PT0gJ2F1ZGlvJykge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGBbVm9pY2VEZWJ1Z10gR290IGF1ZGlvIHRyYWNrIGZyb20gYmFja2VuZCAodHJhY2stc3RhcnRlZCkg4oCUIHJlYWR5U3RhdGU9JHt0cmFjaz8ucmVhZHlTdGF0ZX0sIG11dGVkPSR7dHJhY2s/Lm11dGVkfSDigJQgJHtuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCl9YCk7XG4gICAgICAgICAgY29uc3QgYXVkaW9UcmFjayA9IHRyYWNrID8/IChwIGFzIHsgdHJhY2tzPzogeyBhdWRpbz86IHsgdHJhY2s/OiBNZWRpYVN0cmVhbVRyYWNrIH0gfSB9KS50cmFja3M/LmF1ZGlvPy50cmFjaztcbiAgICAgICAgICBpZiAoYXVkaW9UcmFjayAmJiB0eXBlb2YgYXVkaW9UcmFjayA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHRoaXMucGxheVJlbW90ZVRyYWNrKGF1ZGlvVHJhY2spO1xuICAgICAgICAgICAgdGhpcy5tb25pdG9yUmVtb3RlQXVkaW8oYXVkaW9UcmFjayk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGNhbGwub24oJ3RyYWNrLXN0b3BwZWQnLCAoZXZlbnQ6IHsgcGFydGljaXBhbnQ/OiBEYWlseVBhcnRpY2lwYW50IHwgbnVsbDsgdHlwZT86IHN0cmluZzsgdHJhY2s/OiBNZWRpYVN0cmVhbVRyYWNrIH0pID0+IHtcbiAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgIGNvbnN0IHAgPSBldmVudD8ucGFydGljaXBhbnQ7XG4gICAgICAgIGNvbnN0IHR5cGUgPSBldmVudD8udHlwZSA/PyBldmVudD8udHJhY2s/LmtpbmQ7XG4gICAgICAgIGlmIChwICYmICFwLmxvY2FsICYmIHR5cGUgPT09ICdhdWRpbycpIHtcbiAgICAgICAgICB0aGlzLnN0b3BSZW1vdGVBdWRpb01vbml0b3IoKTtcbiAgICAgICAgICB0aGlzLnN0b3BSZW1vdGVBdWRpbygpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGNhbGwub24oJ2xlZnQtbWVldGluZycsICgpID0+IHtcbiAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB0aGlzLmNsZWFudXAoKSk7XG4gICAgfSk7XG5cbiAgICBjYWxsLm9uKCdlcnJvcicsIChldmVudD86IHsgZXJyb3JNc2c/OiBzdHJpbmcgfSkgPT4ge1xuICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcignRGFpbHlWb2ljZUNsaWVudDogRGFpbHkgZXJyb3InLCBldmVudD8uZXJyb3JNc2cgPz8gZXZlbnQpO1xuICAgICAgICB0aGlzLmNsZWFudXAoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFBsYXkgcmVtb3RlIChib3QpIGF1ZGlvIHRyYWNrIHZpYSBhIGRlZGljYXRlZCBhdWRpbyBlbGVtZW50LlxuICAgKiBSZXF1aXJlZCBpbiBtYW55IGJyb3dzZXJzIHdoZXJlIERhaWx5J3MgaW50ZXJuYWwgcGxheWJhY2sgZG9lcyBub3Qgb3V0cHV0IHRvIHNwZWFrZXJzLlxuICAgKi9cbiAgcHJpdmF0ZSBwbGF5UmVtb3RlVHJhY2sodHJhY2s6IE1lZGlhU3RyZWFtVHJhY2spOiB2b2lkIHtcbiAgICB0aGlzLnN0b3BSZW1vdGVBdWRpbygpO1xuICAgIHRyeSB7XG4gICAgICBjb25zb2xlLmxvZyhgW1ZvaWNlRGVidWddIHBsYXlSZW1vdGVUcmFjayBjYWxsZWQg4oCUIHRyYWNrLnJlYWR5U3RhdGU9JHt0cmFjay5yZWFkeVN0YXRlfSwgdHJhY2subXV0ZWQ9JHt0cmFjay5tdXRlZH0g4oCUICR7bmV3IERhdGUoKS50b0lTT1N0cmluZygpfWApO1xuXG4gICAgICB0cmFjay5vbnVubXV0ZSA9ICgpID0+IHtcbiAgICAgICAgY29uc29sZS5sb2coYFtWb2ljZURlYnVnXSBSZW1vdGUgYXVkaW8gdHJhY2sgVU5NVVRFRCAoYXVkaW8gZGF0YSBhcnJpdmluZykg4oCUICR7bmV3IERhdGUoKS50b0lTT1N0cmluZygpfWApO1xuICAgICAgfTtcblxuICAgICAgY29uc3Qgc3RyZWFtID0gbmV3IE1lZGlhU3RyZWFtKFt0cmFja10pO1xuICAgICAgY29uc3QgYXVkaW8gPSBuZXcgQXVkaW8oKTtcbiAgICAgIGF1ZGlvLmF1dG9wbGF5ID0gdHJ1ZTtcbiAgICAgIGF1ZGlvLnNyY09iamVjdCA9IHN0cmVhbTtcbiAgICAgIHRoaXMucmVtb3RlQXVkaW9FbGVtZW50ID0gYXVkaW87XG5cbiAgICAgIGF1ZGlvLm9ucGxheWluZyA9ICgpID0+IHtcbiAgICAgICAgY29uc29sZS5sb2coYFtWb2ljZURlYnVnXSBBdWRpbyBlbGVtZW50IFBMQVlJTkcgKGJyb3dzZXIgc3RhcnRlZCBwbGF5YmFjaykg4oCUICR7bmV3IERhdGUoKS50b0lTT1N0cmluZygpfWApO1xuICAgICAgfTtcblxuICAgICAgbGV0IGZpcnN0VGltZVVwZGF0ZSA9IHRydWU7XG4gICAgICBhdWRpby5vbnRpbWV1cGRhdGUgPSAoKSA9PiB7XG4gICAgICAgIGlmIChmaXJzdFRpbWVVcGRhdGUpIHtcbiAgICAgICAgICBmaXJzdFRpbWVVcGRhdGUgPSBmYWxzZTtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgW1ZvaWNlRGVidWddIEF1ZGlvIGVsZW1lbnQgZmlyc3QgVElNRVVQREFURSAoYWN0dWFsIGF1ZGlvIG91dHB1dCkg4oCUICR7bmV3IERhdGUoKS50b0lTT1N0cmluZygpfWApO1xuICAgICAgICAgIHRoaXMuZmlyc3RSZW1vdGVBdWRpb0ZyYW1lU3ViamVjdC5uZXh0KHRydWUpO1xuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICBjb25zdCBwID0gYXVkaW8ucGxheSgpO1xuICAgICAgaWYgKHAgJiYgdHlwZW9mIHAudGhlbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBwLnRoZW4oKCkgPT4ge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGBbVm9pY2VEZWJ1Z10gYXVkaW8ucGxheSgpIHJlc29sdmVkIOKAlCAke25ldyBEYXRlKCkudG9JU09TdHJpbmcoKX1gKTtcbiAgICAgICAgICB0aGlzLmZpcnN0UmVtb3RlQXVkaW9GcmFtZVN1YmplY3QubmV4dCh0cnVlKTtcbiAgICAgICAgfSkuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgIGNvbnNvbGUud2FybignRGFpbHlWb2ljZUNsaWVudDogcmVtb3RlIGF1ZGlvIHBsYXkgZmFpbGVkIChtYXkgbmVlZCB1c2VyIGdlc3R1cmUpJywgZXJyKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ0RhaWx5Vm9pY2VDbGllbnQ6IGZhaWxlZCB0byBjcmVhdGUgcmVtb3RlIGF1ZGlvIGVsZW1lbnQnLCBlcnIpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBNb25pdG9yIHJlbW90ZSBhdWRpbyB0cmFjayBlbmVyZ3kgdmlhIEFuYWx5c2VyTm9kZS5cbiAgICogUG9sbHMgYXQgfjYwZnBzIGFuZCBmbGlwcyBzcGVha2luZ1N1YmplY3QgYmFzZWQgb24gYWN0dWFsIGF1ZGlvIGVuZXJneS5cbiAgICovXG4gIHByaXZhdGUgbW9uaXRvclJlbW90ZUF1ZGlvKHRyYWNrOiBNZWRpYVN0cmVhbVRyYWNrKTogdm9pZCB7XG4gICAgdGhpcy5zdG9wUmVtb3RlQXVkaW9Nb25pdG9yKCk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGN0eCA9IG5ldyBBdWRpb0NvbnRleHQoKTtcbiAgICAgIGNvbnN0IHNvdXJjZSA9IGN0eC5jcmVhdGVNZWRpYVN0cmVhbVNvdXJjZShuZXcgTWVkaWFTdHJlYW0oW3RyYWNrXSkpO1xuICAgICAgY29uc3QgYW5hbHlzZXIgPSBjdHguY3JlYXRlQW5hbHlzZXIoKTtcbiAgICAgIGFuYWx5c2VyLmZmdFNpemUgPSAyNTY7XG4gICAgICBzb3VyY2UuY29ubmVjdChhbmFseXNlcik7XG4gICAgICB0aGlzLnJlbW90ZUF1ZGlvQ29udGV4dCA9IGN0eDtcblxuICAgICAgY29uc3QgZGF0YUFycmF5ID0gbmV3IFVpbnQ4QXJyYXkoYW5hbHlzZXIuZnJlcXVlbmN5QmluQ291bnQpO1xuICAgICAgY29uc3QgVEhSRVNIT0xEID0gNTtcbiAgICAgIGNvbnN0IFNJTEVOQ0VfTVMgPSAxNTAwO1xuICAgICAgbGV0IGxhc3RTb3VuZFRpbWUgPSAwO1xuICAgICAgbGV0IGlzU3BlYWtpbmcgPSBmYWxzZTtcblxuICAgICAgY29uc3QgcG9sbCA9ICgpID0+IHtcbiAgICAgICAgaWYgKCF0aGlzLnJlbW90ZUF1ZGlvQ29udGV4dCkgcmV0dXJuO1xuICAgICAgICBhbmFseXNlci5nZXRCeXRlRnJlcXVlbmN5RGF0YShkYXRhQXJyYXkpO1xuXG4gICAgICAgIGxldCBzdW0gPSAwO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRhdGFBcnJheS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHN1bSArPSBkYXRhQXJyYXlbaV07XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYXZnID0gc3VtIC8gZGF0YUFycmF5Lmxlbmd0aDtcblxuICAgICAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgICAgICBpZiAoYXZnID4gVEhSRVNIT0xEKSB7XG4gICAgICAgICAgbGFzdFNvdW5kVGltZSA9IG5vdztcbiAgICAgICAgICBpZiAoIWlzU3BlYWtpbmcpIHtcbiAgICAgICAgICAgIGlzU3BlYWtpbmcgPSB0cnVlO1xuICAgICAgICAgICAgY29uc29sZS5sb2coYFtWb2ljZURlYnVnXSBCb3QgYXVkaW8gZW5lcmd5IGRldGVjdGVkIChzcGVha2luZz10cnVlKSDigJQgYXZnPSR7YXZnLnRvRml4ZWQoMSl9IOKAlCAke25ldyBEYXRlKCkudG9JU09TdHJpbmcoKX1gKTtcbiAgICAgICAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgICAgICAgIHRoaXMudXNlclNwZWFraW5nU3ViamVjdC5uZXh0KGZhbHNlKTtcbiAgICAgICAgICAgICAgdGhpcy5zcGVha2luZ1N1YmplY3QubmV4dCh0cnVlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChpc1NwZWFraW5nICYmIG5vdyAtIGxhc3RTb3VuZFRpbWUgPiBTSUxFTkNFX01TKSB7XG4gICAgICAgICAgaXNTcGVha2luZyA9IGZhbHNlO1xuICAgICAgICAgIGNvbnNvbGUubG9nKGBbVm9pY2VEZWJ1Z10gQm90IGF1ZGlvIHNpbGVuY2UgZGV0ZWN0ZWQgKHNwZWFraW5nPWZhbHNlKSDigJQgJHtuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCl9YCk7XG4gICAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHRoaXMuc3BlYWtpbmdTdWJqZWN0Lm5leHQoZmFsc2UpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVtb3RlU3BlYWtpbmdSQUYgPSByZXF1ZXN0QW5pbWF0aW9uRnJhbWUocG9sbCk7XG4gICAgICB9O1xuXG4gICAgICB0aGlzLnJlbW90ZVNwZWFraW5nUkFGID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKHBvbGwpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS53YXJuKCdEYWlseVZvaWNlQ2xpZW50OiBmYWlsZWQgdG8gY3JlYXRlIHJlbW90ZSBhdWRpbyBtb25pdG9yJywgZXJyKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHN0b3BSZW1vdGVBdWRpb01vbml0b3IoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucmVtb3RlU3BlYWtpbmdSQUYpIHtcbiAgICAgIGNhbmNlbEFuaW1hdGlvbkZyYW1lKHRoaXMucmVtb3RlU3BlYWtpbmdSQUYpO1xuICAgICAgdGhpcy5yZW1vdGVTcGVha2luZ1JBRiA9IG51bGw7XG4gICAgfVxuICAgIGlmICh0aGlzLnJlbW90ZUF1ZGlvQ29udGV4dCkge1xuICAgICAgdGhpcy5yZW1vdGVBdWRpb0NvbnRleHQuY2xvc2UoKS5jYXRjaCgoKSA9PiB7fSk7XG4gICAgICB0aGlzLnJlbW90ZUF1ZGlvQ29udGV4dCA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzdG9wUmVtb3RlQXVkaW8oKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucmVtb3RlQXVkaW9FbGVtZW50KSB7XG4gICAgICB0cnkge1xuICAgICAgICB0aGlzLnJlbW90ZUF1ZGlvRWxlbWVudC5wYXVzZSgpO1xuICAgICAgICB0aGlzLnJlbW90ZUF1ZGlvRWxlbWVudC5zcmNPYmplY3QgPSBudWxsO1xuICAgICAgfSBjYXRjaCAoXykge31cbiAgICAgIHRoaXMucmVtb3RlQXVkaW9FbGVtZW50ID0gbnVsbDtcbiAgICB9XG4gIH1cblxuICAvKiogU2V0IG1pYyBtdXRlZCBzdGF0ZS4gKi9cbiAgc2V0TXV0ZWQobXV0ZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuY2FsbE9iamVjdCkgcmV0dXJuO1xuICAgIHRoaXMuY2FsbE9iamVjdC5zZXRMb2NhbEF1ZGlvKCFtdXRlZCk7XG4gICAgdGhpcy5taWNNdXRlZFN1YmplY3QubmV4dChtdXRlZCk7XG4gIH1cblxuICAvKiogRGlzY29ubmVjdCBhbmQgY2xlYW51cC4gKi9cbiAgYXN5bmMgZGlzY29ubmVjdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMuY2FsbE9iamVjdCkge1xuICAgICAgdGhpcy5jbGVhbnVwKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmNhbGxPYmplY3QubGVhdmUoKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyBpZ25vcmVcbiAgICB9XG4gICAgdGhpcy5jbGVhbnVwKCk7XG4gIH1cblxuICBwcml2YXRlIGNsZWFudXAoKTogdm9pZCB7XG4gICAgdGhpcy5zdG9wUmVtb3RlQXVkaW9Nb25pdG9yKCk7XG4gICAgdGhpcy5zdG9wUmVtb3RlQXVkaW8oKTtcbiAgICBpZiAodGhpcy5jYWxsT2JqZWN0KSB7XG4gICAgICB0aGlzLmNhbGxPYmplY3QuZGVzdHJveSgpLmNhdGNoKCgpID0+IHt9KTtcbiAgICAgIHRoaXMuY2FsbE9iamVjdCA9IG51bGw7XG4gICAgfVxuICAgIGlmICh0aGlzLmxvY2FsU3RyZWFtKSB7XG4gICAgICB0aGlzLmxvY2FsU3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goKHQpID0+IHQuc3RvcCgpKTtcbiAgICAgIHRoaXMubG9jYWxTdHJlYW0gPSBudWxsO1xuICAgIH1cbiAgICB0aGlzLmxvY2FsU2Vzc2lvbklkID0gbnVsbDtcbiAgICB0aGlzLnNwZWFraW5nU3ViamVjdC5uZXh0KGZhbHNlKTtcbiAgICB0aGlzLnVzZXJTcGVha2luZ1N1YmplY3QubmV4dChmYWxzZSk7XG4gICAgdGhpcy5sb2NhbFN0cmVhbVN1YmplY3QubmV4dChudWxsKTtcbiAgICB0aGlzLmZpcnN0UmVtb3RlQXVkaW9GcmFtZVN1YmplY3QubmV4dChmYWxzZSk7XG4gICAgLy8gS2VlcCBsYXN0IG1pY011dGVkIHN0YXRlOyB3aWxsIHJlc2V0IG9uIG5leHQgY29ubmVjdFxuICB9XG59XG4iXX0=