@authrim/setup 0.1.51 → 0.1.58
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/core/admin.d.ts +1 -1
- package/dist/core/admin.js +3 -3
- package/dist/core/admin.js.map +1 -1
- package/dist/core/cloudflare.d.ts +15 -0
- package/dist/core/cloudflare.d.ts.map +1 -1
- package/dist/core/cloudflare.js +99 -2
- package/dist/core/cloudflare.js.map +1 -1
- package/dist/core/deploy.d.ts.map +1 -1
- package/dist/core/deploy.js.map +1 -1
- package/dist/core/naming.d.ts +1 -1
- package/dist/core/naming.js +1 -1
- package/dist/core/source.js.map +1 -1
- package/dist/core/wrangler.d.ts.map +1 -1
- package/dist/core/wrangler.js +50 -20
- package/dist/core/wrangler.js.map +1 -1
- package/dist/web/api.d.ts.map +1 -1
- package/dist/web/api.js +3 -2
- package/dist/web/api.js.map +1 -1
- package/dist/web/server.js +1 -1
- package/dist/web/server.js.map +1 -1
- package/dist/web/ui.d.ts.map +1 -1
- package/dist/web/ui.js +170 -19
- package/dist/web/ui.js.map +1 -1
- package/package.json +1 -1
package/dist/web/ui.js
CHANGED
|
@@ -452,6 +452,8 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
452
452
|
|
|
453
453
|
.url-value {
|
|
454
454
|
color: var(--primary);
|
|
455
|
+
word-break: break-all;
|
|
456
|
+
overflow-wrap: break-word;
|
|
455
457
|
}
|
|
456
458
|
|
|
457
459
|
.file-input-wrapper {
|
|
@@ -496,6 +498,37 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
496
498
|
|
|
497
499
|
.hidden { display: none; }
|
|
498
500
|
|
|
501
|
+
/* Modal styles */
|
|
502
|
+
.modal {
|
|
503
|
+
position: fixed;
|
|
504
|
+
top: 0;
|
|
505
|
+
left: 0;
|
|
506
|
+
right: 0;
|
|
507
|
+
bottom: 0;
|
|
508
|
+
z-index: 1000;
|
|
509
|
+
display: flex;
|
|
510
|
+
align-items: center;
|
|
511
|
+
justify-content: center;
|
|
512
|
+
}
|
|
513
|
+
.modal.hidden { display: none; }
|
|
514
|
+
.modal-backdrop {
|
|
515
|
+
position: absolute;
|
|
516
|
+
top: 0;
|
|
517
|
+
left: 0;
|
|
518
|
+
right: 0;
|
|
519
|
+
bottom: 0;
|
|
520
|
+
background: rgba(0, 0, 0, 0.5);
|
|
521
|
+
}
|
|
522
|
+
.modal-content {
|
|
523
|
+
position: relative;
|
|
524
|
+
background: var(--card-bg);
|
|
525
|
+
border-radius: 12px;
|
|
526
|
+
padding: 1.5rem;
|
|
527
|
+
max-width: 450px;
|
|
528
|
+
width: 90%;
|
|
529
|
+
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
|
|
530
|
+
}
|
|
531
|
+
|
|
499
532
|
/* Resource preview styles */
|
|
500
533
|
.resource-preview {
|
|
501
534
|
background: var(--bg);
|
|
@@ -755,6 +788,13 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
755
788
|
margin-bottom: 1.5rem;
|
|
756
789
|
}
|
|
757
790
|
|
|
791
|
+
.database-config-stack {
|
|
792
|
+
display: flex;
|
|
793
|
+
flex-direction: column;
|
|
794
|
+
gap: 1.5rem;
|
|
795
|
+
margin-bottom: 1.5rem;
|
|
796
|
+
}
|
|
797
|
+
|
|
758
798
|
.database-card {
|
|
759
799
|
background: var(--bg);
|
|
760
800
|
border: 1px solid var(--border);
|
|
@@ -1135,16 +1175,20 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1135
1175
|
<div id="section-database" class="card hidden">
|
|
1136
1176
|
<h2 class="card-title">🗄️ Database Configuration</h2>
|
|
1137
1177
|
|
|
1138
|
-
<
|
|
1139
|
-
|
|
1140
|
-
</
|
|
1178
|
+
<p style="margin-bottom: 1rem; color: var(--text-muted);">
|
|
1179
|
+
Authrim uses two separate D1 databases to isolate personal data from application data.
|
|
1180
|
+
</p>
|
|
1141
1181
|
|
|
1142
|
-
<
|
|
1143
|
-
|
|
1182
|
+
<p style="margin-bottom: 1.5rem; font-size: 0.85rem; color: var(--text-muted);">
|
|
1183
|
+
Note: Database region cannot be changed after creation.
|
|
1184
|
+
</p>
|
|
1185
|
+
|
|
1186
|
+
<div class="database-config-stack">
|
|
1187
|
+
<!-- Core Database (Non-PII) -->
|
|
1144
1188
|
<div class="database-card">
|
|
1145
|
-
<h3>🗄️ Core Database</h3>
|
|
1189
|
+
<h3>🗄️ Core Database <span style="font-size: 0.8rem; font-weight: normal; color: var(--text-muted);">(Non-PII)</span></h3>
|
|
1146
1190
|
<div class="db-description">
|
|
1147
|
-
<p>Stores application data including:</p>
|
|
1191
|
+
<p>Stores non-personal application data including:</p>
|
|
1148
1192
|
<ul>
|
|
1149
1193
|
<li>OAuth clients and their configurations</li>
|
|
1150
1194
|
<li>Authorization codes and access tokens</li>
|
|
@@ -1198,7 +1242,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1198
1242
|
|
|
1199
1243
|
<!-- PII Database -->
|
|
1200
1244
|
<div class="database-card">
|
|
1201
|
-
<h3>🔒 PII Database</h3>
|
|
1245
|
+
<h3>🔒 PII Database <span style="font-size: 0.8rem; font-weight: normal; color: var(--text-muted);">(Personal Identifiable Information)</span></h3>
|
|
1202
1246
|
<div class="db-description">
|
|
1203
1247
|
<p>Stores personal user data including:</p>
|
|
1204
1248
|
<ul>
|
|
@@ -1263,7 +1307,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1263
1307
|
<h2 class="card-title">📧 Email Provider</h2>
|
|
1264
1308
|
|
|
1265
1309
|
<p style="margin-bottom: 1rem; color: var(--text-muted);">
|
|
1266
|
-
|
|
1310
|
+
Used for sending Mail OTP and email address verification.
|
|
1267
1311
|
You can configure this later if you prefer.
|
|
1268
1312
|
</p>
|
|
1269
1313
|
|
|
@@ -1272,7 +1316,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1272
1316
|
<input type="radio" name="email-setup-choice" value="later" checked>
|
|
1273
1317
|
<span style="display: flex; flex-direction: column; gap: 0.25rem;">
|
|
1274
1318
|
<strong>Configure later</strong>
|
|
1275
|
-
<small style="color: var(--text-muted);">Skip for now
|
|
1319
|
+
<small style="color: var(--text-muted);">Skip for now and configure later.</small>
|
|
1276
1320
|
</span>
|
|
1277
1321
|
</label>
|
|
1278
1322
|
<label class="radio-item" style="padding: 0.75rem; border: 1px solid var(--border); border-radius: 8px; margin-top: 0.5rem;">
|
|
@@ -1394,7 +1438,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1394
1438
|
|
|
1395
1439
|
<div class="button-group">
|
|
1396
1440
|
<button class="btn-secondary" id="btn-back-provision">Back</button>
|
|
1397
|
-
<button class="btn-primary" id="btn-deploy">Deploy</button>
|
|
1441
|
+
<button class="btn-primary" id="btn-deploy">Start Deploy</button>
|
|
1398
1442
|
</div>
|
|
1399
1443
|
</div>
|
|
1400
1444
|
|
|
@@ -1502,6 +1546,14 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1502
1546
|
</div>
|
|
1503
1547
|
<div class="resource-list" id="detail-r2-list"></div>
|
|
1504
1548
|
</div>
|
|
1549
|
+
|
|
1550
|
+
<!-- Pages Projects -->
|
|
1551
|
+
<div class="resource-section" id="detail-pages-section">
|
|
1552
|
+
<div class="resource-section-title">
|
|
1553
|
+
📄 Pages Projects <span class="count" id="detail-pages-count">(0)</span>
|
|
1554
|
+
</div>
|
|
1555
|
+
<div class="resource-list" id="detail-pages-list"></div>
|
|
1556
|
+
</div>
|
|
1505
1557
|
</div>
|
|
1506
1558
|
|
|
1507
1559
|
<div class="button-group">
|
|
@@ -1567,6 +1619,14 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1567
1619
|
<small id="delete-r2-count">(0 buckets)</small>
|
|
1568
1620
|
</span>
|
|
1569
1621
|
</label>
|
|
1622
|
+
|
|
1623
|
+
<label class="checkbox-item delete-option">
|
|
1624
|
+
<input type="checkbox" id="delete-pages" checked>
|
|
1625
|
+
<span>
|
|
1626
|
+
<strong>Pages Projects</strong>
|
|
1627
|
+
<small id="delete-pages-count">(0 projects)</small>
|
|
1628
|
+
</span>
|
|
1629
|
+
</label>
|
|
1570
1630
|
</div>
|
|
1571
1631
|
</div>
|
|
1572
1632
|
|
|
@@ -1583,6 +1643,22 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1583
1643
|
</div>
|
|
1584
1644
|
</div>
|
|
1585
1645
|
|
|
1646
|
+
<!-- Save Config Modal -->
|
|
1647
|
+
<div id="save-config-modal" class="modal hidden">
|
|
1648
|
+
<div class="modal-backdrop"></div>
|
|
1649
|
+
<div class="modal-content">
|
|
1650
|
+
<h3 style="margin: 0 0 1rem 0;">💾 Save Configuration?</h3>
|
|
1651
|
+
<p style="color: var(--text-muted); margin-bottom: 1.5rem;">
|
|
1652
|
+
Would you like to save your configuration to a file before proceeding?
|
|
1653
|
+
This allows you to resume setup later or use the same settings for another deployment.
|
|
1654
|
+
</p>
|
|
1655
|
+
<div class="button-group" style="justify-content: flex-end;">
|
|
1656
|
+
<button class="btn-secondary" id="modal-skip-save">Skip</button>
|
|
1657
|
+
<button class="btn-primary" id="modal-save-config">Save Configuration</button>
|
|
1658
|
+
</div>
|
|
1659
|
+
</div>
|
|
1660
|
+
</div>
|
|
1661
|
+
|
|
1586
1662
|
<script>
|
|
1587
1663
|
// Session token for API authentication (embedded by server)
|
|
1588
1664
|
const SESSION_TOKEN = '${safeToken}';
|
|
@@ -2360,10 +2436,47 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
2360
2436
|
};
|
|
2361
2437
|
}
|
|
2362
2438
|
|
|
2363
|
-
//
|
|
2439
|
+
// Show save config modal before proceeding
|
|
2440
|
+
const modal = document.getElementById('save-config-modal');
|
|
2441
|
+
modal.classList.remove('hidden');
|
|
2442
|
+
});
|
|
2443
|
+
|
|
2444
|
+
// Modal handlers
|
|
2445
|
+
document.getElementById('modal-skip-save').addEventListener('click', () => {
|
|
2446
|
+
document.getElementById('save-config-modal').classList.add('hidden');
|
|
2447
|
+
proceedToProvision();
|
|
2448
|
+
});
|
|
2449
|
+
|
|
2450
|
+
document.getElementById('modal-save-config').addEventListener('click', async () => {
|
|
2451
|
+
const modal = document.getElementById('save-config-modal');
|
|
2452
|
+
const btn = document.getElementById('modal-save-config');
|
|
2453
|
+
btn.disabled = true;
|
|
2454
|
+
btn.textContent = 'Saving...';
|
|
2455
|
+
|
|
2456
|
+
try {
|
|
2457
|
+
await saveConfigToFile();
|
|
2458
|
+
modal.classList.add('hidden');
|
|
2459
|
+
btn.disabled = false;
|
|
2460
|
+
btn.textContent = 'Save Configuration';
|
|
2461
|
+
proceedToProvision();
|
|
2462
|
+
} catch (error) {
|
|
2463
|
+
alert('Failed to save configuration: ' + error.message);
|
|
2464
|
+
btn.disabled = false;
|
|
2465
|
+
btn.textContent = 'Save Configuration';
|
|
2466
|
+
}
|
|
2467
|
+
});
|
|
2468
|
+
|
|
2469
|
+
// Close modal on backdrop click
|
|
2470
|
+
document.querySelector('.modal-backdrop').addEventListener('click', () => {
|
|
2471
|
+
document.getElementById('save-config-modal').classList.add('hidden');
|
|
2472
|
+
proceedToProvision();
|
|
2473
|
+
});
|
|
2474
|
+
|
|
2475
|
+
function proceedToProvision() {
|
|
2476
|
+
updateResourcePreview(config.env);
|
|
2364
2477
|
setStep(6);
|
|
2365
2478
|
showSection('provision');
|
|
2366
|
-
}
|
|
2479
|
+
}
|
|
2367
2480
|
|
|
2368
2481
|
// Provision
|
|
2369
2482
|
document.getElementById('btn-provision').addEventListener('click', async () => {
|
|
@@ -2584,7 +2697,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
2584
2697
|
method: 'POST',
|
|
2585
2698
|
body: {
|
|
2586
2699
|
env: config.env,
|
|
2587
|
-
baseUrl:
|
|
2700
|
+
baseUrl: apiUrl, // Setup page is served by ar-auth worker (API)
|
|
2588
2701
|
keysDir: '.keys',
|
|
2589
2702
|
},
|
|
2590
2703
|
});
|
|
@@ -2674,6 +2787,12 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
2674
2787
|
const setupItem = createUrlItem('Admin Setup:', result.setupUrl);
|
|
2675
2788
|
setupItem.querySelector('a').style.fontWeight = 'bold';
|
|
2676
2789
|
urlsEl.appendChild(setupItem);
|
|
2790
|
+
|
|
2791
|
+
// Add warning about one-time use and time limit
|
|
2792
|
+
const setupNote = document.createElement('div');
|
|
2793
|
+
setupNote.style.cssText = 'margin-top: 0.5rem; margin-bottom: 0.5rem; padding: 0.5rem 0.75rem; background: #fef3c7; border-radius: 0.375rem; font-size: 0.85rem; color: #92400e;';
|
|
2794
|
+
setupNote.innerHTML = '⚠️ This URL can only be used <strong>once</strong> and expires in <strong>1 hour</strong>.';
|
|
2795
|
+
urlsEl.appendChild(setupNote);
|
|
2677
2796
|
} else {
|
|
2678
2797
|
// Show debug info when setup URL is missing
|
|
2679
2798
|
const debugDiv = document.createElement('div');
|
|
@@ -2728,6 +2847,23 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
2728
2847
|
};
|
|
2729
2848
|
}
|
|
2730
2849
|
|
|
2850
|
+
// Get human-readable label for database region
|
|
2851
|
+
function getRegionLabel(location, jurisdiction) {
|
|
2852
|
+
if (jurisdiction === 'eu') {
|
|
2853
|
+
return 'EU Jurisdiction';
|
|
2854
|
+
}
|
|
2855
|
+
const labels = {
|
|
2856
|
+
'auto': 'Automatic',
|
|
2857
|
+
'wnam': 'North America (West)',
|
|
2858
|
+
'enam': 'North America (East)',
|
|
2859
|
+
'weur': 'Europe (West)',
|
|
2860
|
+
'eeur': 'Europe (East)',
|
|
2861
|
+
'apac': 'Asia Pacific',
|
|
2862
|
+
'oc': 'Oceania',
|
|
2863
|
+
};
|
|
2864
|
+
return labels[location] || 'Automatic';
|
|
2865
|
+
}
|
|
2866
|
+
|
|
2731
2867
|
function updateResourcePreview(env) {
|
|
2732
2868
|
const resources = getResourceNames(env);
|
|
2733
2869
|
|
|
@@ -2739,11 +2875,21 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
2739
2875
|
kvList.innerHTML = '';
|
|
2740
2876
|
keysList.innerHTML = '';
|
|
2741
2877
|
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2878
|
+
// Get region info from config
|
|
2879
|
+
const coreRegion = config.database?.core || { location: 'auto', jurisdiction: 'none' };
|
|
2880
|
+
const piiRegion = config.database?.pii || { location: 'auto', jurisdiction: 'none' };
|
|
2881
|
+
|
|
2882
|
+
// D1 databases with region info
|
|
2883
|
+
const coreDbName = env + '-authrim-core-db';
|
|
2884
|
+
const piiDbName = env + '-authrim-pii-db';
|
|
2885
|
+
|
|
2886
|
+
const coreLi = document.createElement('li');
|
|
2887
|
+
coreLi.innerHTML = coreDbName + ' <span style="color: var(--text-muted); font-size: 0.85em;">(' + getRegionLabel(coreRegion.location, coreRegion.jurisdiction) + ')</span>';
|
|
2888
|
+
d1List.appendChild(coreLi);
|
|
2889
|
+
|
|
2890
|
+
const piiLi = document.createElement('li');
|
|
2891
|
+
piiLi.innerHTML = piiDbName + ' <span style="color: var(--text-muted); font-size: 0.85em;">(' + getRegionLabel(piiRegion.location, piiRegion.jurisdiction) + ')</span>';
|
|
2892
|
+
d1List.appendChild(piiLi);
|
|
2747
2893
|
|
|
2748
2894
|
resources.kv.forEach(name => {
|
|
2749
2895
|
const li = document.createElement('li');
|
|
@@ -3013,10 +3159,12 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
3013
3159
|
renderResourceList('detail-kv-list', 'detail-kv-count', env.kv, 'name', 'kv');
|
|
3014
3160
|
renderResourceList('detail-queues-list', 'detail-queues-count', env.queues, 'name', 'queue');
|
|
3015
3161
|
renderResourceList('detail-r2-list', 'detail-r2-count', env.r2, 'name', 'r2');
|
|
3162
|
+
renderResourceList('detail-pages-list', 'detail-pages-count', env.pages || [], 'name', 'pages');
|
|
3016
3163
|
|
|
3017
3164
|
// Hide empty sections
|
|
3018
3165
|
document.getElementById('detail-queues-section').style.display = env.queues.length === 0 ? 'none' : 'block';
|
|
3019
3166
|
document.getElementById('detail-r2-section').style.display = env.r2.length === 0 ? 'none' : 'block';
|
|
3167
|
+
document.getElementById('detail-pages-section').style.display = (env.pages || []).length === 0 ? 'none' : 'block';
|
|
3020
3168
|
|
|
3021
3169
|
showSection('envDetail');
|
|
3022
3170
|
|
|
@@ -3184,6 +3332,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
3184
3332
|
document.getElementById('delete-kv-count').textContent = '(' + env.kv.length + ' namespaces)';
|
|
3185
3333
|
document.getElementById('delete-queues-count').textContent = '(' + env.queues.length + ' queues)';
|
|
3186
3334
|
document.getElementById('delete-r2-count').textContent = '(' + env.r2.length + ' buckets)';
|
|
3335
|
+
document.getElementById('delete-pages-count').textContent = '(' + (env.pages || []).length + ' projects)';
|
|
3187
3336
|
|
|
3188
3337
|
// Reset checkboxes
|
|
3189
3338
|
document.getElementById('delete-workers').checked = true;
|
|
@@ -3191,6 +3340,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
3191
3340
|
document.getElementById('delete-kv').checked = true;
|
|
3192
3341
|
document.getElementById('delete-queues').checked = true;
|
|
3193
3342
|
document.getElementById('delete-r2').checked = true;
|
|
3343
|
+
document.getElementById('delete-pages').checked = true;
|
|
3194
3344
|
|
|
3195
3345
|
// Reset UI state
|
|
3196
3346
|
document.getElementById('delete-log').classList.add('hidden');
|
|
@@ -3249,6 +3399,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
3249
3399
|
deleteKV: document.getElementById('delete-kv').checked,
|
|
3250
3400
|
deleteQueues: document.getElementById('delete-queues').checked,
|
|
3251
3401
|
deleteR2: document.getElementById('delete-r2').checked,
|
|
3402
|
+
deletePages: document.getElementById('delete-pages').checked,
|
|
3252
3403
|
};
|
|
3253
3404
|
|
|
3254
3405
|
// Poll for progress
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAqnDoB,SAAS;0BACZ,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA6wDhC,CAAC;AACT,CAAC"}
|