@hivegpt/hiveai-angular 0.0.581 → 0.0.583
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.
- package/bundles/hivegpt-hiveai-angular.umd.js +420 -490
- package/bundles/hivegpt-hiveai-angular.umd.js.map +1 -1
- package/bundles/hivegpt-hiveai-angular.umd.min.js +1 -1
- package/bundles/hivegpt-hiveai-angular.umd.min.js.map +1 -1
- package/esm2015/hivegpt-hiveai-angular.js +4 -5
- package/esm2015/lib/components/voice-agent/services/audio-analyzer.service.js +3 -3
- package/esm2015/lib/components/voice-agent/services/voice-agent.service.js +195 -83
- package/esm2015/lib/components/voice-agent/services/websocket-voice-client.service.js +160 -49
- package/esm2015/lib/components/voice-agent/voice-agent.module.js +3 -5
- package/fesm2015/hivegpt-hiveai-angular.js +338 -416
- package/fesm2015/hivegpt-hiveai-angular.js.map +1 -1
- package/hivegpt-hiveai-angular.d.ts +3 -4
- package/hivegpt-hiveai-angular.d.ts.map +1 -1
- package/hivegpt-hiveai-angular.metadata.json +1 -1
- package/lib/components/voice-agent/services/audio-analyzer.service.d.ts +2 -2
- package/lib/components/voice-agent/services/voice-agent.service.d.ts +22 -13
- package/lib/components/voice-agent/services/voice-agent.service.d.ts.map +1 -1
- package/lib/components/voice-agent/services/websocket-voice-client.service.d.ts +30 -20
- package/lib/components/voice-agent/services/websocket-voice-client.service.d.ts.map +1 -1
- package/lib/components/voice-agent/voice-agent.module.d.ts +1 -1
- package/lib/components/voice-agent/voice-agent.module.d.ts.map +1 -1
- package/package.json +1 -1
- package/esm2015/lib/components/voice-agent/services/daily-voice-client.service.js +0 -305
- package/lib/components/voice-agent/services/daily-voice-client.service.d.ts +0 -62
- package/lib/components/voice-agent/services/daily-voice-client.service.d.ts.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
/**
|
|
3
|
-
* Audio analyzer for waveform visualization
|
|
4
|
-
*
|
|
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;
|
|
@@ -3,27 +3,19 @@ import { Observable } from 'rxjs';
|
|
|
3
3
|
import { PlatformTokenRefreshService } from '../../../services/platform-token-refresh.service';
|
|
4
4
|
import { AudioAnalyzerService } from './audio-analyzer.service';
|
|
5
5
|
import { WebSocketVoiceClientService } from './websocket-voice-client.service';
|
|
6
|
-
import { DailyVoiceClientService } from './daily-voice-client.service';
|
|
7
6
|
export declare type CallState = 'idle' | 'connecting' | 'connected' | 'listening' | 'talking' | 'ended';
|
|
8
7
|
export interface TranscriptData {
|
|
9
8
|
text: string;
|
|
10
9
|
final: boolean;
|
|
11
10
|
}
|
|
12
11
|
/**
|
|
13
|
-
* Voice agent orchestrator
|
|
14
|
-
*
|
|
15
|
-
*
|
|
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
|
|
12
|
+
* Voice agent orchestrator: single WebSocket (`ws_url` from POST /ai/ask-voice-socket)
|
|
13
|
+
* for session events, transcripts, and optional speaking hints; local mic for capture
|
|
14
|
+
* and waveform only (no Daily/WebRTC room).
|
|
22
15
|
*/
|
|
23
16
|
export declare class VoiceAgentService implements OnDestroy {
|
|
24
17
|
private audioAnalyzer;
|
|
25
18
|
private wsClient;
|
|
26
|
-
private dailyClient;
|
|
27
19
|
private platformTokenRefresh;
|
|
28
20
|
/** `Object` not `object` — ngc metadata collection rejects the `object` type in DI params. */
|
|
29
21
|
private platformId;
|
|
@@ -37,6 +29,11 @@ export declare class VoiceAgentService implements OnDestroy {
|
|
|
37
29
|
private botTranscriptSubject;
|
|
38
30
|
private callStartTime;
|
|
39
31
|
private durationInterval;
|
|
32
|
+
private localMicStream;
|
|
33
|
+
private remoteAudioContext;
|
|
34
|
+
private pendingRemoteAudio;
|
|
35
|
+
private remoteAudioPlaying;
|
|
36
|
+
private readonly endCall$;
|
|
40
37
|
private subscriptions;
|
|
41
38
|
private destroy$;
|
|
42
39
|
callState$: Observable<CallState>;
|
|
@@ -47,14 +44,26 @@ export declare class VoiceAgentService implements OnDestroy {
|
|
|
47
44
|
audioLevels$: Observable<number[]>;
|
|
48
45
|
userTranscript$: Observable<TranscriptData>;
|
|
49
46
|
botTranscript$: Observable<string>;
|
|
50
|
-
constructor(audioAnalyzer: AudioAnalyzerService, wsClient: WebSocketVoiceClientService,
|
|
47
|
+
constructor(audioAnalyzer: AudioAnalyzerService, wsClient: WebSocketVoiceClientService, platformTokenRefresh: PlatformTokenRefreshService,
|
|
51
48
|
/** `Object` not `object` — ngc metadata collection rejects the `object` type in DI params. */
|
|
52
49
|
platformId: Object);
|
|
53
50
|
ngOnDestroy(): void;
|
|
54
51
|
/** Reset to idle state (e.g. when modal opens so user can click Start Call). */
|
|
55
52
|
resetToIdle(): void;
|
|
56
53
|
connect(apiUrl: string, token: string, botId: string, conversationId: string, apiKey: string, eventToken: string, eventId: string, eventUrl: string, domainAuthority: string, usersApiUrl?: string): Promise<void>;
|
|
57
|
-
private
|
|
54
|
+
private onWebsocketOpened;
|
|
55
|
+
private wireSpeakingState;
|
|
56
|
+
private startLocalMic;
|
|
57
|
+
private stopLocalMic;
|
|
58
|
+
private enqueueRemoteAudio;
|
|
59
|
+
private playRemoteAudioQueue;
|
|
60
|
+
private getOrCreateRemoteAudioContext;
|
|
61
|
+
private decodeAudioChunk;
|
|
62
|
+
private playDecodedBuffer;
|
|
63
|
+
private assistantAudioStarted;
|
|
64
|
+
private assistantAudioStopped;
|
|
65
|
+
private resetRemoteAudioPlayback;
|
|
66
|
+
private handleRemoteClose;
|
|
58
67
|
disconnect(): Promise<void>;
|
|
59
68
|
toggleMic(): void;
|
|
60
69
|
private startDurationTimer;
|
|
@@ -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,
|
|
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":"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"}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
+
import { NgZone } from '@angular/core';
|
|
1
2
|
import { Observable } from 'rxjs';
|
|
2
|
-
/** WebSocket message types from backend
|
|
3
|
-
export interface WsMessageRoomCreated {
|
|
4
|
-
type: 'room_created';
|
|
5
|
-
room_url: string;
|
|
6
|
-
}
|
|
3
|
+
/** WebSocket message types from backend (voice session over a single WS). */
|
|
7
4
|
export interface WsMessageUserTranscript {
|
|
8
5
|
type: 'user_transcript';
|
|
9
6
|
text: string;
|
|
@@ -13,37 +10,50 @@ export interface WsMessageBotTranscript {
|
|
|
13
10
|
type: 'bot_transcript';
|
|
14
11
|
text: string;
|
|
15
12
|
}
|
|
16
|
-
export declare type WsMessage =
|
|
13
|
+
export declare type WsMessage = WsMessageUserTranscript | WsMessageBotTranscript;
|
|
17
14
|
export interface TranscriptData {
|
|
18
15
|
text: string;
|
|
19
16
|
final: boolean;
|
|
20
17
|
}
|
|
21
18
|
/**
|
|
22
|
-
* WebSocket
|
|
19
|
+
* Native WebSocket client for voice session (signaling, transcripts, speaking hints).
|
|
23
20
|
* CRITICAL: Uses native WebSocket only. NO Socket.IO, NO ngx-socket-io.
|
|
24
21
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* - Parse JSON messages (room_created, user_transcript, bot_transcript)
|
|
28
|
-
* - Emit roomCreated$, userTranscript$, botTranscript$
|
|
29
|
-
* - NO audio logic, NO mic logic. Audio is handled by Daily.js (WebRTC).
|
|
22
|
+
* Connects to `ws_url` from `POST {baseUrl}/ai/ask-voice-socket`.
|
|
23
|
+
* Parses JSON messages for transcripts and optional assistant/user speaking flags.
|
|
30
24
|
*/
|
|
31
25
|
export declare class WebSocketVoiceClientService {
|
|
26
|
+
private ngZone;
|
|
32
27
|
private ws;
|
|
33
|
-
|
|
28
|
+
/** True when {@link disconnect} initiated the close (not counted as remote close). */
|
|
29
|
+
private closeInitiatedByClient;
|
|
30
|
+
private openedSubject;
|
|
31
|
+
private remoteCloseSubject;
|
|
34
32
|
private userTranscriptSubject;
|
|
35
33
|
private botTranscriptSubject;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
private assistantSpeakingSubject;
|
|
35
|
+
private serverUserSpeakingSubject;
|
|
36
|
+
private audioChunkSubject;
|
|
37
|
+
/** Fires once each time the WebSocket reaches OPEN. */
|
|
38
|
+
opened$: Observable<void>;
|
|
39
|
+
/** Fires when the socket closes without a client-initiated {@link disconnect}. */
|
|
40
|
+
remoteClose$: Observable<void>;
|
|
39
41
|
userTranscript$: Observable<TranscriptData>;
|
|
40
|
-
/** Emits bot transcript updates. */
|
|
41
42
|
botTranscript$: Observable<string>;
|
|
42
|
-
/**
|
|
43
|
+
/** Assistant/bot speaking, when the server sends explicit events (see {@link handleJsonMessage}). */
|
|
44
|
+
assistantSpeaking$: Observable<boolean>;
|
|
45
|
+
/** User speaking from server-side VAD, if provided. */
|
|
46
|
+
serverUserSpeaking$: Observable<boolean>;
|
|
47
|
+
/** Binary audio frames from server (when backend streams bot audio over WS). */
|
|
48
|
+
audioChunk$: Observable<ArrayBuffer>;
|
|
49
|
+
constructor(ngZone: NgZone);
|
|
43
50
|
connect(wsUrl: string): void;
|
|
44
|
-
|
|
51
|
+
private handleIncomingMessage;
|
|
52
|
+
private handleJsonString;
|
|
53
|
+
private handleBinaryMessage;
|
|
54
|
+
private tryDecodeUtf8;
|
|
55
|
+
private handleJsonMessage;
|
|
45
56
|
disconnect(): void;
|
|
46
|
-
/** Whether the WebSocket is open. */
|
|
47
57
|
get isConnected(): boolean;
|
|
48
58
|
}
|
|
49
59
|
//# sourceMappingURL=websocket-voice-client.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-voice-client.service.d.ts","sourceRoot":"/Users/rohitthakur/hive-gpt/HiveAI-Packages/Angular/projects/hivegpt/eventsgpt-angular/src/","sources":["lib/components/voice-agent/services/websocket-voice-client.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"websocket-voice-client.service.d.ts","sourceRoot":"/Users/rohitthakur/hive-gpt/HiveAI-Packages/Angular/projects/hivegpt/eventsgpt-angular/src/","sources":["lib/components/voice-agent/services/websocket-voice-client.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,UAAU,EAAW,MAAM,MAAM,CAAC;AAE3C,6EAA6E;AAC7E,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,oBAAY,SAAS,GACjB,uBAAuB,GACvB,sBAAsB,CAAC;AAE3B,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;GAMG;AACH,qBAGa,2BAA2B;IAoC1B,OAAO,CAAC,MAAM;IAnC1B,OAAO,CAAC,EAAE,CAA0B;IACpC,sFAAsF;IACtF,OAAO,CAAC,sBAAsB,CAAS;IAEvC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,qBAAqB,CAAiC;IAC9D,OAAO,CAAC,oBAAoB,CAAyB;IACrD,OAAO,CAAC,wBAAwB,CAA0B;IAC1D,OAAO,CAAC,yBAAyB,CAA0B;IAC3D,OAAO,CAAC,iBAAiB,CAA8B;IAEvD,uDAAuD;IACvD,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,CAAqC;IAE9D,kFAAkF;IAClF,YAAY,EAAE,UAAU,CAAC,IAAI,CAAC,CAA0C;IAExE,eAAe,EAAE,UAAU,CAAC,cAAc,CAAC,CACC;IAE5C,cAAc,EAAE,UAAU,CAAC,MAAM,CAAC,CACS;IAE3C,qGAAqG;IACrG,kBAAkB,EAAE,UAAU,CAAC,OAAO,CAAC,CACQ;IAE/C,uDAAuD;IACvD,mBAAmB,EAAE,UAAU,CAAC,OAAO,CAAC,CACQ;IAEhD,gFAAgF;IAChF,WAAW,EAAE,UAAU,CAAC,WAAW,CAAC,CAAyC;gBAEzD,MAAM,EAAE,MAAM;IAElC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;YA4Cd,qBAAqB;IAenC,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,iBAAiB;IA8DzB,UAAU,IAAI,IAAI;IAQlB,IAAI,WAAW,IAAI,OAAO,CAEzB;CACF"}
|
|
@@ -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":"
|
|
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":"AAOA;;;GAGG;AACH,qBAgBa,gBAAgB;CAAI"}
|
package/package.json
CHANGED
|
@@ -1,305 +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
|
-
/** True when bot (remote participant) is the active speaker. */
|
|
33
|
-
this.speaking$ = this.speakingSubject.asObservable();
|
|
34
|
-
/** True when user (local participant) is the active speaker. */
|
|
35
|
-
this.userSpeaking$ = this.userSpeakingSubject.asObservable();
|
|
36
|
-
/** True when mic is muted. */
|
|
37
|
-
this.micMuted$ = this.micMutedSubject.asObservable();
|
|
38
|
-
/** Emits local mic stream for waveform visualization. */
|
|
39
|
-
this.localStream$ = this.localStreamSubject.asObservable();
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Connect to Daily room. Acquires mic first for waveform, then joins with audio.
|
|
43
|
-
* @param roomUrl Daily room URL (from room_created)
|
|
44
|
-
* @param token Optional meeting token
|
|
45
|
-
*/
|
|
46
|
-
connect(roomUrl, token) {
|
|
47
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
-
if (this.callObject) {
|
|
49
|
-
yield this.disconnect();
|
|
50
|
-
}
|
|
51
|
-
try {
|
|
52
|
-
// Get mic stream for both Daily and waveform (single capture)
|
|
53
|
-
const stream = yield navigator.mediaDevices.getUserMedia({ audio: true });
|
|
54
|
-
const audioTrack = stream.getAudioTracks()[0];
|
|
55
|
-
if (!audioTrack) {
|
|
56
|
-
stream.getTracks().forEach((t) => t.stop());
|
|
57
|
-
throw new Error('No audio track');
|
|
58
|
-
}
|
|
59
|
-
this.localStream = stream;
|
|
60
|
-
this.localStreamSubject.next(stream);
|
|
61
|
-
// Create audio-only call object
|
|
62
|
-
// videoSource: false = no camera, audioSource = our mic track
|
|
63
|
-
const callObject = Daily.createCallObject({
|
|
64
|
-
videoSource: false,
|
|
65
|
-
audioSource: audioTrack,
|
|
66
|
-
});
|
|
67
|
-
this.callObject = callObject;
|
|
68
|
-
this.setupEventHandlers(callObject);
|
|
69
|
-
// Join room; Daily handles playback of remote (bot) audio automatically.
|
|
70
|
-
// Only pass token when it's a non-empty string (Daily rejects undefined/non-string).
|
|
71
|
-
const joinOptions = { url: roomUrl };
|
|
72
|
-
if (typeof token === 'string' && token.trim() !== '') {
|
|
73
|
-
joinOptions.token = token;
|
|
74
|
-
}
|
|
75
|
-
yield callObject.join(joinOptions);
|
|
76
|
-
console.log(`[VoiceDebug] Room connected (Daily join complete) — ${new Date().toISOString()}`);
|
|
77
|
-
const participants = callObject.participants();
|
|
78
|
-
if (participants === null || participants === void 0 ? void 0 : participants.local) {
|
|
79
|
-
this.localSessionId = participants.local.session_id;
|
|
80
|
-
}
|
|
81
|
-
// Initial mute state: Daily starts with audio on
|
|
82
|
-
this.micMutedSubject.next(!callObject.localAudio());
|
|
83
|
-
}
|
|
84
|
-
catch (err) {
|
|
85
|
-
this.cleanup();
|
|
86
|
-
throw err;
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
setupEventHandlers(call) {
|
|
91
|
-
// active-speaker-change: used ONLY for user speaking detection.
|
|
92
|
-
// Bot speaking is detected by our own AnalyserNode (instant, no debounce).
|
|
93
|
-
call.on('active-speaker-change', (event) => {
|
|
94
|
-
this.ngZone.run(() => {
|
|
95
|
-
var _a;
|
|
96
|
-
const peerId = (_a = event === null || event === void 0 ? void 0 : event.activeSpeaker) === null || _a === void 0 ? void 0 : _a.peerId;
|
|
97
|
-
if (!peerId || !this.localSessionId) {
|
|
98
|
-
this.userSpeakingSubject.next(false);
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
const isLocal = peerId === this.localSessionId;
|
|
102
|
-
this.userSpeakingSubject.next(isLocal);
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
// track-started / track-stopped: set up remote audio playback + AnalyserNode monitor.
|
|
106
|
-
call.on('track-started', (event) => {
|
|
107
|
-
this.ngZone.run(() => {
|
|
108
|
-
var _a, _b, _c, _d;
|
|
109
|
-
const p = event === null || event === void 0 ? void 0 : event.participant;
|
|
110
|
-
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;
|
|
111
|
-
const track = event === null || event === void 0 ? void 0 : event.track;
|
|
112
|
-
if (p && !p.local && type === 'audio') {
|
|
113
|
-
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()}`);
|
|
114
|
-
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;
|
|
115
|
-
if (audioTrack && typeof audioTrack === 'object') {
|
|
116
|
-
this.playRemoteTrack(audioTrack);
|
|
117
|
-
this.monitorRemoteAudio(audioTrack);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
call.on('track-stopped', (event) => {
|
|
123
|
-
this.ngZone.run(() => {
|
|
124
|
-
var _a, _b;
|
|
125
|
-
const p = event === null || event === void 0 ? void 0 : event.participant;
|
|
126
|
-
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;
|
|
127
|
-
if (p && !p.local && type === 'audio') {
|
|
128
|
-
this.stopRemoteAudioMonitor();
|
|
129
|
-
this.stopRemoteAudio();
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
call.on('left-meeting', () => {
|
|
134
|
-
this.ngZone.run(() => this.cleanup());
|
|
135
|
-
});
|
|
136
|
-
call.on('error', (event) => {
|
|
137
|
-
this.ngZone.run(() => {
|
|
138
|
-
var _a;
|
|
139
|
-
console.error('DailyVoiceClient: Daily error', (_a = event === null || event === void 0 ? void 0 : event.errorMsg) !== null && _a !== void 0 ? _a : event);
|
|
140
|
-
this.cleanup();
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Play remote (bot) audio track via a dedicated audio element.
|
|
146
|
-
* Required in many browsers where Daily's internal playback does not output to speakers.
|
|
147
|
-
*/
|
|
148
|
-
playRemoteTrack(track) {
|
|
149
|
-
this.stopRemoteAudio();
|
|
150
|
-
try {
|
|
151
|
-
console.log(`[VoiceDebug] playRemoteTrack called — track.readyState=${track.readyState}, track.muted=${track.muted} — ${new Date().toISOString()}`);
|
|
152
|
-
track.onunmute = () => {
|
|
153
|
-
console.log(`[VoiceDebug] Remote audio track UNMUTED (audio data arriving) — ${new Date().toISOString()}`);
|
|
154
|
-
};
|
|
155
|
-
const stream = new MediaStream([track]);
|
|
156
|
-
const audio = new Audio();
|
|
157
|
-
audio.autoplay = true;
|
|
158
|
-
audio.srcObject = stream;
|
|
159
|
-
this.remoteAudioElement = audio;
|
|
160
|
-
audio.onplaying = () => {
|
|
161
|
-
console.log(`[VoiceDebug] Audio element PLAYING (browser started playback) — ${new Date().toISOString()}`);
|
|
162
|
-
};
|
|
163
|
-
let firstTimeUpdate = true;
|
|
164
|
-
audio.ontimeupdate = () => {
|
|
165
|
-
if (firstTimeUpdate) {
|
|
166
|
-
firstTimeUpdate = false;
|
|
167
|
-
console.log(`[VoiceDebug] Audio element first TIMEUPDATE (actual audio output) — ${new Date().toISOString()}`);
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
const p = audio.play();
|
|
171
|
-
if (p && typeof p.then === 'function') {
|
|
172
|
-
p.then(() => {
|
|
173
|
-
console.log(`[VoiceDebug] audio.play() resolved — ${new Date().toISOString()}`);
|
|
174
|
-
}).catch((err) => {
|
|
175
|
-
console.warn('DailyVoiceClient: remote audio play failed (may need user gesture)', err);
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
catch (err) {
|
|
180
|
-
console.warn('DailyVoiceClient: failed to create remote audio element', err);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Monitor remote audio track energy via AnalyserNode.
|
|
185
|
-
* Polls at ~60fps and flips speakingSubject based on actual audio energy.
|
|
186
|
-
*/
|
|
187
|
-
monitorRemoteAudio(track) {
|
|
188
|
-
this.stopRemoteAudioMonitor();
|
|
189
|
-
try {
|
|
190
|
-
const ctx = new AudioContext();
|
|
191
|
-
const source = ctx.createMediaStreamSource(new MediaStream([track]));
|
|
192
|
-
const analyser = ctx.createAnalyser();
|
|
193
|
-
analyser.fftSize = 256;
|
|
194
|
-
source.connect(analyser);
|
|
195
|
-
this.remoteAudioContext = ctx;
|
|
196
|
-
const dataArray = new Uint8Array(analyser.frequencyBinCount);
|
|
197
|
-
const THRESHOLD = 5;
|
|
198
|
-
const SILENCE_MS = 1500;
|
|
199
|
-
let lastSoundTime = 0;
|
|
200
|
-
let isSpeaking = false;
|
|
201
|
-
const poll = () => {
|
|
202
|
-
if (!this.remoteAudioContext)
|
|
203
|
-
return;
|
|
204
|
-
analyser.getByteFrequencyData(dataArray);
|
|
205
|
-
let sum = 0;
|
|
206
|
-
for (let i = 0; i < dataArray.length; i++) {
|
|
207
|
-
sum += dataArray[i];
|
|
208
|
-
}
|
|
209
|
-
const avg = sum / dataArray.length;
|
|
210
|
-
const now = Date.now();
|
|
211
|
-
if (avg > THRESHOLD) {
|
|
212
|
-
lastSoundTime = now;
|
|
213
|
-
if (!isSpeaking) {
|
|
214
|
-
isSpeaking = true;
|
|
215
|
-
console.log(`[VoiceDebug] Bot audio energy detected (speaking=true) — avg=${avg.toFixed(1)} — ${new Date().toISOString()}`);
|
|
216
|
-
this.ngZone.run(() => {
|
|
217
|
-
this.userSpeakingSubject.next(false);
|
|
218
|
-
this.speakingSubject.next(true);
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
else if (isSpeaking && now - lastSoundTime > SILENCE_MS) {
|
|
223
|
-
isSpeaking = false;
|
|
224
|
-
console.log(`[VoiceDebug] Bot audio silence detected (speaking=false) — ${new Date().toISOString()}`);
|
|
225
|
-
this.ngZone.run(() => this.speakingSubject.next(false));
|
|
226
|
-
}
|
|
227
|
-
this.remoteSpeakingRAF = requestAnimationFrame(poll);
|
|
228
|
-
};
|
|
229
|
-
this.remoteSpeakingRAF = requestAnimationFrame(poll);
|
|
230
|
-
}
|
|
231
|
-
catch (err) {
|
|
232
|
-
console.warn('DailyVoiceClient: failed to create remote audio monitor', err);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
stopRemoteAudioMonitor() {
|
|
236
|
-
if (this.remoteSpeakingRAF) {
|
|
237
|
-
cancelAnimationFrame(this.remoteSpeakingRAF);
|
|
238
|
-
this.remoteSpeakingRAF = null;
|
|
239
|
-
}
|
|
240
|
-
if (this.remoteAudioContext) {
|
|
241
|
-
this.remoteAudioContext.close().catch(() => { });
|
|
242
|
-
this.remoteAudioContext = null;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
stopRemoteAudio() {
|
|
246
|
-
if (this.remoteAudioElement) {
|
|
247
|
-
try {
|
|
248
|
-
this.remoteAudioElement.pause();
|
|
249
|
-
this.remoteAudioElement.srcObject = null;
|
|
250
|
-
}
|
|
251
|
-
catch (_) { }
|
|
252
|
-
this.remoteAudioElement = null;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
/** Set mic muted state. */
|
|
256
|
-
setMuted(muted) {
|
|
257
|
-
if (!this.callObject)
|
|
258
|
-
return;
|
|
259
|
-
this.callObject.setLocalAudio(!muted);
|
|
260
|
-
this.micMutedSubject.next(muted);
|
|
261
|
-
}
|
|
262
|
-
/** Disconnect and cleanup. */
|
|
263
|
-
disconnect() {
|
|
264
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
265
|
-
if (!this.callObject) {
|
|
266
|
-
this.cleanup();
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
try {
|
|
270
|
-
yield this.callObject.leave();
|
|
271
|
-
}
|
|
272
|
-
catch (e) {
|
|
273
|
-
// ignore
|
|
274
|
-
}
|
|
275
|
-
this.cleanup();
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
cleanup() {
|
|
279
|
-
this.stopRemoteAudioMonitor();
|
|
280
|
-
this.stopRemoteAudio();
|
|
281
|
-
if (this.callObject) {
|
|
282
|
-
this.callObject.destroy().catch(() => { });
|
|
283
|
-
this.callObject = null;
|
|
284
|
-
}
|
|
285
|
-
if (this.localStream) {
|
|
286
|
-
this.localStream.getTracks().forEach((t) => t.stop());
|
|
287
|
-
this.localStream = null;
|
|
288
|
-
}
|
|
289
|
-
this.localSessionId = null;
|
|
290
|
-
this.speakingSubject.next(false);
|
|
291
|
-
this.userSpeakingSubject.next(false);
|
|
292
|
-
this.localStreamSubject.next(null);
|
|
293
|
-
// Keep last micMuted state; will reset on next connect
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
DailyVoiceClientService.ɵprov = i0.ɵɵdefineInjectable({ factory: function DailyVoiceClientService_Factory() { return new DailyVoiceClientService(i0.ɵɵinject(i0.NgZone)); }, token: DailyVoiceClientService, providedIn: "root" });
|
|
297
|
-
DailyVoiceClientService.decorators = [
|
|
298
|
-
{ type: Injectable, args: [{
|
|
299
|
-
providedIn: 'root',
|
|
300
|
-
},] }
|
|
301
|
-
];
|
|
302
|
-
DailyVoiceClientService.ctorParameters = () => [
|
|
303
|
-
{ type: NgZone }
|
|
304
|
-
];
|
|
305
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGFpbHktdm9pY2UtY2xpZW50LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiL1VzZXJzL3JvaGl0dGhha3VyL2hpdmUtZ3B0L0hpdmVBSS1QYWNrYWdlcy9Bbmd1bGFyL3Byb2plY3RzL2hpdmVncHQvZXZlbnRzZ3B0LWFuZ3VsYXIvc3JjLyIsInNvdXJjZXMiOlsibGliL2NvbXBvbmVudHMvdm9pY2UtYWdlbnQvc2VydmljZXMvZGFpbHktdm9pY2UtY2xpZW50LnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBRSxlQUFlLEVBQWMsTUFBTSxNQUFNLENBQUM7QUFDbkQsT0FBTyxLQUFLLE1BQU0sb0JBQW9CLENBQUM7O0FBR3ZDOzs7Ozs7Ozs7O0dBVUc7QUFJSCxNQUFNLE9BQU8sdUJBQXVCO0lBNkJsQyxZQUFvQixNQUFjO1FBQWQsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQTVCMUIsZUFBVSxHQUFxQixJQUFJLENBQUM7UUFDcEMsZ0JBQVcsR0FBdUIsSUFBSSxDQUFDO1FBQ3ZDLG1CQUFjLEdBQWtCLElBQUksQ0FBQztRQUM3QywwRUFBMEU7UUFDbEUsdUJBQWtCLEdBQTRCLElBQUksQ0FBQztRQUUzRCxrRkFBa0Y7UUFDMUUsdUJBQWtCLEdBQXdCLElBQUksQ0FBQztRQUMvQyxzQkFBaUIsR0FBa0IsSUFBSSxDQUFDO1FBRXhDLG9CQUFlLEdBQUcsSUFBSSxlQUFlLENBQVUsS0FBSyxDQUFDLENBQUM7UUFDdEQsd0JBQW1CLEdBQUcsSUFBSSxlQUFlLENBQVUsS0FBSyxDQUFDLENBQUM7UUFDMUQsb0JBQWUsR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztRQUN0RCx1QkFBa0IsR0FBRyxJQUFJLGVBQWUsQ0FBcUIsSUFBSSxDQUFDLENBQUM7UUFFM0UsZ0VBQWdFO1FBQ2hFLGNBQVMsR0FBd0IsSUFBSSxDQUFDLGVBQWUsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUVyRSxnRUFBZ0U7UUFDaEUsa0JBQWEsR0FBd0IsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFlBQVksRUFBRSxDQUFDO1FBRTdFLDhCQUE4QjtRQUM5QixjQUFTLEdBQXdCLElBQUksQ0FBQyxlQUFlLENBQUMsWUFBWSxFQUFFLENBQUM7UUFFckUseURBQXlEO1FBQ3pELGlCQUFZLEdBQ1YsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFlBQVksRUFBRSxDQUFDO0lBRUosQ0FBQztJQUV0Qzs7OztPQUlHO0lBQ0csT0FBTyxDQUFDLE9BQWUsRUFBRSxLQUFjOztZQUMzQyxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUU7Z0JBQ25CLE1BQU0sSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO2FBQ3pCO1lBRUQsSUFBSTtnQkFDRiw4REFBOEQ7Z0JBQzlELE1BQU0sTUFBTSxHQUFHLE1BQU0sU0FBUyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDMUUsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUM5QyxJQUFJLENBQUMsVUFBVSxFQUFFO29CQUNmLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUM1QyxNQUFNLElBQUksS0FBSyxDQUFDLGdCQUFnQixDQUFDLENBQUM7aUJBQ25DO2dCQUVELElBQUksQ0FBQyxXQUFXLEdBQUcsTUFBTSxDQUFDO2dCQUMxQixJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUVyQyxnQ0FBZ0M7Z0JBQ2hDLDhEQUE4RDtnQkFDOUQsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLGdCQUFnQixDQUFDO29CQUN4QyxXQUFXLEVBQUUsS0FBSztvQkFDbEIsV0FBVyxFQUFFLFVBQVU7aUJBQ3hCLENBQUMsQ0FBQztnQkFFSCxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztnQkFFN0IsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUVwQyx5RUFBeUU7Z0JBQ3pFLHFGQUFxRjtnQkFDckYsTUFBTSxXQUFXLEdBQW9DLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxDQUFDO2dCQUN0RSxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO29CQUNwRCxXQUFXLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztpQkFDM0I7Z0JBQ0QsTUFBTSxVQUFVLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO2dCQUNuQyxPQUFPLENBQUMsR0FBRyxDQUFDLHVEQUF1RCxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFFL0YsTUFBTSxZQUFZLEdBQUcsVUFBVSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUMvQyxJQUFJLFlBQVksYUFBWixZQUFZLHVCQUFaLFlBQVksQ0FBRSxLQUFLLEVBQUU7b0JBQ3ZCLElBQUksQ0FBQyxjQUFjLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUM7aUJBQ3JEO2dCQUVELGlEQUFpRDtnQkFDakQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQzthQUNyRDtZQUFDLE9BQU8sR0FBRyxFQUFFO2dCQUNaLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDZixNQUFNLEdBQUcsQ0FBQzthQUNYO1FBQ0gsQ0FBQztLQUFBO0lBRU8sa0JBQWtCLENBQUMsSUFBZTtRQUN4QyxnRUFBZ0U7UUFDaEUsMkVBQTJFO1FBQzNFLElBQUksQ0FBQyxFQUFFLENBQUMsdUJBQXVCLEVBQUUsQ0FBQyxLQUE4QyxFQUFFLEVBQUU7WUFDbEYsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFOztnQkFDbkIsTUFBTSxNQUFNLEdBQUcsTUFBQSxLQUFLLGFBQUwsS0FBSyx1QkFBTCxLQUFLLENBQUUsYUFBYSwwQ0FBRSxNQUFNLENBQUM7Z0JBQzVDLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFO29CQUNuQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUNyQyxPQUFPO2lCQUNSO2dCQUNELE1BQU0sT0FBTyxHQUFHLE1BQU0sS0FBSyxJQUFJLENBQUMsY0FBYyxDQUFDO2dCQUMvQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3pDLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFFSCxzRkFBc0Y7UUFDdEYsSUFBSSxDQUFDLEVBQUUsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxLQUF5RixFQUFFLEVBQUU7WUFDckgsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFOztnQkFDbkIsTUFBTSxDQUFDLEdBQUcsS0FBSyxhQUFMLEtBQUssdUJBQUwsS0FBSyxDQUFFLFdBQVcsQ0FBQztnQkFDN0IsTUFBTSxJQUFJLEdBQUcsTUFBQSxLQUFLLGFBQUwsS0FBSyx1QkFBTCxLQUFLLENBQUUsSUFBSSxtQ0FBSSxNQUFBLEtBQUssYUFBTCxLQUFLLHVCQUFMLEtBQUssQ0FBRSxLQUFLLDBDQUFFLElBQUksQ0FBQztnQkFDL0MsTUFBTSxLQUFLLEdBQUcsS0FBSyxhQUFMLEtBQUssdUJBQUwsS0FBSyxDQUFFLEtBQUssQ0FBQztnQkFDM0IsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxJQUFJLElBQUksS0FBSyxPQUFPLEVBQUU7b0JBQ3JDLE9BQU8sQ0FBQyxHQUFHLENBQUMsMEVBQTBFLEtBQUssYUFBTCxLQUFLLHVCQUFMLEtBQUssQ0FBRSxVQUFVLFdBQVcsS0FBSyxhQUFMLEtBQUssdUJBQUwsS0FBSyxDQUFFLEtBQUssTUFBTSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztvQkFDaEssTUFBTSxVQUFVLEdBQUcsS0FBSyxhQUFMLEtBQUssY0FBTCxLQUFLLEdBQUksTUFBQSxNQUFDLENBQTJELENBQUMsTUFBTSwwQ0FBRSxLQUFLLDBDQUFFLEtBQUssQ0FBQztvQkFDOUcsSUFBSSxVQUFVLElBQUksT0FBTyxVQUFVLEtBQUssUUFBUSxFQUFFO3dCQUNoRCxJQUFJLENBQUMsZUFBZSxDQUFDLFVBQVUsQ0FBQyxDQUFDO3dCQUNqQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsVUFBVSxDQUFDLENBQUM7cUJBQ3JDO2lCQUNGO1lBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxFQUFFLENBQUMsZUFBZSxFQUFFLENBQUMsS0FBeUYsRUFBRSxFQUFFO1lBQ3JILElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRTs7Z0JBQ25CLE1BQU0sQ0FBQyxHQUFHLEtBQUssYUFBTCxLQUFLLHVCQUFMLEtBQUssQ0FBRSxXQUFXLENBQUM7Z0JBQzdCLE1BQU0sSUFBSSxHQUFHLE1BQUEsS0FBSyxhQUFMLEtBQUssdUJBQUwsS0FBSyxDQUFFLElBQUksbUNBQUksTUFBQSxLQUFLLGFBQUwsS0FBSyx1QkFBTCxLQUFLLENBQUUsS0FBSywwQ0FBRSxJQUFJLENBQUM7Z0JBQy9DLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssSUFBSSxJQUFJLEtBQUssT0FBTyxFQUFFO29CQUNyQyxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztvQkFDOUIsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO2lCQUN4QjtZQUNILENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsRUFBRSxDQUFDLGNBQWMsRUFBRSxHQUFHLEVBQUU7WUFDM0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDeEMsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLEtBQTZCLEVBQUUsRUFBRTtZQUNqRCxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUU7O2dCQUNuQixPQUFPLENBQUMsS0FBSyxDQUFDLCtCQUErQixFQUFFLE1BQUEsS0FBSyxhQUFMLEtBQUssdUJBQUwsS0FBSyxDQUFFLFFBQVEsbUNBQUksS0FBSyxDQUFDLENBQUM7Z0JBQ3pFLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNqQixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7T0FHRztJQUNLLGVBQWUsQ0FBQyxLQUF1QjtRQUM3QyxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDdkIsSUFBSTtZQUNGLE9BQU8sQ0FBQyxHQUFHLENBQUMsMERBQTBELEtBQUssQ0FBQyxVQUFVLGlCQUFpQixLQUFLLENBQUMsS0FBSyxNQUFNLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBRXBKLEtBQUssQ0FBQyxRQUFRLEdBQUcsR0FBRyxFQUFFO2dCQUNwQixPQUFPLENBQUMsR0FBRyxDQUFDLG1FQUFtRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUM3RyxDQUFDLENBQUM7WUFFRixNQUFNLE1BQU0sR0FBRyxJQUFJLFdBQVcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFDeEMsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUMxQixLQUFLLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztZQUN0QixLQUFLLENBQUMsU0FBUyxHQUFHLE1BQU0sQ0FBQztZQUN6QixJQUFJLENBQUMsa0JBQWtCLEdBQUcsS0FBSyxDQUFDO1lBRWhDLEtBQUssQ0FBQyxTQUFTLEdBQUcsR0FBRyxFQUFFO2dCQUNyQixPQUFPLENBQUMsR0FBRyxDQUFDLG1FQUFtRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUM3RyxDQUFDLENBQUM7WUFFRixJQUFJLGVBQWUsR0FBRyxJQUFJLENBQUM7WUFDM0IsS0FBSyxDQUFDLFlBQVksR0FBRyxHQUFHLEVBQUU7Z0JBQ3hCLElBQUksZUFBZSxFQUFFO29CQUNuQixlQUFlLEdBQUcsS0FBSyxDQUFDO29CQUN4QixPQUFPLENBQUMsR0FBRyxDQUFDLHVFQUF1RSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztpQkFDaEg7WUFDSCxDQUFDLENBQUM7WUFFRixNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDdkIsSUFBSSxDQUFDLElBQUksT0FBTyxDQUFDLENBQUMsSUFBSSxLQUFLLFVBQVUsRUFBRTtnQkFDckMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUU7b0JBQ1YsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3Q0FBd0MsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ2xGLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO29CQUNmLE9BQU8sQ0FBQyxJQUFJLENBQUMsb0VBQW9FLEVBQUUsR0FBRyxDQUFDLENBQUM7Z0JBQzFGLENBQUMsQ0FBQyxDQUFDO2FBQ0o7U0FDRjtRQUFDLE9BQU8sR0FBRyxFQUFFO1lBQ1osT0FBTyxDQUFDLElBQUksQ0FBQyx5REFBeUQsRUFBRSxHQUFHLENBQUMsQ0FBQztTQUM5RTtJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSyxrQkFBa0IsQ0FBQyxLQUF1QjtRQUNoRCxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztRQUM5QixJQUFJO1lBQ0YsTUFBTSxHQUFHLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztZQUMvQixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsdUJBQXVCLENBQUMsSUFBSSxXQUFXLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDckUsTUFBTSxRQUFRLEdBQUcsR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3RDLFFBQVEsQ0FBQyxPQUFPLEdBQUcsR0FBRyxDQUFDO1lBQ3ZCLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDekIsSUFBSSxDQUFDLGtCQUFrQixHQUFHLEdBQUcsQ0FBQztZQUU5QixNQUFNLFNBQVMsR0FBRyxJQUFJLFVBQVUsQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUMsQ0FBQztZQUM3RCxNQUFNLFNBQVMsR0FBRyxDQUFDLENBQUM7WUFDcEIsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDO1lBQ3hCLElBQUksYUFBYSxHQUFHLENBQUMsQ0FBQztZQUN0QixJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUM7WUFFdkIsTUFBTSxJQUFJLEdBQUcsR0FBRyxFQUFFO2dCQUNoQixJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQjtvQkFBRSxPQUFPO2dCQUNyQyxRQUFRLENBQUMsb0JBQW9CLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBRXpDLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQztnQkFDWixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtvQkFDekMsR0FBRyxJQUFJLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztpQkFDckI7Z0JBQ0QsTUFBTSxHQUFHLEdBQUcsR0FBRyxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUM7Z0JBRW5DLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDdkIsSUFBSSxHQUFHLEdBQUcsU0FBUyxFQUFFO29CQUNuQixhQUFhLEdBQUcsR0FBRyxDQUFDO29CQUNwQixJQUFJLENBQUMsVUFBVSxFQUFFO3dCQUNmLFVBQVUsR0FBRyxJQUFJLENBQUM7d0JBQ2xCLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0VBQWdFLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLENBQUM7d0JBQzVILElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRTs0QkFDbkIsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQzs0QkFDckMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7d0JBQ2xDLENBQUMsQ0FBQyxDQUFDO3FCQUNKO2lCQUNGO3FCQUFNLElBQUksVUFBVSxJQUFJLEdBQUcsR0FBRyxhQUFhLEdBQUcsVUFBVSxFQUFFO29CQUN6RCxVQUFVLEdBQUcsS0FBSyxDQUFDO29CQUNuQixPQUFPLENBQUMsR0FBRyxDQUFDLDhEQUE4RCxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztvQkFDdEcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztpQkFDekQ7Z0JBRUQsSUFBSSxDQUFDLGlCQUFpQixHQUFHLHFCQUFxQixDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3ZELENBQUMsQ0FBQztZQUVGLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUN0RDtRQUFDLE9BQU8sR0FBRyxFQUFFO1lBQ1osT0FBTyxDQUFDLElBQUksQ0FBQyx5REFBeUQsRUFBRSxHQUFHLENBQUMsQ0FBQztTQUM5RTtJQUNILENBQUM7SUFFTyxzQkFBc0I7UUFDNUIsSUFBSSxJQUFJLENBQUMsaUJBQWlCLEVBQUU7WUFDMUIsb0JBQW9CLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7WUFDN0MsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQztTQUMvQjtRQUNELElBQUksSUFBSSxDQUFDLGtCQUFrQixFQUFFO1lBQzNCLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7WUFDaEQsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQztTQUNoQztJQUNILENBQUM7SUFFTyxlQUFlO1FBQ3JCLElBQUksSUFBSSxDQUFDLGtCQUFrQixFQUFFO1lBQzNCLElBQUk7Z0JBQ0YsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUNoQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQzthQUMxQztZQUFDLE9BQU8sQ0FBQyxFQUFFLEdBQUU7WUFDZCxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDO1NBQ2hDO0lBQ0gsQ0FBQztJQUVELDJCQUEyQjtJQUMzQixRQUFRLENBQUMsS0FBYztRQUNyQixJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVU7WUFBRSxPQUFPO1FBQzdCLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdEMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUVELDhCQUE4QjtJQUN4QixVQUFVOztZQUNkLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFO2dCQUNwQixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ2YsT0FBTzthQUNSO1lBQ0QsSUFBSTtnQkFDRixNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7YUFDL0I7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDVixTQUFTO2FBQ1Y7WUFDRCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDakIsQ0FBQztLQUFBO0lBRU8sT0FBTztRQUNiLElBQUksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO1FBQzlCLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN2QixJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDbkIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7WUFDMUMsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUM7U0FDeEI7UUFDRCxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDcEIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQ3RELElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1NBQ3pCO1FBQ0QsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7UUFDM0IsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDakMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNyQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ25DLHVEQUF1RDtJQUN6RCxDQUFDOzs7O1lBOVNGLFVBQVUsU0FBQztnQkFDVixVQUFVLEVBQUUsTUFBTTthQUNuQjs7O1lBbEJvQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgTmdab25lIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcbmltcG9ydCBEYWlseSBmcm9tICdAZGFpbHktY28vZGFpbHktanMnO1xuaW1wb3J0IHR5cGUgeyBEYWlseUNhbGwsIERhaWx5UGFydGljaXBhbnQgfSBmcm9tICdAZGFpbHktY28vZGFpbHktanMnO1xuXG4vKipcbiAqIERhaWx5LmpzIFdlYlJUQyBjbGllbnQgZm9yIHZvaWNlIGFnZW50IGF1ZGlvLlxuICogUmVzcG9uc2liaWxpdGllczpcbiAqIC0gQ3JlYXRlIGFuZCBtYW5hZ2UgRGFpbHkgQ2FsbE9iamVjdFxuICogLSBKb2luIERhaWx5IHJvb20gdXNpbmcgcm9vbV91cmxcbiAqIC0gSGFuZGxlIG1pYyBjYXB0dXJlICsgc3BlYWtlciBwbGF5YmFja1xuICogLSBCb3Qgc3BlYWtpbmcgZGV0ZWN0aW9uIHZpYSBBbmFseXNlck5vZGUgb24gcmVtb3RlIHRyYWNrIChpbnN0YW50KVxuICogLSBVc2VyIHNwZWFraW5nIGRldGVjdGlvbiB2aWEgYWN0aXZlLXNwZWFrZXItY2hhbmdlXG4gKiAtIEV4cG9zZSBzcGVha2luZyQgKGJvdCBzcGVha2luZyksIHVzZXJTcGVha2luZyQgKHVzZXIgc3BlYWtpbmcpLCBtaWNNdXRlZCRcbiAqIC0gRXhwb3NlIGxvY2FsU3RyZWFtJCBmb3Igd2F2ZWZvcm0gdmlzdWFsaXphdGlvbiAoQXVkaW9BbmFseXplclNlcnZpY2UpXG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxufSlcbmV4cG9ydCBjbGFzcyBEYWlseVZvaWNlQ2xpZW50U2VydmljZSB7XG4gIHByaXZhdGUgY2FsbE9iamVjdDogRGFpbHlDYWxsIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgbG9jYWxTdHJlYW06IE1lZGlhU3RyZWFtIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgbG9jYWxTZXNzaW9uSWQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAvKiogRXhwbGljaXQgcGxheWJhY2sgb2YgcmVtb3RlIChib3QpIGF1ZGlvOyByZXF1aXJlZCBpbiBzb21lIGJyb3dzZXJzLiAqL1xuICBwcml2YXRlIHJlbW90ZUF1ZGlvRWxlbWVudDogSFRNTEF1ZGlvRWxlbWVudCB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBBbmFseXNlck5vZGUtYmFzZWQgcmVtb3RlIGF1ZGlvIG1vbml0b3IgZm9yIGluc3RhbnQgYm90IHNwZWFraW5nIGRldGVjdGlvbi4gKi9cbiAgcHJpdmF0ZSByZW1vdGVBdWRpb0NvbnRleHQ6IEF1ZGlvQ29udGV4dCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHJlbW90ZVNwZWFraW5nUkFGOiBudW1iZXIgfCBudWxsID0gbnVsbDtcblxuICBwcml2YXRlIHNwZWFraW5nU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICBwcml2YXRlIHVzZXJTcGVha2luZ1N1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgcHJpdmF0ZSBtaWNNdXRlZFN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgcHJpdmF0ZSBsb2NhbFN0cmVhbVN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PE1lZGlhU3RyZWFtIHwgbnVsbD4obnVsbCk7XG5cbiAgLyoqIFRydWUgd2hlbiBib3QgKHJlbW90ZSBwYXJ0aWNpcGFudCkgaXMgdGhlIGFjdGl2ZSBzcGVha2VyLiAqL1xuICBzcGVha2luZyQ6IE9ic2VydmFibGU8Ym9vbGVhbj4gPSB0aGlzLnNwZWFraW5nU3ViamVjdC5hc09ic2VydmFibGUoKTtcblxuICAvKiogVHJ1ZSB3aGVuIHVzZXIgKGxvY2FsIHBhcnRpY2lwYW50KSBpcyB0aGUgYWN0aXZlIHNwZWFrZXIuICovXG4gIHVzZXJTcGVha2luZyQ6IE9ic2VydmFibGU8Ym9vbGVhbj4gPSB0aGlzLnVzZXJTcGVha2luZ1N1YmplY3QuYXNPYnNlcnZhYmxlKCk7XG5cbiAgLyoqIFRydWUgd2hlbiBtaWMgaXMgbXV0ZWQuICovXG4gIG1pY011dGVkJDogT2JzZXJ2YWJsZTxib29sZWFuPiA9IHRoaXMubWljTXV0ZWRTdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xuXG4gIC8qKiBFbWl0cyBsb2NhbCBtaWMgc3RyZWFtIGZvciB3YXZlZm9ybSB2aXN1YWxpemF0aW9uLiAqL1xuICBsb2NhbFN0cmVhbSQ6IE9ic2VydmFibGU8TWVkaWFTdHJlYW0gfCBudWxsPiA9XG4gICAgdGhpcy5sb2NhbFN0cmVhbVN1YmplY3QuYXNPYnNlcnZhYmxlKCk7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBuZ1pvbmU6IE5nWm9uZSkge31cblxuICAvKipcbiAgICogQ29ubmVjdCB0byBEYWlseSByb29tLiBBY3F1aXJlcyBtaWMgZmlyc3QgZm9yIHdhdmVmb3JtLCB0aGVuIGpvaW5zIHdpdGggYXVkaW8uXG4gICAqIEBwYXJhbSByb29tVXJsIERhaWx5IHJvb20gVVJMIChmcm9tIHJvb21fY3JlYXRlZClcbiAgICogQHBhcmFtIHRva2VuIE9wdGlvbmFsIG1lZXRpbmcgdG9rZW5cbiAgICovXG4gIGFzeW5jIGNvbm5lY3Qocm9vbVVybDogc3RyaW5nLCB0b2tlbj86IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNhbGxPYmplY3QpIHtcbiAgICAgIGF3YWl0IHRoaXMuZGlzY29ubmVjdCgpO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICAvLyBHZXQgbWljIHN0cmVhbSBmb3IgYm90aCBEYWlseSBhbmQgd2F2ZWZvcm0gKHNpbmdsZSBjYXB0dXJlKVxuICAgICAgY29uc3Qgc3RyZWFtID0gYXdhaXQgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEoeyBhdWRpbzogdHJ1ZSB9KTtcbiAgICAgIGNvbnN0IGF1ZGlvVHJhY2sgPSBzdHJlYW0uZ2V0QXVkaW9UcmFja3MoKVswXTtcbiAgICAgIGlmICghYXVkaW9UcmFjaykge1xuICAgICAgICBzdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaCgodCkgPT4gdC5zdG9wKCkpO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGF1ZGlvIHRyYWNrJyk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMubG9jYWxTdHJlYW0gPSBzdHJlYW07XG4gICAgICB0aGlzLmxvY2FsU3RyZWFtU3ViamVjdC5uZXh0KHN0cmVhbSk7XG5cbiAgICAgIC8vIENyZWF0ZSBhdWRpby1vbmx5IGNhbGwgb2JqZWN0XG4gICAgICAvLyB2aWRlb1NvdXJjZTogZmFsc2UgPSBubyBjYW1lcmEsIGF1ZGlvU291cmNlID0gb3VyIG1pYyB0cmFja1xuICAgICAgY29uc3QgY2FsbE9iamVjdCA9IERhaWx5LmNyZWF0ZUNhbGxPYmplY3Qoe1xuICAgICAgICB2aWRlb1NvdXJjZTogZmFsc2UsXG4gICAgICAgIGF1ZGlvU291cmNlOiBhdWRpb1RyYWNrLFxuICAgICAgfSk7XG5cbiAgICAgIHRoaXMuY2FsbE9iamVjdCA9IGNhbGxPYmplY3Q7XG5cbiAgICAgIHRoaXMuc2V0dXBFdmVudEhhbmRsZXJzKGNhbGxPYmplY3QpO1xuXG4gICAgICAvLyBKb2luIHJvb207IERhaWx5IGhhbmRsZXMgcGxheWJhY2sgb2YgcmVtb3RlIChib3QpIGF1ZGlvIGF1dG9tYXRpY2FsbHkuXG4gICAgICAvLyBPbmx5IHBhc3MgdG9rZW4gd2hlbiBpdCdzIGEgbm9uLWVtcHR5IHN0cmluZyAoRGFpbHkgcmVqZWN0cyB1bmRlZmluZWQvbm9uLXN0cmluZykuXG4gICAgICBjb25zdCBqb2luT3B0aW9uczogeyB1cmw6IHN0cmluZzsgdG9rZW4/OiBzdHJpbmcgfSA9IHsgdXJsOiByb29tVXJsIH07XG4gICAgICBpZiAodHlwZW9mIHRva2VuID09PSAnc3RyaW5nJyAmJiB0b2tlbi50cmltKCkgIT09ICcnKSB7XG4gICAgICAgIGpvaW5PcHRpb25zLnRva2VuID0gdG9rZW47XG4gICAgICB9XG4gICAgICBhd2FpdCBjYWxsT2JqZWN0LmpvaW4oam9pbk9wdGlvbnMpO1xuICAgICAgY29uc29sZS5sb2coYFtWb2ljZURlYnVnXSBSb29tIGNvbm5lY3RlZCAoRGFpbHkgam9pbiBjb21wbGV0ZSkg4oCUICR7bmV3IERhdGUoKS50b0lTT1N0cmluZygpfWApO1xuXG4gICAgICBjb25zdCBwYXJ0aWNpcGFudHMgPSBjYWxsT2JqZWN0LnBhcnRpY2lwYW50cygpO1xuICAgICAgaWYgKHBhcnRpY2lwYW50cz8ubG9jYWwpIHtcbiAgICAgICAgdGhpcy5sb2NhbFNlc3Npb25JZCA9IHBhcnRpY2lwYW50cy5sb2NhbC5zZXNzaW9uX2lkO1xuICAgICAgfVxuXG4gICAgICAvLyBJbml0aWFsIG11dGUgc3RhdGU6IERhaWx5IHN0YXJ0cyB3aXRoIGF1ZGlvIG9uXG4gICAgICB0aGlzLm1pY011dGVkU3ViamVjdC5uZXh0KCFjYWxsT2JqZWN0LmxvY2FsQXVkaW8oKSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aGlzLmNsZWFudXAoKTtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldHVwRXZlbnRIYW5kbGVycyhjYWxsOiBEYWlseUNhbGwpOiB2b2lkIHtcbiAgICAvLyBhY3RpdmUtc3BlYWtlci1jaGFuZ2U6IHVzZWQgT05MWSBmb3IgdXNlciBzcGVha2luZyBkZXRlY3Rpb24uXG4gICAgLy8gQm90IHNwZWFraW5nIGlzIGRldGVjdGVkIGJ5IG91ciBvd24gQW5hbHlzZXJOb2RlIChpbnN0YW50LCBubyBkZWJvdW5jZSkuXG4gICAgY2FsbC5vbignYWN0aXZlLXNwZWFrZXItY2hhbmdlJywgKGV2ZW50OiB7IGFjdGl2ZVNwZWFrZXI/OiB7IHBlZXJJZD86IHN0cmluZyB9IH0pID0+IHtcbiAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgIGNvbnN0IHBlZXJJZCA9IGV2ZW50Py5hY3RpdmVTcGVha2VyPy5wZWVySWQ7XG4gICAgICAgIGlmICghcGVlcklkIHx8ICF0aGlzLmxvY2FsU2Vzc2lvbklkKSB7XG4gICAgICAgICAgdGhpcy51c2VyU3BlYWtpbmdTdWJqZWN0Lm5leHQoZmFsc2UpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBpc0xvY2FsID0gcGVlcklkID09PSB0aGlzLmxvY2FsU2Vzc2lvbklkO1xuICAgICAgICB0aGlzLnVzZXJTcGVha2luZ1N1YmplY3QubmV4dChpc0xvY2FsKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgLy8gdHJhY2stc3RhcnRlZCAvIHRyYWNrLXN0b3BwZWQ6IHNldCB1cCByZW1vdGUgYXVkaW8gcGxheWJhY2sgKyBBbmFseXNlck5vZGUgbW9uaXRvci5cbiAgICBjYWxsLm9uKCd0cmFjay1zdGFydGVkJywgKGV2ZW50OiB7IHBhcnRpY2lwYW50PzogRGFpbHlQYXJ0aWNpcGFudCB8IG51bGw7IHR5cGU/OiBzdHJpbmc7IHRyYWNrPzogTWVkaWFTdHJlYW1UcmFjayB9KSA9PiB7XG4gICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICBjb25zdCBwID0gZXZlbnQ/LnBhcnRpY2lwYW50O1xuICAgICAgICBjb25zdCB0eXBlID0gZXZlbnQ/LnR5cGUgPz8gZXZlbnQ/LnRyYWNrPy5raW5kO1xuICAgICAgICBjb25zdCB0cmFjayA9IGV2ZW50Py50cmFjaztcbiAgICAgICAgaWYgKHAgJiYgIXAubG9jYWwgJiYgdHlwZSA9PT0gJ2F1ZGlvJykge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGBbVm9pY2VEZWJ1Z10gR290IGF1ZGlvIHRyYWNrIGZyb20gYmFja2VuZCAodHJhY2stc3RhcnRlZCkg4oCUIHJlYWR5U3RhdGU9JHt0cmFjaz8ucmVhZHlTdGF0ZX0sIG11dGVkPSR7dHJhY2s/Lm11dGVkfSDigJQgJHtuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCl9YCk7XG4gICAgICAgICAgY29uc3QgYXVkaW9UcmFjayA9IHRyYWNrID8/IChwIGFzIHsgdHJhY2tzPzogeyBhdWRpbz86IHsgdHJhY2s/OiBNZWRpYVN0cmVhbVRyYWNrIH0gfSB9KS50cmFja3M/LmF1ZGlvPy50cmFjaztcbiAgICAgICAgICBpZiAoYXVkaW9UcmFjayAmJiB0eXBlb2YgYXVkaW9UcmFjayA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHRoaXMucGxheVJlbW90ZVRyYWNrKGF1ZGlvVHJhY2spO1xuICAgICAgICAgICAgdGhpcy5tb25pdG9yUmVtb3RlQXVkaW8oYXVkaW9UcmFjayk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGNhbGwub24oJ3RyYWNrLXN0b3BwZWQnLCAoZXZlbnQ6IHsgcGFydGljaXBhbnQ/OiBEYWlseVBhcnRpY2lwYW50IHwgbnVsbDsgdHlwZT86IHN0cmluZzsgdHJhY2s/OiBNZWRpYVN0cmVhbVRyYWNrIH0pID0+IHtcbiAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgIGNvbnN0IHAgPSBldmVudD8ucGFydGljaXBhbnQ7XG4gICAgICAgIGNvbnN0IHR5cGUgPSBldmVudD8udHlwZSA/PyBldmVudD8udHJhY2s/LmtpbmQ7XG4gICAgICAgIGlmIChwICYmICFwLmxvY2FsICYmIHR5cGUgPT09ICdhdWRpbycpIHtcbiAgICAgICAgICB0aGlzLnN0b3BSZW1vdGVBdWRpb01vbml0b3IoKTtcbiAgICAgICAgICB0aGlzLnN0b3BSZW1vdGVBdWRpbygpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGNhbGwub24oJ2xlZnQtbWVldGluZycsICgpID0+IHtcbiAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB0aGlzLmNsZWFudXAoKSk7XG4gICAgfSk7XG5cbiAgICBjYWxsLm9uKCdlcnJvcicsIChldmVudD86IHsgZXJyb3JNc2c/OiBzdHJpbmcgfSkgPT4ge1xuICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcignRGFpbHlWb2ljZUNsaWVudDogRGFpbHkgZXJyb3InLCBldmVudD8uZXJyb3JNc2cgPz8gZXZlbnQpO1xuICAgICAgICB0aGlzLmNsZWFudXAoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFBsYXkgcmVtb3RlIChib3QpIGF1ZGlvIHRyYWNrIHZpYSBhIGRlZGljYXRlZCBhdWRpbyBlbGVtZW50LlxuICAgKiBSZXF1aXJlZCBpbiBtYW55IGJyb3dzZXJzIHdoZXJlIERhaWx5J3MgaW50ZXJuYWwgcGxheWJhY2sgZG9lcyBub3Qgb3V0cHV0IHRvIHNwZWFrZXJzLlxuICAgKi9cbiAgcHJpdmF0ZSBwbGF5UmVtb3RlVHJhY2sodHJhY2s6IE1lZGlhU3RyZWFtVHJhY2spOiB2b2lkIHtcbiAgICB0aGlzLnN0b3BSZW1vdGVBdWRpbygpO1xuICAgIHRyeSB7XG4gICAgICBjb25zb2xlLmxvZyhgW1ZvaWNlRGVidWddIHBsYXlSZW1vdGVUcmFjayBjYWxsZWQg4oCUIHRyYWNrLnJlYWR5U3RhdGU9JHt0cmFjay5yZWFkeVN0YXRlfSwgdHJhY2subXV0ZWQ9JHt0cmFjay5tdXRlZH0g4oCUICR7bmV3IERhdGUoKS50b0lTT1N0cmluZygpfWApO1xuXG4gICAgICB0cmFjay5vbnVubXV0ZSA9ICgpID0+IHtcbiAgICAgICAgY29uc29sZS5sb2coYFtWb2ljZURlYnVnXSBSZW1vdGUgYXVkaW8gdHJhY2sgVU5NVVRFRCAoYXVkaW8gZGF0YSBhcnJpdmluZykg4oCUICR7bmV3IERhdGUoKS50b0lTT1N0cmluZygpfWApO1xuICAgICAgfTtcblxuICAgICAgY29uc3Qgc3RyZWFtID0gbmV3IE1lZGlhU3RyZWFtKFt0cmFja10pO1xuICAgICAgY29uc3QgYXVkaW8gPSBuZXcgQXVkaW8oKTtcbiAgICAgIGF1ZGlvLmF1dG9wbGF5ID0gdHJ1ZTtcbiAgICAgIGF1ZGlvLnNyY09iamVjdCA9IHN0cmVhbTtcbiAgICAgIHRoaXMucmVtb3RlQXVkaW9FbGVtZW50ID0gYXVkaW87XG5cbiAgICAgIGF1ZGlvLm9ucGxheWluZyA9ICgpID0+IHtcbiAgICAgICAgY29uc29sZS5sb2coYFtWb2ljZURlYnVnXSBBdWRpbyBlbGVtZW50IFBMQVlJTkcgKGJyb3dzZXIgc3RhcnRlZCBwbGF5YmFjaykg4oCUICR7bmV3IERhdGUoKS50b0lTT1N0cmluZygpfWApO1xuICAgICAgfTtcblxuICAgICAgbGV0IGZpcnN0VGltZVVwZGF0ZSA9IHRydWU7XG4gICAgICBhdWRpby5vbnRpbWV1cGRhdGUgPSAoKSA9PiB7XG4gICAgICAgIGlmIChmaXJzdFRpbWVVcGRhdGUpIHtcbiAgICAgICAgICBmaXJzdFRpbWVVcGRhdGUgPSBmYWxzZTtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgW1ZvaWNlRGVidWddIEF1ZGlvIGVsZW1lbnQgZmlyc3QgVElNRVVQREFURSAoYWN0dWFsIGF1ZGlvIG91dHB1dCkg4oCUICR7bmV3IERhdGUoKS50b0lTT1N0cmluZygpfWApO1xuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICBjb25zdCBwID0gYXVkaW8ucGxheSgpO1xuICAgICAgaWYgKHAgJiYgdHlwZW9mIHAudGhlbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBwLnRoZW4oKCkgPT4ge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGBbVm9pY2VEZWJ1Z10gYXVkaW8ucGxheSgpIHJlc29sdmVkIOKAlCAke25ldyBEYXRlKCkudG9JU09TdHJpbmcoKX1gKTtcbiAgICAgICAgfSkuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgIGNvbnNvbGUud2FybignRGFpbHlWb2ljZUNsaWVudDogcmVtb3RlIGF1ZGlvIHBsYXkgZmFpbGVkIChtYXkgbmVlZCB1c2VyIGdlc3R1cmUpJywgZXJyKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ0RhaWx5Vm9pY2VDbGllbnQ6IGZhaWxlZCB0byBjcmVhdGUgcmVtb3RlIGF1ZGlvIGVsZW1lbnQnLCBlcnIpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBNb25pdG9yIHJlbW90ZSBhdWRpbyB0cmFjayBlbmVyZ3kgdmlhIEFuYWx5c2VyTm9kZS5cbiAgICogUG9sbHMgYXQgfjYwZnBzIGFuZCBmbGlwcyBzcGVha2luZ1N1YmplY3QgYmFzZWQgb24gYWN0dWFsIGF1ZGlvIGVuZXJneS5cbiAgICovXG4gIHByaXZhdGUgbW9uaXRvclJlbW90ZUF1ZGlvKHRyYWNrOiBNZWRpYVN0cmVhbVRyYWNrKTogdm9pZCB7XG4gICAgdGhpcy5zdG9wUmVtb3RlQXVkaW9Nb25pdG9yKCk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGN0eCA9IG5ldyBBdWRpb0NvbnRleHQoKTtcbiAgICAgIGNvbnN0IHNvdXJjZSA9IGN0eC5jcmVhdGVNZWRpYVN0cmVhbVNvdXJjZShuZXcgTWVkaWFTdHJlYW0oW3RyYWNrXSkpO1xuICAgICAgY29uc3QgYW5hbHlzZXIgPSBjdHguY3JlYXRlQW5hbHlzZXIoKTtcbiAgICAgIGFuYWx5c2VyLmZmdFNpemUgPSAyNTY7XG4gICAgICBzb3VyY2UuY29ubmVjdChhbmFseXNlcik7XG4gICAgICB0aGlzLnJlbW90ZUF1ZGlvQ29udGV4dCA9IGN0eDtcblxuICAgICAgY29uc3QgZGF0YUFycmF5ID0gbmV3IFVpbnQ4QXJyYXkoYW5hbHlzZXIuZnJlcXVlbmN5QmluQ291bnQpO1xuICAgICAgY29uc3QgVEhSRVNIT0xEID0gNTtcbiAgICAgIGNvbnN0IFNJTEVOQ0VfTVMgPSAxNTAwO1xuICAgICAgbGV0IGxhc3RTb3VuZFRpbWUgPSAwO1xuICAgICAgbGV0IGlzU3BlYWtpbmcgPSBmYWxzZTtcblxuICAgICAgY29uc3QgcG9sbCA9ICgpID0+IHtcbiAgICAgICAgaWYgKCF0aGlzLnJlbW90ZUF1ZGlvQ29udGV4dCkgcmV0dXJuO1xuICAgICAgICBhbmFseXNlci5nZXRCeXRlRnJlcXVlbmN5RGF0YShkYXRhQXJyYXkpO1xuXG4gICAgICAgIGxldCBzdW0gPSAwO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRhdGFBcnJheS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHN1bSArPSBkYXRhQXJyYXlbaV07XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYXZnID0gc3VtIC8gZGF0YUFycmF5Lmxlbmd0aDtcblxuICAgICAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgICAgICBpZiAoYXZnID4gVEhSRVNIT0xEKSB7XG4gICAgICAgICAgbGFzdFNvdW5kVGltZSA9IG5vdztcbiAgICAgICAgICBpZiAoIWlzU3BlYWtpbmcpIHtcbiAgICAgICAgICAgIGlzU3BlYWtpbmcgPSB0cnVlO1xuICAgICAgICAgICAgY29uc29sZS5sb2coYFtWb2ljZURlYnVnXSBCb3QgYXVkaW8gZW5lcmd5IGRldGVjdGVkIChzcGVha2luZz10cnVlKSDigJQgYXZnPSR7YXZnLnRvRml4ZWQoMSl9IOKAlCAke25ldyBEYXRlKCkudG9JU09TdHJpbmcoKX1gKTtcbiAgICAgICAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgICAgICAgIHRoaXMudXNlclNwZWFraW5nU3ViamVjdC5uZXh0KGZhbHNlKTtcbiAgICAgICAgICAgICAgdGhpcy5zcGVha2luZ1N1YmplY3QubmV4dCh0cnVlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChpc1NwZWFraW5nICYmIG5vdyAtIGxhc3RTb3VuZFRpbWUgPiBTSUxFTkNFX01TKSB7XG4gICAgICAgICAgaXNTcGVha2luZyA9IGZhbHNlO1xuICAgICAgICAgIGNvbnNvbGUubG9nKGBbVm9pY2VEZWJ1Z10gQm90IGF1ZGlvIHNpbGVuY2UgZGV0ZWN0ZWQgKHNwZWFraW5nPWZhbHNlKSDigJQgJHtuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCl9YCk7XG4gICAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHRoaXMuc3BlYWtpbmdTdWJqZWN0Lm5leHQoZmFsc2UpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVtb3RlU3BlYWtpbmdSQUYgPSByZXF1ZXN0QW5pbWF0aW9uRnJhbWUocG9sbCk7XG4gICAgICB9O1xuXG4gICAgICB0aGlzLnJlbW90ZVNwZWFraW5nUkFGID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKHBvbGwpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS53YXJuKCdEYWlseVZvaWNlQ2xpZW50OiBmYWlsZWQgdG8gY3JlYXRlIHJlbW90ZSBhdWRpbyBtb25pdG9yJywgZXJyKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHN0b3BSZW1vdGVBdWRpb01vbml0b3IoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucmVtb3RlU3BlYWtpbmdSQUYpIHtcbiAgICAgIGNhbmNlbEFuaW1hdGlvbkZyYW1lKHRoaXMucmVtb3RlU3BlYWtpbmdSQUYpO1xuICAgICAgdGhpcy5yZW1vdGVTcGVha2luZ1JBRiA9IG51bGw7XG4gICAgfVxuICAgIGlmICh0aGlzLnJlbW90ZUF1ZGlvQ29udGV4dCkge1xuICAgICAgdGhpcy5yZW1vdGVBdWRpb0NvbnRleHQuY2xvc2UoKS5jYXRjaCgoKSA9PiB7fSk7XG4gICAgICB0aGlzLnJlbW90ZUF1ZGlvQ29udGV4dCA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzdG9wUmVtb3RlQXVkaW8oKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucmVtb3RlQXVkaW9FbGVtZW50KSB7XG4gICAgICB0cnkge1xuICAgICAgICB0aGlzLnJlbW90ZUF1ZGlvRWxlbWVudC5wYXVzZSgpO1xuICAgICAgICB0aGlzLnJlbW90ZUF1ZGlvRWxlbWVudC5zcmNPYmplY3QgPSBudWxsO1xuICAgICAgfSBjYXRjaCAoXykge31cbiAgICAgIHRoaXMucmVtb3RlQXVkaW9FbGVtZW50ID0gbnVsbDtcbiAgICB9XG4gIH1cblxuICAvKiogU2V0IG1pYyBtdXRlZCBzdGF0ZS4gKi9cbiAgc2V0TXV0ZWQobXV0ZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuY2FsbE9iamVjdCkgcmV0dXJuO1xuICAgIHRoaXMuY2FsbE9iamVjdC5zZXRMb2NhbEF1ZGlvKCFtdXRlZCk7XG4gICAgdGhpcy5taWNNdXRlZFN1YmplY3QubmV4dChtdXRlZCk7XG4gIH1cblxuICAvKiogRGlzY29ubmVjdCBhbmQgY2xlYW51cC4gKi9cbiAgYXN5bmMgZGlzY29ubmVjdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMuY2FsbE9iamVjdCkge1xuICAgICAgdGhpcy5jbGVhbnVwKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmNhbGxPYmplY3QubGVhdmUoKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyBpZ25vcmVcbiAgICB9XG4gICAgdGhpcy5jbGVhbnVwKCk7XG4gIH1cblxuICBwcml2YXRlIGNsZWFudXAoKTogdm9pZCB7XG4gICAgdGhpcy5zdG9wUmVtb3RlQXVkaW9Nb25pdG9yKCk7XG4gICAgdGhpcy5zdG9wUmVtb3RlQXVkaW8oKTtcbiAgICBpZiAodGhpcy5jYWxsT2JqZWN0KSB7XG4gICAgICB0aGlzLmNhbGxPYmplY3QuZGVzdHJveSgpLmNhdGNoKCgpID0+IHt9KTtcbiAgICAgIHRoaXMuY2FsbE9iamVjdCA9IG51bGw7XG4gICAgfVxuICAgIGlmICh0aGlzLmxvY2FsU3RyZWFtKSB7XG4gICAgICB0aGlzLmxvY2FsU3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goKHQpID0+IHQuc3RvcCgpKTtcbiAgICAgIHRoaXMubG9jYWxTdHJlYW0gPSBudWxsO1xuICAgIH1cbiAgICB0aGlzLmxvY2FsU2Vzc2lvbklkID0gbnVsbDtcbiAgICB0aGlzLnNwZWFraW5nU3ViamVjdC5uZXh0KGZhbHNlKTtcbiAgICB0aGlzLnVzZXJTcGVha2luZ1N1YmplY3QubmV4dChmYWxzZSk7XG4gICAgdGhpcy5sb2NhbFN0cmVhbVN1YmplY3QubmV4dChudWxsKTtcbiAgICAvLyBLZWVwIGxhc3QgbWljTXV0ZWQgc3RhdGU7IHdpbGwgcmVzZXQgb24gbmV4dCBjb25uZWN0XG4gIH1cbn1cbiJdfQ==
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { NgZone } from '@angular/core';
|
|
2
|
-
import { Observable } from 'rxjs';
|
|
3
|
-
/**
|
|
4
|
-
* Daily.js WebRTC client for voice agent audio.
|
|
5
|
-
* Responsibilities:
|
|
6
|
-
* - Create and manage Daily CallObject
|
|
7
|
-
* - Join Daily room using room_url
|
|
8
|
-
* - Handle mic capture + speaker playback
|
|
9
|
-
* - Bot speaking detection via AnalyserNode on remote track (instant)
|
|
10
|
-
* - User speaking detection via active-speaker-change
|
|
11
|
-
* - Expose speaking$ (bot speaking), userSpeaking$ (user speaking), micMuted$
|
|
12
|
-
* - Expose localStream$ for waveform visualization (AudioAnalyzerService)
|
|
13
|
-
*/
|
|
14
|
-
export declare class DailyVoiceClientService {
|
|
15
|
-
private ngZone;
|
|
16
|
-
private callObject;
|
|
17
|
-
private localStream;
|
|
18
|
-
private localSessionId;
|
|
19
|
-
/** Explicit playback of remote (bot) audio; required in some browsers. */
|
|
20
|
-
private remoteAudioElement;
|
|
21
|
-
/** AnalyserNode-based remote audio monitor for instant bot speaking detection. */
|
|
22
|
-
private remoteAudioContext;
|
|
23
|
-
private remoteSpeakingRAF;
|
|
24
|
-
private speakingSubject;
|
|
25
|
-
private userSpeakingSubject;
|
|
26
|
-
private micMutedSubject;
|
|
27
|
-
private localStreamSubject;
|
|
28
|
-
/** True when bot (remote participant) is the active speaker. */
|
|
29
|
-
speaking$: Observable<boolean>;
|
|
30
|
-
/** True when user (local participant) is the active speaker. */
|
|
31
|
-
userSpeaking$: Observable<boolean>;
|
|
32
|
-
/** True when mic is muted. */
|
|
33
|
-
micMuted$: Observable<boolean>;
|
|
34
|
-
/** Emits local mic stream for waveform visualization. */
|
|
35
|
-
localStream$: Observable<MediaStream | null>;
|
|
36
|
-
constructor(ngZone: NgZone);
|
|
37
|
-
/**
|
|
38
|
-
* Connect to Daily room. Acquires mic first for waveform, then joins with audio.
|
|
39
|
-
* @param roomUrl Daily room URL (from room_created)
|
|
40
|
-
* @param token Optional meeting token
|
|
41
|
-
*/
|
|
42
|
-
connect(roomUrl: string, token?: string): Promise<void>;
|
|
43
|
-
private setupEventHandlers;
|
|
44
|
-
/**
|
|
45
|
-
* Play remote (bot) audio track via a dedicated audio element.
|
|
46
|
-
* Required in many browsers where Daily's internal playback does not output to speakers.
|
|
47
|
-
*/
|
|
48
|
-
private playRemoteTrack;
|
|
49
|
-
/**
|
|
50
|
-
* Monitor remote audio track energy via AnalyserNode.
|
|
51
|
-
* Polls at ~60fps and flips speakingSubject based on actual audio energy.
|
|
52
|
-
*/
|
|
53
|
-
private monitorRemoteAudio;
|
|
54
|
-
private stopRemoteAudioMonitor;
|
|
55
|
-
private stopRemoteAudio;
|
|
56
|
-
/** Set mic muted state. */
|
|
57
|
-
setMuted(muted: boolean): void;
|
|
58
|
-
/** Disconnect and cleanup. */
|
|
59
|
-
disconnect(): Promise<void>;
|
|
60
|
-
private cleanup;
|
|
61
|
-
}
|
|
62
|
-
//# sourceMappingURL=daily-voice-client.service.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"daily-voice-client.service.d.ts","sourceRoot":"/Users/rohitthakur/hive-gpt/HiveAI-Packages/Angular/projects/hivegpt/eventsgpt-angular/src/","sources":["lib/components/voice-agent/services/daily-voice-client.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAmB,UAAU,EAAE,MAAM,MAAM,CAAC;AAInD;;;;;;;;;;GAUG;AACH,qBAGa,uBAAuB;IA6BtB,OAAO,CAAC,MAAM;IA5B1B,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,cAAc,CAAuB;IAC7C,0EAA0E;IAC1E,OAAO,CAAC,kBAAkB,CAAiC;IAE3D,kFAAkF;IAClF,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,iBAAiB,CAAuB;IAEhD,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,mBAAmB,CAAuC;IAClE,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,kBAAkB,CAAiD;IAE3E,gEAAgE;IAChE,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,CAAuC;IAErE,gEAAgE;IAChE,aAAa,EAAE,UAAU,CAAC,OAAO,CAAC,CAA2C;IAE7E,8BAA8B;IAC9B,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,CAAuC;IAErE,yDAAyD;IACzD,YAAY,EAAE,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC,CACH;gBAErB,MAAM,EAAE,MAAM;IAElC;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkD7D,OAAO,CAAC,kBAAkB;IAuD1B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAwCvB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAoD1B,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,eAAe;IAUvB,2BAA2B;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAM9B,8BAA8B;IACxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAajC,OAAO,CAAC,OAAO;CAiBhB"}
|