@conference-kit/vue 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,10 @@
1
1
  import { ref, onMounted, onUnmounted, computed, watch } from "vue";
2
2
  import { Peer } from "@conference-kit/core";
3
3
  import { SignalingClient } from "./signaling";
4
+ import { mergeFeatures } from "./features";
4
5
  export function useMeshRoom(options) {
5
- const { peerId, room, signalingUrl, mediaConstraints, rtcConfig, trickle, autoReconnect, } = options;
6
+ const { peerId, displayName: initialDisplayName, room, signalingUrl, isHost, mediaConstraints, rtcConfig, trickle, autoReconnect, } = options;
7
+ const features = mergeFeatures(options.features ?? {});
6
8
  const localStream = ref(null);
7
9
  const requesting = ref(false);
8
10
  const mediaError = ref(null);
@@ -10,26 +12,64 @@ export function useMeshRoom(options) {
10
12
  const roster = ref([]);
11
13
  const participants = ref([]);
12
14
  const error = ref(null);
15
+ const waitingList = ref([]);
16
+ const peerDisplayNames = ref({});
17
+ const inWaitingRoom = ref(features.enableWaitingRoom && !isHost);
18
+ const activeSpeakerId = ref(null);
19
+ const raisedHands = ref(new Set());
20
+ const signalingStatus = ref("idle");
13
21
  const signaling = new SignalingClient({
14
22
  url: signalingUrl,
15
23
  peerId,
24
+ displayName: initialDisplayName,
16
25
  room,
26
+ isHost,
27
+ enableWaitingRoom: features.enableWaitingRoom,
17
28
  autoReconnect,
18
29
  });
19
- const enableDataChannel = options.features?.enableDataChannel ?? true;
20
30
  const peers = new Map();
31
+ // Active speaker detection state
32
+ const analyzers = new Map();
33
+ let activeCandidate = null;
34
+ let activeSince = 0;
35
+ let silenceSince = 0;
36
+ let speakerInterval = null;
21
37
  const sideForPeer = (otherId) => peerId > otherId ? "initiator" : "responder";
22
38
  const requestStream = async () => {
39
+ const wantsAudio = Boolean(mediaConstraints?.audio);
40
+ const wantsVideo = Boolean(mediaConstraints?.video);
41
+ if (!wantsAudio && !wantsVideo) {
42
+ localStream.value = null;
43
+ requesting.value = false;
44
+ mediaError.value = null;
45
+ return null;
46
+ }
47
+ if (typeof window !== "undefined") {
48
+ const host = window.location.hostname;
49
+ const isLocal = host === "localhost" || host === "127.0.0.1" || host === "::1";
50
+ const isSecure = window.isSecureContext;
51
+ if (!isSecure && !isLocal) {
52
+ mediaError.value = new Error("Media devices require a secure origin (https) or localhost.");
53
+ return null;
54
+ }
55
+ }
56
+ if (typeof navigator === "undefined" ||
57
+ !navigator.mediaDevices?.getUserMedia) {
58
+ mediaError.value = new Error("Media devices are not available in this environment");
59
+ return null;
60
+ }
23
61
  try {
24
62
  requesting.value = true;
63
+ mediaError.value = null;
25
64
  const constraints = mediaConstraints ?? { audio: true, video: true };
26
65
  const stream = await navigator.mediaDevices.getUserMedia(constraints);
27
66
  localStream.value = stream;
28
- mediaError.value = null;
67
+ return stream;
29
68
  }
30
69
  catch (err) {
31
70
  mediaError.value = err;
32
71
  localStream.value = null;
72
+ return null;
33
73
  }
34
74
  finally {
35
75
  requesting.value = false;
@@ -62,11 +102,17 @@ export function useMeshRoom(options) {
62
102
  ];
63
103
  return;
64
104
  }
105
+ const changed = Object.keys(patch).some((key) => patch[key] !==
106
+ existing[key]);
107
+ if (!changed)
108
+ return;
65
109
  participants.value = participants.value.map((p) => p.id === id ? { ...p, ...patch } : p);
66
110
  };
67
111
  const ensurePeer = (id, side) => {
68
112
  if (id === peerId)
69
113
  return null;
114
+ if (features.enableWaitingRoom && inWaitingRoom.value)
115
+ return null;
70
116
  const existing = peers.get(id);
71
117
  if (existing)
72
118
  return existing;
@@ -75,7 +121,7 @@ export function useMeshRoom(options) {
75
121
  stream: localStream.value ?? undefined,
76
122
  config: rtcConfig,
77
123
  trickle,
78
- enableDataChannel,
124
+ enableDataChannel: features.enableDataChannel,
79
125
  });
80
126
  peers.set(id, peer);
81
127
  upsertParticipant(id, {
@@ -101,28 +147,214 @@ export function useMeshRoom(options) {
101
147
  return peer;
102
148
  };
103
149
  const handlePresence = (payload) => {
104
- roster.value = payload.peers;
105
- payload.peers.filter((id) => id !== peerId).forEach((id) => ensurePeer(id));
106
- participants.value = participants.value.filter((p) => payload.peers.includes(p.id));
150
+ if (payload.peerDisplayNames) {
151
+ peerDisplayNames.value = payload.peerDisplayNames;
152
+ }
153
+ const ids = payload.peers;
154
+ if (roster.value.length !== ids.length ||
155
+ !roster.value.every((id, i) => id === ids[i])) {
156
+ roster.value = ids;
157
+ }
158
+ ids.filter((id) => id !== peerId).forEach((id) => ensurePeer(id));
159
+ const filtered = participants.value.filter((p) => ids.includes(p.id));
160
+ if (filtered.length !== participants.value.length) {
161
+ participants.value = filtered;
162
+ }
107
163
  Array.from(peers.keys()).forEach((id) => {
108
- if (!payload.peers.includes(id))
164
+ if (!ids.includes(id))
109
165
  destroyPeer(id);
110
166
  });
111
167
  };
168
+ const handleControl = ({ action, data, }) => {
169
+ if (action === "waiting-list") {
170
+ const waiting = data?.waiting ?? [];
171
+ if (waitingList.value.length !== waiting.length ||
172
+ !waitingList.value.every((id, i) => id === waiting[i])) {
173
+ waitingList.value = waiting;
174
+ }
175
+ return;
176
+ }
177
+ if (action === "waiting") {
178
+ inWaitingRoom.value = true;
179
+ return;
180
+ }
181
+ if (action === "admitted") {
182
+ inWaitingRoom.value = false;
183
+ return;
184
+ }
185
+ if (action === "rejected") {
186
+ inWaitingRoom.value = false;
187
+ error.value = new Error("Rejected by host");
188
+ return;
189
+ }
190
+ if (action === "raise-hand") {
191
+ const peer = data?.peerId ?? null;
192
+ if (!peer)
193
+ return;
194
+ if (!raisedHands.value.has(peer)) {
195
+ const next = new Set(raisedHands.value);
196
+ next.add(peer);
197
+ raisedHands.value = next;
198
+ }
199
+ return;
200
+ }
201
+ if (action === "hand-lowered") {
202
+ const peer = data?.peerId ?? null;
203
+ if (!peer)
204
+ return;
205
+ if (raisedHands.value.has(peer)) {
206
+ const next = new Set(raisedHands.value);
207
+ next.delete(peer);
208
+ raisedHands.value = next;
209
+ }
210
+ return;
211
+ }
212
+ if (action === "display-name-changed") {
213
+ const names = data?.peerDisplayNames ?? null;
214
+ if (names) {
215
+ peerDisplayNames.value = names;
216
+ }
217
+ return;
218
+ }
219
+ if (action === "host-blocked") {
220
+ error.value = new Error("A host is already present in this room.");
221
+ signalingStatus.value = "closed";
222
+ return;
223
+ }
224
+ };
112
225
  const handleSignal = ({ from, data }) => {
113
226
  const peer = ensurePeer(from, sideForPeer(from));
114
227
  void peer?.signal(data);
115
228
  };
229
+ const handleOpen = () => {
230
+ signalingStatus.value = "open";
231
+ };
232
+ const handleClose = () => {
233
+ signalingStatus.value = "closed";
234
+ };
235
+ const handleError = (err) => {
236
+ if (error.value?.message !== err.message) {
237
+ error.value = err;
238
+ }
239
+ };
240
+ // Active speaker detection
241
+ const ensureAnalyzer = (id, stream) => {
242
+ if (analyzers.has(id))
243
+ return;
244
+ const ctx = new AudioContext();
245
+ const source = ctx.createMediaStreamSource(stream);
246
+ const analyser = ctx.createAnalyser();
247
+ analyser.fftSize = 256;
248
+ source.connect(analyser);
249
+ analyzers.set(id, { ctx, analyser, source });
250
+ };
251
+ const cleanupAnalyzers = () => {
252
+ analyzers.forEach((entry) => {
253
+ entry.source.disconnect();
254
+ entry.analyser.disconnect();
255
+ entry.ctx.close();
256
+ });
257
+ analyzers.clear();
258
+ activeCandidate = null;
259
+ activeSince = 0;
260
+ silenceSince = 0;
261
+ };
262
+ const startActiveSpeakerDetection = () => {
263
+ if (!features.enableActiveSpeaker || speakerInterval)
264
+ return;
265
+ const minHoldMs = 700;
266
+ const minLevel = 18;
267
+ const silenceHoldMs = 1200;
268
+ speakerInterval = setInterval(() => {
269
+ let loudestId = null;
270
+ let loudest = 0;
271
+ analyzers.forEach((entry, id) => {
272
+ const data = new Uint8Array(entry.analyser.frequencyBinCount);
273
+ entry.analyser.getByteFrequencyData(data);
274
+ const avg = data.reduce((acc, v) => acc + v, 0) / data.length;
275
+ if (avg > loudest) {
276
+ loudest = avg;
277
+ loudestId = avg > minLevel ? id : null;
278
+ }
279
+ });
280
+ const now = performance.now();
281
+ if (loudestId !== activeCandidate) {
282
+ activeCandidate = loudestId;
283
+ activeSince = now;
284
+ }
285
+ const heldLongEnough = now - activeSince >= minHoldMs;
286
+ if (heldLongEnough && activeSpeakerId.value !== activeCandidate) {
287
+ activeSpeakerId.value = activeCandidate;
288
+ }
289
+ if (!loudestId) {
290
+ if (!silenceSince)
291
+ silenceSince = now;
292
+ const silentLongEnough = now - silenceSince >= silenceHoldMs;
293
+ if (silentLongEnough && activeSpeakerId.value !== null) {
294
+ activeSpeakerId.value = null;
295
+ }
296
+ }
297
+ else {
298
+ silenceSince = 0;
299
+ }
300
+ }, 400);
301
+ };
302
+ const stopActiveSpeakerDetection = () => {
303
+ if (speakerInterval) {
304
+ clearInterval(speakerInterval);
305
+ speakerInterval = null;
306
+ }
307
+ cleanupAnalyzers();
308
+ activeSpeakerId.value = null;
309
+ };
310
+ // Watch participants for active speaker detection
311
+ watch(() => participants.value, (currentParticipants) => {
312
+ if (!features.enableActiveSpeaker || signalingStatus.value !== "open")
313
+ return;
314
+ currentParticipants.forEach((p) => {
315
+ if (p.remoteStream)
316
+ ensureAnalyzer(p.id, p.remoteStream);
317
+ });
318
+ analyzers.forEach((_value, id) => {
319
+ const stillPresent = currentParticipants.find((p) => p.id === id && p.remoteStream);
320
+ if (!stillPresent) {
321
+ const entry = analyzers.get(id);
322
+ entry?.source.disconnect();
323
+ entry?.analyser.disconnect();
324
+ entry?.ctx.close();
325
+ analyzers.delete(id);
326
+ }
327
+ });
328
+ });
329
+ // Watch signaling status for active speaker detection
330
+ watch(() => signalingStatus.value, (status) => {
331
+ if (features.enableActiveSpeaker && status === "open") {
332
+ startActiveSpeakerDetection();
333
+ }
334
+ else {
335
+ stopActiveSpeakerDetection();
336
+ }
337
+ });
116
338
  onMounted(() => {
339
+ signalingStatus.value = "connecting";
117
340
  signaling.on("presence", handlePresence);
118
341
  signaling.on("signal", handleSignal);
342
+ signaling.on("control", handleControl);
343
+ signaling.on("open", handleOpen);
344
+ signaling.on("close", handleClose);
345
+ signaling.on("error", handleError);
119
346
  signaling.connect();
120
347
  });
121
348
  onUnmounted(() => {
122
349
  signaling.off("presence", handlePresence);
123
350
  signaling.off("signal", handleSignal);
351
+ signaling.off("control", handleControl);
352
+ signaling.off("open", handleOpen);
353
+ signaling.off("close", handleClose);
354
+ signaling.off("error", handleError);
124
355
  Array.from(peers.values()).forEach((p) => p.destroy());
125
356
  peers.clear();
357
+ stopActiveSpeakerDetection();
126
358
  stopStream();
127
359
  signaling.close();
128
360
  });
@@ -131,9 +363,37 @@ export function useMeshRoom(options) {
131
363
  peers.clear();
132
364
  participants.value = [];
133
365
  roster.value = [];
366
+ waitingList.value = [];
367
+ inWaitingRoom.value = false;
368
+ raisedHands.value = new Set();
369
+ stopActiveSpeakerDetection();
134
370
  stopStream();
135
371
  signaling.close();
136
372
  };
373
+ const admitPeer = (id) => {
374
+ if (!features.enableWaitingRoom || !isHost)
375
+ return;
376
+ signaling.sendControl("admit", { peerId: id });
377
+ };
378
+ const rejectPeer = (id) => {
379
+ if (!features.enableWaitingRoom || !isHost)
380
+ return;
381
+ signaling.sendControl("reject", { peerId: id });
382
+ };
383
+ const raiseHand = () => {
384
+ if (!features.enableHostControls)
385
+ return;
386
+ signaling.sendControl("raise-hand", { peerId });
387
+ };
388
+ const lowerHand = (targetPeerId) => {
389
+ if (!features.enableHostControls)
390
+ return;
391
+ const peerTarget = targetPeerId ?? peerId;
392
+ signaling.sendControl("hand-lowered", { peerId: peerTarget });
393
+ };
394
+ const setDisplayName = (displayName) => {
395
+ signaling.setDisplayName(displayName);
396
+ };
137
397
  const ready = computed(() => Boolean(localStream.value));
138
398
  watch(() => localStream.value, (next, prev) => {
139
399
  if (prev === next)
@@ -153,6 +413,17 @@ export function useMeshRoom(options) {
153
413
  mediaError,
154
414
  participants,
155
415
  roster,
416
+ waitingList,
417
+ inWaitingRoom,
418
+ activeSpeakerId,
419
+ raisedHands,
420
+ peerDisplayNames,
421
+ signalingStatus,
422
+ admitPeer,
423
+ rejectPeer,
424
+ raiseHand,
425
+ lowerHand,
426
+ setDisplayName,
156
427
  requestStream,
157
428
  stopStream,
158
429
  leave,
@@ -1 +1 @@
1
- {"version":3,"file":"useMeshRoom.js","sourceRoot":"","sources":["../src/useMeshRoom.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useMeshRoom.js","sourceRoot":"","sources":["../src/useMeshRoom.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conference-kit/vue",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -0,0 +1,17 @@
1
+ export type FeatureConfig = {
2
+ enableDataChannel?: boolean;
3
+ enableScreenShare?: boolean;
4
+ enableWaitingRoom?: boolean;
5
+ enableHostControls?: boolean;
6
+ enableActiveSpeaker?: boolean;
7
+ };
8
+
9
+ export function mergeFeatures(
10
+ defaultConfig: FeatureConfig,
11
+ userConfig?: FeatureConfig
12
+ ): FeatureConfig {
13
+ return {
14
+ ...defaultConfig,
15
+ ...userConfig,
16
+ };
17
+ }
package/src/index.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./useMeshRoom";
2
2
  export * from "./signaling";
3
+ export * from "./features";
package/src/signaling.ts CHANGED
@@ -1,13 +1,21 @@
1
- type EventMap = {
1
+ export type EventMap = {
2
2
  open: void;
3
3
  close: CloseEvent | undefined;
4
4
  error: Error;
5
5
  signal: { from: string; data: unknown };
6
6
  broadcast: { from: string; room?: string | null; data: unknown };
7
+ control: {
8
+ action: string;
9
+ from: string;
10
+ room?: string | null;
11
+ data?: unknown;
12
+ };
7
13
  presence: {
8
14
  room?: string | null;
9
15
  peerId: string;
16
+ displayName?: string;
10
17
  peers: string[];
18
+ peerDisplayNames?: Record<string, string>;
11
19
  action: "join" | "leave";
12
20
  };
13
21
  };
@@ -41,7 +49,10 @@ function createEmitter() {
41
49
  export type SignalingClientOptions = {
42
50
  url: string;
43
51
  peerId: string;
52
+ displayName?: string;
44
53
  room?: string | null;
54
+ isHost?: boolean;
55
+ enableWaitingRoom?: boolean;
45
56
  autoReconnect?: boolean;
46
57
  reconnectDelayMs?: number;
47
58
  };
@@ -49,17 +60,27 @@ export type SignalingClientOptions = {
49
60
  type IncomingMessage =
50
61
  | { type: "signal"; from: string; data: unknown }
51
62
  | { type: "broadcast"; from: string; room?: string | null; data: unknown }
63
+ | {
64
+ type: "control";
65
+ from: string;
66
+ room?: string | null;
67
+ action: string;
68
+ data?: unknown;
69
+ }
52
70
  | {
53
71
  type: "presence";
54
72
  room?: string | null;
55
73
  peerId: string;
74
+ displayName?: string;
56
75
  peers: string[];
76
+ peerDisplayNames?: Record<string, string>;
57
77
  action: "join" | "leave";
58
78
  };
59
79
 
60
80
  type OutgoingMessage =
61
81
  | { type: "signal"; to: string; data: unknown }
62
- | { type: "broadcast"; data: unknown };
82
+ | { type: "broadcast"; data: unknown }
83
+ | { type: "control"; action: string; data?: unknown };
63
84
 
64
85
  export class SignalingClient {
65
86
  private ws: WebSocket | null = null;
@@ -68,6 +89,8 @@ export class SignalingClient {
68
89
  private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;
69
90
  private shouldReconnect: boolean;
70
91
  private pendingQueue: OutgoingMessage[] = [];
92
+ private reconnectAttempts = 0;
93
+ private maxReconnectAttempts = 10;
71
94
 
72
95
  constructor(options: SignalingClientOptions) {
73
96
  this.options = options;
@@ -84,13 +107,41 @@ export class SignalingClient {
84
107
  return;
85
108
  }
86
109
 
87
- const { url, peerId, room } = this.options;
88
- const wsUrl = `${url}?peerId=${encodeURIComponent(peerId)}${
89
- room ? `&room=${encodeURIComponent(room)}` : ""
90
- }`;
91
- this.ws = new WebSocket(wsUrl);
110
+ const { url, peerId, displayName, room, isHost, enableWaitingRoom } =
111
+ this.options;
112
+
113
+ // Normalize URL: convert http(s):// to ws(s)://
114
+ let normalizedUrl = url.trim();
115
+ if (normalizedUrl.startsWith("https://")) {
116
+ normalizedUrl = "wss://" + normalizedUrl.slice(8);
117
+ } else if (normalizedUrl.startsWith("http://")) {
118
+ normalizedUrl = "ws://" + normalizedUrl.slice(7);
119
+ } else if (
120
+ !normalizedUrl.startsWith("ws://") &&
121
+ !normalizedUrl.startsWith("wss://")
122
+ ) {
123
+ normalizedUrl = "ws://" + normalizedUrl;
124
+ }
125
+
126
+ const params = new URLSearchParams({ peerId });
127
+ if (displayName) params.set("displayName", displayName);
128
+ if (room) params.set("room", room);
129
+ if (isHost) params.set("host", "1");
130
+ if (enableWaitingRoom) params.set("waitingRoom", "1");
131
+ const wsUrl = `${normalizedUrl}?${params.toString()}`;
132
+ console.log("[SignalingClient] Connecting to:", wsUrl);
133
+
134
+ try {
135
+ this.ws = new WebSocket(wsUrl);
136
+ } catch (err) {
137
+ console.error("[SignalingClient] Failed to create WebSocket:", err);
138
+ this.emitter.emit("error", err as Error);
139
+ return;
140
+ }
92
141
 
93
142
  this.ws.addEventListener("open", () => {
143
+ console.log("[SignalingClient] WebSocket connected successfully");
144
+ this.reconnectAttempts = 0;
94
145
  this.emitter.emit("open", undefined as void);
95
146
  this.flushQueue();
96
147
  });
@@ -113,6 +164,15 @@ export class SignalingClient {
113
164
  peerId: parsed.peerId,
114
165
  peers: parsed.peers,
115
166
  action: parsed.action,
167
+ displayName: parsed.displayName,
168
+ peerDisplayNames: parsed.peerDisplayNames,
169
+ });
170
+ } else if (parsed.type === "control") {
171
+ this.emitter.emit("control", {
172
+ from: parsed.from,
173
+ room: parsed.room,
174
+ action: parsed.action,
175
+ data: parsed.data,
116
176
  });
117
177
  }
118
178
  } catch (error) {
@@ -121,11 +181,17 @@ export class SignalingClient {
121
181
  });
122
182
 
123
183
  this.ws.addEventListener("close", (event) => {
184
+ console.log(
185
+ "[SignalingClient] WebSocket closed:",
186
+ event.code,
187
+ event.reason
188
+ );
124
189
  this.emitter.emit("close", event);
125
190
  this.scheduleReconnect();
126
191
  });
127
192
 
128
- this.ws.addEventListener("error", () => {
193
+ this.ws.addEventListener("error", (evt) => {
194
+ console.error("[SignalingClient] WebSocket error:", evt);
129
195
  this.emitter.emit("error", new Error("WebSocket error"));
130
196
  });
131
197
  }
@@ -145,6 +211,15 @@ export class SignalingClient {
145
211
  this.enqueue({ type: "broadcast", data });
146
212
  }
147
213
 
214
+ sendControl(action: string, data?: unknown) {
215
+ this.enqueue({ type: "control", action, data });
216
+ }
217
+
218
+ setDisplayName(displayName: string) {
219
+ this.options.displayName = displayName;
220
+ this.sendControl("set-display-name", { displayName });
221
+ }
222
+
148
223
  on<K extends EventKey>(event: K, handler: Handler<K>) {
149
224
  this.emitter.on(event, handler);
150
225
  }
@@ -171,7 +246,31 @@ export class SignalingClient {
171
246
 
172
247
  private scheduleReconnect() {
173
248
  if (!this.shouldReconnect) return;
174
- const delay = this.options.reconnectDelayMs ?? 1000;
249
+
250
+ this.reconnectAttempts++;
251
+ if (this.reconnectAttempts > this.maxReconnectAttempts) {
252
+ console.warn(
253
+ `[SignalingClient] Max reconnection attempts (${this.maxReconnectAttempts}) reached. Giving up.`
254
+ );
255
+ this.emitter.emit(
256
+ "error",
257
+ new Error(
258
+ `Failed to connect after ${this.maxReconnectAttempts} attempts`
259
+ )
260
+ );
261
+ return;
262
+ }
263
+
264
+ // Exponential backoff: 1s, 2s, 4s, 8s, ... up to 30s
265
+ const baseDelay = this.options.reconnectDelayMs ?? 1000;
266
+ const delay = Math.min(
267
+ baseDelay * Math.pow(2, this.reconnectAttempts - 1),
268
+ 30000
269
+ );
270
+ console.log(
271
+ `[SignalingClient] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`
272
+ );
273
+
175
274
  if (this.reconnectTimeout) clearTimeout(this.reconnectTimeout);
176
275
  this.reconnectTimeout = setTimeout(() => this.connect(), delay);
177
276
  }