@fin.cx/skr
Version:
SKR03 and SKR04 German accounting standards for double-entry bookkeeping
556 lines • 46 kB
JavaScript
import * as plugins from './plugins.js';
import { JournalEntry } from './skr.classes.journalentry.js';
import { SKRInvoiceMapper } from './skr.invoice.mapper.js';
/**
* Automatic booking engine for invoices
* Creates journal entries from invoice data based on SKR mapping rules
*/
export class InvoiceBookingEngine {
constructor(skrType) {
this.skrType = skrType;
this.mapper = new SKRInvoiceMapper(skrType);
this.logger = new plugins.smartlog.ConsoleLog();
}
/**
* Book an invoice to the ledger
*/
async bookInvoice(invoice, bookingRules, options) {
try {
// Get complete booking rules
const rules = this.mapper.mapInvoiceToSKR(invoice, bookingRules);
// Calculate confidence
const confidence = this.mapper.calculateConfidence(invoice, rules);
// Check if auto-booking is allowed
if (options?.autoBook && confidence < (options.confidenceThreshold || 80)) {
return {
success: false,
confidence,
warnings: [`Confidence score ${confidence}% is below threshold ${options.confidenceThreshold || 80}%`]
};
}
// Validate invoice before booking
if (!options?.skipValidation) {
const validationErrors = this.validateInvoice(invoice);
if (validationErrors.length > 0) {
return {
success: false,
confidence,
errors: validationErrors
};
}
}
// Build journal entry
const journalEntry = await this.buildJournalEntry(invoice, rules, options);
// Create booking info
const bookingInfo = {
journalEntryId: journalEntry.id,
transactionIds: journalEntry.transactionIds || [],
bookedAt: new Date(),
bookedBy: 'system',
bookingRules: {
vendorAccount: rules.vendorControlAccount,
customerAccount: rules.customerControlAccount,
expenseAccounts: this.getUsedExpenseAccounts(invoice, rules),
revenueAccounts: this.getUsedRevenueAccounts(invoice, rules),
vatAccounts: this.getUsedVATAccounts(invoice, rules)
},
confidence,
autoBooked: options?.autoBook || false
};
// Post the journal entry
// TODO: When MongoDB transactions are available, wrap this in a transaction
// Example: await db.withTransaction(async (session) => { ... })
try {
await journalEntry.validate();
await journalEntry.post();
// Mark invoice as posted if we have a reference to it
if (invoice.status !== 'posted') {
invoice.status = 'posted';
}
}
catch (postError) {
this.logger.log('error', `Failed to post journal entry: ${postError}`);
throw postError; // Re-throw to trigger rollback when transactions are available
}
return {
success: true,
journalEntry,
bookingInfo,
confidence,
warnings: this.generateWarnings(invoice, rules)
};
}
catch (error) {
this.logger.log('error', `Failed to book invoice: ${error}`);
return {
success: false,
confidence: 0,
errors: [`Booking failed: ${error.message}`]
};
}
}
/**
* Build journal entry from invoice
*/
async buildJournalEntry(invoice, rules, options) {
const lines = [];
const isInbound = invoice.direction === 'inbound';
const isCredit = invoice.invoiceTypeCode === '381'; // Credit note
// Determine if we need to reverse the normal booking direction
const reverseDirection = isCredit;
if (isInbound) {
// Inbound invoice (AP)
lines.push(...this.buildAPEntry(invoice, rules, reverseDirection));
}
else {
// Outbound invoice (AR)
lines.push(...this.buildAREntry(invoice, rules, reverseDirection));
}
// Create journal entry
const journalData = {
date: options?.bookingDate || invoice.issueDate,
description: this.buildDescription(invoice),
reference: options?.bookingReference || invoice.invoiceNumber,
lines,
skrType: this.skrType
};
const journalEntry = new JournalEntry(journalData);
return journalEntry;
}
/**
* Build AP (Accounts Payable) journal entry lines
*/
buildAPEntry(invoice, rules, reverseDirection) {
const lines = [];
// Group lines by account
const accountGroups = this.groupLinesByAccount(invoice, rules);
// Create expense/asset entries
for (const [accountNumber, group] of Object.entries(accountGroups)) {
const amount = group.reduce((sum, line) => sum + line.netAmount, 0);
if (reverseDirection) {
// Credit note: credit expense account
lines.push({
accountNumber,
credit: Math.abs(amount),
description: this.getAccountDescription(accountNumber, group)
});
}
else {
// Regular invoice: debit expense account
lines.push({
accountNumber,
debit: Math.abs(amount),
description: this.getAccountDescription(accountNumber, group)
});
}
}
// Create VAT entries
const vatLines = this.buildVATLines(invoice, rules, 'input', reverseDirection);
lines.push(...vatLines);
// Create vendor control account entry
const controlAccount = this.mapper.getControlAccount(invoice, rules);
const totalAmount = Math.abs(invoice.payableAmount);
if (reverseDirection) {
// Credit note: debit vendor account
lines.push({
accountNumber: controlAccount,
debit: totalAmount,
description: `${invoice.supplier.name} - Credit Note ${invoice.invoiceNumber}`
});
}
else {
// Regular invoice: credit vendor account
lines.push({
accountNumber: controlAccount,
credit: totalAmount,
description: `${invoice.supplier.name} - Invoice ${invoice.invoiceNumber}`
});
}
return lines;
}
/**
* Build AR (Accounts Receivable) journal entry lines
*/
buildAREntry(invoice, rules, reverseDirection) {
const lines = [];
// Group lines by account
const accountGroups = this.groupLinesByAccount(invoice, rules);
// Create revenue entries
for (const [accountNumber, group] of Object.entries(accountGroups)) {
const amount = group.reduce((sum, line) => sum + line.netAmount, 0);
if (reverseDirection) {
// Credit note: debit revenue account
lines.push({
accountNumber,
debit: Math.abs(amount),
description: this.getAccountDescription(accountNumber, group)
});
}
else {
// Regular invoice: credit revenue account
lines.push({
accountNumber,
credit: Math.abs(amount),
description: this.getAccountDescription(accountNumber, group)
});
}
}
// Create VAT entries
const vatLines = this.buildVATLines(invoice, rules, 'output', reverseDirection);
lines.push(...vatLines);
// Create customer control account entry
const controlAccount = this.mapper.getControlAccount(invoice, rules);
const totalAmount = Math.abs(invoice.payableAmount);
if (reverseDirection) {
// Credit note: credit customer account
lines.push({
accountNumber: controlAccount,
credit: totalAmount,
description: `${invoice.customer.name} - Credit Note ${invoice.invoiceNumber}`
});
}
else {
// Regular invoice: debit customer account
lines.push({
accountNumber: controlAccount,
debit: totalAmount,
description: `${invoice.customer.name} - Invoice ${invoice.invoiceNumber}`
});
}
return lines;
}
/**
* Build VAT lines
*/
buildVATLines(invoice, rules, direction, reverseDirection) {
const lines = [];
const taxScenario = invoice.taxScenario || 'domestic_taxed';
// Handle reverse charge specially
if (taxScenario === 'reverse_charge') {
return this.buildReverseChargeVATLines(invoice, rules);
}
// Standard VAT booking
for (const vatBreak of invoice.vatBreakdown) {
if (vatBreak.taxAmount === 0)
continue;
const vatAccount = this.mapper.getVATAccount(vatBreak.vatCategory, direction, taxScenario);
const amount = Math.abs(vatBreak.taxAmount);
const description = `VAT ${vatBreak.vatCategory.rate}%`;
if (direction === 'input') {
// Input VAT (Vorsteuer)
if (reverseDirection) {
lines.push({ accountNumber: vatAccount, credit: amount, description });
}
else {
lines.push({ accountNumber: vatAccount, debit: amount, description });
}
}
else {
// Output VAT (Umsatzsteuer)
if (reverseDirection) {
lines.push({ accountNumber: vatAccount, debit: amount, description });
}
else {
lines.push({ accountNumber: vatAccount, credit: amount, description });
}
}
}
return lines;
}
/**
* Calculate VAT amount from taxable amount and rate
*/
calculateVAT(taxableAmount, rate) {
return Math.round(taxableAmount * rate / 100 * 100) / 100; // Round to 2 decimals
}
/**
* Calculate effective VAT rate for the invoice (weighted average)
*/
calculateEffectiveVATRate(invoice) {
const totalTaxable = invoice.vatBreakdown.reduce((sum, vb) => sum + vb.taxableAmount, 0);
if (totalTaxable === 0) {
return 19; // Default to standard German VAT rate
}
// Calculate weighted average VAT rate
const weightedRate = invoice.vatBreakdown.reduce((sum, vb) => {
return sum + (vb.vatCategory.rate * vb.taxableAmount);
}, 0);
return Math.round(weightedRate / totalTaxable * 100) / 100;
}
/**
* Build reverse charge VAT lines (§13b UStG)
*/
buildReverseChargeVATLines(invoice, rules) {
const lines = [];
// For reverse charge, we book both input and output VAT
for (const vatBreak of invoice.vatBreakdown) {
// For reverse charge, calculate VAT if not provided
const amount = vatBreak.taxAmount > 0
? Math.abs(vatBreak.taxAmount)
: this.calculateVAT(Math.abs(vatBreak.taxableAmount), vatBreak.vatCategory.rate);
// Input VAT (deductible)
const inputVATAccount = this.mapper.getVATAccount(vatBreak.vatCategory, 'input', 'reverse_charge');
// Output VAT (payable)
const outputVATAccount = this.mapper.getVATAccount(vatBreak.vatCategory, 'output', 'reverse_charge');
lines.push({
accountNumber: inputVATAccount,
debit: amount,
description: `Reverse charge input VAT ${vatBreak.vatCategory.rate}%`
}, {
accountNumber: outputVATAccount,
credit: amount,
description: `Reverse charge output VAT ${vatBreak.vatCategory.rate}%`
});
}
return lines;
}
/**
* Group invoice lines by account
*/
groupLinesByAccount(invoice, rules) {
const groups = {};
for (const line of invoice.lines) {
const account = this.mapper.mapInvoiceLineToAccount(line, invoice, rules);
if (!groups[account]) {
groups[account] = [];
}
groups[account].push(line);
}
return groups;
}
/**
* Book payment for an invoice
*/
async bookPayment(invoice, payment, rules) {
try {
const lines = [];
const isInbound = invoice.direction === 'inbound';
const controlAccount = this.mapper.getControlAccount(invoice, rules);
// Check for skonto
const skontoAmount = payment.skontoTaken || 0;
const paymentAmount = payment.amount;
const fullAmount = paymentAmount + skontoAmount;
if (isInbound) {
// Payment for vendor invoice
lines.push({
accountNumber: controlAccount,
debit: fullAmount,
description: `Payment to ${invoice.supplier.name}`
}, {
accountNumber: '1000', // Bank account (would be configurable)
credit: paymentAmount,
description: `Bank payment ${payment.endToEndId || payment.paymentId}`
});
// Book skonto if taken
if (skontoAmount > 0) {
const skontoAccounts = this.mapper.getSkontoAccounts(invoice);
lines.push({
accountNumber: skontoAccounts.skontoAccount,
credit: skontoAmount,
description: `Skonto received`
});
// VAT correction for skonto
if (rules.skontoMethod === 'gross') {
const effectiveRate = this.calculateEffectiveVATRate(invoice);
const vatCorrection = Math.round(skontoAmount * effectiveRate / (100 + effectiveRate) * 100) / 100;
lines.push({
accountNumber: skontoAccounts.vatCorrectionAccount,
credit: vatCorrection,
description: `Skonto VAT correction`
});
}
}
}
else {
// Payment from customer
lines.push({
accountNumber: '1000', // Bank account
debit: paymentAmount,
description: `Payment from ${invoice.customer.name}`
}, {
accountNumber: controlAccount,
credit: fullAmount,
description: `Customer payment ${payment.endToEndId || payment.paymentId}`
});
// Book skonto if granted
if (skontoAmount > 0) {
const skontoAccounts = this.mapper.getSkontoAccounts(invoice);
lines.push({
accountNumber: skontoAccounts.skontoAccount,
debit: skontoAmount,
description: `Skonto granted`
});
// VAT correction for skonto
if (rules.skontoMethod === 'gross') {
const effectiveRate = this.calculateEffectiveVATRate(invoice);
const vatCorrection = Math.round(skontoAmount * effectiveRate / (100 + effectiveRate) * 100) / 100;
lines.push({
accountNumber: skontoAccounts.vatCorrectionAccount,
debit: vatCorrection,
description: `Skonto VAT correction`
});
}
}
}
// Create journal entry for payment
const journalData = {
date: payment.paymentDate,
description: `Payment for invoice ${invoice.invoiceNumber}`,
reference: payment.endToEndId || payment.remittanceInfo || payment.paymentId,
lines,
skrType: this.skrType
};
const journalEntry = new JournalEntry(journalData);
await journalEntry.validate();
await journalEntry.post();
return {
success: true,
journalEntry,
confidence: 100
};
}
catch (error) {
this.logger.log('error', `Failed to book payment: ${error}`);
return {
success: false,
confidence: 0,
errors: [`Payment booking failed: ${error.message}`]
};
}
}
/**
* Validate invoice before booking
*/
validateInvoice(invoice) {
const errors = [];
// Check required fields
if (!invoice.invoiceNumber) {
errors.push('Invoice number is required');
}
if (!invoice.issueDate) {
errors.push('Issue date is required');
}
if (!invoice.supplier || !invoice.supplier.name) {
errors.push('Supplier information is required');
}
if (!invoice.customer || !invoice.customer.name) {
errors.push('Customer information is required');
}
if (invoice.lines.length === 0) {
errors.push('Invoice must have at least one line item');
}
// Validate amounts
const calculatedNet = invoice.lines.reduce((sum, line) => sum + line.netAmount, 0);
const tolerance = 0.01;
if (Math.abs(calculatedNet - invoice.lineNetAmount) > tolerance) {
errors.push(`Line net amount mismatch: calculated ${calculatedNet}, stated ${invoice.lineNetAmount}`);
}
// Validate VAT
const calculatedVAT = invoice.vatBreakdown.reduce((sum, vb) => sum + vb.taxAmount, 0);
if (Math.abs(calculatedVAT - invoice.totalVATAmount) > tolerance) {
errors.push(`VAT amount mismatch: calculated ${calculatedVAT}, stated ${invoice.totalVATAmount}`);
}
// Validate total
const calculatedTotal = invoice.taxExclusiveAmount + invoice.totalVATAmount;
if (Math.abs(calculatedTotal - invoice.taxInclusiveAmount) > tolerance) {
errors.push(`Total amount mismatch: calculated ${calculatedTotal}, stated ${invoice.taxInclusiveAmount}`);
}
return errors;
}
/**
* Generate warnings for the booking
*/
generateWarnings(invoice, rules) {
const warnings = [];
// Warn about default account usage
const hasDefaultAccounts = invoice.lines.some(line => !line.accountNumber && !line.productCode);
if (hasDefaultAccounts) {
warnings.push('Some lines are using default expense/revenue accounts');
}
// Warn about mixed VAT rates
if (invoice.vatBreakdown.length > 1) {
warnings.push('Invoice contains mixed VAT rates');
}
// Warn about reverse charge
if (invoice.taxScenario === 'reverse_charge') {
warnings.push('Reverse charge procedure applied - verify VAT treatment');
}
// Warn about credit notes
if (invoice.invoiceTypeCode === '381') {
warnings.push('This is a credit note - amounts will be reversed');
}
// Warn about foreign currency
if (invoice.currencyCode !== 'EUR') {
warnings.push(`Invoice is in foreign currency: ${invoice.currencyCode}`);
}
return warnings;
}
/**
* Build description for journal entry
*/
buildDescription(invoice) {
const type = invoice.invoiceTypeCode === '381' ? 'Credit Note' : 'Invoice';
const party = invoice.direction === 'inbound'
? invoice.supplier.name
: invoice.customer.name;
return `${type} ${invoice.invoiceNumber} - ${party}`;
}
/**
* Get account description for a group of lines
*/
getAccountDescription(accountNumber, lines) {
if (lines.length === 1) {
return lines[0].description;
}
return `${this.mapper.getAccountDescription(accountNumber)} (${lines.length} items)`;
}
/**
* Get used expense accounts
*/
getUsedExpenseAccounts(invoice, rules) {
if (invoice.direction !== 'inbound')
return [];
const accounts = new Set();
for (const line of invoice.lines) {
const account = this.mapper.mapInvoiceLineToAccount(line, invoice, rules);
accounts.add(account);
}
return Array.from(accounts);
}
/**
* Get used revenue accounts
*/
getUsedRevenueAccounts(invoice, rules) {
if (invoice.direction !== 'outbound')
return [];
const accounts = new Set();
for (const line of invoice.lines) {
const account = this.mapper.mapInvoiceLineToAccount(line, invoice, rules);
accounts.add(account);
}
return Array.from(accounts);
}
/**
* Get used VAT accounts
*/
getUsedVATAccounts(invoice, rules) {
const accounts = new Set();
const direction = invoice.direction === 'inbound' ? 'input' : 'output';
const taxScenario = invoice.taxScenario || 'domestic_taxed';
for (const vatBreak of invoice.vatBreakdown) {
const account = this.mapper.getVATAccount(vatBreak.vatCategory, direction, taxScenario);
accounts.add(account);
}
// Add reverse charge accounts if applicable
if (taxScenario === 'reverse_charge') {
for (const vatBreak of invoice.vatBreakdown) {
const inputAccount = this.mapper.getVATAccount(vatBreak.vatCategory, 'input', 'reverse_charge');
const outputAccount = this.mapper.getVATAccount(vatBreak.vatCategory, 'output', 'reverse_charge');
accounts.add(inputAccount);
accounts.add(outputAccount);
}
}
return Array.from(accounts);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLmludm9pY2UuYm9va2luZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3Nrci5pbnZvaWNlLmJvb2tpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzdELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBa0MzRDs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sb0JBQW9CO0lBSy9CLFlBQVksT0FBaUI7UUFDM0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzVDLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBQ2xELENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxXQUFXLENBQ3RCLE9BQWlCLEVBQ2pCLFlBQXFDLEVBQ3JDLE9BQXlCO1FBRXpCLElBQUksQ0FBQztZQUNILDZCQUE2QjtZQUM3QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxPQUFPLEVBQUUsWUFBWSxDQUFDLENBQUM7WUFFakUsdUJBQXVCO1lBQ3ZCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBRW5FLG1DQUFtQztZQUNuQyxJQUFJLE9BQU8sRUFBRSxRQUFRLElBQUksVUFBVSxHQUFHLENBQUMsT0FBTyxDQUFDLG1CQUFtQixJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUM7Z0JBQzFFLE9BQU87b0JBQ0wsT0FBTyxFQUFFLEtBQUs7b0JBQ2QsVUFBVTtvQkFDVixRQUFRLEVBQUUsQ0FBQyxvQkFBb0IsVUFBVSx3QkFBd0IsT0FBTyxDQUFDLG1CQUFtQixJQUFJLEVBQUUsR0FBRyxDQUFDO2lCQUN2RyxDQUFDO1lBQ0osQ0FBQztZQUVELGtDQUFrQztZQUNsQyxJQUFJLENBQUMsT0FBTyxFQUFFLGNBQWMsRUFBRSxDQUFDO2dCQUM3QixNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3ZELElBQUksZ0JBQWdCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUNoQyxPQUFPO3dCQUNMLE9BQU8sRUFBRSxLQUFLO3dCQUNkLFVBQVU7d0JBQ1YsTUFBTSxFQUFFLGdCQUFnQjtxQkFDekIsQ0FBQztnQkFDSixDQUFDO1lBQ0gsQ0FBQztZQUVELHNCQUFzQjtZQUN0QixNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBRTNFLHNCQUFzQjtZQUN0QixNQUFNLFdBQVcsR0FBaUI7Z0JBQ2hDLGNBQWMsRUFBRSxZQUFZLENBQUMsRUFBRTtnQkFDL0IsY0FBYyxFQUFFLFlBQVksQ0FBQyxjQUFjLElBQUksRUFBRTtnQkFDakQsUUFBUSxFQUFFLElBQUksSUFBSSxFQUFFO2dCQUNwQixRQUFRLEVBQUUsUUFBUTtnQkFDbEIsWUFBWSxFQUFFO29CQUNaLGFBQWEsRUFBRSxLQUFLLENBQUMsb0JBQW9CO29CQUN6QyxlQUFlLEVBQUUsS0FBSyxDQUFDLHNCQUFzQjtvQkFDN0MsZUFBZSxFQUFFLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDO29CQUM1RCxlQUFlLEVBQUUsSUFBSSxDQUFDLHNCQUFzQixDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUM7b0JBQzVELFdBQVcsRUFBRSxJQUFJLENBQUMsa0JBQWtCLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQztpQkFDckQ7Z0JBQ0QsVUFBVTtnQkFDVixVQUFVLEVBQUUsT0FBTyxFQUFFLFFBQVEsSUFBSSxLQUFLO2FBQ3ZDLENBQUM7WUFFRix5QkFBeUI7WUFDekIsNEVBQTRFO1lBQzVFLGdFQUFnRTtZQUNoRSxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxZQUFZLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQzlCLE1BQU0sWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUUxQixzREFBc0Q7Z0JBQ3RELElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxRQUFRLEVBQUUsQ0FBQztvQkFDaEMsT0FBTyxDQUFDLE1BQU0sR0FBRyxRQUFRLENBQUM7Z0JBQzVCLENBQUM7WUFDSCxDQUFDO1lBQUMsT0FBTyxTQUFTLEVBQUUsQ0FBQztnQkFDbkIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLGlDQUFpQyxTQUFTLEVBQUUsQ0FBQyxDQUFDO2dCQUN2RSxNQUFNLFNBQVMsQ0FBQyxDQUFDLCtEQUErRDtZQUNsRixDQUFDO1lBRUQsT0FBTztnQkFDTCxPQUFPLEVBQUUsSUFBSTtnQkFDYixZQUFZO2dCQUNaLFdBQVc7Z0JBQ1gsVUFBVTtnQkFDVixRQUFRLEVBQUUsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUM7YUFDaEQsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLDJCQUEyQixLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQzdELE9BQU87Z0JBQ0wsT0FBTyxFQUFFLEtBQUs7Z0JBQ2QsVUFBVSxFQUFFLENBQUM7Z0JBQ2IsTUFBTSxFQUFFLENBQUMsbUJBQW1CLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQzthQUM3QyxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLEtBQUssQ0FBQyxpQkFBaUIsQ0FDN0IsT0FBaUIsRUFDakIsS0FBb0IsRUFDcEIsT0FBeUI7UUFFekIsTUFBTSxLQUFLLEdBQXdCLEVBQUUsQ0FBQztRQUN0QyxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsU0FBUyxLQUFLLFNBQVMsQ0FBQztRQUNsRCxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsZUFBZSxLQUFLLEtBQUssQ0FBQyxDQUFDLGNBQWM7UUFFbEUsK0RBQStEO1FBQy9ELE1BQU0sZ0JBQWdCLEdBQUcsUUFBUSxDQUFDO1FBRWxDLElBQUksU0FBUyxFQUFFLENBQUM7WUFDZCx1QkFBdUI7WUFDdkIsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDLENBQUM7UUFDckUsQ0FBQzthQUFNLENBQUM7WUFDTix3QkFBd0I7WUFDeEIsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDLENBQUM7UUFDckUsQ0FBQztRQUVELHVCQUF1QjtRQUN2QixNQUFNLFdBQVcsR0FBa0I7WUFDakMsSUFBSSxFQUFFLE9BQU8sRUFBRSxXQUFXLElBQUksT0FBTyxDQUFDLFNBQVM7WUFDL0MsV0FBVyxFQUFFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUM7WUFDM0MsU0FBUyxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsSUFBSSxPQUFPLENBQUMsYUFBYTtZQUM3RCxLQUFLO1lBQ0wsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO1NBQ3RCLENBQUM7UUFFRixNQUFNLFlBQVksR0FBRyxJQUFJLFlBQVksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUNuRCxPQUFPLFlBQVksQ0FBQztJQUN0QixDQUFDO0lBRUQ7O09BRUc7SUFDSyxZQUFZLENBQ2xCLE9BQWlCLEVBQ2pCLEtBQW9CLEVBQ3BCLGdCQUF5QjtRQUV6QixNQUFNLEtBQUssR0FBd0IsRUFBRSxDQUFDO1FBRXRDLHlCQUF5QjtRQUN6QixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRS9ELCtCQUErQjtRQUMvQixLQUFLLE1BQU0sQ0FBQyxhQUFhLEVBQUUsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDO1lBQ25FLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUVwRSxJQUFJLGdCQUFnQixFQUFFLENBQUM7Z0JBQ3JCLHNDQUFzQztnQkFDdEMsS0FBSyxDQUFDLElBQUksQ0FBQztvQkFDVCxhQUFhO29CQUNiLE1BQU0sRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQztvQkFDeEIsV0FBVyxFQUFFLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxhQUFhLEVBQUUsS0FBSyxDQUFDO2lCQUM5RCxDQUFDLENBQUM7WUFDTCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04seUNBQXlDO2dCQUN6QyxLQUFLLENBQUMsSUFBSSxDQUFDO29CQUNULGFBQWE7b0JBQ2IsS0FBSyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDO29CQUN2QixXQUFXLEVBQUUsSUFBSSxDQUFDLHFCQUFxQixDQUFDLGFBQWEsRUFBRSxLQUFLLENBQUM7aUJBQzlELENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO1FBRUQscUJBQXFCO1FBQ3JCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztRQUMvRSxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUM7UUFFeEIsc0NBQXNDO1FBQ3RDLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3JFLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRXBELElBQUksZ0JBQWdCLEVBQUUsQ0FBQztZQUNyQixvQ0FBb0M7WUFDcEMsS0FBSyxDQUFDLElBQUksQ0FBQztnQkFDVCxhQUFhLEVBQUUsY0FBYztnQkFDN0IsS0FBSyxFQUFFLFdBQVc7Z0JBQ2xCLFdBQVcsRUFBRSxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxrQkFBa0IsT0FBTyxDQUFDLGFBQWEsRUFBRTthQUMvRSxDQUFDLENBQUM7UUFDTCxDQUFDO2FBQU0sQ0FBQztZQUNOLHlDQUF5QztZQUN6QyxLQUFLLENBQUMsSUFBSSxDQUFDO2dCQUNULGFBQWEsRUFBRSxjQUFjO2dCQUM3QixNQUFNLEVBQUUsV0FBVztnQkFDbkIsV0FBVyxFQUFFLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLGNBQWMsT0FBTyxDQUFDLGFBQWEsRUFBRTthQUMzRSxDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQ7O09BRUc7SUFDSyxZQUFZLENBQ2xCLE9BQWlCLEVBQ2pCLEtBQW9CLEVBQ3BCLGdCQUF5QjtRQUV6QixNQUFNLEtBQUssR0FBd0IsRUFBRSxDQUFDO1FBRXRDLHlCQUF5QjtRQUN6QixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRS9ELHlCQUF5QjtRQUN6QixLQUFLLE1BQU0sQ0FBQyxhQUFhLEVBQUUsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDO1lBQ25FLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUVwRSxJQUFJLGdCQUFnQixFQUFFLENBQUM7Z0JBQ3JCLHFDQUFxQztnQkFDckMsS0FBSyxDQUFDLElBQUksQ0FBQztvQkFDVCxhQUFhO29CQUNiLEtBQUssRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQztvQkFDdkIsV0FBVyxFQUFFLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxhQUFhLEVBQUUsS0FBSyxDQUFDO2lCQUM5RCxDQUFDLENBQUM7WUFDTCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sMENBQTBDO2dCQUMxQyxLQUFLLENBQUMsSUFBSSxDQUFDO29CQUNULGFBQWE7b0JBQ2IsTUFBTSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDO29CQUN4QixXQUFXLEVBQUUsSUFBSSxDQUFDLHFCQUFxQixDQUFDLGFBQWEsRUFBRSxLQUFLLENBQUM7aUJBQzlELENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO1FBRUQscUJBQXFCO1FBQ3JCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztRQUNoRixLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUM7UUFFeEIsd0NBQXdDO1FBQ3hDLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3JFLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRXBELElBQUksZ0JBQWdCLEVBQUUsQ0FBQztZQUNyQix1Q0FBdUM7WUFDdkMsS0FBSyxDQUFDLElBQUksQ0FBQztnQkFDVCxhQUFhLEVBQUUsY0FBYztnQkFDN0IsTUFBTSxFQUFFLFdBQVc7Z0JBQ25CLFdBQVcsRUFBRSxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxrQkFBa0IsT0FBTyxDQUFDLGFBQWEsRUFBRTthQUMvRSxDQUFDLENBQUM7UUFDTCxDQUFDO2FBQU0sQ0FBQztZQUNOLDBDQUEwQztZQUMxQyxLQUFLLENBQUMsSUFBSSxDQUFDO2dCQUNULGFBQWEsRUFBRSxjQUFjO2dCQUM3QixLQUFLLEVBQUUsV0FBVztnQkFDbEIsV0FBVyxFQUFFLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLGNBQWMsT0FBTyxDQUFDLGFBQWEsRUFBRTthQUMzRSxDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQ7O09BRUc7SUFDSyxhQUFhLENBQ25CLE9BQWlCLEVBQ2pCLEtBQW9CLEVBQ3BCLFNBQTZCLEVBQzdCLGdCQUF5QjtRQUV6QixNQUFNLEtBQUssR0FBd0IsRUFBRSxDQUFDO1FBQ3RDLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxXQUFXLElBQUksZ0JBQWdCLENBQUM7UUFFNUQsa0NBQWtDO1FBQ2xDLElBQUksV0FBVyxLQUFLLGdCQUFnQixFQUFFLENBQUM7WUFDckMsT0FBTyxJQUFJLENBQUMsMEJBQTBCLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3pELENBQUM7UUFFRCx1QkFBdUI7UUFDdkIsS0FBSyxNQUFNLFFBQVEsSUFBSSxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDNUMsSUFBSSxRQUFRLENBQUMsU0FBUyxLQUFLLENBQUM7Z0JBQUUsU0FBUztZQUV2QyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FDMUMsUUFBUSxDQUFDLFdBQVcsRUFDcEIsU0FBUyxFQUNULFdBQVcsQ0FDWixDQUFDO1lBRUYsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDNUMsTUFBTSxXQUFXLEdBQUcsT0FBTyxRQUFRLENBQUMsV0FBVyxDQUFDLElBQUksR0FBRyxDQUFDO1lBRXhELElBQUksU0FBUyxLQUFLLE9BQU8sRUFBRSxDQUFDO2dCQUMxQix3QkFBd0I7Z0JBQ3hCLElBQUksZ0JBQWdCLEVBQUUsQ0FBQztvQkFDckIsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLGFBQWEsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO2dCQUN6RSxDQUFDO3FCQUFNLENBQUM7b0JBQ04sS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLGFBQWEsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO2dCQUN4RSxDQUFDO1lBQ0gsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLDRCQUE0QjtnQkFDNUIsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO29CQUNyQixLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsYUFBYSxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUM7Z0JBQ3hFLENBQUM7cUJBQU0sQ0FBQztvQkFDTixLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsYUFBYSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUM7Z0JBQ3pFLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOztPQUVHO0lBQ0ssWUFBWSxDQUFDLGFBQXFCLEVBQUUsSUFBWTtRQUN0RCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYSxHQUFHLElBQUksR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsc0JBQXNCO0lBQ25GLENBQUM7SUFFRDs7T0FFRztJQUNLLHlCQUF5QixDQUFDLE9BQWlCO1FBQ2pELE1BQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDekYsSUFBSSxZQUFZLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDdkIsT0FBTyxFQUFFLENBQUMsQ0FBQyxzQ0FBc0M7UUFDbkQsQ0FBQztRQUVELHNDQUFzQztRQUN0QyxNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRTtZQUMzRCxPQUFPLEdBQUcsR0FBRyxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsSUFBSSxHQUFHLEVBQUUsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUN4RCxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFFTixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxHQUFHLFlBQVksR0FBRyxHQUFHLENBQUMsR0FBRyxHQUFHLENBQUM7SUFDN0QsQ0FBQztJQUVEOztPQUVHO0lBQ0ssMEJBQTBCLENBQ2hDLE9BQWlCLEVBQ2pCLEtBQW9CO1FBRXBCLE1BQU0sS0FBSyxHQUF3QixFQUFFLENBQUM7UUFFdEMsd0RBQXdEO1FBQ3hELEtBQUssTUFBTSxRQUFRLElBQUksT0FBTyxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQzVDLG9EQUFvRDtZQUNwRCxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsU0FBUyxHQUFHLENBQUM7Z0JBQ25DLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUM7Z0JBQzlCLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7WUFFbkYseUJBQXlCO1lBQ3pCLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUMvQyxRQUFRLENBQUMsV0FBVyxFQUNwQixPQUFPLEVBQ1AsZ0JBQWdCLENBQ2pCLENBQUM7WUFFRix1QkFBdUI7WUFDdkIsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FDaEQsUUFBUSxDQUFDLFdBQVcsRUFDcEIsUUFBUSxFQUNSLGdCQUFnQixDQUNqQixDQUFDO1lBRUYsS0FBSyxDQUFDLElBQUksQ0FDUjtnQkFDRSxhQUFhLEVBQUUsZUFBZTtnQkFDOUIsS0FBSyxFQUFFLE1BQU07Z0JBQ2IsV0FBVyxFQUFFLDRCQUE0QixRQUFRLENBQUMsV0FBVyxDQUFDLElBQUksR0FBRzthQUN0RSxFQUNEO2dCQUNFLGFBQWEsRUFBRSxnQkFBZ0I7Z0JBQy9CLE1BQU0sRUFBRSxNQUFNO2dCQUNkLFdBQVcsRUFBRSw2QkFBNkIsUUFBUSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEdBQUc7YUFDdkUsQ0FDRixDQUFDO1FBQ0osQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOztPQUVHO0lBQ0ssbUJBQW1CLENBQ3pCLE9BQWlCLEVBQ2pCLEtBQW9CO1FBRXBCLE1BQU0sTUFBTSxHQUFtQyxFQUFFLENBQUM7UUFFbEQsS0FBSyxNQUFNLElBQUksSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDakMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBRTFFLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztnQkFDckIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUN2QixDQUFDO1lBQ0QsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM3QixDQUFDO1FBRUQsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLFdBQVcsQ0FDdEIsT0FBaUIsRUFDakIsT0FBcUIsRUFDckIsS0FBb0I7UUFFcEIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxLQUFLLEdBQXdCLEVBQUUsQ0FBQztZQUN0QyxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsU0FBUyxLQUFLLFNBQVMsQ0FBQztZQUNsRCxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztZQUVyRSxtQkFBbUI7WUFDbkIsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLFdBQVcsSUFBSSxDQUFDLENBQUM7WUFDOUMsTUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQztZQUNyQyxNQUFNLFVBQVUsR0FBRyxhQUFhLEdBQUcsWUFBWSxDQUFDO1lBRWhELElBQUksU0FBUyxFQUFFLENBQUM7Z0JBQ2QsNkJBQTZCO2dCQUM3QixLQUFLLENBQUMsSUFBSSxDQUNSO29CQUNFLGFBQWEsRUFBRSxjQUFjO29CQUM3QixLQUFLLEVBQUUsVUFBVTtvQkFDakIsV0FBVyxFQUFFLGNBQWMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUU7aUJBQ25ELEVBQ0Q7b0JBQ0UsYUFBYSxFQUFFLE1BQU0sRUFBRSx1Q0FBdUM7b0JBQzlELE1BQU0sRUFBRSxhQUFhO29CQUNyQixXQUFXLEVBQUUsZ0JBQWdCLE9BQU8sQ0FBQyxVQUFVLElBQUksT0FBTyxDQUFDLFNBQVMsRUFBRTtpQkFDdkUsQ0FDRixDQUFDO2dCQUVGLHVCQUF1QjtnQkFDdkIsSUFBSSxZQUFZLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQ3JCLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsT0FBTyxDQUFDLENBQUM7b0JBQzlELEtBQUssQ0FBQyxJQUFJLENBQUM7d0JBQ1QsYUFBYSxFQUFFLGNBQWMsQ0FBQyxhQUFhO3dCQUMzQyxNQUFNLEVBQUUsWUFBWTt3QkFDcEIsV0FBVyxFQUFFLGlCQUFpQjtxQkFDL0IsQ0FBQyxDQUFDO29CQUVILDRCQUE0QjtvQkFDNUIsSUFBSSxLQUFLLENBQUMsWUFBWSxLQUFLLE9BQU8sRUFBRSxDQUFDO3dCQUNuQyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMseUJBQXlCLENBQUMsT0FBTyxDQUFDLENBQUM7d0JBQzlELE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxHQUFHLGFBQWEsR0FBRyxDQUFDLEdBQUcsR0FBRyxhQUFhLENBQUMsR0FBRyxHQUFHLENBQUMsR0FBRyxHQUFHLENBQUM7d0JBQ25HLEtBQUssQ0FBQyxJQUFJLENBQ1I7NEJBQ0UsYUFBYSxFQUFFLGNBQWMsQ0FBQyxvQkFBb0I7NEJBQ2xELE1BQU0sRUFBRSxhQUFhOzRCQUNyQixXQUFXLEVBQUUsdUJBQXVCO3lCQUNyQyxDQUNGLENBQUM7b0JBQ0osQ0FBQztnQkFDSCxDQUFDO1lBQ0gsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLHdCQUF3QjtnQkFDeEIsS0FBSyxDQUFDLElBQUksQ0FDUjtvQkFDRSxhQUFhLEVBQUUsTUFBTSxFQUFFLGVBQWU7b0JBQ3RDLEtBQUssRUFBRSxhQUFhO29CQUNwQixXQUFXLEVBQUUsZ0JBQWdCLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFO2lCQUNyRCxFQUNEO29CQUNFLGFBQWEsRUFBRSxjQUFjO29CQUM3QixNQUFNLEVBQUUsVUFBVTtvQkFDbEIsV0FBVyxFQUFFLG9CQUFvQixPQUFPLENBQUMsVUFBVSxJQUFJLE9BQU8sQ0FBQyxTQUFTLEVBQUU7aUJBQzNFLENBQ0YsQ0FBQztnQkFFRix5QkFBeUI7Z0JBQ3pCLElBQUksWUFBWSxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUNyQixNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFDO29CQUM5RCxLQUFLLENBQUMsSUFBSSxDQUFDO3dCQUNULGFBQWEsRUFBRSxjQUFjLENBQUMsYUFBYTt3QkFDM0MsS0FBSyxFQUFFLFlBQVk7d0JBQ25CLFdBQVcsRUFBRSxnQkFBZ0I7cUJBQzlCLENBQUMsQ0FBQztvQkFFSCw0QkFBNEI7b0JBQzVCLElBQUksS0FBSyxDQUFDLFlBQVksS0FBSyxPQUFPLEVBQUUsQ0FBQzt3QkFDbkMsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLHlCQUF5QixDQUFDLE9BQU8sQ0FBQyxDQUFDO3dCQUM5RCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVksR0FBRyxhQUFhLEdBQUcsQ0FBQyxHQUFHLEdBQUcsYUFBYSxDQUFDLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxDQUFDO3dCQUNuRyxLQUFLLENBQUMsSUFBSSxDQUNSOzRCQUNFLGFBQWEsRUFBRSxjQUFjLENBQUMsb0JBQW9COzRCQUNsRCxLQUFLLEVBQUUsYUFBYTs0QkFDcEIsV0FBVyxFQUFFLHVCQUF1Qjt5QkFDckMsQ0FDRixDQUFDO29CQUNKLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7WUFFRCxtQ0FBbUM7WUFDbkMsTUFBTSxXQUFXLEdBQWtCO2dCQUNqQyxJQUFJLEVBQUUsT0FBTyxDQUFDLFdBQVc7Z0JBQ3pCLFdBQVcsRUFBRSx1QkFBdUIsT0FBTyxDQUFDLGFBQWEsRUFBRTtnQkFDM0QsU0FBUyxFQUFFLE9BQU8sQ0FBQyxVQUFVLElBQUksT0FBTyxDQUFDLGNBQWMsSUFBSSxPQUFPLENBQUMsU0FBUztnQkFDNUUsS0FBSztnQkFDTCxPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU87YUFDdEIsQ0FBQztZQUVGLE1BQU0sWUFBWSxHQUFHLElBQUksWUFBWSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQ25ELE1BQU0sWUFBWSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQzlCLE1BQU0sWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDO1lBRTFCLE9BQU87Z0JBQ0wsT0FBTyxFQUFFLElBQUk7Z0JBQ2IsWUFBWTtnQkFDWixVQUFVLEVBQUUsR0FBRzthQUNoQixDQUFDO1FBQ0osQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsMkJBQTJCLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDN0QsT0FBTztnQkFDTCxPQUFPLEVBQUUsS0FBSztnQkFDZCxVQUFVLEVBQUUsQ0FBQztnQkFDYixNQUFNLEVBQUUsQ0FBQywyQkFBMkIsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO2FBQ3JELENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssZUFBZSxDQUFDLE9BQWlCO1FBQ3ZDLE1BQU0sTUFBTSxHQUFhLEVBQUUsQ0FBQztRQUU1Qix3QkFBd0I7UUFDeEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUMzQixNQUFNLENBQUMsSUFBSSxDQUFDLDRCQUE0QixDQUFDLENBQUM7UUFDNUMsQ0FBQztRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDdkIsTUFBTSxDQUFDLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1FBQ3hDLENBQUM7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDaEQsTUFBTSxDQUFDLElBQUksQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO1FBQ2xELENBQUM7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDaEQsTUFBTSxDQUFDLElBQUksQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO1FBQ2xELENBQUM7UUFFRCxJQUFJLE9BQU8sQ0FBQyxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQy9CLE1BQU0sQ0FBQyxJQUFJLENBQUMsMENBQTBDLENBQUMsQ0FBQztRQUMxRCxDQUFDO1FBRUQsbUJBQW1CO1FBQ25CLE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDbkYsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDO1FBRXZCLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxhQUFhLEdBQUcsT0FBTyxDQUFDLGFBQWEsQ0FBQyxHQUFHLFNBQVMsRUFBRSxDQUFDO1lBQ2hFLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0NBQXdDLGFBQWEsWUFBWSxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQztRQUN4RyxDQUFDO1FBRUQsZUFBZTtRQUNmLE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDdEYsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDLEdBQUcsU0FBUyxFQUFFLENBQUM7WUFDakUsTUFBTSxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsYUFBYSxZQUFZLE9BQU8sQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDO1FBQ3BHLENBQUM7UUFFRCxpQkFBaUI7UUFDakIsTUFBTSxlQUFlLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixHQUFHLE9BQU8sQ0FBQyxjQUFjLENBQUM7UUFDNUUsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLGVBQWUsR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUMsR0FBRyxTQUFTLEVBQUUsQ0FBQztZQUN2RSxNQUFNLENBQUMsSUFBSSxDQUFDLHFDQUFxQyxlQUFlLFlBQVksT0FBTyxDQUFDLGtCQUFrQixFQUFFLENBQUMsQ0FBQztRQUM1RyxDQUFDO1FBRUQsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssZ0JBQWdCLENBQUMsT0FBaUIsRUFBRSxLQUFvQjtRQUM5RCxNQUFNLFFBQVEsR0FBYSxFQUFFLENBQUM7UUFFOUIsbUNBQW1DO1FBQ25DLE1BQU0sa0JBQWtCLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FDbkQsQ0FBQyxJQUFJLENBQUMsYUFBYSxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FDekMsQ0FBQztRQUNGLElBQUksa0JBQWtCLEVBQUUsQ0FBQztZQUN2QixRQUFRLENBQUMsSUFBSSxDQUFDLHVEQUF1RCxDQUFDLENBQUM7UUFDekUsQ0FBQztRQUVELDZCQUE2QjtRQUM3QixJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3BDLFFBQVEsQ0FBQyxJQUFJLENBQUMsa0NBQWtDLENBQUMsQ0FBQztRQUNwRCxDQUFDO1FBRUQsNEJBQTRCO1FBQzVCLElBQUksT0FBTyxDQUFDLFdBQVcsS0FBSyxnQkFBZ0IsRUFBRSxDQUFDO1lBQzdDLFFBQVEsQ0FBQyxJQUFJLENBQUMseURBQXlELENBQUMsQ0FBQztRQUMzRSxDQUFDO1FBRUQsMEJBQTBCO1FBQzFCLElBQUksT0FBTyxDQUFDLGVBQWUsS0FBSyxLQUFLLEVBQUUsQ0FBQztZQUN0QyxRQUFRLENBQUMsSUFBSSxDQUFDLGtEQUFrRCxDQUFDLENBQUM7UUFDcEUsQ0FBQztRQUVELDhCQUE4QjtRQUM5QixJQUFJLE9BQU8sQ0FBQyxZQUFZLEtBQUssS0FBSyxFQUFFLENBQUM7WUFDbkMsUUFBUSxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsT0FBTyxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUM7UUFDM0UsQ0FBQztRQUVELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFFRDs7T0FFRztJQUNLLGdCQUFnQixDQUFDLE9BQWlCO1FBQ3hDLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxlQUFlLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUMzRSxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsU0FBUyxLQUFLLFNBQVM7WUFDM0MsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSTtZQUN2QixDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7UUFFMUIsT0FBTyxHQUFHLElBQUksSUFBSSxPQUFPLENBQUMsYUFBYSxNQUFNLEtBQUssRUFBRSxDQUFDO0lBQ3ZELENBQUM7SUFFRDs7T0FFRztJQUNLLHFCQUFxQixDQUFDLGFBQXFCLEVBQUUsS0FBcUI7UUFDeEUsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLE9BQU8sS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQztRQUM5QixDQUFDO1FBRUQsT0FBTyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMscUJBQXFCLENBQUMsYUFBYSxDQUFDLEtBQUssS0FBSyxDQUFDLE1BQU0sU0FBUyxDQUFDO0lBQ3ZGLENBQUM7SUFFRDs7T0FFRztJQUNLLHNCQUFzQixDQUFDLE9BQWlCLEVBQUUsS0FBb0I7UUFDcEUsSUFBSSxPQUFPLENBQUMsU0FBUyxLQUFLLFNBQVM7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUUvQyxNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO1FBQ25DLEtBQUssTUFBTSxJQUFJLElBQUksT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2pDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsdUJBQXVCLENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMxRSxRQUFRLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3hCLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssc0JBQXNCLENBQUMsT0FBaUIsRUFBRSxLQUFvQjtRQUNwRSxJQUFJLE9BQU8sQ0FBQyxTQUFTLEtBQUssVUFBVTtZQUFFLE9BQU8sRUFBRSxDQUFDO1FBRWhELE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7UUFDbkMsS0FBSyxNQUFNLElBQUksSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDakMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzFFLFFBQVEsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDeEIsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM5QixDQUFDO0lBRUQ7O09BRUc7SUFDSyxrQkFBa0IsQ0FBQyxPQUFpQixFQUFFLEtBQW9CO1FBQ2hFLE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7UUFDbkMsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLFNBQVMsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDO1FBQ3ZFLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxXQUFXLElBQUksZ0JBQWdCLENBQUM7UUFFNUQsS0FBSyxNQUFNLFFBQVEsSUFBSSxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDNUMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQ3ZDLFFBQVEsQ0FBQyxXQUFXLEVBQ3BCLFNBQVMsRUFDVCxXQUFXLENBQ1osQ0FBQztZQUNGLFFBQVEsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDeEIsQ0FBQztRQUVELDRDQUE0QztRQUM1QyxJQUFJLFdBQVcsS0FBSyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ3JDLEtBQUssTUFBTSxRQUFRLElBQUksT0FBTyxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUM1QyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FDNUMsUUFBUSxDQUFDLFdBQVcsRUFDcEIsT0FBTyxFQUNQLGdCQUFnQixDQUNqQixDQUFDO2dCQUNGLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUM3QyxRQUFRLENBQUMsV0FBVyxFQUNwQixRQUFRLEVBQ1IsZ0JBQWdCLENBQ2pCLENBQUM7Z0JBQ0YsUUFBUSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztnQkFDM0IsUUFBUSxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUM5QixDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM5QixDQUFDO0NBQ0YifQ==