@serve.zone/dcrouter 17.0.0 → 17.1.1
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/.smartconfig.json +7 -4
- package/deno.json +1 -1
- package/dist_serve/bundle.js +1316 -1151
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.d.ts +3 -1
- package/dist_ts/classes.dcrouter.js +113 -52
- package/dist_ts/db/classes.cache.cleaner.d.ts +3 -0
- package/dist_ts/db/classes.cache.cleaner.js +7 -3
- package/dist_ts/db/classes.dcrouter-db.js +1 -2
- package/dist_ts/db/documents/classes.cached.email.d.ts +41 -4
- package/dist_ts/db/documents/classes.cached.email.js +36 -5
- package/dist_ts/db/documents/classes.dns-record.doc.js +3 -1
- package/dist_ts/dns/classes.dns-server-runtime.d.ts +0 -1
- package/dist_ts/dns/classes.dns-server-runtime.js +4 -36
- package/dist_ts/dns/index.d.ts +1 -0
- package/dist_ts/dns/index.js +2 -1
- package/dist_ts/dns/manager.dns.d.ts +1 -0
- package/dist_ts/dns/manager.dns.js +49 -14
- package/dist_ts/dns/providers/cloudflare.provider.js +19 -4
- package/dist_ts/dns/txt-record-presentation.d.ts +20 -0
- package/dist_ts/dns/txt-record-presentation.js +131 -0
- package/dist_ts/email/classes.accepted-email-spool.d.ts +32 -3
- package/dist_ts/email/classes.accepted-email-spool.js +174 -13
- package/dist_ts/email/classes.email-domain.manager.d.ts +14 -1
- package/dist_ts/email/classes.email-domain.manager.js +151 -8
- package/dist_ts/email/classes.email-settings.manager.js +2 -2
- package/dist_ts/email/classes.mail-dns-sync.d.ts +31 -5
- package/dist_ts/email/classes.mail-dns-sync.js +508 -117
- package/dist_ts/email/classes.smartmta-blob-storage-manager.d.ts +2 -2
- package/dist_ts/email/classes.smartmta-blob-storage-manager.js +4 -3
- package/dist_ts/email/classes.workapp-mail-manager.d.ts +1 -0
- package/dist_ts/email/classes.workapp-mail-manager.js +26 -2
- package/dist_ts/email/index.d.ts +2 -0
- package/dist_ts/email/index.js +3 -1
- package/dist_ts/email/mail-dns-txt-policy.d.ts +18 -0
- package/dist_ts/email/mail-dns-txt-policy.js +466 -0
- package/dist_ts/email/reconcile-mail-dns-singleton.d.ts +47 -0
- package/dist_ts/email/reconcile-mail-dns-singleton.js +159 -0
- package/dist_ts/opsserver/classes.opsserver.d.ts +8 -0
- package/dist_ts/opsserver/classes.opsserver.js +34 -1
- package/dist_ts/opsserver/handlers/certificate.handler.js +25 -4
- package/dist_ts/opsserver/handlers/config.handler.js +9 -5
- package/dist_ts/opsserver/handlers/dns-provider.handler.js +19 -2
- package/dist_ts/opsserver/handlers/dns-record.handler.js +25 -4
- package/dist_ts/opsserver/handlers/domain.handler.js +37 -3
- package/dist_ts/opsserver/handlers/email-domain.handler.js +5 -7
- package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +1 -0
- package/dist_ts/opsserver/handlers/email-ops.handler.js +26 -7
- package/dist_ts/opsserver/handlers/index.d.ts +1 -0
- package/dist_ts/opsserver/handlers/index.js +2 -1
- package/dist_ts/opsserver/handlers/logs.handler.d.ts +1 -1
- package/dist_ts/opsserver/handlers/logs.handler.js +3 -3
- package/dist_ts/opsserver/handlers/realtime.handler.d.ts +37 -0
- package/dist_ts/opsserver/handlers/realtime.handler.js +154 -0
- package/dist_ts/opsserver/handlers/remoteingress.handler.js +22 -1
- package/dist_ts/opsserver/handlers/route-management.handler.js +47 -5
- package/dist_ts/opsserver/handlers/stats.handler.js +5 -1
- package/dist_ts/paths.d.ts +0 -11
- package/dist_ts/paths.js +1 -22
- package/dist_ts/plugins.d.ts +0 -34
- package/dist_ts/plugins.js +1 -62
- package/dist_ts_interfaces/data/email-domain.d.ts +14 -0
- package/dist_ts_interfaces/requests/config.d.ts +1 -1
- package/dist_ts_interfaces/requests/email-ops.d.ts +34 -1
- package/dist_ts_interfaces/requests/index.d.ts +1 -0
- package/dist_ts_interfaces/requests/index.js +2 -1
- package/dist_ts_interfaces/requests/realtime.d.ts +38 -0
- package/dist_ts_interfaces/requests/realtime.js +11 -0
- package/dist_ts_migrations/index.d.ts +6 -0
- package/dist_ts_migrations/index.js +208 -9
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate/certificates.js +9 -2
- package/dist_ts_web/appstate/domains.js +16 -5
- package/dist_ts_web/appstate/email-domains.d.ts +3 -0
- package/dist_ts_web/appstate/email-domains.js +47 -14
- package/dist_ts_web/appstate/email-ops.d.ts +1 -0
- package/dist_ts_web/appstate/email-ops.js +20 -2
- package/dist_ts_web/appstate/realtime.d.ts +27 -0
- package/dist_ts_web/appstate/realtime.js +71 -0
- package/dist_ts_web/appstate/remoteingress.js +9 -3
- package/dist_ts_web/appstate/routes.js +16 -5
- package/dist_ts_web/appstate/runtime.js +135 -7
- package/dist_ts_web/appstate.d.ts +1 -0
- package/dist_ts_web/appstate.js +2 -1
- package/dist_ts_web/elements/email/email-domain-creation-progress.d.ts +33 -0
- package/dist_ts_web/elements/email/email-domain-creation-progress.js +257 -0
- package/dist_ts_web/elements/email/ops-view-email-domains.js +233 -68
- package/dist_ts_web/elements/email/ops-view-emails.d.ts +4 -2
- package/dist_ts_web/elements/email/ops-view-emails.js +25 -13
- package/dist_ts_web/elements/overview/ops-view-config.js +5 -5
- package/package.json +22 -19
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +124 -57
- package/ts/db/classes.cache.cleaner.ts +18 -3
- package/ts/db/classes.dcrouter-db.ts +0 -2
- package/ts/db/documents/classes.cached.email.ts +78 -4
- package/ts/db/documents/classes.dns-record.doc.ts +1 -0
- package/ts/dns/classes.dns-server-runtime.ts +9 -45
- package/ts/dns/index.ts +1 -0
- package/ts/dns/manager.dns.ts +50 -16
- package/ts/dns/providers/cloudflare.provider.ts +21 -3
- package/ts/dns/txt-record-presentation.ts +134 -0
- package/ts/email/classes.accepted-email-spool.ts +220 -14
- package/ts/email/classes.email-domain.manager.ts +201 -7
- package/ts/email/classes.email-settings.manager.ts +1 -1
- package/ts/email/classes.mail-dns-sync.ts +588 -122
- package/ts/email/classes.smartmta-blob-storage-manager.ts +3 -2
- package/ts/email/classes.workapp-mail-manager.ts +34 -1
- package/ts/email/index.ts +2 -0
- package/ts/email/mail-dns-txt-policy.ts +505 -0
- package/ts/email/reconcile-mail-dns-singleton.ts +224 -0
- package/ts/opsserver/classes.opsserver.ts +42 -0
- package/ts/opsserver/handlers/certificate.handler.ts +24 -3
- package/ts/opsserver/handlers/config.handler.ts +9 -5
- package/ts/opsserver/handlers/dns-provider.handler.ts +18 -1
- package/ts/opsserver/handlers/dns-record.handler.ts +24 -3
- package/ts/opsserver/handlers/domain.handler.ts +36 -2
- package/ts/opsserver/handlers/email-domain.handler.ts +4 -5
- package/ts/opsserver/handlers/email-ops.handler.ts +29 -6
- package/ts/opsserver/handlers/index.ts +1 -0
- package/ts/opsserver/handlers/logs.handler.ts +2 -2
- package/ts/opsserver/handlers/realtime.handler.ts +222 -0
- package/ts/opsserver/handlers/remoteingress.handler.ts +21 -0
- package/ts/opsserver/handlers/route-management.handler.ts +46 -4
- package/ts/opsserver/handlers/stats.handler.ts +4 -0
- package/ts/paths.ts +0 -25
- package/ts/plugins.ts +0 -68
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate/certificates.ts +6 -1
- package/ts_web/appstate/domains.ts +11 -4
- package/ts_web/appstate/email-domains.ts +68 -14
- package/ts_web/appstate/email-ops.ts +20 -1
- package/ts_web/appstate/realtime.ts +109 -0
- package/ts_web/appstate/remoteingress.ts +6 -2
- package/ts_web/appstate/routes.ts +11 -4
- package/ts_web/appstate/runtime.ts +176 -7
- package/ts_web/appstate.ts +1 -0
- package/ts_web/elements/email/email-domain-creation-progress.ts +340 -0
- package/ts_web/elements/email/ops-view-email-domains.ts +273 -74
- package/ts_web/elements/email/ops-view-emails.ts +23 -16
- package/ts_web/elements/overview/ops-view-config.ts +4 -4
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
const settledIntentStatuses = new Set([
|
|
2
|
+
'satisfied',
|
|
3
|
+
'valid',
|
|
4
|
+
'conflict',
|
|
5
|
+
'failed',
|
|
6
|
+
]);
|
|
7
|
+
const formatOperationError = (errorArg) => {
|
|
8
|
+
const location = errorArg.recordKey ? `${errorArg.recordKey}: ` : '';
|
|
9
|
+
return `${location}${errorArg.message} [${errorArg.code}]`;
|
|
10
|
+
};
|
|
11
|
+
const appendDnsStatusLines = (linesArg, dnsStatusArg) => {
|
|
12
|
+
for (const [label, status] of [
|
|
13
|
+
['MX', dnsStatusArg.mx],
|
|
14
|
+
['SPF', dnsStatusArg.spf],
|
|
15
|
+
['DKIM', dnsStatusArg.dkim],
|
|
16
|
+
['DMARC', dnsStatusArg.dmarc],
|
|
17
|
+
]) {
|
|
18
|
+
if (status !== 'unchecked') {
|
|
19
|
+
linesArg.push(`${label}: ${status}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
export const getEmailDomainCreationProgress = (inputArg) => {
|
|
24
|
+
const { domain, operation, requestCompleted } = inputArg;
|
|
25
|
+
if (!domain) {
|
|
26
|
+
if (!requestCompleted) {
|
|
27
|
+
return {
|
|
28
|
+
percentage: 0,
|
|
29
|
+
indeterminate: true,
|
|
30
|
+
showPercentage: false,
|
|
31
|
+
statusText: 'Generating DKIM material and creating the domain record...',
|
|
32
|
+
terminalLines: ['Submitting email domain configuration'],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const lines = ['Email domain creation request completed without a persisted domain'];
|
|
36
|
+
for (const error of operation?.errors || []) {
|
|
37
|
+
lines.push(formatOperationError(error));
|
|
38
|
+
}
|
|
39
|
+
if (operation?.message && !lines.includes(operation.message)) {
|
|
40
|
+
lines.push(operation.message);
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
percentage: 100,
|
|
44
|
+
indeterminate: false,
|
|
45
|
+
showPercentage: false,
|
|
46
|
+
statusText: operation?.message || 'Email domain creation failed.',
|
|
47
|
+
terminalLines: lines,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const reconciliation = domain.reconciliation;
|
|
51
|
+
const lines = [`Domain record persisted: ${domain.domain}`];
|
|
52
|
+
if (!reconciliation || reconciliation.intents.length === 0) {
|
|
53
|
+
if (!requestCompleted) {
|
|
54
|
+
lines.push('Preparing the managed DNS plan');
|
|
55
|
+
return {
|
|
56
|
+
percentage: 0,
|
|
57
|
+
indeterminate: true,
|
|
58
|
+
showPercentage: false,
|
|
59
|
+
statusText: 'Preparing the managed DNS plan...',
|
|
60
|
+
terminalLines: lines,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
lines.push('No DNS reconciliation plan is available');
|
|
64
|
+
const errors = reconciliation?.errors.length
|
|
65
|
+
? reconciliation.errors
|
|
66
|
+
: operation?.errors || [];
|
|
67
|
+
for (const error of errors) {
|
|
68
|
+
lines.push(formatOperationError(error));
|
|
69
|
+
}
|
|
70
|
+
const retryAt = reconciliation?.retryAt || operation?.retryAt;
|
|
71
|
+
if (retryAt) {
|
|
72
|
+
lines.push(`Retry scheduled for ${retryAt}`);
|
|
73
|
+
}
|
|
74
|
+
const statusText = reconciliation?.lifecycleStatus === 'failed'
|
|
75
|
+
? operation?.message || `DNS setup failed for ${domain.domain}.`
|
|
76
|
+
: retryAt
|
|
77
|
+
? 'DNS reconciliation is pending and will retry automatically.'
|
|
78
|
+
: operation?.message || 'The domain was created without a DNS reconciliation plan.';
|
|
79
|
+
return {
|
|
80
|
+
percentage: 100,
|
|
81
|
+
indeterminate: false,
|
|
82
|
+
showPercentage: false,
|
|
83
|
+
statusText,
|
|
84
|
+
terminalLines: lines,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const settledCount = reconciliation.intents.filter((intent) => settledIntentStatuses.has(intent.status)).length;
|
|
88
|
+
lines.push(`DNS plan prepared: ${reconciliation.intents.length} managed records`);
|
|
89
|
+
lines.push(`DNS reconciliation: ${settledCount} settled, ${reconciliation.intents.length - settledCount} pending`);
|
|
90
|
+
appendDnsStatusLines(lines, domain.dnsStatus);
|
|
91
|
+
if (reconciliation.lifecycleStatus === 'active') {
|
|
92
|
+
lines.push('Email domain is active');
|
|
93
|
+
return {
|
|
94
|
+
percentage: 100,
|
|
95
|
+
indeterminate: false,
|
|
96
|
+
showPercentage: true,
|
|
97
|
+
statusText: `${domain.domain} is active.`,
|
|
98
|
+
terminalLines: lines,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (!requestCompleted) {
|
|
102
|
+
return {
|
|
103
|
+
percentage: 0,
|
|
104
|
+
indeterminate: true,
|
|
105
|
+
showPercentage: false,
|
|
106
|
+
statusText: 'Reconciling and validating managed DNS records...',
|
|
107
|
+
terminalLines: lines,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const errors = reconciliation.errors.length > 0
|
|
111
|
+
? reconciliation.errors
|
|
112
|
+
: operation?.errors || [];
|
|
113
|
+
for (const error of errors) {
|
|
114
|
+
lines.push(formatOperationError(error));
|
|
115
|
+
}
|
|
116
|
+
const retryAt = reconciliation.retryAt || operation?.retryAt;
|
|
117
|
+
if (retryAt) {
|
|
118
|
+
lines.push(`Retry scheduled for ${retryAt}`);
|
|
119
|
+
}
|
|
120
|
+
if (reconciliation.lifecycleStatus === 'failed') {
|
|
121
|
+
return {
|
|
122
|
+
percentage: 100,
|
|
123
|
+
indeterminate: false,
|
|
124
|
+
showPercentage: false,
|
|
125
|
+
statusText: operation?.message || `DNS setup failed for ${domain.domain}.`,
|
|
126
|
+
terminalLines: lines,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
percentage: 100,
|
|
131
|
+
indeterminate: false,
|
|
132
|
+
showPercentage: false,
|
|
133
|
+
statusText: retryAt
|
|
134
|
+
? `DNS reconciliation is pending and will retry automatically.`
|
|
135
|
+
: `DNS reconciliation is pending for ${domain.domain}.`,
|
|
136
|
+
terminalLines: lines,
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
export const findNewEmailDomain = (domainsArg, expectedDomainArg, existingIdsArg) => {
|
|
140
|
+
const expectedDomain = expectedDomainArg.trim().toLowerCase();
|
|
141
|
+
const candidates = domainsArg.filter((domain) => domain.domain.toLowerCase() === expectedDomain && !existingIdsArg.has(domain.id));
|
|
142
|
+
if (candidates.length > 1) {
|
|
143
|
+
throw new Error(`Multiple new email domains appeared for ${expectedDomain}`);
|
|
144
|
+
}
|
|
145
|
+
return candidates[0];
|
|
146
|
+
};
|
|
147
|
+
const waitForPollInterval = async (delayMsArg, signalArg) => {
|
|
148
|
+
if (signalArg.aborted)
|
|
149
|
+
return;
|
|
150
|
+
await new Promise((resolve) => {
|
|
151
|
+
const finish = () => {
|
|
152
|
+
signalArg.removeEventListener('abort', handleAbort);
|
|
153
|
+
resolve();
|
|
154
|
+
};
|
|
155
|
+
const handleAbort = () => {
|
|
156
|
+
clearTimeout(timeoutId);
|
|
157
|
+
finish();
|
|
158
|
+
};
|
|
159
|
+
const timeoutId = setTimeout(finish, delayMsArg);
|
|
160
|
+
signalArg.addEventListener('abort', handleAbort, { once: true });
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
export const observeNewEmailDomain = async (optionsArg) => {
|
|
164
|
+
const startedAt = Date.now();
|
|
165
|
+
const pollIntervalMs = optionsArg.pollIntervalMs ?? (optionsArg.subscribeToDomains ? 15_000 : 600);
|
|
166
|
+
const timeoutMs = optionsArg.timeoutMs ?? 120_000;
|
|
167
|
+
let observedId;
|
|
168
|
+
let latestDomain;
|
|
169
|
+
let pushedDomains;
|
|
170
|
+
let wakeObserver;
|
|
171
|
+
const unsubscribe = optionsArg.subscribeToDomains?.((domainsArg) => {
|
|
172
|
+
pushedDomains = domainsArg;
|
|
173
|
+
wakeObserver?.();
|
|
174
|
+
});
|
|
175
|
+
try {
|
|
176
|
+
while (!optionsArg.signal.aborted && Date.now() - startedAt < timeoutMs) {
|
|
177
|
+
try {
|
|
178
|
+
let domain;
|
|
179
|
+
if (!observedId) {
|
|
180
|
+
const domainSnapshot = pushedDomains || await optionsArg.listDomains();
|
|
181
|
+
pushedDomains = undefined;
|
|
182
|
+
const foundDomain = findNewEmailDomain(domainSnapshot, optionsArg.expectedDomain, optionsArg.existingIds);
|
|
183
|
+
observedId = foundDomain?.id;
|
|
184
|
+
domain = foundDomain;
|
|
185
|
+
}
|
|
186
|
+
else if (pushedDomains) {
|
|
187
|
+
domain = pushedDomains.find((candidate) => candidate.id === observedId);
|
|
188
|
+
pushedDomains = undefined;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
domain = await optionsArg.getDomain(observedId);
|
|
192
|
+
}
|
|
193
|
+
if (optionsArg.signal.aborted)
|
|
194
|
+
break;
|
|
195
|
+
if (domain) {
|
|
196
|
+
if (domain !== latestDomain) {
|
|
197
|
+
latestDomain = domain;
|
|
198
|
+
optionsArg.onDomain(domain);
|
|
199
|
+
}
|
|
200
|
+
const lifecycleStatus = domain.reconciliation?.lifecycleStatus;
|
|
201
|
+
if (lifecycleStatus === 'active' || lifecycleStatus === 'failed') {
|
|
202
|
+
return domain;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
if (error instanceof Error && error.message.startsWith('Multiple new email domains')) {
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
// The realtime subscription or bounded fallback read will retry.
|
|
211
|
+
}
|
|
212
|
+
const updatePromise = new Promise((resolve) => {
|
|
213
|
+
wakeObserver = resolve;
|
|
214
|
+
});
|
|
215
|
+
if (pushedDomains) {
|
|
216
|
+
wakeObserver = undefined;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
await Promise.race([
|
|
220
|
+
updatePromise,
|
|
221
|
+
waitForPollInterval(pollIntervalMs, optionsArg.signal),
|
|
222
|
+
]);
|
|
223
|
+
wakeObserver = undefined;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
unsubscribe?.();
|
|
228
|
+
wakeObserver?.();
|
|
229
|
+
}
|
|
230
|
+
return latestDomain;
|
|
231
|
+
};
|
|
232
|
+
export const withAbortableDeadline = async (promiseArg, optionsArg) => {
|
|
233
|
+
return new Promise((resolve, reject) => {
|
|
234
|
+
let settled = false;
|
|
235
|
+
const finish = (callbackArg) => {
|
|
236
|
+
if (settled)
|
|
237
|
+
return;
|
|
238
|
+
settled = true;
|
|
239
|
+
clearTimeout(timeoutId);
|
|
240
|
+
optionsArg.signal?.removeEventListener('abort', handleAbort);
|
|
241
|
+
callbackArg();
|
|
242
|
+
};
|
|
243
|
+
const handleAbort = () => {
|
|
244
|
+
finish(() => reject(new Error('Email domain creation progress was interrupted')));
|
|
245
|
+
};
|
|
246
|
+
const timeoutId = setTimeout(() => {
|
|
247
|
+
finish(() => reject(new Error(optionsArg.timeoutMessage)));
|
|
248
|
+
}, optionsArg.timeoutMs);
|
|
249
|
+
if (optionsArg.signal?.aborted) {
|
|
250
|
+
handleAbort();
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
optionsArg.signal?.addEventListener('abort', handleAbort, { once: true });
|
|
254
|
+
promiseArg.then((value) => finish(() => resolve(value)), (error) => finish(() => reject(error)));
|
|
255
|
+
});
|
|
256
|
+
};
|
|
257
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1haWwtZG9tYWluLWNyZWF0aW9uLXByb2dyZXNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHNfd2ViL2VsZW1lbnRzL2VtYWlsL2VtYWlsLWRvbWFpbi1jcmVhdGlvbi1wcm9ncmVzcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFnQkEsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLEdBQUcsQ0FBd0M7SUFDM0UsV0FBVztJQUNYLE9BQU87SUFDUCxVQUFVO0lBQ1YsUUFBUTtDQUNULENBQUMsQ0FBQztBQUVILE1BQU0sb0JBQW9CLEdBQUcsQ0FDM0IsUUFBa0csRUFDMUYsRUFBRTtJQUNWLE1BQU0sUUFBUSxHQUFHLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEdBQUcsUUFBUSxDQUFDLFNBQVMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDckUsT0FBTyxHQUFHLFFBQVEsR0FBRyxRQUFRLENBQUMsT0FBTyxLQUFLLFFBQVEsQ0FBQyxJQUFJLEdBQUcsQ0FBQztBQUM3RCxDQUFDLENBQUM7QUFFRixNQUFNLG9CQUFvQixHQUFHLENBQzNCLFFBQWtCLEVBQ2xCLFlBQW1ELEVBQzdDLEVBQUU7SUFDUixLQUFLLE1BQU0sQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLElBQUk7UUFDNUIsQ0FBQyxJQUFJLEVBQUUsWUFBWSxDQUFDLEVBQUUsQ0FBQztRQUN2QixDQUFDLEtBQUssRUFBRSxZQUFZLENBQUMsR0FBRyxDQUFDO1FBQ3pCLENBQUMsTUFBTSxFQUFFLFlBQVksQ0FBQyxJQUFJLENBQUM7UUFDM0IsQ0FBQyxPQUFPLEVBQUUsWUFBWSxDQUFDLEtBQUssQ0FBQztLQUNyQixFQUFFLENBQUM7UUFDWCxJQUFJLE1BQU0sS0FBSyxXQUFXLEVBQUUsQ0FBQztZQUMzQixRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxLQUFLLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDdkMsQ0FBQztJQUNILENB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
|