@cemscale-voip/voip-sdk 1.26.0 → 1.27.0

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/README.md CHANGED
@@ -87,48 +87,165 @@ voip.onWsEvent('call_end', (event) => {
87
87
  ### Call Forwarding & CRM Integration
88
88
 
89
89
  ```typescript
90
- // List only forwarded calls (calls that hit an extension and were diverted to external number)
90
+ // List only forwarded calls (calls that hit an extension and were diverted)
91
91
  const { calls } = await voip.listCalls({ forwarded: 'true' });
92
92
  for (const call of calls) {
93
93
  console.log(`${call.caller_id_number} -> ext ${call.destination} -> FWD ${call.forwarded_to}`);
94
- // forwarded_to: the external number the call was forwarded to (null if not forwarded)
94
+ // forwarded_to: the external/internal number the call was forwarded to (null if not forwarded)
95
+ // audio_url: recording URL (forwarded calls are now recorded end-to-end)
96
+ if (call.audio_url) {
97
+ const playUrl = voip.getRecordingAudioUrl(call.id);
98
+ console.log(`Recording: ${playUrl}`);
99
+ }
95
100
  }
96
101
 
97
102
  // Search by the external number calls were forwarded to
98
103
  const { calls: fwdCalls } = await voip.listCalls({ forwardedTo: '+1305' });
99
104
 
100
- // Get a single call with forwarding info
105
+ // Get a single call with forwarding info + recording
101
106
  const { call } = await voip.getCall('call-uuid');
102
107
  if (call.forwarded_to) {
103
- // This call was forwarded — log it in CRM with the real destination
104
108
  logForwardedCall(call.caller_id_number, call.destination, call.forwarded_to);
109
+ // Play the recording of the forwarded conversation:
110
+ const audioUrl = voip.getRecordingAudioUrl(call.id);
111
+ // => "https://api.example.com/api/recordings/<id>/audio?apiKey=..."
105
112
  }
106
113
  ```
107
114
 
108
- ### Webhooks
115
+ ### Webhooks — Typed Event Payloads
116
+
117
+ The SDK exports typed interfaces for every webhook event payload. Import them
118
+ to get full IntelliSense in your CRM webhook handler:
109
119
 
110
120
  ```typescript
111
- // Subscribe to call.forwarded for real-time CRM notifications
121
+ import type {
122
+ WebhookEnvelope,
123
+ CallStartedEvent,
124
+ CallAnsweredEvent,
125
+ CallForwardedEvent,
126
+ CallEndedEvent,
127
+ } from '@cemscale-voip/voip-sdk';
128
+
129
+ // Register a webhook subscription
112
130
  await voip.createWebhook({
113
131
  name: 'CRM Events',
114
132
  url: 'https://your-crm.com/api/voip-webhook',
115
133
  events: ['call.started', 'call.answered', 'call.forwarded', 'call.ended'],
134
+ secret: 'your-hmac-secret', // optional — enables X-Webhook-Signature header
116
135
  });
136
+ ```
117
137
 
118
- // Webhook payload for call.forwarded:
119
- // {
120
- // "event": "call.forwarded",
121
- // "callUuid": "a1b2c3d4-...",
122
- // "caller": "+17861234567",
123
- // "originalDestination": "1001",
124
- // "forwardedTo": "+13055559999",
125
- // "forwardType": "always", // "always" | "no-answer" | "busy"
126
- // "inboundDid": "+17868392727",
127
- // "timestamp": "2026-04-07T14:15:02Z"
128
- // }
138
+ #### `call.forwarded` 3-stage lifecycle
139
+
140
+ The `call.forwarded` event fires at up to 3 stages during a forwarded call.
141
+ Each delivery includes a `status` field so your CRM knows the current stage:
142
+
143
+ | Status | When | What it means |
144
+ |---|---|---|
145
+ | `initiated` | Call created | Forward will happen (only for `always` type) |
146
+ | `answered` | Forwarded party picks up | Forward is connected (all types) |
147
+ | `completed` | Call ends | Full CDR data: duration, recording, hangup cause |
148
+
149
+ ```typescript
150
+ // Express webhook handler with full type safety
151
+ app.post('/api/voip-webhook', (req, res) => {
152
+ const envelope = req.body as WebhookEnvelope;
153
+
154
+ switch (envelope.event) {
155
+ case 'call.forwarded': {
156
+ const fwd = envelope.data as CallForwardedEvent;
157
+ // fwd.status: 'initiated' | 'answered' | 'completed'
158
+ // fwd.forwardedTo: '+13055559999'
159
+ // fwd.forwardType: 'always' | 'no-answer' | 'busy'
160
+ // fwd.originalDestination: '1001' (the extension)
161
+ // fwd.caller: '+17861234567' (who called)
162
+
163
+ if (fwd.status === 'initiated') {
164
+ // Real-time: show "Forwarding to +1305..." in CRM UI
165
+ updateCrmCallStatus(fwd.callUuid, `Forwarding to ${fwd.forwardedTo}`);
166
+ }
167
+
168
+ if (fwd.status === 'answered') {
169
+ // Forward connected — update CRM
170
+ updateCrmCallStatus(fwd.callUuid, `Connected to ${fwd.forwardedTo}`);
171
+ }
172
+
173
+ if (fwd.status === 'completed') {
174
+ // Call ended — save CDR with recording
175
+ saveCdrWithForwarding({
176
+ callUuid: fwd.callUuid,
177
+ forwardedTo: fwd.forwardedTo,
178
+ duration: fwd.duration, // seconds (only on completed)
179
+ hangupCause: fwd.hangupCause, // only on completed
180
+ recordingFile: fwd.recordingFile, // only on completed
181
+ });
182
+ }
183
+ break;
184
+ }
185
+
186
+ case 'call.ended': {
187
+ const ended = envelope.data as CallEndedEvent;
188
+ // ended.forwardedTo is non-null when the call was forwarded
189
+ saveCdr(ended);
190
+ break;
191
+ }
192
+
193
+ case 'call.answered': {
194
+ const answered = envelope.data as CallAnsweredEvent;
195
+ // answered.forwardedTo is present when a forwarded call was answered
196
+ if (answered.forwardedTo) {
197
+ console.log(`Forwarded call answered: ${answered.forwardedTo}`);
198
+ }
199
+ break;
200
+ }
201
+ }
202
+
203
+ res.sendStatus(200);
204
+ });
205
+ ```
129
206
 
130
- // call.ended also includes forwardedTo when the call was forwarded:
131
- // { ..., "forwardedTo": "+13055559999", ... }
207
+ #### Webhook payload examples
208
+
209
+ **`call.forwarded` (status: completed):**
210
+ ```json
211
+ {
212
+ "event": "call.forwarded",
213
+ "timestamp": "2026-04-07T14:15:02Z",
214
+ "data": {
215
+ "callUuid": "a1b2c3d4-...",
216
+ "caller": "+17861234567",
217
+ "originalDestination": "1001",
218
+ "forwardedTo": "+13055559999",
219
+ "forwardType": "always",
220
+ "status": "completed",
221
+ "duration": 142,
222
+ "billsec": 138,
223
+ "hangupCause": "NORMAL_CLEARING",
224
+ "recordingFile": "/var/lib/voip-recordings/.../uuid.wav",
225
+ "inboundDid": "+17862757830",
226
+ "timestamp": "2026-04-07T14:17:24Z"
227
+ }
228
+ }
229
+ ```
230
+
231
+ **`call.ended` (with forwarding):**
232
+ ```json
233
+ {
234
+ "event": "call.ended",
235
+ "timestamp": "2026-04-07T14:17:24Z",
236
+ "data": {
237
+ "callUuid": "a1b2c3d4-...",
238
+ "direction": "inbound",
239
+ "caller": "+17861234567",
240
+ "destination": "+17862757830",
241
+ "duration": 142,
242
+ "billsec": 138,
243
+ "hangupCause": "NORMAL_CLEARING",
244
+ "status": "completed",
245
+ "forwardedTo": "+13055559999",
246
+ "recordingFile": "/var/lib/voip-recordings/.../uuid.mp3"
247
+ }
248
+ }
132
249
  ```
133
250
 
134
251
  ### Call Queues
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,289 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { VoIPClient, HttpError } from '../client.js';
3
+ // ── Mock fetch ──
4
+ const mockFetch = vi.fn();
5
+ globalThis.fetch = mockFetch;
6
+ function jsonResponse(data, status = 200) {
7
+ return {
8
+ ok: status >= 200 && status < 300,
9
+ status,
10
+ statusText: status === 200 ? 'OK' : 'Error',
11
+ headers: new Headers({ 'content-type': 'application/json' }),
12
+ json: () => Promise.resolve(data),
13
+ text: () => Promise.resolve(JSON.stringify(data)),
14
+ };
15
+ }
16
+ function textResponse(text, status = 200) {
17
+ return {
18
+ ok: status >= 200 && status < 300,
19
+ status,
20
+ statusText: 'OK',
21
+ headers: new Headers({ 'content-type': 'text/csv' }),
22
+ json: () => Promise.reject(new Error('not json')),
23
+ text: () => Promise.resolve(text),
24
+ };
25
+ }
26
+ describe('VoIPClient', () => {
27
+ let client;
28
+ beforeEach(() => {
29
+ mockFetch.mockReset();
30
+ client = new VoIPClient({
31
+ apiUrl: 'https://api.example.com',
32
+ apiKey: 'csk_live_testkey123',
33
+ tenantId: 'tenant-abc',
34
+ });
35
+ });
36
+ // ── Auth Headers ──
37
+ describe('Authentication headers', () => {
38
+ it('sends X-API-Key when apiKey is set', async () => {
39
+ mockFetch.mockResolvedValue(jsonResponse({ extensions: [] }));
40
+ await client.listExtensions();
41
+ const [url, opts] = mockFetch.mock.calls[0];
42
+ expect(opts.headers['X-API-Key']).toBe('csk_live_testkey123');
43
+ expect(opts.headers['Authorization']).toBeUndefined();
44
+ });
45
+ it('sends Bearer token when only token is set', async () => {
46
+ const tokenClient = new VoIPClient({
47
+ apiUrl: 'https://api.example.com',
48
+ token: 'jwt-token-abc',
49
+ });
50
+ mockFetch.mockResolvedValue(jsonResponse({ extensions: [] }));
51
+ await tokenClient.listExtensions();
52
+ const [, opts] = mockFetch.mock.calls[0];
53
+ expect(opts.headers['Authorization']).toBe('Bearer jwt-token-abc');
54
+ expect(opts.headers['X-API-Key']).toBeUndefined();
55
+ });
56
+ it('sends X-Tenant-ID header', async () => {
57
+ mockFetch.mockResolvedValue(jsonResponse({ extensions: [] }));
58
+ await client.listExtensions();
59
+ const [, opts] = mockFetch.mock.calls[0];
60
+ expect(opts.headers['X-Tenant-ID']).toBe('tenant-abc');
61
+ });
62
+ it('does not send X-Tenant-ID when tenantId is "all"', async () => {
63
+ client.setTenantId('all');
64
+ mockFetch.mockResolvedValue(jsonResponse({ extensions: [] }));
65
+ await client.listExtensions();
66
+ const [, opts] = mockFetch.mock.calls[0];
67
+ expect(opts.headers['X-Tenant-ID']).toBeUndefined();
68
+ });
69
+ });
70
+ // ── Auth Endpoints ──
71
+ describe('Auth', () => {
72
+ it('login() POSTs to /api/auth/login and stores token', async () => {
73
+ mockFetch.mockResolvedValue(jsonResponse({ token: 'new-jwt' }));
74
+ const result = await client.login({ username: '1001', password: 'pass', tenantId: 't1' });
75
+ const [url, opts] = mockFetch.mock.calls[0];
76
+ expect(url).toBe('https://api.example.com/api/auth/login');
77
+ expect(opts.method).toBe('POST');
78
+ expect(JSON.parse(opts.body)).toEqual({ username: '1001', password: 'pass', tenantId: 't1' });
79
+ expect(result.token).toBe('new-jwt');
80
+ expect(client.getToken()).toBe('new-jwt');
81
+ });
82
+ it('adminLogin() POSTs to /api/auth/admin-login', async () => {
83
+ mockFetch.mockResolvedValue(jsonResponse({ token: 'admin-jwt', tenant: { id: 't2', subdomain: 'demo', companyName: 'Demo' } }));
84
+ await client.adminLogin({ email: 'admin@test.com', password: 'pass' });
85
+ const [url] = mockFetch.mock.calls[0];
86
+ expect(url).toBe('https://api.example.com/api/auth/admin-login');
87
+ expect(client.getTenantId()).toBe('t2');
88
+ });
89
+ it('me() GETs /api/auth/me', async () => {
90
+ mockFetch.mockResolvedValue(jsonResponse({ user: { id: '1' } }));
91
+ await client.me();
92
+ expect(mockFetch.mock.calls[0][0]).toBe('https://api.example.com/api/auth/me');
93
+ });
94
+ it('getTurnCredentials() GETs /api/auth/turn-credentials', async () => {
95
+ mockFetch.mockResolvedValue(jsonResponse({ urls: ['turn:server'], username: 'u', credential: 'c', ttl: 86400 }));
96
+ const result = await client.getTurnCredentials();
97
+ expect(result.urls).toEqual(['turn:server']);
98
+ });
99
+ });
100
+ // ── Calls ──
101
+ describe('Calls', () => {
102
+ it('listCalls() sends correct query params', async () => {
103
+ mockFetch.mockResolvedValue(jsonResponse({ calls: [], pagination: {} }));
104
+ await client.listCalls({ page: 2, limit: 10, direction: 'inbound' });
105
+ const url = mockFetch.mock.calls[0][0];
106
+ expect(url).toContain('/api/calls');
107
+ expect(url).toContain('page=2');
108
+ expect(url).toContain('limit=10');
109
+ expect(url).toContain('direction=inbound');
110
+ });
111
+ it('originate() POSTs to /api/calls/originate', async () => {
112
+ mockFetch.mockResolvedValue(jsonResponse({ message: 'ok', callUuid: 'uuid-1' }));
113
+ const result = await client.originate({ fromExtension: '1001', toNumber: '+15551234567' });
114
+ const [url, opts] = mockFetch.mock.calls[0];
115
+ expect(url).toBe('https://api.example.com/api/calls/originate');
116
+ expect(opts.method).toBe('POST');
117
+ expect(JSON.parse(opts.body)).toEqual({ fromExtension: '1001', toNumber: '+15551234567' });
118
+ expect(result.callUuid).toBe('uuid-1');
119
+ });
120
+ it('hangup() POSTs to /api/calls/:uuid/hangup', async () => {
121
+ mockFetch.mockResolvedValue(jsonResponse({ message: 'Hung up' }));
122
+ await client.hangup('call-uuid-123');
123
+ expect(mockFetch.mock.calls[0][0]).toBe('https://api.example.com/api/calls/call-uuid-123/hangup');
124
+ });
125
+ it('holdCall() sends hold=true by default', async () => {
126
+ mockFetch.mockResolvedValue(jsonResponse({ message: 'ok' }));
127
+ await client.holdCall('uuid-1');
128
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
129
+ expect(body).toEqual({ hold: true });
130
+ });
131
+ it('holdCall() can send hold=false', async () => {
132
+ mockFetch.mockResolvedValue(jsonResponse({ message: 'ok' }));
133
+ await client.holdCall('uuid-1', false);
134
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
135
+ expect(body).toEqual({ hold: false });
136
+ });
137
+ it('transfer() sends correct body', async () => {
138
+ mockFetch.mockResolvedValue(jsonResponse({ message: 'ok' }));
139
+ await client.transfer('uuid-1', { targetExtension: '1002', type: 'blind' });
140
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
141
+ expect(body).toEqual({ targetExtension: '1002', type: 'blind' });
142
+ });
143
+ it('exportCalls() returns CSV text', async () => {
144
+ mockFetch.mockResolvedValue(textResponse('id,caller\n1,1001'));
145
+ const csv = await client.exportCalls({ direction: 'inbound' });
146
+ expect(csv).toContain('id,caller');
147
+ });
148
+ });
149
+ // ── Extensions ──
150
+ describe('Extensions', () => {
151
+ it('createExtension() POSTs correctly', async () => {
152
+ mockFetch.mockResolvedValue(jsonResponse({ extension: { id: '1' } }));
153
+ await client.createExtension({ extension: '1003', password: 'pass', displayName: 'Test' });
154
+ const [url, opts] = mockFetch.mock.calls[0];
155
+ expect(url).toBe('https://api.example.com/api/extensions');
156
+ expect(opts.method).toBe('POST');
157
+ });
158
+ it('getSipCredentials() GETs correct URL', async () => {
159
+ mockFetch.mockResolvedValue(jsonResponse({ sipCredentials: { extension: '1001' } }));
160
+ await client.getSipCredentials('ext-uuid');
161
+ expect(mockFetch.mock.calls[0][0]).toBe('https://api.example.com/api/extensions/ext-uuid/sip-credentials');
162
+ });
163
+ it('getSipCredentialsByNumber() GETs by number', async () => {
164
+ mockFetch.mockResolvedValue(jsonResponse({ sipCredentials: { extension: '1001' } }));
165
+ await client.getSipCredentialsByNumber('1001');
166
+ expect(mockFetch.mock.calls[0][0]).toBe('https://api.example.com/api/extensions/by-number/1001/sip-credentials');
167
+ });
168
+ it('setCallForward() PUTs to correct endpoint', async () => {
169
+ mockFetch.mockResolvedValue(jsonResponse({ extension: '1001', callForward: {} }));
170
+ await client.setCallForward('ext-id', { enabled: true, number: '+15551234567', type: 'always' });
171
+ const [url, opts] = mockFetch.mock.calls[0];
172
+ expect(url).toBe('https://api.example.com/api/extensions/ext-id/forward');
173
+ expect(opts.method).toBe('PUT');
174
+ });
175
+ });
176
+ // ── Tenants ──
177
+ describe('Tenants', () => {
178
+ it('createTenant() POSTs to /api/tenants', async () => {
179
+ mockFetch.mockResolvedValue(jsonResponse({ tenant: { id: 't1' } }));
180
+ await client.createTenant({ subdomain: 'demo', companyName: 'Demo' });
181
+ expect(mockFetch.mock.calls[0][0]).toBe('https://api.example.com/api/tenants');
182
+ });
183
+ it('deleteTenant() DELETEs to /api/tenants/:id', async () => {
184
+ mockFetch.mockResolvedValue(jsonResponse({ message: 'deleted' }));
185
+ await client.deleteTenant('t1');
186
+ const [url, opts] = mockFetch.mock.calls[0];
187
+ expect(url).toBe('https://api.example.com/api/tenants/t1');
188
+ expect(opts.method).toBe('DELETE');
189
+ });
190
+ });
191
+ // ── Conferences ──
192
+ describe('Conferences', () => {
193
+ it('muteConferenceMember() POSTs with correct body', async () => {
194
+ mockFetch.mockResolvedValue(jsonResponse({ message: 'ok' }));
195
+ await client.muteConferenceMember('conf_1', 'member-1', true);
196
+ const [url, opts] = mockFetch.mock.calls[0];
197
+ expect(url).toBe('https://api.example.com/api/conferences/conf_1/mute');
198
+ expect(JSON.parse(opts.body)).toEqual({ memberId: 'member-1', mute: true });
199
+ });
200
+ });
201
+ // ── Webhooks ──
202
+ describe('Webhooks', () => {
203
+ it('createWebhook() POSTs with events array', async () => {
204
+ mockFetch.mockResolvedValue(jsonResponse({ webhook: { id: 'w1', secret: 'abc' } }));
205
+ await client.createWebhook({ name: 'Test', url: 'https://hook.test', events: ['call.started'] });
206
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
207
+ expect(body.events).toEqual(['call.started']);
208
+ });
209
+ it('testWebhook() POSTs to /:id/test', async () => {
210
+ mockFetch.mockResolvedValue(jsonResponse({ message: 'sent' }));
211
+ await client.testWebhook('w1');
212
+ const [url, opts] = mockFetch.mock.calls[0];
213
+ expect(url).toBe('https://api.example.com/api/webhooks/w1/test');
214
+ expect(opts.method).toBe('POST');
215
+ });
216
+ });
217
+ // ── API Keys ──
218
+ describe('API Keys', () => {
219
+ it('createApiKey() returns key only once', async () => {
220
+ mockFetch.mockResolvedValue(jsonResponse({ apiKey: { id: 'k1', key: 'csk_live_full_key' } }));
221
+ const result = await client.createApiKey({ name: 'Test' });
222
+ expect(result.apiKey.key).toBe('csk_live_full_key');
223
+ });
224
+ it('regenerateApiKey() POSTs to /:id/regenerate', async () => {
225
+ mockFetch.mockResolvedValue(jsonResponse({ apiKey: { id: 'k1', key: 'csk_live_new' } }));
226
+ await client.regenerateApiKey('k1');
227
+ expect(mockFetch.mock.calls[0][0]).toBe('https://api.example.com/api/api-keys/k1/regenerate');
228
+ });
229
+ });
230
+ // ── Blocklist ──
231
+ describe('Blocklist', () => {
232
+ it('checkBlocked() URL-encodes the number', async () => {
233
+ mockFetch.mockResolvedValue(jsonResponse({ blocked: false, entry: null }));
234
+ await client.checkBlocked('+15551234567');
235
+ expect(mockFetch.mock.calls[0][0]).toContain('/api/blocklist/check/%2B15551234567');
236
+ });
237
+ });
238
+ // ── Error Handling ──
239
+ describe('Error handling', () => {
240
+ it('throws HttpError on non-OK response', async () => {
241
+ mockFetch.mockResolvedValue(jsonResponse({ error: 'Not found' }, 404));
242
+ await expect(client.getExtension('nonexistent')).rejects.toThrow(HttpError);
243
+ });
244
+ it('HttpError contains status and body', async () => {
245
+ mockFetch.mockResolvedValue(jsonResponse({ error: 'Forbidden' }, 403));
246
+ try {
247
+ await client.listTenants();
248
+ expect.fail('should throw');
249
+ }
250
+ catch (err) {
251
+ expect(err).toBeInstanceOf(HttpError);
252
+ expect(err.status).toBe(403);
253
+ }
254
+ });
255
+ });
256
+ // ── Credential Management ──
257
+ describe('Credential management', () => {
258
+ it('setApiKey/getApiKey work', () => {
259
+ client.setApiKey('new-key');
260
+ expect(client.getApiKey()).toBe('new-key');
261
+ });
262
+ it('setToken/getToken work', () => {
263
+ client.setToken('new-token');
264
+ expect(client.getToken()).toBe('new-token');
265
+ });
266
+ it('destroy() clears all credentials', () => {
267
+ client.destroy();
268
+ expect(client.getApiKey()).toBeNull();
269
+ expect(client.getToken()).toBeNull();
270
+ expect(client.getTenantId()).toBeNull();
271
+ });
272
+ });
273
+ // ── Content-Type ──
274
+ describe('Content-Type', () => {
275
+ it('does not send Content-Type for GET requests', async () => {
276
+ mockFetch.mockResolvedValue(jsonResponse({ extensions: [] }));
277
+ await client.listExtensions();
278
+ const headers = mockFetch.mock.calls[0][1].headers;
279
+ expect(headers['Content-Type']).toBeUndefined();
280
+ });
281
+ it('sends Content-Type for POST with body', async () => {
282
+ mockFetch.mockResolvedValue(jsonResponse({ message: 'ok', callUuid: 'u1' }));
283
+ await client.originate({ fromExtension: '1001', toNumber: '1002' });
284
+ const headers = mockFetch.mock.calls[0][1].headers;
285
+ expect(headers['Content-Type']).toBe('application/json');
286
+ });
287
+ });
288
+ });
289
+ //# sourceMappingURL=client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../src/__tests__/client.test.ts"],"names":[],"mappings":"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"}