@authrim/setup 0.1.10 ā 0.1.12
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/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +54 -11
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/core/cloudflare.d.ts +17 -0
- package/dist/core/cloudflare.d.ts.map +1 -1
- package/dist/core/cloudflare.js +76 -0
- package/dist/core/cloudflare.js.map +1 -1
- package/dist/core/deploy.d.ts.map +1 -1
- package/dist/core/deploy.js +6 -17
- package/dist/core/deploy.js.map +1 -1
- package/dist/core/source.d.ts.map +1 -1
- package/dist/core/source.js +8 -2
- package/dist/core/source.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/web/api.d.ts.map +1 -1
- package/dist/web/api.js +3 -0
- package/dist/web/api.js.map +1 -1
- package/dist/web/server.js.map +1 -1
- package/dist/web/ui.d.ts.map +1 -1
- package/dist/web/ui.js +72 -58
- package/dist/web/ui.js.map +1 -1
- package/package.json +1 -1
package/dist/web/ui.js
CHANGED
|
@@ -529,8 +529,6 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
529
529
|
background: var(--bg);
|
|
530
530
|
border-radius: 8px;
|
|
531
531
|
padding: 0.75rem;
|
|
532
|
-
max-height: 200px;
|
|
533
|
-
overflow-y: auto;
|
|
534
532
|
}
|
|
535
533
|
|
|
536
534
|
.resource-item {
|
|
@@ -665,7 +663,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
665
663
|
</div>
|
|
666
664
|
|
|
667
665
|
<div class="mode-card" id="menu-manage-env">
|
|
668
|
-
<div class="mode-icon"
|
|
666
|
+
<div class="mode-icon">āļø</div>
|
|
669
667
|
<h3>Manage Environments</h3>
|
|
670
668
|
<p>View, inspect, or delete existing environments</p>
|
|
671
669
|
</div>
|
|
@@ -736,18 +734,8 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
736
734
|
<h2 class="card-title">Configuration</h2>
|
|
737
735
|
|
|
738
736
|
<div class="form-group">
|
|
739
|
-
<label for="env">Environment
|
|
740
|
-
<
|
|
741
|
-
<option value="prod">Production (prod)</option>
|
|
742
|
-
<option value="staging">Staging</option>
|
|
743
|
-
<option value="dev">Development (dev)</option>
|
|
744
|
-
<option value="custom">Custom...</option>
|
|
745
|
-
</select>
|
|
746
|
-
</div>
|
|
747
|
-
|
|
748
|
-
<div class="form-group hidden" id="custom-env-group">
|
|
749
|
-
<label for="custom-env">Custom Environment Name</label>
|
|
750
|
-
<input type="text" id="custom-env" placeholder="e.g., test, demo, myenv">
|
|
737
|
+
<label for="env">Environment Name <span style="color: var(--error);">*</span></label>
|
|
738
|
+
<input type="text" id="env" placeholder="e.g., prod, staging, dev, myenv" required>
|
|
751
739
|
<small style="color: var(--text-muted)">Lowercase letters, numbers, and hyphens only</small>
|
|
752
740
|
</div>
|
|
753
741
|
|
|
@@ -1081,6 +1069,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1081
1069
|
let detectedEnvironments = [];
|
|
1082
1070
|
let selectedEnvForDetail = null;
|
|
1083
1071
|
let selectedEnvForDelete = null;
|
|
1072
|
+
let workingDirectory = '';
|
|
1084
1073
|
|
|
1085
1074
|
// API helpers (with session token authentication)
|
|
1086
1075
|
async function api(endpoint, options = {}) {
|
|
@@ -1109,6 +1098,13 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1109
1098
|
sections[name].classList.remove('hidden');
|
|
1110
1099
|
}
|
|
1111
1100
|
|
|
1101
|
+
// Auto-scroll helper for progress logs
|
|
1102
|
+
function scrollToBottom(element) {
|
|
1103
|
+
if (element) {
|
|
1104
|
+
element.scrollTop = element.scrollHeight;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1112
1108
|
// Safe DOM element creation helpers
|
|
1113
1109
|
function createAlert(type, content) {
|
|
1114
1110
|
const div = document.createElement('div');
|
|
@@ -1215,6 +1211,9 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1215
1211
|
prereqStatus.textContent = 'Ready';
|
|
1216
1212
|
prereqStatus.className = 'status-badge status-success';
|
|
1217
1213
|
|
|
1214
|
+
// Store working directory for later use
|
|
1215
|
+
workingDirectory = result.cwd || '';
|
|
1216
|
+
|
|
1218
1217
|
const alertDiv = document.createElement('div');
|
|
1219
1218
|
alertDiv.className = 'alert alert-success';
|
|
1220
1219
|
|
|
@@ -1331,14 +1330,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1331
1330
|
};
|
|
1332
1331
|
|
|
1333
1332
|
// Set form values
|
|
1334
|
-
|
|
1335
|
-
if (['prod', 'staging', 'dev'].includes(config.env)) {
|
|
1336
|
-
envSelect.value = config.env;
|
|
1337
|
-
} else {
|
|
1338
|
-
envSelect.value = 'custom';
|
|
1339
|
-
document.getElementById('custom-env').value = config.env;
|
|
1340
|
-
document.getElementById('custom-env-group').classList.remove('hidden');
|
|
1341
|
-
}
|
|
1333
|
+
document.getElementById('env').value = config.env;
|
|
1342
1334
|
document.getElementById('domain').value = config.domain || '';
|
|
1343
1335
|
|
|
1344
1336
|
// Skip to provisioning if resources already exist
|
|
@@ -1351,16 +1343,6 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1351
1343
|
}
|
|
1352
1344
|
});
|
|
1353
1345
|
|
|
1354
|
-
// Environment dropdown handler
|
|
1355
|
-
document.getElementById('env').addEventListener('change', (e) => {
|
|
1356
|
-
const customGroup = document.getElementById('custom-env-group');
|
|
1357
|
-
if (e.target.value === 'custom') {
|
|
1358
|
-
customGroup.classList.remove('hidden');
|
|
1359
|
-
} else {
|
|
1360
|
-
customGroup.classList.add('hidden');
|
|
1361
|
-
}
|
|
1362
|
-
});
|
|
1363
|
-
|
|
1364
1346
|
// Configuration handlers
|
|
1365
1347
|
document.getElementById('btn-back-mode').addEventListener('click', () => {
|
|
1366
1348
|
setStep(1);
|
|
@@ -1368,13 +1350,34 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1368
1350
|
});
|
|
1369
1351
|
|
|
1370
1352
|
document.getElementById('btn-configure').addEventListener('click', async () => {
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1353
|
+
// Get and validate environment name
|
|
1354
|
+
let env = document.getElementById('env').value.toLowerCase().replace(/[^a-z0-9-]/g, '');
|
|
1355
|
+
if (!env) {
|
|
1356
|
+
alert('Please enter a valid environment name');
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
// Check if environment already exists
|
|
1361
|
+
const configureBtn = document.getElementById('btn-configure');
|
|
1362
|
+
const originalText = configureBtn.textContent;
|
|
1363
|
+
configureBtn.textContent = 'Checking...';
|
|
1364
|
+
configureBtn.disabled = true;
|
|
1365
|
+
|
|
1366
|
+
try {
|
|
1367
|
+
const envResult = await api('/environments');
|
|
1368
|
+
if (envResult.success && envResult.environments) {
|
|
1369
|
+
const existingEnv = envResult.environments.find(e => e.name === env);
|
|
1370
|
+
if (existingEnv) {
|
|
1371
|
+
alert('Environment "' + env + '" already exists.\\n\\nWorkers: ' + existingEnv.workers.length + ', D1: ' + existingEnv.d1.length + ', KV: ' + existingEnv.kv.length + '\\n\\nPlease choose a different name or use "Manage Environments" to delete it first.');
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1377
1374
|
}
|
|
1375
|
+
} catch (e) {
|
|
1376
|
+
// Continue if check fails - will catch errors later
|
|
1377
|
+
console.warn('Environment check failed:', e);
|
|
1378
|
+
} finally {
|
|
1379
|
+
configureBtn.textContent = originalText;
|
|
1380
|
+
configureBtn.disabled = false;
|
|
1378
1381
|
}
|
|
1379
1382
|
|
|
1380
1383
|
const domain = document.getElementById('domain').value;
|
|
@@ -1443,8 +1446,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1443
1446
|
output.textContent += msg + '\\n';
|
|
1444
1447
|
});
|
|
1445
1448
|
lastProgressLength = statusResult.progress.length;
|
|
1446
|
-
|
|
1447
|
-
log.scrollTop = log.scrollHeight;
|
|
1449
|
+
scrollToBottom(log);
|
|
1448
1450
|
}
|
|
1449
1451
|
} catch (e) {
|
|
1450
1452
|
// Ignore polling errors
|
|
@@ -1454,6 +1456,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1454
1456
|
try {
|
|
1455
1457
|
// Generate keys
|
|
1456
1458
|
output.textContent += 'š Generating cryptographic keys...\\n';
|
|
1459
|
+
scrollToBottom(log);
|
|
1457
1460
|
const keyResult = await api('/keys/generate', {
|
|
1458
1461
|
method: 'POST',
|
|
1459
1462
|
body: { keyId: config.env + '-key-' + Date.now() },
|
|
@@ -1462,12 +1465,14 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1462
1465
|
output.textContent += ' ā Encryption keys generated\\n';
|
|
1463
1466
|
output.textContent += ' ā Admin secrets generated\\n';
|
|
1464
1467
|
output.textContent += '\\n';
|
|
1468
|
+
scrollToBottom(log);
|
|
1465
1469
|
|
|
1466
|
-
// Show keys saved location (
|
|
1467
|
-
keysPath.textContent = './.keys/';
|
|
1470
|
+
// Show keys saved location (full path)
|
|
1471
|
+
keysPath.textContent = workingDirectory ? workingDirectory + '/.keys/' : './.keys/';
|
|
1468
1472
|
|
|
1469
1473
|
// Provision resources
|
|
1470
1474
|
output.textContent += 'āļø Provisioning Cloudflare resources...\\n';
|
|
1475
|
+
scrollToBottom(log);
|
|
1471
1476
|
|
|
1472
1477
|
const result = await api('/provision', {
|
|
1473
1478
|
method: 'POST',
|
|
@@ -1482,6 +1487,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1482
1487
|
|
|
1483
1488
|
if (result.success) {
|
|
1484
1489
|
output.textContent += '\\nā
Provisioning complete!\\n';
|
|
1490
|
+
scrollToBottom(log);
|
|
1485
1491
|
status.textContent = 'Complete';
|
|
1486
1492
|
status.className = 'status-badge status-success';
|
|
1487
1493
|
|
|
@@ -1506,6 +1512,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1506
1512
|
}
|
|
1507
1513
|
|
|
1508
1514
|
output.textContent += '\\nā Error: ' + error.message + '\\n';
|
|
1515
|
+
scrollToBottom(log);
|
|
1509
1516
|
status.textContent = 'Error';
|
|
1510
1517
|
status.className = 'status-badge status-error';
|
|
1511
1518
|
btn.disabled = false;
|
|
@@ -1542,24 +1549,29 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1542
1549
|
status.className = 'status-badge status-running';
|
|
1543
1550
|
log.classList.remove('hidden');
|
|
1544
1551
|
output.textContent = 'Starting deployment...\\n\\n';
|
|
1552
|
+
scrollToBottom(log);
|
|
1545
1553
|
|
|
1546
1554
|
try {
|
|
1547
1555
|
// Generate wrangler configs first
|
|
1548
1556
|
output.textContent += 'Generating wrangler.toml files...\\n';
|
|
1557
|
+
scrollToBottom(log);
|
|
1549
1558
|
await api('/wrangler/generate', {
|
|
1550
1559
|
method: 'POST',
|
|
1551
1560
|
body: { env: config.env },
|
|
1552
1561
|
});
|
|
1553
1562
|
output.textContent += 'ā Config files generated\\n\\n';
|
|
1563
|
+
scrollToBottom(log);
|
|
1554
1564
|
|
|
1555
1565
|
// Start deployment
|
|
1556
1566
|
output.textContent += 'Deploying workers...\\n';
|
|
1567
|
+
scrollToBottom(log);
|
|
1557
1568
|
|
|
1558
1569
|
// Poll for status updates
|
|
1559
1570
|
const pollInterval = setInterval(async () => {
|
|
1560
1571
|
const statusResult = await api('/deploy/status');
|
|
1561
1572
|
if (statusResult.progress && statusResult.progress.length > 0) {
|
|
1562
1573
|
output.textContent = statusResult.progress.join('\\n') + '\\n';
|
|
1574
|
+
scrollToBottom(log);
|
|
1563
1575
|
}
|
|
1564
1576
|
}, 1000);
|
|
1565
1577
|
|
|
@@ -1575,6 +1587,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1575
1587
|
|
|
1576
1588
|
if (result.success) {
|
|
1577
1589
|
output.textContent += '\\nā Deployment complete!\\n';
|
|
1590
|
+
scrollToBottom(log);
|
|
1578
1591
|
status.textContent = 'Complete';
|
|
1579
1592
|
status.className = 'status-badge status-success';
|
|
1580
1593
|
|
|
@@ -1585,6 +1598,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1585
1598
|
}
|
|
1586
1599
|
} catch (error) {
|
|
1587
1600
|
output.textContent += '\\nā Error: ' + error.message + '\\n';
|
|
1601
|
+
scrollToBottom(log);
|
|
1588
1602
|
status.textContent = 'Error';
|
|
1589
1603
|
status.className = 'status-badge status-error';
|
|
1590
1604
|
btn.disabled = false;
|
|
@@ -1619,29 +1633,29 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1619
1633
|
|
|
1620
1634
|
// Resource naming functions
|
|
1621
1635
|
function getResourceNames(env) {
|
|
1622
|
-
const
|
|
1636
|
+
const keysDir = workingDirectory ? workingDirectory + '/.keys' : '.keys';
|
|
1623
1637
|
return {
|
|
1624
1638
|
d1: [
|
|
1625
1639
|
env + '-authrim-core-db',
|
|
1626
1640
|
env + '-authrim-pii-db'
|
|
1627
1641
|
],
|
|
1628
1642
|
kv: [
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1643
|
+
env + '-CLIENTS_CACHE',
|
|
1644
|
+
env + '-INITIAL_ACCESS_TOKENS',
|
|
1645
|
+
env + '-SETTINGS',
|
|
1646
|
+
env + '-REBAC_CACHE',
|
|
1647
|
+
env + '-USER_CACHE',
|
|
1648
|
+
env + '-AUTHRIM_CONFIG',
|
|
1649
|
+
env + '-STATE_STORE',
|
|
1650
|
+
env + '-CONSENT_CACHE'
|
|
1637
1651
|
],
|
|
1638
1652
|
keys: [
|
|
1639
|
-
'
|
|
1640
|
-
'
|
|
1641
|
-
'
|
|
1642
|
-
'
|
|
1643
|
-
'
|
|
1644
|
-
'
|
|
1653
|
+
keysDir + '/private.pem (RSA Private Key)',
|
|
1654
|
+
keysDir + '/public.jwk.json (JWK Public Key)',
|
|
1655
|
+
keysDir + '/rp_token_encryption_key.txt',
|
|
1656
|
+
keysDir + '/admin_api_secret.txt',
|
|
1657
|
+
keysDir + '/key_manager_secret.txt',
|
|
1658
|
+
keysDir + '/setup_token.txt'
|
|
1645
1659
|
]
|
|
1646
1660
|
};
|
|
1647
1661
|
}
|
package/dist/web/ui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,UAAU,eAAe,CAAC,YAAqB,EAAE,UAAoB;IACzE,gDAAgD;IAChD,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,MAAM,cAAc,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAErD,OAAO
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,UAAU,eAAe,CAAC,YAAqB,EAAE,UAAoB;IACzE,gDAAgD;IAChD,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,MAAM,cAAc,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAErD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAggCoB,SAAS;0BACZ,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAulChC,CAAC;AACT,CAAC"}
|