@pipeline-builder/pipeline-data 0.0.1
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/LICENSE +202 -0
- package/README.md +61 -0
- package/drizzle.config.ts +17 -0
- package/lib/api/access-control-builder.d.ts +148 -0
- package/lib/api/access-control-builder.js +199 -0
- package/lib/api/crud-service.d.ts +343 -0
- package/lib/api/crud-service.js +849 -0
- package/lib/api/query-builders.d.ts +82 -0
- package/lib/api/query-builders.js +460 -0
- package/lib/api/reporting-service.d.ts +685 -0
- package/lib/api/reporting-service.js +1564 -0
- package/lib/api/soft-delete-sweep.d.ts +65 -0
- package/lib/api/soft-delete-sweep.js +124 -0
- package/lib/api/viewer-context.d.ts +29 -0
- package/lib/api/viewer-context.js +63 -0
- package/lib/core/query-filters.d.ts +263 -0
- package/lib/core/query-filters.js +4 -0
- package/lib/database/drizzle-schema.d.ts +7357 -0
- package/lib/database/drizzle-schema.js +66 -0
- package/lib/database/index.d.ts +5 -0
- package/lib/database/index.js +8 -0
- package/lib/database/migrator.d.ts +20 -0
- package/lib/database/migrator.js +80 -0
- package/lib/database/postgres-connection.d.ts +201 -0
- package/lib/database/postgres-connection.js +413 -0
- package/lib/database/retry-strategy.d.ts +68 -0
- package/lib/database/retry-strategy.js +122 -0
- package/lib/database/schema/alert.d.ts +588 -0
- package/lib/database/schema/alert.js +130 -0
- package/lib/database/schema/compliance.d.ts +3319 -0
- package/lib/database/schema/compliance.js +377 -0
- package/lib/database/schema/dashboard.d.ts +474 -0
- package/lib/database/schema/dashboard.js +129 -0
- package/lib/database/schema/message-attachment.d.ts +183 -0
- package/lib/database/schema/message-attachment.js +40 -0
- package/lib/database/schema/message.d.ts +411 -0
- package/lib/database/schema/message.js +114 -0
- package/lib/database/schema/pipeline-template.d.ts +466 -0
- package/lib/database/schema/pipeline-template.js +80 -0
- package/lib/database/schema/pipeline.d.ts +1613 -0
- package/lib/database/schema/pipeline.js +332 -0
- package/lib/database/schema/plugin.d.ts +749 -0
- package/lib/database/schema/plugin.js +166 -0
- package/lib/database/tenancy.d.ts +103 -0
- package/lib/database/tenancy.js +167 -0
- package/lib/index.d.ts +32 -0
- package/lib/index.js +38 -0
- package/package.json +161 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { createLogger } from '@pipeline-builder/api-core';
|
|
4
|
+
const logger = createLogger('retry-strategy');
|
|
5
|
+
/**
|
|
6
|
+
* Implements exponential backoff retry strategy for database connections.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Exponential backoff with configurable base delay
|
|
10
|
+
* - Attempt tracking and logging
|
|
11
|
+
* - Graceful failure after max retries
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const strategy = new ConnectionRetryStrategy({ maxRetries: 3, baseDelay: 1000 });
|
|
16
|
+
*
|
|
17
|
+
* const result = await strategy.execute(async () => {
|
|
18
|
+
* return await db.query('SELECT 1');
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export class ConnectionRetryStrategy {
|
|
23
|
+
config;
|
|
24
|
+
attempts = 0;
|
|
25
|
+
constructor(config) {
|
|
26
|
+
this.config = config;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Executes an operation with retry logic
|
|
30
|
+
*
|
|
31
|
+
* @param operation - Async function to execute with retries
|
|
32
|
+
* @returns Promise resolving to operation result
|
|
33
|
+
* @throws Error if all retry attempts fail
|
|
34
|
+
*/
|
|
35
|
+
async execute(operation) {
|
|
36
|
+
this.attempts = 0;
|
|
37
|
+
while (this.attempts < this.config.maxRetries) {
|
|
38
|
+
try {
|
|
39
|
+
const result = await operation();
|
|
40
|
+
if (this.attempts > 0) {
|
|
41
|
+
logger.info('Operation succeeded after retry');
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
this.attempts++;
|
|
47
|
+
if (this.attempts >= this.config.maxRetries) {
|
|
48
|
+
logger.error(`Max retry attempts (${this.config.maxRetries}) reached`);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
const delay = this.calculateBackoff(this.attempts);
|
|
52
|
+
logger.warn(`Operation failed (attempt ${this.attempts}/${this.config.maxRetries}), retrying in ${delay}ms...`, { error: error instanceof Error ? error.message : String(error) });
|
|
53
|
+
await this.sleep(delay);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
throw new Error('Retry logic failed unexpectedly');
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Handles connection errors with retry tracking
|
|
60
|
+
*
|
|
61
|
+
* @param error - Error that occurred
|
|
62
|
+
* @param testConnection - Function to test if connection is restored
|
|
63
|
+
*/
|
|
64
|
+
async handleConnectionError(error, testConnection) {
|
|
65
|
+
this.attempts++;
|
|
66
|
+
logger.error(`Connection error (attempt ${this.attempts}/${this.config.maxRetries}):`, error.message);
|
|
67
|
+
if (this.attempts < this.config.maxRetries) {
|
|
68
|
+
const delay = this.calculateBackoff(this.attempts);
|
|
69
|
+
logger.info(`Retrying connection in ${delay}ms...`);
|
|
70
|
+
await this.sleep(delay);
|
|
71
|
+
try {
|
|
72
|
+
const isHealthy = await testConnection();
|
|
73
|
+
if (isHealthy) {
|
|
74
|
+
logger.info('Connection restored');
|
|
75
|
+
this.attempts = 0; // Reset on successful connection
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
logger.error('Connection test failed after retry');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (retryError) {
|
|
82
|
+
logger.error('Retry failed:', retryError);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
logger.error('Max connection retry attempts reached');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Resets the attempt counter
|
|
91
|
+
* Call this after a successful operation
|
|
92
|
+
*/
|
|
93
|
+
reset() {
|
|
94
|
+
this.attempts = 0;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Gets the current attempt count
|
|
98
|
+
*/
|
|
99
|
+
getAttempts() {
|
|
100
|
+
return this.attempts;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Calculates exponential backoff delay
|
|
104
|
+
*
|
|
105
|
+
* @param attempt - Current attempt number (1-indexed)
|
|
106
|
+
* @returns Delay in milliseconds
|
|
107
|
+
*/
|
|
108
|
+
calculateBackoff(attempt) {
|
|
109
|
+
const base = this.config.baseDelay * Math.pow(2, attempt - 1);
|
|
110
|
+
const jitter = Math.random() * 0.1 * base;
|
|
111
|
+
return base + jitter;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Sleeps for the specified duration
|
|
115
|
+
*
|
|
116
|
+
* @param ms - Milliseconds to sleep
|
|
117
|
+
*/
|
|
118
|
+
sleep(ms) {
|
|
119
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmV0cnktc3RyYXRlZ3kuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGF0YWJhc2UvcmV0cnktc3RyYXRlZ3kudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFMUQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLGdCQUFnQixDQUFDLENBQUM7QUFZOUM7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCxNQUFNLE9BQU8sdUJBQXVCO0lBR0wsTUFBTTtJQUYzQixRQUFRLEdBQUcsQ0FBQyxDQUFDO0lBRXJCLFlBQTZCLE1BQW1CO3NCQUFuQixNQUFNO0lBQWdCLENBQUM7SUFFcEQ7Ozs7OztPQU1HO0lBQ0gsS0FBSyxDQUFDLE9BQU8sQ0FBSSxTQUEyQjtRQUMxQyxJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQztRQUVsQixPQUFPLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUM5QyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxNQUFNLEdBQUcsTUFBTSxTQUFTLEVBQUUsQ0FBQztnQkFDakMsSUFBSSxJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUN0QixNQUFNLENBQUMsSUFBSSxDQUFDLGlDQUFpQyxDQUFDLENBQUM7Z0JBQ2pELENBQUM7Z0JBQ0QsT0FBTyxNQUFNLENBQUM7WUFDaEIsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUVoQixJQUFJLElBQUksQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztvQkFDNUMsTUFBTSxDQUFDLEtBQUssQ0FBQyx1QkFBdUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLFdBQVcs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QyxDQUFDLENBQUM7SUFDekQsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdyZXRyeS1zdHJhdGVneScpO1xuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIGNvbm5lY3Rpb24gcmV0cnkgc3RyYXRlZ3lcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXRyeUNvbmZpZyB7XG4gIC8qKiBNYXhpbXVtIG51bWJlciBvZiByZXRyeSBhdHRlbXB0cyAqL1xuICBtYXhSZXRyaWVzOiBudW1iZXI7XG4gIC8qKiBCYXNlIGRlbGF5IGJldHdlZW4gcmV0cmllcyBpbiBtaWxsaXNlY29uZHMgKi9cbiAgYmFzZURlbGF5OiBudW1iZXI7XG59XG5cbi8qKlxuICogSW1wbGVtZW50cyBleHBvbmVudGlhbCBiYWNrb2ZmIHJldHJ5IHN0cmF0ZWd5IGZvciBkYXRhYmFzZSBjb25uZWN0aW9ucy5cbiAqXG4gKiBGZWF0dXJlczpcbiAqIC0gRXhwb25lbnRpYWwgYmFja29mZiB3aXRoIGNvbmZpZ3VyYWJsZSBiYXNlIGRlbGF5XG4gKiAtIEF0dGVtcHQgdHJhY2tpbmcgYW5kIGxvZ2dpbmdcbiAqIC0gR3JhY2VmdWwgZmFpbHVyZSBhZnRlciBtYXggcmV0cmllc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBzdHJhdGVneSA9IG5ldyBDb25uZWN0aW9uUmV0cnlTdHJhdGVneSh7IG1heFJldHJpZXM6IDMsIGJhc2VEZWxheTogMTAwMCB9KTtcbiAqXG4gKiBjb25zdCByZXN1bHQgPSBhd2FpdCBzdHJhdGVneS5leGVjdXRlKGFzeW5jICgpID0+IHtcbiAqICAgcmV0dXJuIGF3YWl0IGRiLnF1ZXJ5KCdTRUxFQ1QgMScpO1xuICogfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIENvbm5lY3Rpb25SZXRyeVN0cmF0ZWd5IHtcbiAgcHJpdmF0ZSBhdHRlbXB0cyA9IDA7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBjb25maWc6IFJldHJ5Q29uZmlnKSB7fVxuXG4gIC8qKlxuICAgKiBFeGVjdXRlcyBhbiBvcGVyYXRpb24gd2l0aCByZXRyeSBsb2dpY1xuICAgKlxuICAgKiBAcGFyYW0gb3BlcmF0aW9uIC0gQXN5bmMgZnVuY3Rpb24gdG8gZXhlY3V0ZSB3aXRoIHJldHJpZXNcbiAgICogQHJldHVybnMgUHJvbWlzZSByZXNvbHZpbmcgdG8gb3BlcmF0aW9uIHJlc3VsdFxuICAgKiBAdGhyb3dzIEVycm9yIGlmIGFsbCByZXRyeSBhdHRlbXB0cyBmYWlsXG4gICAqL1xuICBhc3luYyBleGVjdXRlPFQ+KG9wZXJhdGlvbjogKCkgPT4gUHJvbWlzZTxUPik6IFByb21pc2U8VD4ge1xuICAgIHRoaXMuYXR0ZW1wdHMgPSAwO1xuXG4gICAgd2hpbGUgKHRoaXMuYXR0ZW1wdHMgPCB0aGlzLmNvbmZpZy5tYXhSZXRyaWVzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBvcGVyYXRpb24oKTtcbiAgICAgICAgaWYgKHRoaXMuYXR0ZW1wdHMgPiAwKSB7XG4gICAgICAgICAgbG9nZ2VyLmluZm8oJ09wZXJhdGlvbiBzdWNjZWVkZWQgYWZ0ZXIgcmV0cnknKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5hdHRlbXB0cysrO1xuXG4gICAgICAgIGlmICh0aGlzLmF0dGVtcHRzID49IHRoaXMuY29uZmlnLm1heFJldHJpZXMpIHtcbiAgICAgICAgICBsb2dnZXIuZXJyb3IoYE1heCByZXRyeSBhdHRlbXB0cyAoJHt0aGlzLmNvbmZpZy5tYXhSZXRyaWVzfSkgcmVhY2hlZGApO1xuICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZGVsYXkgPSB0aGlzLmNhbGN1bGF0ZUJhY2tvZmYodGhpcy5hdHRlbXB0cyk7XG4gICAgICAgIGxvZ2dlci53YXJuKFxuICAgICAgICAgIGBPcGVyYXRpb24gZmFpbGVkIChhdHRlbXB0ICR7dGhpcy5hdHRlbXB0c30vJHt0aGlzLmNvbmZpZy5tYXhSZXRyaWVzfSksIHJldHJ5aW5nIGluICR7ZGVsYXl9bXMuLi5gLFxuICAgICAgICAgIHsgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKSB9LFxuICAgICAgICApO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuc2xlZXAoZGVsYXkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcignUmV0cnkgbG9naWMgZmFpbGVkIHVuZXhwZWN0ZWRseScpO1xuICB9XG5cbiAgLyoqXG4gICAqIEhhbmRsZXMgY29ubmVjdGlvbiBlcnJvcnMgd2l0aCByZXRyeSB0cmFja2luZ1xuICAgKlxuICAgKiBAcGFyYW0gZXJyb3IgLSBFcnJvciB0aGF0IG9jY3VycmVkXG4gICAqIEBwYXJhbSB0ZXN0Q29ubmVjdGlvbiAtIEZ1bmN0aW9uIHRvIHRlc3QgaWYgY29ubmVjdGlvbiBpcyByZXN0b3JlZFxuICAgKi9cbiAgYXN5bmMgaGFuZGxlQ29ubmVjdGlvbkVycm9yKGVycm9yOiBFcnJvciwgdGVzdENvbm5lY3Rpb246ICgpID0+IFByb21pc2U8Ym9vbGVhbj4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmF0dGVtcHRzKys7XG5cbiAgICBsb2dnZXIuZXJyb3IoXG4gICAgICBgQ29ubmVjdGlvbiBlcnJvciAoYXR0ZW1wdCAke3RoaXMuYXR0ZW1wdHN9LyR7dGhpcy5jb25maWcubWF4UmV0cmllc30pOmAsXG4gICAgICBlcnJvci5tZXNzYWdlLFxuICAgICk7XG5cbiAgICBpZiAodGhpcy5hdHRlbXB0cyA8IHRoaXMuY29uZmlnLm1heFJldHJpZXMpIHtcbiAgICAgIGNvbnN0IGRlbGF5ID0gdGhpcy5jYWxjdWxhdGVCYWNrb2ZmKHRoaXMuYXR0ZW1wdHMpO1xuICAgICAgbG9nZ2VyLmluZm8oYFJldHJ5aW5nIGNvbm5lY3Rpb24gaW4gJHtkZWxheX1tcy4uLmApO1xuXG4gICAgICBhd2FpdCB0aGlzLnNsZWVwKGRlbGF5KTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgaXNIZWFsdGh5ID0gYXdhaXQgdGVzdENvbm5lY3Rpb24oKTtcbiAgICAgICAgaWYgKGlzSGVhbHRoeSkge1xuICAgICAgICAgIGxvZ2dlci5pbmZvKCdDb25uZWN0aW9uIHJlc3RvcmVkJyk7XG4gICAgICAgICAgdGhpcy5hdHRlbXB0cyA9IDA7IC8vIFJlc2V0IG9uIHN1Y2Nlc3NmdWwgY29ubmVjdGlvblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxvZ2dlci5lcnJvcignQ29ubmVjdGlvbiB0ZXN0IGZhaWxlZCBhZnRlciByZXRyeScpO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChyZXRyeUVycm9yKSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcignUmV0cnkgZmFpbGVkOicsIHJldHJ5RXJyb3IpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ01heCBjb25uZWN0aW9uIHJldHJ5IGF0dGVtcHRzIHJlYWNoZWQnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVzZXRzIHRoZSBhdHRlbXB0IGNvdW50ZXJcbiAgICogQ2FsbCB0aGlzIGFmdGVyIGEgc3VjY2Vzc2Z1bCBvcGVyYXRpb25cbiAgICovXG4gIHJlc2V0KCk6IHZvaWQge1xuICAgIHRoaXMuYXR0ZW1wdHMgPSAwO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGN1cnJlbnQgYXR0ZW1wdCBjb3VudFxuICAgKi9cbiAgZ2V0QXR0ZW1wdHMoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5hdHRlbXB0cztcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIGV4cG9uZW50aWFsIGJhY2tvZmYgZGVsYXlcbiAgICpcbiAgICogQHBhcmFtIGF0dGVtcHQgLSBDdXJyZW50IGF0dGVtcHQgbnVtYmVyICgxLWluZGV4ZWQpXG4gICAqIEByZXR1cm5zIERlbGF5IGluIG1pbGxpc2Vjb25kc1xuICAgKi9cbiAgcHJpdmF0ZSBjYWxjdWxhdGVCYWNrb2ZmKGF0dGVtcHQ6IG51bWJlcik6IG51bWJlciB7XG4gICAgY29uc3QgYmFzZSA9IHRoaXMuY29uZmlnLmJhc2VEZWxheSAqIE1hdGgucG93KDIsIGF0dGVtcHQgLSAxKTtcbiAgICBjb25zdCBqaXR0ZXIgPSBNYXRoLnJhbmRvbSgpICogMC4xICogYmFzZTtcbiAgICByZXR1cm4gYmFzZSArIGppdHRlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBTbGVlcHMgZm9yIHRoZSBzcGVjaWZpZWQgZHVyYXRpb25cbiAgICpcbiAgICogQHBhcmFtIG1zIC0gTWlsbGlzZWNvbmRzIHRvIHNsZWVwXG4gICAqL1xuICBwcml2YXRlIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSk7XG4gIH1cbn1cbiJdfQ==
|