@fedify/postgres 0.3.0-dev.16 → 0.3.0-dev.18
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 +10 -2
- package/esm/src/kv.js +8 -0
- package/esm/src/mq.js +29 -4
- package/package.json +5 -4
- package/script/src/kv.js +8 -0
- package/script/src/mq.js +29 -4
- package/types/src/kv.d.ts.map +1 -1
- package/types/src/mq.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -30,8 +30,8 @@ const federation = createFederation({
|
|
|
30
30
|
[JSR badge]: https://jsr.io/badges/@fedify/postgres
|
|
31
31
|
[npm]: https://www.npmjs.com/package/@fedify/postgres
|
|
32
32
|
[npm badge]: https://img.shields.io/npm/v/@fedify/postgres?logo=npm
|
|
33
|
-
[GitHub Actions]: https://github.com/
|
|
34
|
-
[GitHub Actions badge]: https://github.com/
|
|
33
|
+
[GitHub Actions]: https://github.com/fedify-dev/postgres/actions/workflows/main.yaml
|
|
34
|
+
[GitHub Actions badge]: https://github.com/fedify-dev/postgres/actions/workflows/main.yaml/badge.svg
|
|
35
35
|
[Fedify]: https://fedify.dev/
|
|
36
36
|
[`KvStore`]: https://jsr.io/@fedify/fedify/doc/federation/~/KvStore
|
|
37
37
|
[`MessageQueue`]: https://jsr.io/@fedify/fedify/doc/federation/~/MessageQueue
|
|
@@ -68,6 +68,14 @@ Changelog
|
|
|
68
68
|
|
|
69
69
|
To be released.
|
|
70
70
|
|
|
71
|
+
- Added some logging using [LogTape] for the sake of debugging. The following
|
|
72
|
+
categories are used:
|
|
73
|
+
|
|
74
|
+
- `["fedify", "postgres", "kv"]`
|
|
75
|
+
- `["fedify", "postgres", "mq"]`
|
|
76
|
+
|
|
77
|
+
[LogTape]: https://logtape.org/
|
|
78
|
+
|
|
71
79
|
### Version 0.2.2
|
|
72
80
|
|
|
73
81
|
Released on November 18, 2024.
|
package/esm/src/kv.js
CHANGED
|
@@ -10,7 +10,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
12
|
var _PostgresKvStore_instances, _PostgresKvStore_sql, _PostgresKvStore_tableName, _PostgresKvStore_initialized, _PostgresKvStore_driverSerializesJson, _PostgresKvStore_expire, _PostgresKvStore_json;
|
|
13
|
+
import { getLogger } from "@logtape/logtape";
|
|
13
14
|
import { driverSerializesJson } from "./utils.js";
|
|
15
|
+
const logger = getLogger(["fedify", "postgres", "kv"]);
|
|
14
16
|
/**
|
|
15
17
|
* A key-value store that uses PostgreSQL as the underlying storage.
|
|
16
18
|
*
|
|
@@ -86,6 +88,9 @@ export class PostgresKvStore {
|
|
|
86
88
|
async initialize() {
|
|
87
89
|
if (__classPrivateFieldGet(this, _PostgresKvStore_initialized, "f"))
|
|
88
90
|
return;
|
|
91
|
+
logger.debug("Initializing the key-value store table {tableName}...", {
|
|
92
|
+
tableName: __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"),
|
|
93
|
+
});
|
|
89
94
|
await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
|
|
90
95
|
CREATE UNLOGGED TABLE IF NOT EXISTS ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))} (
|
|
91
96
|
key text[] PRIMARY KEY,
|
|
@@ -96,6 +101,9 @@ export class PostgresKvStore {
|
|
|
96
101
|
`;
|
|
97
102
|
__classPrivateFieldSet(this, _PostgresKvStore_driverSerializesJson, await driverSerializesJson(__classPrivateFieldGet(this, _PostgresKvStore_sql, "f")), "f");
|
|
98
103
|
__classPrivateFieldSet(this, _PostgresKvStore_initialized, true, "f");
|
|
104
|
+
logger.debug("Initialized the key-value store table {tableName}.", {
|
|
105
|
+
tableName: __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"),
|
|
106
|
+
});
|
|
99
107
|
}
|
|
100
108
|
/**
|
|
101
109
|
* Drops the table used by the key-value store. Does nothing if the table
|
package/esm/src/mq.js
CHANGED
|
@@ -11,8 +11,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
11
11
|
};
|
|
12
12
|
var _PostgresMessageQueue_instances, _PostgresMessageQueue_sql, _PostgresMessageQueue_tableName, _PostgresMessageQueue_channelName, _PostgresMessageQueue_pollIntervalMs, _PostgresMessageQueue_initialized, _PostgresMessageQueue_driverSerializesJson, _PostgresMessageQueue_json;
|
|
13
13
|
import * as dntShim from "../_dnt.shims.js";
|
|
14
|
+
import { getLogger } from "@logtape/logtape";
|
|
14
15
|
import postgres from "postgres";
|
|
15
16
|
import { driverSerializesJson } from "./utils.js";
|
|
17
|
+
const logger = getLogger(["fedify", "postgres", "mq"]);
|
|
16
18
|
/**
|
|
17
19
|
* A message queue that uses PostgreSQL as the underlying storage.
|
|
18
20
|
*
|
|
@@ -53,6 +55,15 @@ export class PostgresMessageQueue {
|
|
|
53
55
|
message, options) {
|
|
54
56
|
await this.initialize();
|
|
55
57
|
const delay = options?.delay ?? dntShim.Temporal.Duration.from({ seconds: 0 });
|
|
58
|
+
if (options?.delay) {
|
|
59
|
+
logger.debug("Enqueuing a message with a delay of {delay}...", {
|
|
60
|
+
delay,
|
|
61
|
+
message,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
logger.debug("Enqueuing a message...", { message });
|
|
66
|
+
}
|
|
56
67
|
await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `
|
|
57
68
|
INSERT INTO ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))} (message, delay)
|
|
58
69
|
VALUES (
|
|
@@ -60,7 +71,12 @@ export class PostgresMessageQueue {
|
|
|
60
71
|
${delay.toString()}
|
|
61
72
|
);
|
|
62
73
|
`;
|
|
74
|
+
logger.debug("Enqueued a message.", { message });
|
|
63
75
|
await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").notify(__classPrivateFieldGet(this, _PostgresMessageQueue_channelName, "f"), delay.toString());
|
|
76
|
+
logger.debug("Notified the message queue channel {channelName}.", {
|
|
77
|
+
channelName: __classPrivateFieldGet(this, _PostgresMessageQueue_channelName, "f"),
|
|
78
|
+
message,
|
|
79
|
+
});
|
|
64
80
|
}
|
|
65
81
|
async listen(
|
|
66
82
|
// deno-lint-ignore no-explicit-any
|
|
@@ -134,6 +150,9 @@ export class PostgresMessageQueue {
|
|
|
134
150
|
async initialize() {
|
|
135
151
|
if (__classPrivateFieldGet(this, _PostgresMessageQueue_initialized, "f"))
|
|
136
152
|
return;
|
|
153
|
+
logger.debug("Initializing the message queue table {tableName}...", {
|
|
154
|
+
tableName: __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"),
|
|
155
|
+
});
|
|
137
156
|
try {
|
|
138
157
|
await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `
|
|
139
158
|
CREATE TABLE IF NOT EXISTS ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))} (
|
|
@@ -144,14 +163,20 @@ export class PostgresMessageQueue {
|
|
|
144
163
|
);
|
|
145
164
|
`;
|
|
146
165
|
}
|
|
147
|
-
catch (
|
|
148
|
-
if (!(
|
|
149
|
-
|
|
150
|
-
|
|
166
|
+
catch (error) {
|
|
167
|
+
if (!(error instanceof postgres.PostgresError &&
|
|
168
|
+
error.constraint_name === "pg_type_typname_nsp_index")) {
|
|
169
|
+
logger.error("Failed to initialize the message queue table: {error}", {
|
|
170
|
+
error,
|
|
171
|
+
});
|
|
172
|
+
throw error;
|
|
151
173
|
}
|
|
152
174
|
}
|
|
153
175
|
__classPrivateFieldSet(this, _PostgresMessageQueue_driverSerializesJson, await driverSerializesJson(__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f")), "f");
|
|
154
176
|
__classPrivateFieldSet(this, _PostgresMessageQueue_initialized, true, "f");
|
|
177
|
+
logger.debug("Initialized the message queue table {tableName}.", {
|
|
178
|
+
tableName: __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"),
|
|
179
|
+
});
|
|
155
180
|
}
|
|
156
181
|
/**
|
|
157
182
|
* Drops the message queue table if it exists.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/postgres",
|
|
3
|
-
"version": "0.3.0-dev.
|
|
3
|
+
"version": "0.3.0-dev.18+ccf67837",
|
|
4
4
|
"description": "PostgreSQL drivers for Fedify",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fedify",
|
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
"email": "hong@minhee.org",
|
|
13
13
|
"url": "https://hongminhee.org/"
|
|
14
14
|
},
|
|
15
|
-
"homepage": "https://github.com/
|
|
15
|
+
"homepage": "https://github.com/fedify-dev/postgres",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/
|
|
18
|
+
"url": "git+https://github.com/fedify-dev/postgres.git"
|
|
19
19
|
},
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"bugs": {
|
|
22
|
-
"url": "https://github.com/
|
|
22
|
+
"url": "https://github.com/fedify-dev/postgres/issues"
|
|
23
23
|
},
|
|
24
24
|
"main": "./script/mod.js",
|
|
25
25
|
"module": "./esm/mod.js",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
],
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@fedify/fedify": "^1.0.0",
|
|
64
|
+
"@logtape/logtape": "^0.8.0",
|
|
64
65
|
"postgres": "^3.4.5",
|
|
65
66
|
"@deno/shim-deno": "~0.18.0",
|
|
66
67
|
"@js-temporal/polyfill": "^0.4.4"
|
package/script/src/kv.js
CHANGED
|
@@ -13,7 +13,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
13
13
|
var _PostgresKvStore_instances, _PostgresKvStore_sql, _PostgresKvStore_tableName, _PostgresKvStore_initialized, _PostgresKvStore_driverSerializesJson, _PostgresKvStore_expire, _PostgresKvStore_json;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.PostgresKvStore = void 0;
|
|
16
|
+
const logtape_1 = require("@logtape/logtape");
|
|
16
17
|
const utils_js_1 = require("./utils.js");
|
|
18
|
+
const logger = (0, logtape_1.getLogger)(["fedify", "postgres", "kv"]);
|
|
17
19
|
/**
|
|
18
20
|
* A key-value store that uses PostgreSQL as the underlying storage.
|
|
19
21
|
*
|
|
@@ -89,6 +91,9 @@ class PostgresKvStore {
|
|
|
89
91
|
async initialize() {
|
|
90
92
|
if (__classPrivateFieldGet(this, _PostgresKvStore_initialized, "f"))
|
|
91
93
|
return;
|
|
94
|
+
logger.debug("Initializing the key-value store table {tableName}...", {
|
|
95
|
+
tableName: __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"),
|
|
96
|
+
});
|
|
92
97
|
await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
|
|
93
98
|
CREATE UNLOGGED TABLE IF NOT EXISTS ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))} (
|
|
94
99
|
key text[] PRIMARY KEY,
|
|
@@ -99,6 +104,9 @@ class PostgresKvStore {
|
|
|
99
104
|
`;
|
|
100
105
|
__classPrivateFieldSet(this, _PostgresKvStore_driverSerializesJson, await (0, utils_js_1.driverSerializesJson)(__classPrivateFieldGet(this, _PostgresKvStore_sql, "f")), "f");
|
|
101
106
|
__classPrivateFieldSet(this, _PostgresKvStore_initialized, true, "f");
|
|
107
|
+
logger.debug("Initialized the key-value store table {tableName}.", {
|
|
108
|
+
tableName: __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"),
|
|
109
|
+
});
|
|
102
110
|
}
|
|
103
111
|
/**
|
|
104
112
|
* Drops the table used by the key-value store. Does nothing if the table
|
package/script/src/mq.js
CHANGED
|
@@ -40,8 +40,10 @@ var _PostgresMessageQueue_instances, _PostgresMessageQueue_sql, _PostgresMessage
|
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
41
|
exports.PostgresMessageQueue = void 0;
|
|
42
42
|
const dntShim = __importStar(require("../_dnt.shims.js"));
|
|
43
|
+
const logtape_1 = require("@logtape/logtape");
|
|
43
44
|
const postgres_1 = __importDefault(require("postgres"));
|
|
44
45
|
const utils_js_1 = require("./utils.js");
|
|
46
|
+
const logger = (0, logtape_1.getLogger)(["fedify", "postgres", "mq"]);
|
|
45
47
|
/**
|
|
46
48
|
* A message queue that uses PostgreSQL as the underlying storage.
|
|
47
49
|
*
|
|
@@ -82,6 +84,15 @@ class PostgresMessageQueue {
|
|
|
82
84
|
message, options) {
|
|
83
85
|
await this.initialize();
|
|
84
86
|
const delay = options?.delay ?? dntShim.Temporal.Duration.from({ seconds: 0 });
|
|
87
|
+
if (options?.delay) {
|
|
88
|
+
logger.debug("Enqueuing a message with a delay of {delay}...", {
|
|
89
|
+
delay,
|
|
90
|
+
message,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
logger.debug("Enqueuing a message...", { message });
|
|
95
|
+
}
|
|
85
96
|
await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `
|
|
86
97
|
INSERT INTO ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))} (message, delay)
|
|
87
98
|
VALUES (
|
|
@@ -89,7 +100,12 @@ class PostgresMessageQueue {
|
|
|
89
100
|
${delay.toString()}
|
|
90
101
|
);
|
|
91
102
|
`;
|
|
103
|
+
logger.debug("Enqueued a message.", { message });
|
|
92
104
|
await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").notify(__classPrivateFieldGet(this, _PostgresMessageQueue_channelName, "f"), delay.toString());
|
|
105
|
+
logger.debug("Notified the message queue channel {channelName}.", {
|
|
106
|
+
channelName: __classPrivateFieldGet(this, _PostgresMessageQueue_channelName, "f"),
|
|
107
|
+
message,
|
|
108
|
+
});
|
|
93
109
|
}
|
|
94
110
|
async listen(
|
|
95
111
|
// deno-lint-ignore no-explicit-any
|
|
@@ -163,6 +179,9 @@ class PostgresMessageQueue {
|
|
|
163
179
|
async initialize() {
|
|
164
180
|
if (__classPrivateFieldGet(this, _PostgresMessageQueue_initialized, "f"))
|
|
165
181
|
return;
|
|
182
|
+
logger.debug("Initializing the message queue table {tableName}...", {
|
|
183
|
+
tableName: __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"),
|
|
184
|
+
});
|
|
166
185
|
try {
|
|
167
186
|
await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `
|
|
168
187
|
CREATE TABLE IF NOT EXISTS ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))} (
|
|
@@ -173,14 +192,20 @@ class PostgresMessageQueue {
|
|
|
173
192
|
);
|
|
174
193
|
`;
|
|
175
194
|
}
|
|
176
|
-
catch (
|
|
177
|
-
if (!(
|
|
178
|
-
|
|
179
|
-
|
|
195
|
+
catch (error) {
|
|
196
|
+
if (!(error instanceof postgres_1.default.PostgresError &&
|
|
197
|
+
error.constraint_name === "pg_type_typname_nsp_index")) {
|
|
198
|
+
logger.error("Failed to initialize the message queue table: {error}", {
|
|
199
|
+
error,
|
|
200
|
+
});
|
|
201
|
+
throw error;
|
|
180
202
|
}
|
|
181
203
|
}
|
|
182
204
|
__classPrivateFieldSet(this, _PostgresMessageQueue_driverSerializesJson, await (0, utils_js_1.driverSerializesJson)(__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f")), "f");
|
|
183
205
|
__classPrivateFieldSet(this, _PostgresMessageQueue_initialized, true, "f");
|
|
206
|
+
logger.debug("Initialized the message queue table {tableName}.", {
|
|
207
|
+
tableName: __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"),
|
|
208
|
+
});
|
|
184
209
|
}
|
|
185
210
|
/**
|
|
186
211
|
* Drops the message queue table if it exists.
|
package/types/src/kv.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kv.d.ts","sourceRoot":"","sources":["../../src/src/kv.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"kv.d.ts","sourceRoot":"","sources":["../../src/src/kv.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExE,OAAO,KAAK,EAAwB,GAAG,EAAE,MAAM,UAAU,CAAC;AAK1D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAgB,YAAW,OAAO;;IAO7C;;;;OAIG;gBAGD,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,EACZ,OAAO,GAAE,sBAA2B;IAchC,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,KAAK,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAWpD,GAAG,CACP,GAAG,EAAE,KAAK,EACV,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,iBAAiB,GAAG,SAAS,GACtC,OAAO,CAAC,IAAI,CAAC;IAgBV,MAAM,CAAC,GAAG,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IASvC;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBjC;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ5B"}
|
package/types/src/mq.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mq.d.ts","sourceRoot":"","sources":["../../src/src/mq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EACV,YAAY,EACZ,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"mq.d.ts","sourceRoot":"","sources":["../../src/src/mq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EACV,YAAY,EACZ,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAwB,GAAG,EAAE,MAAM,UAAU,CAAC;AAM1D;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;CAC1E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,oBAAqB,YAAW,YAAY;;gBAWrD,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,EACZ,OAAO,GAAE,2BAAgC;IAWrC,OAAO,CAEX,OAAO,EAAE,GAAG,EACZ,OAAO,CAAC,EAAE,0BAA0B,GACnC,OAAO,CAAC,IAAI,CAAC;IA0BV,MAAM,CAEV,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EAC/C,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,IAAI,CAAC;IA8DhB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgCjC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ5B"}
|