@logg/signals 0.1.1 → 0.1.3
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/dist/index.d.mts +38 -4
- package/dist/index.d.ts +38 -4
- package/dist/index.js +83 -10
- package/dist/index.mjs +83 -10
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
|
+
interface UserContext {
|
|
2
|
+
user_id?: string;
|
|
3
|
+
anon_id?: string;
|
|
4
|
+
session_id: string;
|
|
5
|
+
}
|
|
6
|
+
interface EventContext {
|
|
7
|
+
screen?: string;
|
|
8
|
+
surface?: string;
|
|
9
|
+
request_id?: string;
|
|
10
|
+
entry_point?: string;
|
|
11
|
+
referrer_surface?: string;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
interface EventTarget {
|
|
15
|
+
type: string;
|
|
16
|
+
id: string;
|
|
17
|
+
}
|
|
1
18
|
interface EventData {
|
|
2
19
|
type: string;
|
|
20
|
+
target?: EventTarget;
|
|
3
21
|
[key: string]: unknown;
|
|
4
22
|
}
|
|
5
23
|
interface Event {
|
|
@@ -7,6 +25,9 @@ interface Event {
|
|
|
7
25
|
timestamp: string;
|
|
8
26
|
session_id: string;
|
|
9
27
|
type: string;
|
|
28
|
+
user: UserContext;
|
|
29
|
+
context: EventContext;
|
|
30
|
+
target?: EventTarget;
|
|
10
31
|
[key: string]: unknown;
|
|
11
32
|
}
|
|
12
33
|
interface ClientMetadata {
|
|
@@ -29,7 +50,7 @@ interface EventBatch {
|
|
|
29
50
|
}
|
|
30
51
|
interface SignalsConfig {
|
|
31
52
|
apiKey: string;
|
|
32
|
-
endpoint
|
|
53
|
+
endpoint?: string;
|
|
33
54
|
batchSize?: number;
|
|
34
55
|
batchInterval?: number;
|
|
35
56
|
maxRetries?: number;
|
|
@@ -37,6 +58,9 @@ interface SignalsConfig {
|
|
|
37
58
|
debug?: boolean;
|
|
38
59
|
storage?: StorageAdapter;
|
|
39
60
|
sessionId?: string;
|
|
61
|
+
userId?: string;
|
|
62
|
+
anonymousId?: string;
|
|
63
|
+
context?: EventContext;
|
|
40
64
|
}
|
|
41
65
|
interface StorageAdapter {
|
|
42
66
|
getItem(key: string): Promise<string | null>;
|
|
@@ -54,6 +78,8 @@ declare class Signals {
|
|
|
54
78
|
private flushTimer;
|
|
55
79
|
private isDestroyed;
|
|
56
80
|
private isFlushing;
|
|
81
|
+
private userContext;
|
|
82
|
+
private eventContext;
|
|
57
83
|
constructor(config: SignalsConfig);
|
|
58
84
|
private init;
|
|
59
85
|
event(eventData: EventData): Promise<void>;
|
|
@@ -63,6 +89,13 @@ declare class Signals {
|
|
|
63
89
|
private stopFlushTimer;
|
|
64
90
|
getSessionId(): string;
|
|
65
91
|
getQueueSize(): number;
|
|
92
|
+
identify(userId: string): void;
|
|
93
|
+
setAnonymousId(anonymousId: string): void;
|
|
94
|
+
setContext(context: EventContext): void;
|
|
95
|
+
updateContext(context: Partial<EventContext>): void;
|
|
96
|
+
getUserContext(): UserContext;
|
|
97
|
+
getContext(): EventContext;
|
|
98
|
+
reset(): void;
|
|
66
99
|
destroy(): Promise<void>;
|
|
67
100
|
private log;
|
|
68
101
|
}
|
|
@@ -70,8 +103,9 @@ declare class Signals {
|
|
|
70
103
|
declare class EventQueue {
|
|
71
104
|
private queue;
|
|
72
105
|
private storage;
|
|
73
|
-
private
|
|
74
|
-
|
|
106
|
+
private getUserContext;
|
|
107
|
+
private getEventContext;
|
|
108
|
+
constructor(storage: StorageAdapter, getUserContext: () => UserContext, getEventContext: () => EventContext);
|
|
75
109
|
init(): Promise<void>;
|
|
76
110
|
add(eventData: EventData): Promise<Event>;
|
|
77
111
|
getAll(): Event[];
|
|
@@ -109,4 +143,4 @@ declare class MemoryStorageAdapter implements StorageAdapter {
|
|
|
109
143
|
|
|
110
144
|
declare function getDefaultStorageAdapter(): StorageAdapter;
|
|
111
145
|
|
|
112
|
-
export { AsyncStorageAdapter, type ClientMetadata, type Event, type EventBatch, type EventData, EventQueue, LocalStorageAdapter, MemoryStorageAdapter, type QueuedEvent, Signals, type SignalsConfig, type StorageAdapter, getDefaultStorageAdapter };
|
|
146
|
+
export { AsyncStorageAdapter, type ClientMetadata, type Event, type EventBatch, type EventContext, type EventData, EventQueue, type EventTarget, LocalStorageAdapter, MemoryStorageAdapter, type QueuedEvent, Signals, type SignalsConfig, type StorageAdapter, type UserContext, getDefaultStorageAdapter };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
|
+
interface UserContext {
|
|
2
|
+
user_id?: string;
|
|
3
|
+
anon_id?: string;
|
|
4
|
+
session_id: string;
|
|
5
|
+
}
|
|
6
|
+
interface EventContext {
|
|
7
|
+
screen?: string;
|
|
8
|
+
surface?: string;
|
|
9
|
+
request_id?: string;
|
|
10
|
+
entry_point?: string;
|
|
11
|
+
referrer_surface?: string;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
interface EventTarget {
|
|
15
|
+
type: string;
|
|
16
|
+
id: string;
|
|
17
|
+
}
|
|
1
18
|
interface EventData {
|
|
2
19
|
type: string;
|
|
20
|
+
target?: EventTarget;
|
|
3
21
|
[key: string]: unknown;
|
|
4
22
|
}
|
|
5
23
|
interface Event {
|
|
@@ -7,6 +25,9 @@ interface Event {
|
|
|
7
25
|
timestamp: string;
|
|
8
26
|
session_id: string;
|
|
9
27
|
type: string;
|
|
28
|
+
user: UserContext;
|
|
29
|
+
context: EventContext;
|
|
30
|
+
target?: EventTarget;
|
|
10
31
|
[key: string]: unknown;
|
|
11
32
|
}
|
|
12
33
|
interface ClientMetadata {
|
|
@@ -29,7 +50,7 @@ interface EventBatch {
|
|
|
29
50
|
}
|
|
30
51
|
interface SignalsConfig {
|
|
31
52
|
apiKey: string;
|
|
32
|
-
endpoint
|
|
53
|
+
endpoint?: string;
|
|
33
54
|
batchSize?: number;
|
|
34
55
|
batchInterval?: number;
|
|
35
56
|
maxRetries?: number;
|
|
@@ -37,6 +58,9 @@ interface SignalsConfig {
|
|
|
37
58
|
debug?: boolean;
|
|
38
59
|
storage?: StorageAdapter;
|
|
39
60
|
sessionId?: string;
|
|
61
|
+
userId?: string;
|
|
62
|
+
anonymousId?: string;
|
|
63
|
+
context?: EventContext;
|
|
40
64
|
}
|
|
41
65
|
interface StorageAdapter {
|
|
42
66
|
getItem(key: string): Promise<string | null>;
|
|
@@ -54,6 +78,8 @@ declare class Signals {
|
|
|
54
78
|
private flushTimer;
|
|
55
79
|
private isDestroyed;
|
|
56
80
|
private isFlushing;
|
|
81
|
+
private userContext;
|
|
82
|
+
private eventContext;
|
|
57
83
|
constructor(config: SignalsConfig);
|
|
58
84
|
private init;
|
|
59
85
|
event(eventData: EventData): Promise<void>;
|
|
@@ -63,6 +89,13 @@ declare class Signals {
|
|
|
63
89
|
private stopFlushTimer;
|
|
64
90
|
getSessionId(): string;
|
|
65
91
|
getQueueSize(): number;
|
|
92
|
+
identify(userId: string): void;
|
|
93
|
+
setAnonymousId(anonymousId: string): void;
|
|
94
|
+
setContext(context: EventContext): void;
|
|
95
|
+
updateContext(context: Partial<EventContext>): void;
|
|
96
|
+
getUserContext(): UserContext;
|
|
97
|
+
getContext(): EventContext;
|
|
98
|
+
reset(): void;
|
|
66
99
|
destroy(): Promise<void>;
|
|
67
100
|
private log;
|
|
68
101
|
}
|
|
@@ -70,8 +103,9 @@ declare class Signals {
|
|
|
70
103
|
declare class EventQueue {
|
|
71
104
|
private queue;
|
|
72
105
|
private storage;
|
|
73
|
-
private
|
|
74
|
-
|
|
106
|
+
private getUserContext;
|
|
107
|
+
private getEventContext;
|
|
108
|
+
constructor(storage: StorageAdapter, getUserContext: () => UserContext, getEventContext: () => EventContext);
|
|
75
109
|
init(): Promise<void>;
|
|
76
110
|
add(eventData: EventData): Promise<Event>;
|
|
77
111
|
getAll(): Event[];
|
|
@@ -109,4 +143,4 @@ declare class MemoryStorageAdapter implements StorageAdapter {
|
|
|
109
143
|
|
|
110
144
|
declare function getDefaultStorageAdapter(): StorageAdapter;
|
|
111
145
|
|
|
112
|
-
export { AsyncStorageAdapter, type ClientMetadata, type Event, type EventBatch, type EventData, EventQueue, LocalStorageAdapter, MemoryStorageAdapter, type QueuedEvent, Signals, type SignalsConfig, type StorageAdapter, getDefaultStorageAdapter };
|
|
146
|
+
export { AsyncStorageAdapter, type ClientMetadata, type Event, type EventBatch, type EventContext, type EventData, EventQueue, type EventTarget, LocalStorageAdapter, MemoryStorageAdapter, type QueuedEvent, Signals, type SignalsConfig, type StorageAdapter, type UserContext, getDefaultStorageAdapter };
|
package/dist/index.js
CHANGED
|
@@ -67,10 +67,11 @@ async function retry(fn, options) {
|
|
|
67
67
|
// src/EventQueue.ts
|
|
68
68
|
var STORAGE_KEY = "session_signals_queue";
|
|
69
69
|
var EventQueue = class {
|
|
70
|
-
constructor(storage,
|
|
70
|
+
constructor(storage, getUserContext, getEventContext) {
|
|
71
71
|
this.queue = [];
|
|
72
72
|
this.storage = storage;
|
|
73
|
-
this.
|
|
73
|
+
this.getUserContext = getUserContext;
|
|
74
|
+
this.getEventContext = getEventContext;
|
|
74
75
|
}
|
|
75
76
|
/**
|
|
76
77
|
* Initialize queue by loading persisted events
|
|
@@ -91,11 +92,17 @@ var EventQueue = class {
|
|
|
91
92
|
* Add event to queue
|
|
92
93
|
*/
|
|
93
94
|
async add(eventData) {
|
|
95
|
+
const userContext = this.getUserContext();
|
|
96
|
+
const eventContext = this.getEventContext();
|
|
97
|
+
const { type, ...payload } = eventData;
|
|
94
98
|
const event = {
|
|
95
99
|
event_id: uuid(),
|
|
96
100
|
timestamp: getTimestamp(),
|
|
97
|
-
session_id:
|
|
98
|
-
|
|
101
|
+
session_id: userContext.session_id,
|
|
102
|
+
type,
|
|
103
|
+
user: userContext,
|
|
104
|
+
context: eventContext,
|
|
105
|
+
...payload
|
|
99
106
|
};
|
|
100
107
|
this.queue.push({
|
|
101
108
|
event,
|
|
@@ -334,6 +341,7 @@ function collectMetadata(version) {
|
|
|
334
341
|
|
|
335
342
|
// src/Signals.ts
|
|
336
343
|
var VERSION = "0.1.0";
|
|
344
|
+
var DEFAULT_ENDPOINT = "https://api.logg.com/events";
|
|
337
345
|
var DEFAULT_BATCH_SIZE = 10;
|
|
338
346
|
var DEFAULT_BATCH_INTERVAL = 5e3;
|
|
339
347
|
var DEFAULT_MAX_RETRIES = 3;
|
|
@@ -346,21 +354,30 @@ var Signals = class {
|
|
|
346
354
|
if (!config.apiKey) {
|
|
347
355
|
throw new Error("Signals: apiKey is required");
|
|
348
356
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}
|
|
357
|
+
const sessionId = config.sessionId ?? uuid();
|
|
358
|
+
const anonymousId = config.anonymousId ?? uuid();
|
|
352
359
|
this.config = {
|
|
353
360
|
apiKey: config.apiKey,
|
|
354
|
-
endpoint: config.endpoint,
|
|
361
|
+
endpoint: config.endpoint ?? DEFAULT_ENDPOINT,
|
|
355
362
|
batchSize: config.batchSize ?? DEFAULT_BATCH_SIZE,
|
|
356
363
|
batchInterval: config.batchInterval ?? DEFAULT_BATCH_INTERVAL,
|
|
357
364
|
maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,
|
|
358
365
|
retryDelay: config.retryDelay ?? DEFAULT_RETRY_DELAY,
|
|
359
366
|
debug: config.debug ?? false,
|
|
360
367
|
storage: config.storage ?? getDefaultStorageAdapter(),
|
|
361
|
-
sessionId
|
|
368
|
+
sessionId
|
|
369
|
+
};
|
|
370
|
+
this.userContext = {
|
|
371
|
+
session_id: sessionId,
|
|
372
|
+
anon_id: anonymousId,
|
|
373
|
+
user_id: config.userId
|
|
362
374
|
};
|
|
363
|
-
this.
|
|
375
|
+
this.eventContext = config.context ?? {};
|
|
376
|
+
this.queue = new EventQueue(
|
|
377
|
+
this.config.storage,
|
|
378
|
+
() => this.userContext,
|
|
379
|
+
() => this.eventContext
|
|
380
|
+
);
|
|
364
381
|
this.init();
|
|
365
382
|
}
|
|
366
383
|
/**
|
|
@@ -484,6 +501,62 @@ var Signals = class {
|
|
|
484
501
|
getQueueSize() {
|
|
485
502
|
return this.queue.size();
|
|
486
503
|
}
|
|
504
|
+
/**
|
|
505
|
+
* Identify the current user
|
|
506
|
+
* Call this after user login to associate events with a user ID
|
|
507
|
+
*/
|
|
508
|
+
identify(userId) {
|
|
509
|
+
this.userContext.user_id = userId;
|
|
510
|
+
this.log("User identified", { userId });
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Set anonymous ID (useful for cross-device tracking before login)
|
|
514
|
+
*/
|
|
515
|
+
setAnonymousId(anonymousId) {
|
|
516
|
+
this.userContext.anon_id = anonymousId;
|
|
517
|
+
this.log("Anonymous ID set", { anonymousId });
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Set the event context (replaces existing context)
|
|
521
|
+
* Use for setting screen, surface, and other contextual information
|
|
522
|
+
*/
|
|
523
|
+
setContext(context) {
|
|
524
|
+
this.eventContext = context;
|
|
525
|
+
this.log("Context set", context);
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Update the event context (merges with existing context)
|
|
529
|
+
* Use for updating specific context properties without replacing the entire context
|
|
530
|
+
*/
|
|
531
|
+
updateContext(context) {
|
|
532
|
+
this.eventContext = { ...this.eventContext, ...context };
|
|
533
|
+
this.log("Context updated", context);
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Get current user context
|
|
537
|
+
*/
|
|
538
|
+
getUserContext() {
|
|
539
|
+
return { ...this.userContext };
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Get current event context
|
|
543
|
+
*/
|
|
544
|
+
getContext() {
|
|
545
|
+
return { ...this.eventContext };
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Reset user context (call on logout)
|
|
549
|
+
* Generates a new anonymous ID and clears user ID
|
|
550
|
+
*/
|
|
551
|
+
reset() {
|
|
552
|
+
this.userContext = {
|
|
553
|
+
session_id: this.config.sessionId,
|
|
554
|
+
anon_id: uuid(),
|
|
555
|
+
user_id: void 0
|
|
556
|
+
};
|
|
557
|
+
this.eventContext = {};
|
|
558
|
+
this.log("Context reset");
|
|
559
|
+
}
|
|
487
560
|
/**
|
|
488
561
|
* Destroy client and cleanup
|
|
489
562
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -43,10 +43,11 @@ async function retry(fn, options) {
|
|
|
43
43
|
// src/EventQueue.ts
|
|
44
44
|
var STORAGE_KEY = "session_signals_queue";
|
|
45
45
|
var EventQueue = class {
|
|
46
|
-
constructor(storage,
|
|
46
|
+
constructor(storage, getUserContext, getEventContext) {
|
|
47
47
|
this.queue = [];
|
|
48
48
|
this.storage = storage;
|
|
49
|
-
this.
|
|
49
|
+
this.getUserContext = getUserContext;
|
|
50
|
+
this.getEventContext = getEventContext;
|
|
50
51
|
}
|
|
51
52
|
/**
|
|
52
53
|
* Initialize queue by loading persisted events
|
|
@@ -67,11 +68,17 @@ var EventQueue = class {
|
|
|
67
68
|
* Add event to queue
|
|
68
69
|
*/
|
|
69
70
|
async add(eventData) {
|
|
71
|
+
const userContext = this.getUserContext();
|
|
72
|
+
const eventContext = this.getEventContext();
|
|
73
|
+
const { type, ...payload } = eventData;
|
|
70
74
|
const event = {
|
|
71
75
|
event_id: uuid(),
|
|
72
76
|
timestamp: getTimestamp(),
|
|
73
|
-
session_id:
|
|
74
|
-
|
|
77
|
+
session_id: userContext.session_id,
|
|
78
|
+
type,
|
|
79
|
+
user: userContext,
|
|
80
|
+
context: eventContext,
|
|
81
|
+
...payload
|
|
75
82
|
};
|
|
76
83
|
this.queue.push({
|
|
77
84
|
event,
|
|
@@ -310,6 +317,7 @@ function collectMetadata(version) {
|
|
|
310
317
|
|
|
311
318
|
// src/Signals.ts
|
|
312
319
|
var VERSION = "0.1.0";
|
|
320
|
+
var DEFAULT_ENDPOINT = "https://api.logg.com/events";
|
|
313
321
|
var DEFAULT_BATCH_SIZE = 10;
|
|
314
322
|
var DEFAULT_BATCH_INTERVAL = 5e3;
|
|
315
323
|
var DEFAULT_MAX_RETRIES = 3;
|
|
@@ -322,21 +330,30 @@ var Signals = class {
|
|
|
322
330
|
if (!config.apiKey) {
|
|
323
331
|
throw new Error("Signals: apiKey is required");
|
|
324
332
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
333
|
+
const sessionId = config.sessionId ?? uuid();
|
|
334
|
+
const anonymousId = config.anonymousId ?? uuid();
|
|
328
335
|
this.config = {
|
|
329
336
|
apiKey: config.apiKey,
|
|
330
|
-
endpoint: config.endpoint,
|
|
337
|
+
endpoint: config.endpoint ?? DEFAULT_ENDPOINT,
|
|
331
338
|
batchSize: config.batchSize ?? DEFAULT_BATCH_SIZE,
|
|
332
339
|
batchInterval: config.batchInterval ?? DEFAULT_BATCH_INTERVAL,
|
|
333
340
|
maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,
|
|
334
341
|
retryDelay: config.retryDelay ?? DEFAULT_RETRY_DELAY,
|
|
335
342
|
debug: config.debug ?? false,
|
|
336
343
|
storage: config.storage ?? getDefaultStorageAdapter(),
|
|
337
|
-
sessionId
|
|
344
|
+
sessionId
|
|
345
|
+
};
|
|
346
|
+
this.userContext = {
|
|
347
|
+
session_id: sessionId,
|
|
348
|
+
anon_id: anonymousId,
|
|
349
|
+
user_id: config.userId
|
|
338
350
|
};
|
|
339
|
-
this.
|
|
351
|
+
this.eventContext = config.context ?? {};
|
|
352
|
+
this.queue = new EventQueue(
|
|
353
|
+
this.config.storage,
|
|
354
|
+
() => this.userContext,
|
|
355
|
+
() => this.eventContext
|
|
356
|
+
);
|
|
340
357
|
this.init();
|
|
341
358
|
}
|
|
342
359
|
/**
|
|
@@ -460,6 +477,62 @@ var Signals = class {
|
|
|
460
477
|
getQueueSize() {
|
|
461
478
|
return this.queue.size();
|
|
462
479
|
}
|
|
480
|
+
/**
|
|
481
|
+
* Identify the current user
|
|
482
|
+
* Call this after user login to associate events with a user ID
|
|
483
|
+
*/
|
|
484
|
+
identify(userId) {
|
|
485
|
+
this.userContext.user_id = userId;
|
|
486
|
+
this.log("User identified", { userId });
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Set anonymous ID (useful for cross-device tracking before login)
|
|
490
|
+
*/
|
|
491
|
+
setAnonymousId(anonymousId) {
|
|
492
|
+
this.userContext.anon_id = anonymousId;
|
|
493
|
+
this.log("Anonymous ID set", { anonymousId });
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Set the event context (replaces existing context)
|
|
497
|
+
* Use for setting screen, surface, and other contextual information
|
|
498
|
+
*/
|
|
499
|
+
setContext(context) {
|
|
500
|
+
this.eventContext = context;
|
|
501
|
+
this.log("Context set", context);
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Update the event context (merges with existing context)
|
|
505
|
+
* Use for updating specific context properties without replacing the entire context
|
|
506
|
+
*/
|
|
507
|
+
updateContext(context) {
|
|
508
|
+
this.eventContext = { ...this.eventContext, ...context };
|
|
509
|
+
this.log("Context updated", context);
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Get current user context
|
|
513
|
+
*/
|
|
514
|
+
getUserContext() {
|
|
515
|
+
return { ...this.userContext };
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Get current event context
|
|
519
|
+
*/
|
|
520
|
+
getContext() {
|
|
521
|
+
return { ...this.eventContext };
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Reset user context (call on logout)
|
|
525
|
+
* Generates a new anonymous ID and clears user ID
|
|
526
|
+
*/
|
|
527
|
+
reset() {
|
|
528
|
+
this.userContext = {
|
|
529
|
+
session_id: this.config.sessionId,
|
|
530
|
+
anon_id: uuid(),
|
|
531
|
+
user_id: void 0
|
|
532
|
+
};
|
|
533
|
+
this.eventContext = {};
|
|
534
|
+
this.log("Context reset");
|
|
535
|
+
}
|
|
463
536
|
/**
|
|
464
537
|
* Destroy client and cleanup
|
|
465
538
|
*/
|