UNPKG

@fin.cx/opendata

Version:

A comprehensive TypeScript library for accessing business data and real-time financial information. Features include German company data management with MongoDB integration, JSONL bulk processing, automated Handelsregister interactions, and real-time stoc

495 lines 40.9 kB
import * as plugins from '../plugins.js'; /** * Unified service for managing both stock prices and fundamentals * Provides automatic enrichment and convenient combined data access */ export class StockDataService { priceProviders = new Map(); fundamentalsProviders = new Map(); priceCache = new Map(); fundamentalsCache = new Map(); logger = console; config = { cache: { priceTTL: 24 * 60 * 60 * 1000, // 24 hours fundamentalsTTL: 90 * 24 * 60 * 60 * 1000, // 90 days maxEntries: 10000 }, timeout: { price: 10000, // 10 seconds fundamentals: 30000 // 30 seconds } }; constructor(config) { if (config) { this.config = { cache: { ...this.config.cache, ...config.cache }, timeout: { ...this.config.timeout, ...config.timeout } }; } } // ========== Provider Management ========== /** * Register a price provider */ registerPriceProvider(provider, config) { const defaultConfig = { enabled: true, priority: provider.priority, timeout: this.config.timeout.price, retryAttempts: 2, retryDelay: 1000 }; const mergedConfig = { ...defaultConfig, ...config }; this.priceProviders.set(provider.name, { provider, config: mergedConfig, successCount: 0, errorCount: 0 }); console.log(`Registered price provider: ${provider.name}`); } /** * Register a fundamentals provider */ registerFundamentalsProvider(provider, config) { const defaultConfig = { enabled: true, priority: provider.priority, timeout: this.config.timeout.fundamentals, retryAttempts: 2, retryDelay: 1000, cacheTTL: this.config.cache.fundamentalsTTL }; const mergedConfig = { ...defaultConfig, ...config }; this.fundamentalsProviders.set(provider.name, { provider, config: mergedConfig, successCount: 0, errorCount: 0 }); console.log(`Registered fundamentals provider: ${provider.name}`); } /** * Unregister a price provider */ unregisterPriceProvider(providerName) { this.priceProviders.delete(providerName); console.log(`Unregistered price provider: ${providerName}`); } /** * Unregister a fundamentals provider */ unregisterFundamentalsProvider(providerName) { this.fundamentalsProviders.delete(providerName); console.log(`Unregistered fundamentals provider: ${providerName}`); } /** * Get all registered price providers */ getPriceProviders() { return Array.from(this.priceProviders.values()).map(entry => entry.provider); } /** * Get all registered fundamentals providers */ getFundamentalsProviders() { return Array.from(this.fundamentalsProviders.values()).map(entry => entry.provider); } /** * Get enabled price providers sorted by priority */ getEnabledPriceProviders() { return Array.from(this.priceProviders.values()) .filter(entry => entry.config.enabled) .sort((a, b) => (b.config.priority || 0) - (a.config.priority || 0)) .map(entry => entry.provider); } /** * Get enabled fundamentals providers sorted by priority */ getEnabledFundamentalsProviders() { return Array.from(this.fundamentalsProviders.values()) .filter(entry => entry.config.enabled) .sort((a, b) => (b.config.priority || 0) - (a.config.priority || 0)) .map(entry => entry.provider); } // ========== Data Fetching Methods ========== /** * Get current price for a single ticker */ async getPrice(ticker) { const cacheKey = `price:${ticker}`; const cached = this.getFromCache(this.priceCache, cacheKey); if (cached) { console.log(`Cache hit for price: ${ticker}`); return cached; } const providers = this.getEnabledPriceProviders(); if (providers.length === 0) { throw new Error('No price providers available'); } let lastError; for (const provider of providers) { const entry = this.priceProviders.get(provider.name); try { const result = await this.fetchWithRetry(() => provider.fetchData({ type: 'current', ticker }), entry.config); entry.successCount++; const price = result; this.addToCache(this.priceCache, cacheKey, price, this.config.cache.priceTTL); console.log(`Successfully fetched price for ${ticker} from ${provider.name}`); return price; } catch (error) { entry.errorCount++; entry.lastError = error; entry.lastErrorTime = new Date(); lastError = error; console.warn(`Provider ${provider.name} failed for ${ticker}: ${plugins.getErrorMessage(error)}`); } } throw new Error(`Failed to fetch price for ${ticker} from all providers. Last error: ${lastError?.message}`); } /** * Get current prices for multiple tickers */ async getPrices(tickers) { const cacheKey = `prices:${tickers.sort().join(',')}`; const cached = this.getFromCache(this.priceCache, cacheKey); if (cached) { console.log(`Cache hit for prices: ${tickers.length} tickers`); return cached; } const providers = this.getEnabledPriceProviders(); if (providers.length === 0) { throw new Error('No price providers available'); } let lastError; for (const provider of providers) { const entry = this.priceProviders.get(provider.name); try { const result = await this.fetchWithRetry(() => provider.fetchData({ type: 'batch', tickers }), entry.config); entry.successCount++; const prices = result; this.addToCache(this.priceCache, cacheKey, prices, this.config.cache.priceTTL); console.log(`Successfully fetched ${prices.length} prices from ${provider.name}`); return prices; } catch (error) { entry.errorCount++; entry.lastError = error; entry.lastErrorTime = new Date(); lastError = error; console.warn(`Provider ${provider.name} failed for batch prices: ${plugins.getErrorMessage(error)}`); } } throw new Error(`Failed to fetch prices for ${tickers.length} tickers from all providers. Last error: ${lastError?.message}`); } /** * Get fundamentals for a single ticker */ async getFundamentals(ticker) { const cacheKey = `fundamentals:${ticker}`; const cached = this.getFromCache(this.fundamentalsCache, cacheKey); if (cached) { console.log(`Cache hit for fundamentals: ${ticker}`); return cached; } const providers = this.getEnabledFundamentalsProviders(); if (providers.length === 0) { throw new Error('No fundamentals providers available'); } let lastError; for (const provider of providers) { const entry = this.fundamentalsProviders.get(provider.name); try { const result = await this.fetchWithRetry(() => provider.fetchData({ type: 'fundamentals-current', ticker }), entry.config); entry.successCount++; const fundamentals = result; const ttl = entry.config.cacheTTL || this.config.cache.fundamentalsTTL; this.addToCache(this.fundamentalsCache, cacheKey, fundamentals, ttl); console.log(`Successfully fetched fundamentals for ${ticker} from ${provider.name}`); return fundamentals; } catch (error) { entry.errorCount++; entry.lastError = error; entry.lastErrorTime = new Date(); lastError = error; console.warn(`Provider ${provider.name} failed for ${ticker} fundamentals: ${plugins.getErrorMessage(error)}`); } } throw new Error(`Failed to fetch fundamentals for ${ticker} from all providers. Last error: ${lastError?.message}`); } /** * Get fundamentals for multiple tickers */ async getBatchFundamentals(tickers) { const cacheKey = `fundamentals-batch:${tickers.sort().join(',')}`; const cached = this.getFromCache(this.fundamentalsCache, cacheKey); if (cached) { console.log(`Cache hit for batch fundamentals: ${tickers.length} tickers`); return cached; } const providers = this.getEnabledFundamentalsProviders(); if (providers.length === 0) { throw new Error('No fundamentals providers available'); } let lastError; for (const provider of providers) { const entry = this.fundamentalsProviders.get(provider.name); try { const result = await this.fetchWithRetry(() => provider.fetchData({ type: 'fundamentals-batch', tickers }), entry.config); entry.successCount++; const fundamentals = result; const ttl = entry.config.cacheTTL || this.config.cache.fundamentalsTTL; this.addToCache(this.fundamentalsCache, cacheKey, fundamentals, ttl); console.log(`Successfully fetched ${fundamentals.length} fundamentals from ${provider.name}`); return fundamentals; } catch (error) { entry.errorCount++; entry.lastError = error; entry.lastErrorTime = new Date(); lastError = error; console.warn(`Provider ${provider.name} failed for batch fundamentals: ${plugins.getErrorMessage(error)}`); } } throw new Error(`Failed to fetch fundamentals for ${tickers.length} tickers from all providers. Last error: ${lastError?.message}`); } /** * ✨ Get complete stock data (price + fundamentals) with automatic enrichment */ async getStockData(request) { const normalizedRequest = typeof request === 'string' ? { ticker: request, includeFundamentals: true, enrichFundamentals: true } : { includeFundamentals: true, enrichFundamentals: true, ...request }; const price = await this.getPrice(normalizedRequest.ticker); let fundamentals; if (normalizedRequest.includeFundamentals) { try { fundamentals = await this.getFundamentals(normalizedRequest.ticker); // Enrich fundamentals with price calculations if (normalizedRequest.enrichFundamentals && fundamentals) { fundamentals = this.enrichWithPrice(fundamentals, price.price); } } catch (error) { console.warn(`Failed to fetch fundamentals for ${normalizedRequest.ticker}: ${plugins.getErrorMessage(error)}`); // Continue without fundamentals } } return { ticker: normalizedRequest.ticker, price, fundamentals, fetchedAt: new Date() }; } /** * ✨ Get complete stock data for multiple tickers with automatic enrichment */ async getBatchStockData(request) { const normalizedRequest = Array.isArray(request) ? { tickers: request, includeFundamentals: true, enrichFundamentals: true } : { includeFundamentals: true, enrichFundamentals: true, ...request }; const prices = await this.getPrices(normalizedRequest.tickers); const priceMap = new Map(prices.map(p => [p.ticker, p])); let fundamentalsMap = new Map(); if (normalizedRequest.includeFundamentals) { try { const fundamentals = await this.getBatchFundamentals(normalizedRequest.tickers); // Enrich with prices if requested if (normalizedRequest.enrichFundamentals) { for (const fund of fundamentals) { const price = priceMap.get(fund.ticker); if (price) { fundamentalsMap.set(fund.ticker, this.enrichWithPrice(fund, price.price)); } else { fundamentalsMap.set(fund.ticker, fund); } } } else { fundamentalsMap = new Map(fundamentals.map(f => [f.ticker, f])); } } catch (error) { console.warn(`Failed to fetch batch fundamentals: ${plugins.getErrorMessage(error)}`); // Continue without fundamentals } } return normalizedRequest.tickers.map(ticker => ({ ticker, price: priceMap.get(ticker), fundamentals: fundamentalsMap.get(ticker), fetchedAt: new Date() })); } // ========== Helper Methods ========== /** * Enrich fundamentals with calculated metrics using current price */ enrichWithPrice(fundamentals, price) { const enriched = { ...fundamentals }; // Calculate market cap: price × shares outstanding if (fundamentals.sharesOutstanding) { enriched.marketCap = price * fundamentals.sharesOutstanding; } // Calculate P/E ratio: price / EPS if (fundamentals.earningsPerShareDiluted && fundamentals.earningsPerShareDiluted > 0) { enriched.priceToEarnings = price / fundamentals.earningsPerShareDiluted; } // Calculate price-to-book: market cap / stockholders equity if (enriched.marketCap && fundamentals.stockholdersEquity && fundamentals.stockholdersEquity > 0) { enriched.priceToBook = enriched.marketCap / fundamentals.stockholdersEquity; } return enriched; } /** * Fetch with retry logic */ async fetchWithRetry(fetchFn, config) { const maxAttempts = config.retryAttempts || 1; let lastError; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fetchFn(); } catch (error) { lastError = error; if (attempt < maxAttempts) { const delay = (config.retryDelay || 1000) * attempt; console.log(`Retry attempt ${attempt} after ${delay}ms`); await plugins.smartdelay.delayFor(delay); } } } throw lastError || new Error('Unknown error during fetch'); } /** * Get from cache if not expired */ getFromCache(cache, key) { const entry = cache.get(key); if (!entry) { return null; } // Check if cache entry has expired const age = Date.now() - entry.timestamp.getTime(); if (entry.ttl !== Infinity && age > entry.ttl) { cache.delete(key); return null; } return entry.data; } /** * Add to cache with TTL */ addToCache(cache, key, data, ttl) { // Enforce max entries limit if (cache.size >= this.config.cache.maxEntries) { // Remove oldest entry const oldestKey = cache.keys().next().value; if (oldestKey) { cache.delete(oldestKey); } } cache.set(key, { data, timestamp: new Date(), ttl }); } // ========== Health & Statistics ========== /** * Check health of all providers (both price and fundamentals) */ async checkProvidersHealth() { const health = new Map(); // Check price providers for (const [name, entry] of this.priceProviders) { if (!entry.config.enabled) { health.set(`${name} (price)`, false); continue; } try { const isAvailable = await entry.provider.isAvailable(); health.set(`${name} (price)`, isAvailable); } catch (error) { health.set(`${name} (price)`, false); console.error(`Health check failed for ${name}:`, error); } } // Check fundamentals providers for (const [name, entry] of this.fundamentalsProviders) { if (!entry.config.enabled) { health.set(`${name} (fundamentals)`, false); continue; } try { const isAvailable = await entry.provider.isAvailable(); health.set(`${name} (fundamentals)`, isAvailable); } catch (error) { health.set(`${name} (fundamentals)`, false); console.error(`Health check failed for ${name}:`, error); } } return health; } /** * Get statistics for all providers */ getProviderStats() { const stats = new Map(); // Price provider stats for (const [name, entry] of this.priceProviders) { stats.set(name, { type: 'price', successCount: entry.successCount, errorCount: entry.errorCount, lastError: entry.lastError?.message, lastErrorTime: entry.lastErrorTime }); } // Fundamentals provider stats for (const [name, entry] of this.fundamentalsProviders) { stats.set(name, { type: 'fundamentals', successCount: entry.successCount, errorCount: entry.errorCount, lastError: entry.lastError?.message, lastErrorTime: entry.lastErrorTime }); } return stats; } /** * Clear all caches */ clearCache() { this.priceCache.clear(); this.fundamentalsCache.clear(); console.log('All caches cleared'); } /** * Get cache statistics */ getCacheStats() { return { priceCache: { size: this.priceCache.size, ttl: this.config.cache.priceTTL }, fundamentalsCache: { size: this.fundamentalsCache.size, ttl: this.config.cache.fundamentalsTTL }, maxEntries: this.config.cache.maxEntries }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zdG9ja2RhdGFzZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvc3RvY2tzL2NsYXNzZXMuc3RvY2tkYXRhc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQXFCekM7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLGdCQUFnQjtJQUNuQixjQUFjLEdBQUcsSUFBSSxHQUFHLEVBQTBDLENBQUM7SUFDbkUscUJBQXFCLEdBQUcsSUFBSSxHQUFHLEVBQWlELENBQUM7SUFFakYsVUFBVSxHQUFHLElBQUksR0FBRyxFQUFvRCxDQUFDO0lBQ3pFLGlCQUFpQixHQUFHLElBQUksR0FBRyxFQUFrRSxDQUFDO0lBRTlGLE1BQU0sR0FBRyxPQUFPLENBQUM7SUFFakIsTUFBTSxHQVVWO1FBQ0YsS0FBSyxFQUFFO1lBQ0wsUUFBUSxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksRUFBRSxXQUFXO1lBQzFDLGVBQWUsRUFBRSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxFQUFFLFVBQVU7WUFDckQsVUFBVSxFQUFFLEtBQUs7U0FDbEI7UUFDRCxPQUFPLEVBQUU7WUFDUCxLQUFLLEVBQUUsS0FBSyxFQUFFLGFBQWE7WUFDM0IsWUFBWSxFQUFFLEtBQUssQ0FBQyxhQUFhO1NBQ2xDO0tBQ0YsQ0FBQztJQUVGLFlBQVksTUFBZ0M7UUFDMUMsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUNYLElBQUksQ0FBQyxNQUFNLEdBQUc7Z0JBQ1osS0FBSyxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxHQUFHLE1BQU0sQ0FBQyxLQUFLLEVBQUU7Z0JBQ2hELE9BQU8sRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsR0FBRyxNQUFNLENBQUMsT0FBTyxFQUFFO2FBQ3ZELENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVELDRDQUE0QztJQUU1Qzs7T0FFRztJQUNJLHFCQUFxQixDQUFDLFFBQXdCLEVBQUUsTUFBd0I7UUFDN0UsTUFBTSxhQUFhLEdBQW9CO1lBQ3JDLE9BQU8sRUFBRSxJQUFJO1lBQ2IsUUFBUSxFQUFFLFFBQVEsQ0FBQyxRQUFRO1lBQzNCLE9BQU8sRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLO1lBQ2xDLGFBQWEsRUFBRSxDQUFDO1lBQ2hCLFVBQVUsRUFBRSxJQUFJO1NBQ2pCLENBQUM7UUFFRixNQUFNLFlBQVksR0FBRyxFQUFFLEdBQUcsYUFBYSxFQUFFLEdBQUcsTUFBTSxFQUFFLENBQUM7UUFFckQsSUFBSSxDQUFDLGNBQWMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRTtZQUNyQyxRQUFRO1lBQ1IsTUFBTSxFQUFFLFlBQVk7WUFDcEIsWUFBWSxFQUFFLENBQUM7WUFDZixVQUFVLEVBQUUsQ0FBQztTQUNkLENBQUMsQ0FBQztRQUVILE9BQU8sQ0FBQyxHQUFHLENBQUMsOEJBQThCLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRDs7T0FFRztJQUNJLDRCQUE0QixDQUNqQyxRQUErQixFQUMvQixNQUFvQztRQUVwQyxNQUFNLGFBQWEsR0FBZ0M7WUFDakQsT0FBTyxFQUFFLElBQUk7WUFDYixRQUFRLEVBQUUsUUFBUSxDQUFDLFFBQVE7WUFDM0IsT0FBTyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFlBQVk7WUFDekMsYUFBYSxFQUFFLENBQUM7WUFDaEIsVUFBVSxFQUFFLElBQUk7WUFDaEIsUUFBUSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLGVBQWU7U0FDNUMsQ0FBQztRQUVGLE1BQU0sWUFBWSxHQUFHLEVBQUUsR0FBRyxhQUFhLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztRQUVyRCxJQUFJLENBQUMscUJBQXFCLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUU7WUFDNUMsUUFBUTtZQUNSLE1BQU0sRUFBRSxZQUFZO1lBQ3BCLFlBQVksRUFBRSxDQUFDO1lBQ2YsVUFBVSxFQUFFLENBQUM7U0FDZCxDQUFDLENBQUM7UUFFSCxPQUFPLENBQUMsR0FBRyxDQUFDLHFDQUFxQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBRUQ7O09BRUc7SUFDSSx1QkFBdUIsQ0FBQyxZQUFvQjtRQUNqRCxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUN6QyxPQUFPLENBQUMsR0FBRyxDQUFDLGdDQUFnQyxZQUFZLEVBQUUsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFRDs7T0FFRztJQUNJLDhCQUE4QixDQUFDLFlBQW9CO1FBQ3hELElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDaEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyx1Q0FBdUMsWUFBWSxFQUFFLENBQUMsQ0FBQztJQUNyRSxDQUFDO0lBRUQ7O09BRUc7SUFDSSxpQkFBaUI7UUFDdEIsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDL0UsQ0FBQztJQUVEOztPQUVHO0lBQ0ksd0JBQXdCO1FBQzdCLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDdEYsQ0FBQztJQUVEOztPQUVHO0lBQ0ssd0JBQXdCO1FBQzlCLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxDQUFDO2FBQzVDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDO2FBQ3JDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLFFBQVEsSUFBSSxDQUFDLENBQUMsQ0FBQzthQUNuRSxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUVEOztPQUVHO0lBQ0ssK0JBQStCO1FBQ3JDLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsTUFBTSxFQUFFLENBQUM7YUFDbkQsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUM7YUFDckMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLFFBQVEsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxJQUFJLENBQUMsQ0FBQyxDQUFDO2FBQ25FLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBRUQsOENBQThDO0lBRTlDOztPQUVHO0lBQ0ksS0FBSyxDQUFDLFFBQVEsQ0FBQyxNQUFjO1FBQ2xDLE1BQU0sUUFBUSxHQUFHLFNBQVMsTUFBTSxFQUFFLENBQUM7UUFDbkMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBRTVELElBQUksTUFBTSxFQUFFLENBQUM7WUFDWCxPQUFPLENBQUMsR0FBRyxDQUFDLHdCQUF3QixNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBQzlDLE9BQU8sTUFBcUIsQ0FBQztRQUMvQixDQUFDO1FBRUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7UUFDbEQsSUFBSSxTQUFTLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzNCLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQztRQUNsRCxDQUFDO1FBRUQsSUFBSSxTQUE0QixDQUFDO1FBRWpDLEtBQUssTUFBTSxRQUFRLElBQUksU0FBUyxFQUFFLENBQUM7WUFDakMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBRSxDQUFDO1lBRXRELElBQUksQ0FBQztnQkFDSCxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQ3RDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxDQUFDLEVBQ3JELEtBQUssQ0FBQyxNQUFNLENBQ2IsQ0FBQztnQkFFRixLQUFLLENBQUMsWUFBWSxFQUFFLENBQUM7Z0JBRXJCLE1BQU0sS0FBSyxHQUFHLE1BQXFCLENBQUM7Z0JBQ3BDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUU5RSxPQUFPLENBQUMsR0FBRyxDQUFDLGtDQUFrQyxNQUFNLFNBQVMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7Z0JBQzlFLE9BQU8sS0FBSyxDQUFDO1lBQ2YsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsS0FBSyxDQUFDLFVBQVUsRUFBRSxDQUFDO2dCQUNuQixLQUFLLENBQUMsU0FBUyxHQUFHLEtBQWMsQ0FBQztnQkFDakMsS0FBSyxDQUFDLGFBQWEsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO2dCQUNqQyxTQUFTLEdBQUcsS0FBYyxDQUFDO2dCQUUzQixPQUFPLENBQUMsSUFBSSxDQUFDLFlBQVksUUFBUSxDQUFDLElBQUksZUFBZSxNQUFNLEtBQUssT0FBTyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDcEcsQ0FBQztRQUNILENBQUM7UUFFRCxNQUFNLElBQUksS0FBSyxDQUNiLDZCQUE2QixNQUFNLG9DQUFvQyxTQUFTLEVBQUUsT0FBTyxFQUFFLENBQzVGLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsU0FBUyxDQUFDLE9BQWlCO1FBQ3RDLE1BQU0sUUFBUSxHQUFHLFVBQVUsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ3RELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUU1RCxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ1gsT0FBTyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsT0FBTyxDQUFDLE1BQU0sVUFBVSxDQUFDLENBQUM7WUFDL0QsT0FBTyxNQUF1QixDQUFDO1FBQ2pDLENBQUM7UUFFRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztRQUNsRCxJQUFJLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO1FBQ2xELENBQUM7UUFFRCxJQUFJLFNBQTRCLENBQUM7UUFFakMsS0FBSyxNQUFNLFFBQVEsSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUNqQyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFFLENBQUM7WUFFdEQsSUFBSSxDQUFDO2dCQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FDdEMsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFDcEQsS0FBSyxDQUFDLE1BQU0sQ0FDYixDQUFDO2dCQUVGLEtBQUssQ0FBQyxZQUFZLEVBQUUsQ0FBQztnQkFFckIsTUFBTSxNQUFNLEdBQUcsTUFBdUIsQ0FBQztnQkFDdkMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBRS9FLE9BQU8sQ0FBQyxHQUFHLENBQUMsd0JBQXdCLE1BQU0sQ0FBQyxNQUFNLGdCQUFnQixRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDbEYsT0FBTyxNQUFNLENBQUM7WUFDaEIsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsS0FBSyxDQUFDLFVBQVUsRUFBRSxDQUFDO2dCQUNuQixLQUFLLENBQUMsU0FBUyxHQUFHLEtBQWMsQ0FBQztnQkFDakMsS0FBSyxDQUFDLGFBQWEsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO2dCQUNqQyxTQUFTLEdBQUcsS0FBYyxDQUFDO2dCQUUzQixPQUFPLENBQUMsSUFBSSxDQUFDLFlBQVksUUFBUSxDQUFDLElBQUksNkJBQTZCLE9BQU8sQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZHLENBQUM7UUFDSCxDQUFDO1FBRUQsTUFBTSxJQUFJLEtBQUssQ0FDYiw4QkFBOEIsT0FBTyxDQUFDLE1BQU0sNENBQTRDLFNBQVMsRUFBRSxPQUFPLEVBQUUsQ0FDN0csQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxlQUFlLENBQUMsTUFBYztRQUN6QyxNQUFNLFFBQVEsR0FBRyxnQkFBZ0IsTUFBTSxFQUFFLENBQUM7UUFDMUMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFFbkUsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUNYLE9BQU8sQ0FBQyxHQUFHLENBQUMsK0JBQStCLE1BQU0sRUFBRSxDQUFDLENBQUM7WUFDckQsT0FBTyxNQUE0QixDQUFDO1FBQ3RDLENBQUM7UUFFRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsK0JBQStCLEVBQUUsQ0FBQztRQUN6RCxJQUFJLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxDQUFDO1FBQ3pELENBQUM7UUFFRCxJQUFJLFNBQTRCLENBQUM7UUFFakMsS0FBSyxNQUFNLFFBQVEsSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUNqQyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUUsQ0FBQztZQUU3RCxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUN0QyxHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEVBQUUsSUFBSSxFQUFFLHNCQUFzQixFQUFFLE1BQU0sRUFBRSxDQUFDLEVBQ2xFLEtBQUssQ0FBQyxNQUFNLENBQ2IsQ0FBQztnQkFFRixLQUFLLENBQUMsWUFBWSxFQUFFLENBQUM7Z0JBRXJCLE1BQU0sWUFBWSxHQUFHLE1BQTRCLENBQUM7Z0JBQ2xELE1BQU0sR0FBRyxHQUFJLEtBQUssQ0FBQyxNQUFzQyxDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUM7Z0JBQ3hHLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLGlCQUFpQixFQUFFLFFBQVEsRUFBRSxZQUFZLEVBQUUsR0FBRyxDQUFDLENBQUM7Z0JBRXJFLE9BQU8sQ0FBQyxHQUFHLENBQUMseUNBQXlDLE1BQU0sU0FBUyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDckYsT0FBTyxZQUFZLENBQUM7WUFDdEIsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsS0FBSyxDQUFDLFVBQVUsRUFBRSxDQUFDO2dCQUNuQixLQUFLLENBQUMsU0FBUyxHQUFHLEtBQWMsQ0FBQztnQkFDakMsS0FBSyxDQUFDLGFBQWEsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO2dCQUNqQyxTQUFTLEdBQUcsS0FBYyxDQUFDO2dCQUUzQixPQUFPLENBQUMsSUFBSSxDQUFDLFlBQVksUUFBUSxDQUFDLElBQUksZUFBZSxNQUFNLGtCQUFrQixPQUFPLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNqSCxDQUFDO1FBQ0gsQ0FBQztRQUVELE1BQU0sSUFBSSxLQUFLLENBQ2Isb0NBQW9DLE1BQU0sb0NBQW9DLFNBQVMsRUFBRSxPQUFPLEVBQUUsQ0FDbkcsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxPQUFpQjtRQUNqRCxNQUFNLFFBQVEsR0FBRyxzQkFBc0IsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ2xFLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLGlCQUFpQixFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBRW5FLElBQUksTUFBTSxFQUFFLENBQUM7WUFDWCxPQUFPLENBQUMsR0FBRyxDQUFDLHFDQUFxQyxPQUFPLENBQUMsTUFBTSxVQUFVLENBQUMsQ0FBQztZQUMzRSxPQUFPLE1BQThCLENBQUM7UUFDeEMsQ0FBQztRQUVELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQywrQkFBK0IsRUFBRSxDQUFDO1FBQ3pELElBQUksU0FBUyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLHFDQUFxQyxDQUFDLENBQUM7UUFDekQsQ0FBQztRQUVELElBQUksU0FBNEIsQ0FBQztRQUVqQyxLQUFLLE1BQU0sUUFBUSxJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBRSxDQUFDO1lBRTdELElBQUksQ0FBQztnQkFDSCxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQ3RDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsRUFBRSxJQUFJLEVBQUUsb0JBQW9CLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFDakUsS0FBSyxDQUFDLE1BQU0sQ0FDYixDQUFDO2dCQUVGLEtBQUssQ0FBQyxZQUFZLEVBQUUsQ0FBQztnQkFFckIsTUFBTSxZQUFZLEdBQUcsTUFBOEIsQ0FBQztnQkFDcEQsTUFBTSxHQUFHLEdBQUksS0FBSyxDQUFDLE1BQXNDLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQztnQkFDeEcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxHQUFHLENBQUMsQ0FBQztnQkFFckUsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsWUFBWSxDQUFDLE1BQU0sc0JBQXNCLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO2dCQUM5RixPQUFPLFlBQVksQ0FBQztZQUN0QixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixLQUFLLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQ25CLEtBQUssQ0FBQyxTQUFTLEdBQUcsS0FBYyxDQUFDO2dCQUNqQyxLQUFLLENBQUMsYUFBYSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7Z0JBQ2pDLFNBQVMsR0FBRyxLQUFjLENBQUM7Z0JBRTNCLE9BQU8sQ0FBQyxJQUFJLENBQUMsWUFBWSxRQUFRLENBQUMsSUFBSSxtQ0FBbUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDN0csQ0FBQztRQUNILENBQUM7UUFFRCxNQUFNLElBQUksS0FBSyxDQUNiLG9DQUFvQyxPQUFPLENBQUMsTUFBTSw0Q0FBNEMsU0FBUyxFQUFFLE9BQU8sRUFBRSxDQUNuSCxDQUFDO0lBQ0osQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLFlBQVksQ0FBQyxPQUEyQztRQUNuRSxNQUFNLGlCQUFpQixHQUFHLE9BQU8sT0FBTyxLQUFLLFFBQVE7WUFDbkQsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxJQUFJLEVBQUUsa0JBQWtCLEVBQUUsSUFBSSxFQUFFO1lBQzFFLENBQUMsQ0FBQyxFQUFFLG1CQUFtQixFQUFFLElBQUksRUFBRSxrQkFBa0IsRUFBRSxJQUFJLEVBQUUsR0FBRyxPQUFPLEVBQUUsQ0FBQztRQUV4RSxNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFNUQsSUFBSSxZQUE0QyxDQUFDO1FBRWpELElBQUksaUJBQWlCLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUMxQyxJQUFJLENBQUM7Z0JBQ0gsWUFBWSxHQUFHLE1BQU0sSUFBSSxDQUFDLGVBQWUsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFFcEUsOENBQThDO2dCQUM5QyxJQUFJLGlCQUFpQixDQUFDLGtCQUFrQixJQUFJLFlBQVksRUFBRSxDQUFDO29CQUN6RCxZQUFZLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxZQUFZLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUNqRSxDQUFDO1lBQ0gsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsT0FBTyxDQUFDLElBQUksQ0FBQyxvQ0FBb0MsaUJBQWlCLENBQUMsTUFBTSxLQUFLLE9BQU8sQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUNoSCxnQ0FBZ0M7WUFDbEMsQ0FBQztRQUNILENBQUM7UUFFRCxPQUFPO1lBQ0wsTUFBTSxFQUFFLGlCQUFpQixDQUFDLE1BQU07WUFDaEMsS0FBSztZQUNMLFlBQVk7WUFDWixTQUFTLEVBQUUsSUFBSSxJQUFJLEVBQUU7U0FDdEIsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxPQUFrRDtRQUMvRSxNQUFNLGlCQUFpQixHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO1lBQzlDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsSUFBSSxFQUFFLGtCQUFrQixFQUFFLElBQUksRUFBRTtZQUMzRSxDQUFDLENBQUMsRUFBRSxtQkFBbUIsRUFBRSxJQUFJLEVBQUUsa0JBQWtCLEVBQUUsSUFBSSxFQUFFLEdBQUcsT0FBTyxFQUFFLENBQUM7UUFFeEUsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQy9ELE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRXpELElBQUksZUFBZSxHQUFHLElBQUksR0FBRyxFQUE4QixDQUFDO1FBRTVELElBQUksaUJBQWlCLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUMxQyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUMsaUJBQWlCLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBRWhGLGtDQUFrQztnQkFDbEMsSUFBSSxpQkFBaUIsQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO29CQUN6QyxLQUFLLE1BQU0sSUFBSSxJQUFJLFlBQVksRUFBRSxDQUFDO3dCQUNoQyxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQzt3QkFDeEMsSUFBSSxLQUFLLEVBQUUsQ0FBQzs0QkFDVixlQUFlLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7d0JBQzVFLENBQUM7NkJBQU0sQ0FBQzs0QkFDTixlQUFlLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7d0JBQ3pDLENBQUM7b0JBQ0gsQ0FBQztnQkFDSCxDQUFDO3FCQUFNLENBQUM7b0JBQ04sZUFBZSxHQUFHLElBQUksR0FBRyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUNsRSxDQUFDO1lBQ0gsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsT0FBTyxDQUFDLElBQUksQ0FBQyx1Q0FBdUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQ3RGLGdDQUFnQztZQUNsQyxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8saUJBQWlCLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDOUMsTUFBTTtZQUNOLEtBQUssRUFBRSxRQUFRLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBRTtZQUM1QixZQUFZLEVBQUUsZUFBZSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUM7WUFDekMsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFO1NBQ3RCLENBQUMsQ0FBQyxDQUFDO0lBQ04sQ0FBQztJQUVELHVDQUF1QztJQUV2Qzs7T0FFRztJQUNLLGVBQWUsQ0FBQyxZQUFnQyxFQUFFLEtBQWE7UUFDckUsTUFBTSxRQUFRLEdBQUcsRUFBRSxHQUFHLFlBQVksRUFBRSxDQUFDO1FBRXJDLG1EQUFtRDtRQUNuRCxJQUFJLFlBQVksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQ25DLFFBQVEsQ0FBQyxTQUFTLEdBQUcsS0FBSyxHQUFHLFlBQVksQ0FBQyxpQkFBaUIsQ0FBQztRQUM5RCxDQUFDO1FBRUQsbUNBQW1DO1FBQ25DLElBQUksWUFBWSxDQUFDLHVCQUF1QixJQUFJLFlBQVksQ0FBQyx1QkFBdUIsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNyRixRQUFRLENBQUMsZUFBZSxHQUFHLEtBQUssR0FBRyxZQUFZLENBQUMsdUJBQXVCLENBQUM7UUFDMUUsQ0FBQztRQUVELDREQUE0RDtRQUM1RCxJQUFJLFFBQVEsQ0FBQyxTQUFTLElBQUksWUFBWSxDQUFDLGtCQUFrQixJQUFJLFlBQVksQ0FBQyxrQkFBa0IsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNqRyxRQUFRLENBQUMsV0FBVyxHQUFHLFFBQVEsQ0FBQyxTQUFTLEdBQUcsWUFBWSxDQUFDLGtCQUFrQixDQUFDO1FBQzlFLENBQUM7UUFFRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMsY0FBYyxDQUMxQixPQUF5QixFQUN6QixNQUFxRDtRQUVyRCxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsYUFBYSxJQUFJLENBQUMsQ0FBQztRQUM5QyxJQUFJLFNBQTRCLENBQUM7UUFFakMsS0FBSyxJQUFJLE9BQU8sR0FBRyxDQUFDLEVBQUUsT0FBTyxJQUFJLFdBQVcsRUFBRSxPQUFPLEVBQUUsRUFBRSxDQUFDO1lBQ3hELElBQUksQ0FBQztnQkFDSCxPQUFPLE1BQU0sT0FBTyxFQUFFLENBQUM7WUFDekIsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsU0FBUyxHQUFHLEtBQWMsQ0FBQztnQkFFM0IsSUFBSSxPQUFPLEdBQUcsV0FBVyxFQUFFLENBQUM7b0JBQzFCLE1BQU0sS0FBSyxHQUFHLENBQUMsTUFBTSxDQUFDLFVBQVUsSUFBSSxJQUFJLENBQUMsR0FBRyxPQUFPLENBQUM7b0JBQ3BELE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLE9BQU8sVUFBVSxLQUFLLElBQUksQ0FBQyxDQUFDO29CQUN6RCxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUMzQyxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFFRCxNQUFNLFNBQVMsSUFBSSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRDs7T0FFRztJQUNLLFlBQVksQ0FBSSxLQUFrQyxFQUFFLEdBQVc7UUFDckUsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUU3QixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDWCxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFFRCxtQ0FBbUM7UUFDbkMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDbkQsSUFBSSxLQUFLLENBQUMsR0FBRyxLQUFLLFFBQVEsSUFBSSxHQUFHLEdBQUcsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQzlDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDbEIsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBRUQsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQ3BCLENBQUM7SUFFRDs7T0FFRztJQUNLLFVBQVUsQ0FBSSxLQUFrQyxFQUFFLEdBQVcsRUFBRSxJQUFPLEVBQUUsR0FBVztRQUN6Riw0QkFBNEI7UUFDNUIsSUFBSSxLQUFLLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQy9DLHNCQUFzQjtZQUN0QixNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUMsS0FBSyxDQUFDO1lBQzVDLElBQUksU0FBUyxFQUFFLENBQUM7Z0JBQ2QsS0FBSyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUMxQixDQUFDO1FBQ0gsQ0FBQztRQUVELEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFO1lBQ2IsSUFBSTtZQUNKLFNBQVMsRUFBRSxJQUFJLElBQUksRUFBRTtZQUNyQixHQUFHO1NBQ0osQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELDRDQUE0QztJQUU1Qzs7T0FFRztJQUNJLEtBQUssQ0FBQyxvQkFBb0I7UUFDL0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQW1CLENBQUM7UUFFMUMsd0JBQXdCO1FBQ3hCLEtBQUssTUFBTSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDaEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQzFCLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQztnQkFDckMsU0FBUztZQUNYLENBQUM7WUFFRCxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxXQUFXLEdBQUcsTUFBTSxLQUFLLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxDQUFDO2dCQUN2RCxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSxVQUFVLEVBQUUsV0FBVyxDQUFDLENBQUM7WUFDN0MsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFDO2dCQUNyQyxPQUFPLENBQUMsS0FBSyxDQUFDLDJCQUEyQixJQUFJLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMzRCxDQUFDO1FBQ0gsQ0FBQztRQUVELCtCQUErQjtRQUMvQixLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7WUFDdkQsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQzFCLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLGlCQUFpQixFQUFFLEtBQUssQ0FBQyxDQUFDO2dCQUM1QyxTQUFTO1lBQ1gsQ0FBQztZQUVELElBQUksQ0FBQztnQkFDSCxNQUFNLFdBQVcsR0FBRyxNQUFNLEtBQUssQ0FBQyxRQUFRLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQ3ZELE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLGlCQUFpQixFQUFFLFdBQVcsQ0FBQyxDQUFDO1lBQ3BELENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLGlCQUFpQixFQUFFLEtBQUssQ0FBQyxDQUFDO2dCQUM1QyxPQUFPLENBQUMsS0FBSyxDQUFDLDJCQUEyQixJQUFJLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMzRCxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7SUFFRDs7T0FFRztJQUNJLGdCQUFnQjtRQVVyQixNQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRXhCLHVCQUF1QjtRQUN2QixLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ2hELEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFO2dCQUNkLElBQUksRUFBRSxPQUFPO2dCQUNiLFlBQVksRUFBRSxLQUFLLENBQUMsWUFBWTtnQkFDaEMsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO2dCQUM1QixTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVMsRUFBRSxPQUFPO2dCQUNuQyxhQUFhLEVBQUUsS0FBSyxDQUFDLGFBQWE7YUFDbkMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELDhCQUE4QjtRQUM5QixLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7WUFDdkQsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUU7Z0JBQ2QsSUFBSSxFQUFFLGNBQWM7Z0JBQ3BCLFlBQVksRUFBRSxLQUFLLENBQUMsWUFBWTtnQkFDaEMsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO2dCQUM1QixTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVMsRUFBRSxPQUFPO2dCQUNuQyxhQUFhLEVBQUUsS0FBSyxDQUFDLGFBQWE7YUFDbkMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOztPQUVHO0lBQ0ksVUFBVTtRQUNmLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEtBQUssRUFBRSxDQUFDO1FBQy9CLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxhQUFhO1FBS2xCLE9BQU87WUFDTCxVQUFVLEVBQUU7Z0JBQ1YsSUFBSSxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSTtnQkFDMUIsR0FBRyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVE7YUFDaEM7WUFDRCxpQkFBaUIsRUFBRTtnQkFDakIsSUFBSSxFQUFFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJO2dCQUNqQyxHQUFHLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsZUFBZTthQUN2QztZQUNELFVBQVUsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxVQUFVO1NBQ3pDLENBQUM7SUFDSixDQUFDO0NBQ0YifQ==