@authrim/setup 0.1.11 ā 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.
- package/dist/cli/commands/deploy.d.ts +1 -0
- package/dist/cli/commands/deploy.d.ts.map +1 -1
- package/dist/cli/commands/deploy.js +27 -0
- package/dist/cli/commands/deploy.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +102 -16
- 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/keys.d.ts +11 -3
- package/dist/core/keys.d.ts.map +1 -1
- package/dist/core/keys.js +33 -15
- package/dist/core/keys.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/core/wrangler.d.ts +4 -0
- package/dist/core/wrangler.d.ts.map +1 -1
- package/dist/core/wrangler.js +86 -0
- package/dist/core/wrangler.js.map +1 -1
- package/dist/web/api.d.ts.map +1 -1
- package/dist/web/api.js +58 -14
- 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 +157 -22
- package/dist/web/ui.js.map +1 -1
- package/package.json +1 -1
package/dist/web/ui.js
CHANGED
|
@@ -197,6 +197,66 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
197
197
|
gap: 0.5rem;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
/* Domain configuration section */
|
|
201
|
+
.domain-section {
|
|
202
|
+
background: var(--bg);
|
|
203
|
+
border: 1px solid var(--border);
|
|
204
|
+
border-radius: 8px;
|
|
205
|
+
padding: 1rem;
|
|
206
|
+
margin-bottom: 1rem;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.domain-section h4 {
|
|
210
|
+
margin: 0 0 1rem 0;
|
|
211
|
+
font-size: 0.95rem;
|
|
212
|
+
color: var(--text);
|
|
213
|
+
display: flex;
|
|
214
|
+
align-items: center;
|
|
215
|
+
gap: 0.5rem;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.domain-row {
|
|
219
|
+
display: grid;
|
|
220
|
+
grid-template-columns: 90px 1fr;
|
|
221
|
+
align-items: center;
|
|
222
|
+
gap: 0.75rem;
|
|
223
|
+
margin-bottom: 0.75rem;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.domain-row:last-of-type {
|
|
227
|
+
margin-bottom: 0;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.domain-label {
|
|
231
|
+
font-size: 0.85rem;
|
|
232
|
+
color: var(--text-muted);
|
|
233
|
+
font-weight: 500;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.domain-input-wrapper {
|
|
237
|
+
position: relative;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.domain-input-wrapper input {
|
|
241
|
+
padding-right: 180px;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.domain-default {
|
|
245
|
+
position: absolute;
|
|
246
|
+
right: 10px;
|
|
247
|
+
top: 50%;
|
|
248
|
+
transform: translateY(-50%);
|
|
249
|
+
font-size: 0.7rem;
|
|
250
|
+
color: var(--text-muted);
|
|
251
|
+
background: #f1f5f9;
|
|
252
|
+
padding: 2px 6px;
|
|
253
|
+
border-radius: 4px;
|
|
254
|
+
max-width: 160px;
|
|
255
|
+
overflow: hidden;
|
|
256
|
+
text-overflow: ellipsis;
|
|
257
|
+
white-space: nowrap;
|
|
258
|
+
}
|
|
259
|
+
|
|
200
260
|
button {
|
|
201
261
|
padding: 0.75rem 1.5rem;
|
|
202
262
|
border-radius: 8px;
|
|
@@ -739,10 +799,37 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
739
799
|
<small style="color: var(--text-muted)">Lowercase letters, numbers, and hyphens only</small>
|
|
740
800
|
</div>
|
|
741
801
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
<
|
|
745
|
-
|
|
802
|
+
<!-- Domain Configuration -->
|
|
803
|
+
<div class="domain-section">
|
|
804
|
+
<h4>š Domain Configuration</h4>
|
|
805
|
+
|
|
806
|
+
<div class="domain-row">
|
|
807
|
+
<span class="domain-label">API</span>
|
|
808
|
+
<div class="domain-input-wrapper">
|
|
809
|
+
<input type="text" id="api-domain" placeholder="auth.example.com">
|
|
810
|
+
<span class="domain-default" id="api-default">{env}-ar-router.workers.dev</span>
|
|
811
|
+
</div>
|
|
812
|
+
</div>
|
|
813
|
+
|
|
814
|
+
<div class="domain-row">
|
|
815
|
+
<span class="domain-label">Login UI</span>
|
|
816
|
+
<div class="domain-input-wrapper">
|
|
817
|
+
<input type="text" id="login-domain" placeholder="login.example.com">
|
|
818
|
+
<span class="domain-default" id="login-default">{env}-ar-ui.pages.dev</span>
|
|
819
|
+
</div>
|
|
820
|
+
</div>
|
|
821
|
+
|
|
822
|
+
<div class="domain-row">
|
|
823
|
+
<span class="domain-label">Admin UI</span>
|
|
824
|
+
<div class="domain-input-wrapper">
|
|
825
|
+
<input type="text" id="admin-domain" placeholder="admin.example.com">
|
|
826
|
+
<span class="domain-default" id="admin-default">{env}-ar-ui.pages.dev/admin</span>
|
|
827
|
+
</div>
|
|
828
|
+
</div>
|
|
829
|
+
|
|
830
|
+
<small style="color: var(--text-muted); display: block; margin-top: 0.75rem;">
|
|
831
|
+
š” Leave empty to use default Cloudflare domains (shown on right)
|
|
832
|
+
</small>
|
|
746
833
|
</div>
|
|
747
834
|
|
|
748
835
|
<!-- Advanced options (shown in custom mode) -->
|
|
@@ -1098,6 +1185,13 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1098
1185
|
sections[name].classList.remove('hidden');
|
|
1099
1186
|
}
|
|
1100
1187
|
|
|
1188
|
+
// Auto-scroll helper for progress logs
|
|
1189
|
+
function scrollToBottom(element) {
|
|
1190
|
+
if (element) {
|
|
1191
|
+
element.scrollTop = element.scrollHeight;
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1101
1195
|
// Safe DOM element creation helpers
|
|
1102
1196
|
function createAlert(type, content) {
|
|
1103
1197
|
const div = document.createElement('div');
|
|
@@ -1311,7 +1405,9 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1311
1405
|
// Use loaded config
|
|
1312
1406
|
config = {
|
|
1313
1407
|
env: loadedConfig.environment?.prefix || 'prod',
|
|
1314
|
-
|
|
1408
|
+
apiDomain: loadedConfig.urls?.api?.custom || null,
|
|
1409
|
+
loginUiDomain: loadedConfig.urls?.loginUi?.custom || null,
|
|
1410
|
+
adminUiDomain: loadedConfig.urls?.adminUi?.custom || null,
|
|
1315
1411
|
components: loadedConfig.components || {
|
|
1316
1412
|
api: true,
|
|
1317
1413
|
loginUi: true,
|
|
@@ -1324,7 +1420,11 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1324
1420
|
|
|
1325
1421
|
// Set form values
|
|
1326
1422
|
document.getElementById('env').value = config.env;
|
|
1327
|
-
document.getElementById('domain').value = config.
|
|
1423
|
+
document.getElementById('api-domain').value = config.apiDomain || '';
|
|
1424
|
+
document.getElementById('login-domain').value = config.loginUiDomain || '';
|
|
1425
|
+
document.getElementById('admin-domain').value = config.adminUiDomain || '';
|
|
1426
|
+
// Trigger env input to update default labels
|
|
1427
|
+
document.getElementById('env').dispatchEvent(new Event('input'));
|
|
1328
1428
|
|
|
1329
1429
|
// Skip to provisioning if resources already exist
|
|
1330
1430
|
if (loadedConfig.resources) {
|
|
@@ -1337,6 +1437,14 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1337
1437
|
});
|
|
1338
1438
|
|
|
1339
1439
|
// Configuration handlers
|
|
1440
|
+
// Update domain defaults when environment name changes
|
|
1441
|
+
document.getElementById('env').addEventListener('input', (e) => {
|
|
1442
|
+
const env = e.target.value.trim().toLowerCase().replace(/[^a-z0-9-]/g, '') || '{env}';
|
|
1443
|
+
document.getElementById('api-default').textContent = env + '-ar-router.workers.dev';
|
|
1444
|
+
document.getElementById('login-default').textContent = env + '-ar-ui.pages.dev';
|
|
1445
|
+
document.getElementById('admin-default').textContent = env + '-ar-ui.pages.dev/admin';
|
|
1446
|
+
});
|
|
1447
|
+
|
|
1340
1448
|
document.getElementById('btn-back-mode').addEventListener('click', () => {
|
|
1341
1449
|
setStep(1);
|
|
1342
1450
|
showSection('mode');
|
|
@@ -1373,11 +1481,15 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1373
1481
|
configureBtn.disabled = false;
|
|
1374
1482
|
}
|
|
1375
1483
|
|
|
1376
|
-
const
|
|
1484
|
+
const apiDomain = document.getElementById('api-domain').value.trim();
|
|
1485
|
+
const loginDomain = document.getElementById('login-domain').value.trim();
|
|
1486
|
+
const adminDomain = document.getElementById('admin-domain').value.trim();
|
|
1377
1487
|
|
|
1378
1488
|
config = {
|
|
1379
1489
|
env,
|
|
1380
|
-
|
|
1490
|
+
apiDomain: apiDomain || null,
|
|
1491
|
+
loginUiDomain: loginDomain || null,
|
|
1492
|
+
adminUiDomain: adminDomain || null,
|
|
1381
1493
|
components: {
|
|
1382
1494
|
api: true,
|
|
1383
1495
|
loginUi: setupMode === 'quick' || document.getElementById('comp-login-ui').checked,
|
|
@@ -1391,7 +1503,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1391
1503
|
// Create default config
|
|
1392
1504
|
await api('/config/default', {
|
|
1393
1505
|
method: 'POST',
|
|
1394
|
-
body: { env,
|
|
1506
|
+
body: { env, apiDomain, loginUiDomain: loginDomain, adminUiDomain: adminDomain },
|
|
1395
1507
|
});
|
|
1396
1508
|
|
|
1397
1509
|
// Update resource preview with the selected env
|
|
@@ -1439,8 +1551,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1439
1551
|
output.textContent += msg + '\\n';
|
|
1440
1552
|
});
|
|
1441
1553
|
lastProgressLength = statusResult.progress.length;
|
|
1442
|
-
|
|
1443
|
-
log.scrollTop = log.scrollHeight;
|
|
1554
|
+
scrollToBottom(log);
|
|
1444
1555
|
}
|
|
1445
1556
|
} catch (e) {
|
|
1446
1557
|
// Ignore polling errors
|
|
@@ -1448,22 +1559,34 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1448
1559
|
}, 500);
|
|
1449
1560
|
|
|
1450
1561
|
try {
|
|
1562
|
+
// Check if keys already exist for this environment
|
|
1563
|
+
const keysCheck = await api('/keys/check/' + config.env);
|
|
1564
|
+
if (keysCheck.exists) {
|
|
1565
|
+
output.textContent += 'ā ļø Warning: Keys already exist for environment "' + config.env + '"\\n';
|
|
1566
|
+
output.textContent += ' Existing keys will be overwritten.\\n';
|
|
1567
|
+
output.textContent += '\\n';
|
|
1568
|
+
scrollToBottom(log);
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1451
1571
|
// Generate keys
|
|
1452
1572
|
output.textContent += 'š Generating cryptographic keys...\\n';
|
|
1573
|
+
scrollToBottom(log);
|
|
1453
1574
|
const keyResult = await api('/keys/generate', {
|
|
1454
1575
|
method: 'POST',
|
|
1455
|
-
body: { keyId: config.env + '-key-' + Date.now() },
|
|
1576
|
+
body: { keyId: config.env + '-key-' + Date.now(), env: config.env },
|
|
1456
1577
|
});
|
|
1457
1578
|
output.textContent += ' ā RSA key pair generated\\n';
|
|
1458
1579
|
output.textContent += ' ā Encryption keys generated\\n';
|
|
1459
1580
|
output.textContent += ' ā Admin secrets generated\\n';
|
|
1460
1581
|
output.textContent += '\\n';
|
|
1582
|
+
scrollToBottom(log);
|
|
1461
1583
|
|
|
1462
|
-
// Show keys saved location (full path)
|
|
1463
|
-
keysPath.textContent = workingDirectory ? workingDirectory + '/.keys/' : './.keys/';
|
|
1584
|
+
// Show keys saved location (full path with environment)
|
|
1585
|
+
keysPath.textContent = workingDirectory ? workingDirectory + '/.keys/' + config.env + '/' : './.keys/' + config.env + '/';
|
|
1464
1586
|
|
|
1465
1587
|
// Provision resources
|
|
1466
1588
|
output.textContent += 'āļø Provisioning Cloudflare resources...\\n';
|
|
1589
|
+
scrollToBottom(log);
|
|
1467
1590
|
|
|
1468
1591
|
const result = await api('/provision', {
|
|
1469
1592
|
method: 'POST',
|
|
@@ -1478,6 +1601,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1478
1601
|
|
|
1479
1602
|
if (result.success) {
|
|
1480
1603
|
output.textContent += '\\nā
Provisioning complete!\\n';
|
|
1604
|
+
scrollToBottom(log);
|
|
1481
1605
|
status.textContent = 'Complete';
|
|
1482
1606
|
status.className = 'status-badge status-success';
|
|
1483
1607
|
|
|
@@ -1502,6 +1626,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1502
1626
|
}
|
|
1503
1627
|
|
|
1504
1628
|
output.textContent += '\\nā Error: ' + error.message + '\\n';
|
|
1629
|
+
scrollToBottom(log);
|
|
1505
1630
|
status.textContent = 'Error';
|
|
1506
1631
|
status.className = 'status-badge status-error';
|
|
1507
1632
|
btn.disabled = false;
|
|
@@ -1538,24 +1663,29 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1538
1663
|
status.className = 'status-badge status-running';
|
|
1539
1664
|
log.classList.remove('hidden');
|
|
1540
1665
|
output.textContent = 'Starting deployment...\\n\\n';
|
|
1666
|
+
scrollToBottom(log);
|
|
1541
1667
|
|
|
1542
1668
|
try {
|
|
1543
1669
|
// Generate wrangler configs first
|
|
1544
1670
|
output.textContent += 'Generating wrangler.toml files...\\n';
|
|
1671
|
+
scrollToBottom(log);
|
|
1545
1672
|
await api('/wrangler/generate', {
|
|
1546
1673
|
method: 'POST',
|
|
1547
1674
|
body: { env: config.env },
|
|
1548
1675
|
});
|
|
1549
1676
|
output.textContent += 'ā Config files generated\\n\\n';
|
|
1677
|
+
scrollToBottom(log);
|
|
1550
1678
|
|
|
1551
1679
|
// Start deployment
|
|
1552
1680
|
output.textContent += 'Deploying workers...\\n';
|
|
1681
|
+
scrollToBottom(log);
|
|
1553
1682
|
|
|
1554
1683
|
// Poll for status updates
|
|
1555
1684
|
const pollInterval = setInterval(async () => {
|
|
1556
1685
|
const statusResult = await api('/deploy/status');
|
|
1557
1686
|
if (statusResult.progress && statusResult.progress.length > 0) {
|
|
1558
1687
|
output.textContent = statusResult.progress.join('\\n') + '\\n';
|
|
1688
|
+
scrollToBottom(log);
|
|
1559
1689
|
}
|
|
1560
1690
|
}, 1000);
|
|
1561
1691
|
|
|
@@ -1571,6 +1701,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1571
1701
|
|
|
1572
1702
|
if (result.success) {
|
|
1573
1703
|
output.textContent += '\\nā Deployment complete!\\n';
|
|
1704
|
+
scrollToBottom(log);
|
|
1574
1705
|
status.textContent = 'Complete';
|
|
1575
1706
|
status.className = 'status-badge status-success';
|
|
1576
1707
|
|
|
@@ -1581,6 +1712,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1581
1712
|
}
|
|
1582
1713
|
} catch (error) {
|
|
1583
1714
|
output.textContent += '\\nā Error: ' + error.message + '\\n';
|
|
1715
|
+
scrollToBottom(log);
|
|
1584
1716
|
status.textContent = 'Error';
|
|
1585
1717
|
status.className = 'status-badge status-error';
|
|
1586
1718
|
btn.disabled = false;
|
|
@@ -1591,11 +1723,10 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1591
1723
|
function showComplete(result) {
|
|
1592
1724
|
const urlsEl = document.getElementById('urls');
|
|
1593
1725
|
const env = config.env;
|
|
1594
|
-
const domain = config.domain;
|
|
1595
1726
|
|
|
1596
|
-
const apiUrl =
|
|
1597
|
-
const loginUrl =
|
|
1598
|
-
const adminUrl =
|
|
1727
|
+
const apiUrl = config.apiDomain ? 'https://' + config.apiDomain : 'https://' + env + '-ar-router.workers.dev';
|
|
1728
|
+
const loginUrl = config.loginUiDomain ? 'https://' + config.loginUiDomain : 'https://' + env + '-ar-ui.pages.dev';
|
|
1729
|
+
const adminUrl = config.adminUiDomain ? 'https://' + config.adminUiDomain : 'https://' + env + '-ar-ui.pages.dev/admin';
|
|
1599
1730
|
|
|
1600
1731
|
// Clear and rebuild URLs section safely
|
|
1601
1732
|
urlsEl.textContent = '';
|
|
@@ -1615,7 +1746,8 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1615
1746
|
|
|
1616
1747
|
// Resource naming functions
|
|
1617
1748
|
function getResourceNames(env) {
|
|
1618
|
-
|
|
1749
|
+
// Keys are stored in environment-specific subdirectory: .keys/{env}/
|
|
1750
|
+
const keysDir = workingDirectory ? workingDirectory + '/.keys/' + env : '.keys/' + env;
|
|
1619
1751
|
return {
|
|
1620
1752
|
d1: [
|
|
1621
1753
|
env + '-authrim-core-db',
|
|
@@ -2096,7 +2228,8 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
2096
2228
|
result.classList.remove('hidden');
|
|
2097
2229
|
|
|
2098
2230
|
if (deleteResult.success) {
|
|
2099
|
-
result.
|
|
2231
|
+
result.textContent = '';
|
|
2232
|
+
result.appendChild(createAlert('success', 'ā
Environment deleted successfully!'));
|
|
2100
2233
|
|
|
2101
2234
|
// Refresh environment list after a short delay
|
|
2102
2235
|
setTimeout(() => {
|
|
@@ -2104,13 +2237,15 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
2104
2237
|
showSection('envList');
|
|
2105
2238
|
}, 2000);
|
|
2106
2239
|
} else {
|
|
2107
|
-
result.
|
|
2240
|
+
result.textContent = '';
|
|
2241
|
+
result.appendChild(createAlert('error', 'ā Some errors occurred: ' + (deleteResult.errors || []).join(', ')));
|
|
2108
2242
|
btn.disabled = false;
|
|
2109
2243
|
}
|
|
2110
2244
|
} catch (error) {
|
|
2111
2245
|
clearInterval(pollInterval);
|
|
2112
2246
|
result.classList.remove('hidden');
|
|
2113
|
-
result.
|
|
2247
|
+
result.textContent = '';
|
|
2248
|
+
result.appendChild(createAlert('error', 'ā Error: ' + error.message));
|
|
2114
2249
|
btn.disabled = false;
|
|
2115
2250
|
}
|
|
2116
2251
|
});
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAulCoB,SAAS;0BACZ,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAqnChC,CAAC;AACT,CAAC"}
|