@soulbatical/tetra-core 0.1.13 → 0.1.15
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.
Potentially problematic release.
This version of @soulbatical/tetra-core might be problematic. Click here for more details.
- package/dist/generators/rls-auditor.d.ts +39 -0
- package/dist/generators/rls-auditor.d.ts.map +1 -0
- package/dist/generators/rls-auditor.js +505 -0
- package/dist/generators/rls-auditor.js.map +1 -0
- package/dist/generators/rls-checker.d.ts +94 -0
- package/dist/generators/rls-checker.d.ts.map +1 -0
- package/dist/generators/rls-checker.js +215 -0
- package/dist/generators/rls-checker.js.map +1 -0
- package/dist/generators/rls-generator.d.ts +77 -0
- package/dist/generators/rls-generator.d.ts.map +1 -0
- package/dist/generators/rls-generator.js +402 -0
- package/dist/generators/rls-generator.js.map +1 -0
- package/dist/generators/rpc/detail-rpc-generator.d.ts +58 -0
- package/dist/generators/rpc/detail-rpc-generator.d.ts.map +1 -0
- package/dist/generators/rpc/detail-rpc-generator.js +163 -0
- package/dist/generators/rpc/detail-rpc-generator.js.map +1 -0
- package/dist/generators/rpc/index.d.ts +24 -0
- package/dist/generators/rpc/index.d.ts.map +1 -0
- package/dist/generators/rpc/index.js +20 -0
- package/dist/generators/rpc/index.js.map +1 -0
- package/dist/generators/rpc/rpc-generator.d.ts +150 -0
- package/dist/generators/rpc/rpc-generator.d.ts.map +1 -0
- package/dist/generators/rpc/rpc-generator.js +743 -0
- package/dist/generators/rpc/rpc-generator.js.map +1 -0
- package/dist/generators/rpc/templates/array.d.ts +29 -0
- package/dist/generators/rpc/templates/array.d.ts.map +1 -0
- package/dist/generators/rpc/templates/array.js +40 -0
- package/dist/generators/rpc/templates/array.js.map +1 -0
- package/dist/generators/rpc/templates/auth.d.ts +85 -0
- package/dist/generators/rpc/templates/auth.d.ts.map +1 -0
- package/dist/generators/rpc/templates/auth.js +233 -0
- package/dist/generators/rpc/templates/auth.js.map +1 -0
- package/dist/generators/rpc/templates/column.d.ts +39 -0
- package/dist/generators/rpc/templates/column.d.ts.map +1 -0
- package/dist/generators/rpc/templates/column.js +97 -0
- package/dist/generators/rpc/templates/column.js.map +1 -0
- package/dist/generators/rpc/templates/enum.d.ts +33 -0
- package/dist/generators/rpc/templates/enum.d.ts.map +1 -0
- package/dist/generators/rpc/templates/enum.js +93 -0
- package/dist/generators/rpc/templates/enum.js.map +1 -0
- package/dist/generators/rpc/templates/nullable.d.ts +31 -0
- package/dist/generators/rpc/templates/nullable.d.ts.map +1 -0
- package/dist/generators/rpc/templates/nullable.js +50 -0
- package/dist/generators/rpc/templates/nullable.js.map +1 -0
- package/dist/generators/rpc/templates/related.d.ts +47 -0
- package/dist/generators/rpc/templates/related.d.ts.map +1 -0
- package/dist/generators/rpc/templates/related.js +182 -0
- package/dist/generators/rpc/templates/related.js.map +1 -0
- package/dist/generators/rpc/templates/search.d.ts +42 -0
- package/dist/generators/rpc/templates/search.d.ts.map +1 -0
- package/dist/generators/rpc/templates/search.js +81 -0
- package/dist/generators/rpc/templates/search.js.map +1 -0
- package/dist/generators/rpc/templates/time.d.ts +44 -0
- package/dist/generators/rpc/templates/time.d.ts.map +1 -0
- package/dist/generators/rpc/templates/time.js +143 -0
- package/dist/generators/rpc/templates/time.js.map +1 -0
- package/dist/generators/rpc/utils.d.ts +58 -0
- package/dist/generators/rpc/utils.d.ts.map +1 -0
- package/dist/generators/rpc/utils.js +92 -0
- package/dist/generators/rpc/utils.js.map +1 -0
- package/dist/generators/rpc/validator.d.ts +21 -0
- package/dist/generators/rpc/validator.d.ts.map +1 -0
- package/dist/generators/rpc/validator.js +398 -0
- package/dist/generators/rpc/validator.js.map +1 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/shared/auth/index.d.ts +1 -1
- package/dist/shared/auth/index.d.ts.map +1 -1
- package/dist/shared/auth/routes.d.ts +4 -1
- package/dist/shared/auth/routes.d.ts.map +1 -1
- package/dist/shared/auth/routes.js +83 -1
- package/dist/shared/auth/routes.js.map +1 -1
- package/dist/shared/auth/types.d.ts +24 -0
- package/dist/shared/auth/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tetra RLS Checker v2.0
|
|
3
|
+
*
|
|
4
|
+
* Runs the Tetra RLS audit checks against a live Supabase project
|
|
5
|
+
* and returns a structured report with pass/fail per check.
|
|
6
|
+
*
|
|
7
|
+
* This is NOT just a config checker — it verifies:
|
|
8
|
+
* - Foundation: RLS enabled, FORCE RLS, policies exist
|
|
9
|
+
* - Policy quality: roles, expressions, CRUD coverage
|
|
10
|
+
* - Auth functions: exist, SECURITY DEFINER, search_path
|
|
11
|
+
* - RLS bypass routes: functions/views/grants that skip RLS entirely
|
|
12
|
+
* - Data exposure: Realtime on sensitive tables
|
|
13
|
+
* - Migration state: Tetra standards actually applied in the DB
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* import { runRLSCheck } from '@tetra/core';
|
|
17
|
+
* const report = await runRLSCheck(supabaseClient);
|
|
18
|
+
* console.log(report.text); // Full formatted report
|
|
19
|
+
* console.log(report.passed); // true only if zero errors
|
|
20
|
+
* if (!report.passed) throw new Error(report.summary);
|
|
21
|
+
*/
|
|
22
|
+
import { getAuditChecks } from './rls-auditor.js';
|
|
23
|
+
const CATEGORY_LABELS = {
|
|
24
|
+
foundation: 'A. Foundation (RLS enabled, policies exist)',
|
|
25
|
+
policy: 'B. Policy Quality (roles, expressions)',
|
|
26
|
+
auth: 'C. Auth Functions (exist, secure)',
|
|
27
|
+
bypass: 'D. RLS Bypass Routes (the real dangers)',
|
|
28
|
+
exposure: 'E. Data Exposure (Realtime, grants)',
|
|
29
|
+
migration: 'F. Migration Verification (Tetra standards)',
|
|
30
|
+
};
|
|
31
|
+
const CATEGORY_ORDER = ['foundation', 'policy', 'auth', 'bypass', 'exposure', 'migration'];
|
|
32
|
+
/**
|
|
33
|
+
* Run all Tetra RLS audit checks against a live Supabase project.
|
|
34
|
+
* Uses the combined CTE approach for a single DB round-trip.
|
|
35
|
+
*/
|
|
36
|
+
export async function runRLSCheck(supabase, options) {
|
|
37
|
+
const allChecks = getAuditChecks();
|
|
38
|
+
const { severities, categories: cats, skip = [] } = options ?? {};
|
|
39
|
+
const checks = allChecks.filter(c => {
|
|
40
|
+
if (skip.includes(c.id))
|
|
41
|
+
return false;
|
|
42
|
+
if (severities && !severities.includes(c.severity))
|
|
43
|
+
return false;
|
|
44
|
+
if (cats && !cats.includes(c.category))
|
|
45
|
+
return false;
|
|
46
|
+
return true;
|
|
47
|
+
});
|
|
48
|
+
// Build combined CTE query for single DB round-trip
|
|
49
|
+
const ctes = checks.map((check, i) => {
|
|
50
|
+
const innerSQL = check.sql.trim().replace(/;$/, '');
|
|
51
|
+
return `check_${i} AS (
|
|
52
|
+
SELECT '${check.id}' as check_id, t.table_name, t.issue
|
|
53
|
+
FROM (${innerSQL}) t
|
|
54
|
+
)`;
|
|
55
|
+
});
|
|
56
|
+
const unions = checks.map((_, i) => `SELECT * FROM check_${i}`).join('\nUNION ALL\n');
|
|
57
|
+
const combinedSQL = `WITH\n${ctes.join(',\n')}\n\n${unions}\nORDER BY check_id, table_name;`;
|
|
58
|
+
const rows = await executeSQL(supabase, combinedSQL);
|
|
59
|
+
// Group violations by check_id
|
|
60
|
+
const violationsByCheck = new Map();
|
|
61
|
+
for (const row of rows) {
|
|
62
|
+
const checkId = row.check_id;
|
|
63
|
+
if (!violationsByCheck.has(checkId))
|
|
64
|
+
violationsByCheck.set(checkId, []);
|
|
65
|
+
violationsByCheck.get(checkId).push(row);
|
|
66
|
+
}
|
|
67
|
+
const results = checks.map(check => {
|
|
68
|
+
const violations = violationsByCheck.get(check.id) ?? [];
|
|
69
|
+
return {
|
|
70
|
+
id: check.id,
|
|
71
|
+
name: check.name,
|
|
72
|
+
category: check.category,
|
|
73
|
+
severity: check.severity,
|
|
74
|
+
passed: violations.length === 0,
|
|
75
|
+
violationCount: violations.length,
|
|
76
|
+
violations,
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
return buildReport(results);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Run checks one-by-one (slower but shows which check fails if SQL errors).
|
|
83
|
+
* Use this for debugging when runRLSCheck fails.
|
|
84
|
+
*/
|
|
85
|
+
export async function runRLSCheckDebug(supabase) {
|
|
86
|
+
const checks = getAuditChecks();
|
|
87
|
+
const results = [];
|
|
88
|
+
for (const check of checks) {
|
|
89
|
+
const violations = await executeSQL(supabase, check.sql);
|
|
90
|
+
results.push({
|
|
91
|
+
id: check.id,
|
|
92
|
+
name: check.name,
|
|
93
|
+
category: check.category,
|
|
94
|
+
severity: check.severity,
|
|
95
|
+
passed: violations.length === 0,
|
|
96
|
+
violationCount: violations.length,
|
|
97
|
+
violations,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return buildReport(results);
|
|
101
|
+
}
|
|
102
|
+
// ─── Internal ───────────────────────────────────────────────
|
|
103
|
+
function buildReport(results) {
|
|
104
|
+
const errorCount = results.filter(r => !r.passed && r.severity === 'error').length;
|
|
105
|
+
const warnCount = results.filter(r => !r.passed && r.severity === 'warn').length;
|
|
106
|
+
const infoCount = results.filter(r => !r.passed && r.severity === 'info').length;
|
|
107
|
+
const passedCount = results.filter(r => r.passed).length;
|
|
108
|
+
const passed = errorCount === 0;
|
|
109
|
+
// Build category summaries
|
|
110
|
+
const categories = CATEGORY_ORDER
|
|
111
|
+
.filter(cat => results.some(r => r.category === cat))
|
|
112
|
+
.map(cat => {
|
|
113
|
+
const catChecks = results.filter(r => r.category === cat);
|
|
114
|
+
const catErrors = catChecks.filter(r => !r.passed && r.severity === 'error').length;
|
|
115
|
+
const catWarns = catChecks.filter(r => !r.passed && r.severity === 'warn').length;
|
|
116
|
+
return {
|
|
117
|
+
category: cat,
|
|
118
|
+
label: CATEGORY_LABELS[cat] ?? cat,
|
|
119
|
+
totalChecks: catChecks.length,
|
|
120
|
+
passedChecks: catChecks.filter(r => r.passed).length,
|
|
121
|
+
errorCount: catErrors,
|
|
122
|
+
warnCount: catWarns,
|
|
123
|
+
passed: catErrors === 0,
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
const parts = [];
|
|
127
|
+
if (errorCount > 0)
|
|
128
|
+
parts.push(`${errorCount} error${errorCount > 1 ? 's' : ''}`);
|
|
129
|
+
if (warnCount > 0)
|
|
130
|
+
parts.push(`${warnCount} warning${warnCount > 1 ? 's' : ''}`);
|
|
131
|
+
if (infoCount > 0)
|
|
132
|
+
parts.push(`${infoCount} info`);
|
|
133
|
+
const summary = passed
|
|
134
|
+
? parts.length > 0
|
|
135
|
+
? `PASS: ${passedCount}/${results.length} checks passed (${parts.join(', ')})`
|
|
136
|
+
: `PASS: ${passedCount}/${results.length} checks passed — all clear`
|
|
137
|
+
: `FAIL: ${passedCount}/${results.length} checks passed (${parts.join(', ')})`;
|
|
138
|
+
const text = formatTextReport(results, categories, summary, passed);
|
|
139
|
+
return {
|
|
140
|
+
passed,
|
|
141
|
+
summary,
|
|
142
|
+
totalChecks: results.length,
|
|
143
|
+
passedCount,
|
|
144
|
+
errorCount,
|
|
145
|
+
warnCount,
|
|
146
|
+
infoCount,
|
|
147
|
+
categories,
|
|
148
|
+
checks: results,
|
|
149
|
+
timestamp: new Date().toISOString(),
|
|
150
|
+
text,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async function executeSQL(supabase, sql) {
|
|
154
|
+
// Try common RPC function names for raw SQL execution
|
|
155
|
+
for (const fnName of ['exec_sql', 'execute_sql']) {
|
|
156
|
+
const { data, error } = await supabase.rpc(fnName, { query: sql });
|
|
157
|
+
if (!error && Array.isArray(data))
|
|
158
|
+
return data;
|
|
159
|
+
if (!error && data === null)
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
return [{ table_name: '_rls_checker', issue: 'No exec_sql or execute_sql function found. Create one to run the checker.' }];
|
|
163
|
+
}
|
|
164
|
+
function formatTextReport(results, categories, summary, passed) {
|
|
165
|
+
const w = 64;
|
|
166
|
+
const line = '='.repeat(w);
|
|
167
|
+
const thin = '-'.repeat(w);
|
|
168
|
+
const lines = [
|
|
169
|
+
line,
|
|
170
|
+
' Tetra RLS Security Report v2.0',
|
|
171
|
+
line,
|
|
172
|
+
'',
|
|
173
|
+
` Result: ${passed ? 'PASS' : '*** FAIL ***'}`,
|
|
174
|
+
` ${summary}`,
|
|
175
|
+
'',
|
|
176
|
+
];
|
|
177
|
+
// Category overview
|
|
178
|
+
lines.push(' Category Overview:');
|
|
179
|
+
for (const cat of categories) {
|
|
180
|
+
const icon = cat.passed ? 'OK' : 'XX';
|
|
181
|
+
const detail = cat.passed
|
|
182
|
+
? `${cat.passedChecks}/${cat.totalChecks} passed`
|
|
183
|
+
: `${cat.errorCount} errors, ${cat.warnCount} warnings`;
|
|
184
|
+
lines.push(` [${icon}] ${cat.label}`);
|
|
185
|
+
lines.push(` ${detail}`);
|
|
186
|
+
}
|
|
187
|
+
lines.push('');
|
|
188
|
+
// Detailed results per category
|
|
189
|
+
for (const cat of categories) {
|
|
190
|
+
const catResults = results.filter(r => r.category === cat.category);
|
|
191
|
+
lines.push(thin);
|
|
192
|
+
lines.push(` ${cat.label}`);
|
|
193
|
+
lines.push(thin);
|
|
194
|
+
for (const r of catResults) {
|
|
195
|
+
const icon = r.passed ? 'PASS' : r.severity === 'error' ? 'FAIL' : 'WARN';
|
|
196
|
+
lines.push(` [${icon}] ${r.name}`);
|
|
197
|
+
if (!r.passed) {
|
|
198
|
+
const show = r.violations.slice(0, 8);
|
|
199
|
+
for (const v of show) {
|
|
200
|
+
const issue = v.issue.length > 50 ? v.issue.slice(0, 50) + '...' : v.issue;
|
|
201
|
+
lines.push(` ${v.table_name}: ${issue}`);
|
|
202
|
+
}
|
|
203
|
+
if (r.violationCount > 8) {
|
|
204
|
+
lines.push(` ... and ${r.violationCount - 8} more`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
lines.push('');
|
|
209
|
+
}
|
|
210
|
+
lines.push(line);
|
|
211
|
+
lines.push(` ${new Date().toISOString()}`);
|
|
212
|
+
lines.push(line);
|
|
213
|
+
return lines.join('\n');
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=rls-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rls-checker.js","sourceRoot":"","sources":["../../src/generators/rls-checker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tetra RLS Generator v1.0
|
|
3
|
+
*
|
|
4
|
+
* Generates Row Level Security policies based on SparkBuddy production patterns.
|
|
5
|
+
* Every Tetra project MUST use these patterns for consistent security.
|
|
6
|
+
*
|
|
7
|
+
* NAMING STANDARD (no exceptions):
|
|
8
|
+
* - Organization column: organization_id
|
|
9
|
+
* - User column: user_id
|
|
10
|
+
* - All columns: snake_case
|
|
11
|
+
* - All roles: authenticated (never public)
|
|
12
|
+
*
|
|
13
|
+
* Table types:
|
|
14
|
+
* admin — Only admin/owner can CRUD. Most common. (default)
|
|
15
|
+
* user — Admins see all, users see only own data (user_id = auth.uid())
|
|
16
|
+
* creator — Creator role can INSERT/SELECT own + shared, admin sees all
|
|
17
|
+
* public — Anyone can SELECT, only admin can mutate
|
|
18
|
+
* public-active — Anyone can SELECT where is_active = true, only admin can mutate
|
|
19
|
+
* service — All client access blocked, only service_role can access
|
|
20
|
+
* superadmin — Only superadmins can manage (e.g., organizations table)
|
|
21
|
+
*
|
|
22
|
+
* Special tables (hardcoded, always the same in every project):
|
|
23
|
+
* organizations → superadmin type, org column = 'id'
|
|
24
|
+
* users_public → custom: self-insert, admin+self select/update
|
|
25
|
+
* organization_members → service type
|
|
26
|
+
* organization_invites → service type
|
|
27
|
+
*
|
|
28
|
+
* Prerequisites:
|
|
29
|
+
* - Auth functions from rls-auth-functions.sql must be installed
|
|
30
|
+
* - organization_members table with (user_id, organization_id, role, status)
|
|
31
|
+
* - users_public table with (id, is_superadmin)
|
|
32
|
+
*/
|
|
33
|
+
export type RLSTableType = 'admin' | 'user' | 'creator' | 'public' | 'public-active' | 'service' | 'superadmin';
|
|
34
|
+
export interface RLSConfig {
|
|
35
|
+
/** Table name (without schema) */
|
|
36
|
+
tableName: string;
|
|
37
|
+
/** Table type determines which policies are generated */
|
|
38
|
+
tableType: RLSTableType;
|
|
39
|
+
/** For creator tables: which column controls visibility. Default: 'visibility_level' */
|
|
40
|
+
visibilityColumn?: string;
|
|
41
|
+
/** For creator tables: which values are public/shared. Default: ['shared', 'public'] */
|
|
42
|
+
publicVisibilityValues?: string[];
|
|
43
|
+
/** For public tables: allow anonymous INSERT (e.g., signups). Default: false */
|
|
44
|
+
allowAnonInsert?: boolean;
|
|
45
|
+
/** Additional custom policies to append */
|
|
46
|
+
extraPolicies?: string[];
|
|
47
|
+
}
|
|
48
|
+
export interface RLSGeneratorResult {
|
|
49
|
+
/** Complete SQL migration including ENABLE RLS + policies */
|
|
50
|
+
sql: string;
|
|
51
|
+
/** Number of policies generated */
|
|
52
|
+
policyCount: number;
|
|
53
|
+
/** Table type used */
|
|
54
|
+
tableType: RLSTableType;
|
|
55
|
+
/** Policy names generated */
|
|
56
|
+
policyNames: string[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Generate RLS policies for a table.
|
|
60
|
+
*
|
|
61
|
+
* Usage:
|
|
62
|
+
* const result = generateRLS({ tableName: 'appointments', tableType: 'admin' });
|
|
63
|
+
* // Apply result.sql as a Supabase migration
|
|
64
|
+
*/
|
|
65
|
+
export declare function generateRLS(config: RLSConfig): RLSGeneratorResult;
|
|
66
|
+
/**
|
|
67
|
+
* Generate RLS for multiple tables at once.
|
|
68
|
+
*
|
|
69
|
+
* Usage:
|
|
70
|
+
* const sql = generateRLSBatch([
|
|
71
|
+
* { tableName: 'appointments', tableType: 'admin' },
|
|
72
|
+
* { tableName: 'organizations', tableType: 'superadmin' },
|
|
73
|
+
* { tableName: 'organization_invites', tableType: 'service' },
|
|
74
|
+
* ]);
|
|
75
|
+
*/
|
|
76
|
+
export declare function generateRLSBatch(configs: RLSConfig[]): string;
|
|
77
|
+
//# sourceMappingURL=rls-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rls-generator.d.ts","sourceRoot":"","sources":["../../src/generators/rls-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,MAAM,MAAM,YAAY,GACpB,OAAO,GACP,MAAM,GACN,SAAS,GACT,QAAQ,GACR,eAAe,GACf,SAAS,GACT,YAAY,CAAC;AAEjB,MAAM,WAAW,SAAS;IACxB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,SAAS,EAAE,YAAY,CAAC;IACxB,wFAAwF;IACxF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wFAAwF;IACxF,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,gFAAgF;IAChF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,mCAAmC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,SAAS,EAAE,YAAY,CAAC;IACxB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAMD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,kBAAkB,CA4DjE;AAsTD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,CAe7D"}
|