@energica-city/shared-amplify-utils
Version:
Shared utilities for AWS Amplify projects
570 lines • 91.4 kB
JavaScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { MiddlewareChain, wrapLambdaHandler, wrapGraphQLResolver, } from './middlewareChain';
// Mock the logger
vi.mock('../log', () => ({
logger: {
debug: vi.fn(),
error: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
},
}));
// Mock the error library - we'll import the real implementations for most tests
// but override specific behaviors when needed
vi.mock('../error', async () => {
const actual = await vi.importActual('../error');
return {
...actual,
throwError: vi.fn().mockImplementation((message, context) => {
const error = new Error(message);
// Add the same properties that the real throwError adds
error.__fromErrorLibrary =
true;
if (context) {
Object.assign(error, context);
}
throw error;
}),
};
});
describe('Middleware-Error Library Integration', () => {
beforeEach(() => {
vi.clearAllMocks();
});
describe('Error Library Error Detection', () => {
it('should detect errors thrown by throwError function', async () => {
const chain = new MiddlewareChain();
const middleware = vi.fn().mockImplementation(async (input, next) => {
// Use the real throwError function
const { throwError: realThrowError } = (await vi.importActual('../error'));
realThrowError('Database connection failed', {
operation: 'getUser',
userId: '123',
});
});
chain.use('database', middleware);
try {
await chain.execute({ userId: '123' }, async () => 'success');
expect.fail('Should have thrown an error');
}
catch (error) {
// Should preserve all properties from throwError
expect(error.__fromErrorLibrary).toBe(true);
expect(error.operation).toBe('getUser');
expect(error.userId).toBe('123');
expect(error.middlewareName).toBe('database');
expect(error.middlewareChain).toEqual(['database']);
}
});
it('should distinguish between error library errors and standard errors', async () => {
const chain = new MiddlewareChain();
// Test with standard Error
const standardError = new Error('Standard error');
const middleware1 = vi.fn().mockRejectedValue(standardError);
// Test with error library error
const errorLibraryMiddleware = vi.fn().mockImplementation(async () => {
const { throwError: realThrowError } = (await vi.importActual('../error'));
realThrowError('Error library error', { source: 'middleware' });
});
chain.use('standard', middleware1);
try {
await chain.execute('input', async () => 'success');
expect.fail('Should have thrown');
}
catch (error) {
expect(error.__fromErrorLibrary).toBeUndefined();
expect(error.source).toBeUndefined();
expect(error.middlewareName).toBe('standard');
}
// Clear and test error library error
chain.clear();
chain.use('errorLib', errorLibraryMiddleware);
try {
await chain.execute('input', async () => 'success');
expect.fail('Should have thrown');
}
catch (error) {
expect(error.__fromErrorLibrary).toBe(true);
expect(error.source).toBe('middleware');
expect(error.middlewareName).toBe('errorLib');
}
});
it('should preserve error context from throwError through middleware chain', async () => {
const chain = new MiddlewareChain();
const middleware1 = vi.fn().mockImplementation(async (input, next) => {
try {
return await next();
}
catch (error) {
// Add middleware-specific context while preserving original
throw Object.assign(error, { processedBy: 'middleware1' });
}
});
const middleware2 = vi.fn().mockImplementation(async () => {
const { throwError: realThrowError } = (await vi.importActual('../error'));
realThrowError('Validation failed', {
field: 'email',
value: 'invalid-email',
rule: 'email-format',
});
});
chain.use('processor', middleware1);
chain.use('validator', middleware2);
try {
await chain.execute({ email: 'invalid-email' }, async () => 'success');
expect.fail('Should have thrown');
}
catch (error) {
// Should have both original error context and middleware additions
expect(error.field).toBe('email');
expect(error.value).toBe('invalid-email');
expect(error.rule).toBe('email-format');
expect(error.processedBy).toBe('middleware1');
expect(error.middlewareName).toBe('validator');
expect(error.middlewareChain).toEqual(['processor', 'validator']);
}
});
});
describe('Error Message Extraction Integration', () => {
it('should use extractErrorMessage for consistent error logging', async () => {
const { extractErrorMessage: realExtractErrorMessage } = (await vi.importActual('../error'));
const chain = new MiddlewareChain();
const customError = {
message: 'Custom error message',
code: 'CUSTOM_ERROR',
details: 'Additional details',
};
const middleware = vi.fn().mockRejectedValue(customError);
chain.use('custom', middleware);
try {
await chain.execute('input', async () => 'success');
expect.fail('Should have thrown');
}
catch (error) {
// The extractErrorMessage should work on the caught error
const message = realExtractErrorMessage(error);
expect(message).toBe('[object Object]'); // Because it's not a standard Error
expect(error.originalError).toBe(customError);
}
});
it('should handle complex error objects with extractErrorMessage', async () => {
const { extractErrorMessage: realExtractErrorMessage } = (await vi.importActual('../error'));
const chain = new MiddlewareChain();
const complexError = {
error: 'Nested error message',
statusCode: 400,
timestamp: new Date(),
};
const middleware = vi.fn().mockRejectedValue(complexError);
chain.use('complex', middleware);
try {
await chain.execute('input', async () => 'success');
expect.fail('Should have thrown');
}
catch (error) {
const message = realExtractErrorMessage(complexError);
expect(message).toBe('Nested error message');
}
});
});
describe('Error Context Creation Integration', () => {
it('should use createErrorContext for structured error data', async () => {
const { createErrorContext: realCreateErrorContext } = (await vi.importActual('../error'));
const chain = new MiddlewareChain();
const middleware = vi.fn().mockImplementation(async (input) => {
const errorContext = realCreateErrorContext({
operation: 'processPayment',
amount: 100,
currency: 'USD',
userId: input.userId,
timestamp: undefined, // Should be filtered out
invalidField: null, // Should be kept
});
const error = new Error('Payment processing failed');
Object.assign(error, errorContext);
throw error;
});
chain.use('payment', middleware);
try {
await chain.execute({ userId: 'user123' }, async () => 'success');
expect.fail('Should have thrown');
}
catch (error) {
expect(error.operation).toBe('processPayment');
expect(error.amount).toBe(100);
expect(error.currency).toBe('USD');
expect(error.userId).toBe('user123');
expect(error.invalidField).toBe(null);
expect('timestamp' in error).toBe(false); // undefined values filtered out
expect(error.middlewareName).toBe('payment');
}
});
it('should merge error contexts from multiple sources', async () => {
const { createErrorContext: realCreateErrorContext, throwError: realThrowError, } = (await vi.importActual('../error'));
const chain = new MiddlewareChain();
const middleware1 = vi.fn().mockImplementation(async (input, next) => {
try {
return await next();
}
catch (error) {
const additionalContext = realCreateErrorContext({
middleware1Processing: true,
timestamp: Date.now(),
inputData: input,
});
throw Object.assign(error, additionalContext);
}
});
const middleware2 = vi.fn().mockImplementation(async () => {
realThrowError('Core business logic failed', realCreateErrorContext({
businessRule: 'inventory-check',
requiredQuantity: 5,
availableQuantity: 2,
shortfall: 3,
}));
});
chain.use('processor', middleware1);
chain.use('business', middleware2);
try {
await chain.execute({ productId: 'prod123' }, async () => 'success');
expect.fail('Should have thrown');
}
catch (error) {
// Should have context from both throwError and middleware
expect(error.businessRule).toBe('inventory-check');
expect(error.requiredQuantity).toBe(5);
expect(error.availableQuantity).toBe(2);
expect(error.shortfall).toBe(3);
expect(error.middleware1Processing).toBe(true);
expect(error.inputData).toEqual({ productId: 'prod123' });
expect(error.middlewareName).toBe('business');
expect(error.middlewareChain).toEqual(['processor', 'business']);
}
});
});
describe('Lambda Handler Integration', () => {
it('should preserve error library context through lambda wrapper', async () => {
const { throwError: realThrowError } = (await vi.importActual('../error'));
const chain = MiddlewareChain.createLambdaChain();
const authMiddleware = vi.fn().mockImplementation(async (input, next) => {
if (!input.event.userId) {
realThrowError('Authentication required', {
operation: 'checkAuth',
provided: Object.keys(input.event),
required: ['userId'],
});
}
return next();
});
chain.use('auth', authMiddleware);
const handler = vi.fn().mockResolvedValue({ statusCode: 200 });
const wrappedHandler = wrapLambdaHandler(chain, handler);
const event = { userId: '' }; // Empty userId should trigger error
const context = { functionName: 'testFunction' };
try {
await wrappedHandler(event, context);
expect.fail('Should have thrown');
}
catch (error) {
expect(error.__fromErrorLibrary).toBe(true);
expect(error.operation).toBe('checkAuth');
expect(error.provided).toEqual(['userId']);
expect(error.required).toEqual(['userId']);
expect(error.middlewareName).toBe('auth');
}
});
it('should handle lambda-specific error context creation', async () => {
const { createErrorContext: realCreateErrorContext } = (await vi.importActual('../error'));
const chain = MiddlewareChain.createLambdaChain();
const middleware = vi.fn().mockImplementation(async (input) => {
const lambdaContext = realCreateErrorContext({
requestId: input.context.awsRequestId,
functionName: input.context.functionName,
remainingTime: input.context.getRemainingTimeInMillis?.(),
eventType: input.event.httpMethod || 'unknown',
path: input.event.path,
stage: input.event.requestContext?.stage,
});
const error = new Error('Lambda execution failed');
Object.assign(error, lambdaContext);
throw error;
});
chain.use('lambda-context', middleware);
const handler = vi.fn();
const wrappedHandler = wrapLambdaHandler(chain, handler);
const event = {
httpMethod: 'POST',
path: '/api/users',
requestContext: { stage: 'prod' },
};
const context = {
awsRequestId: 'req-123',
functionName: 'userService',
getRemainingTimeInMillis: () => 5000,
};
try {
await wrappedHandler(event, context);
expect.fail('Should have thrown');
}
catch (error) {
expect(error.requestId).toBe('req-123');
expect(error.functionName).toBe('userService');
expect(error.remainingTime).toBe(5000);
expect(error.eventType).toBe('POST');
expect(error.path).toBe('/api/users');
expect(error.stage).toBe('prod');
expect(error.middlewareName).toBe('lambda-context');
}
});
});
describe('GraphQL Resolver Integration', () => {
it('should preserve error library context through GraphQL wrapper', async () => {
const { throwError: realThrowError } = (await vi.importActual('../error'));
const chain = MiddlewareChain.createGraphQLChain();
const validationMiddleware = vi
.fn()
.mockImplementation(async (input, next) => {
if (!input.args.id || input.args.id.length < 3) {
realThrowError('Invalid arguments provided', {
operation: 'validateArgs',
field: 'id',
provided: input.args.id,
rule: 'minLength:3',
resolver: input.info.fieldName,
parentType: input.info.parentTypeName,
});
}
return next();
});
chain.use('validation', validationMiddleware);
const resolver = vi.fn().mockResolvedValue({ id: 'valid', name: 'Test' });
const wrappedResolver = wrapGraphQLResolver(chain, resolver);
const source = {};
const args = { id: 'ab' }; // Too short
const context = { userId: 'user123' };
const info = {
fieldName: 'getUser',
parentTypeName: 'Query',
};
try {
await wrappedResolver(source, args, context, info);
expect.fail('Should have thrown');
}
catch (error) {
expect(error.__fromErrorLibrary).toBe(true);
expect(error.operation).toBe('validateArgs');
expect(error.field).toBe('id');
expect(error.provided).toBe('ab');
expect(error.rule).toBe('minLength:3');
expect(error.resolver).toBe('getUser');
expect(error.parentType).toBe('Query');
expect(error.middlewareName).toBe('validation');
}
});
it('should handle complex GraphQL error context', async () => {
const { createErrorContext: realCreateErrorContext, throwError: realThrowError, } = (await vi.importActual('../error'));
const chain = MiddlewareChain.createGraphQLChain();
const businessLogicMiddleware = vi
.fn()
.mockImplementation(async (input) => {
const graphqlContext = realCreateErrorContext({
resolver: input.info.fieldName,
parentType: input.info.parentTypeName,
arguments: input.args,
userContext: input.context.user,
requestId: input.context.requestId,
variables: input.info.variables,
operationName: input.info.operation?.name?.value,
});
realThrowError('Business logic validation failed', graphqlContext);
});
chain.use('business-logic', businessLogicMiddleware);
const resolver = vi.fn();
const wrappedResolver = wrapGraphQLResolver(chain, resolver);
const source = {};
const args = { userId: 'user123', includeProfile: true };
const context = {
user: { id: 'user123', role: 'admin' },
requestId: 'gql-req-456',
};
const info = {
fieldName: 'getUserProfile',
parentTypeName: 'Query',
variables: { includeProfile: true },
operation: { name: { value: 'GetUserProfile' } },
};
try {
await wrappedResolver(source, args, context, info);
expect.fail('Should have thrown');
}
catch (error) {
expect(error.resolver).toBe('getUserProfile');
expect(error.parentType).toBe('Query');
expect(error.arguments).toEqual({
userId: 'user123',
includeProfile: true,
});
expect(error.userContext).toEqual({ id: 'user123', role: 'admin' });
expect(error.requestId).toBe('gql-req-456');
expect(error.variables).toEqual({ includeProfile: true });
expect(error.operationName).toBe('GetUserProfile');
expect(error.middlewareName).toBe('business-logic');
}
});
});
describe('Error Chain Propagation', () => {
it('should propagate error library errors through multiple middleware layers', async () => {
const { throwError: realThrowError } = (await vi.importActual('../error'));
const chain = new MiddlewareChain();
const loggerMiddleware = vi
.fn()
.mockImplementation(async (input, next) => {
try {
return await next();
}
catch (error) {
// Add logging context but preserve original error
const logContext = {
loggedAt: new Date().toISOString(),
logLevel: 'error',
};
throw Object.assign(error, logContext);
}
});
const authMiddleware = vi.fn().mockImplementation(async (input, next) => {
try {
return await next();
}
catch (error) {
// Add auth context
const authContext = {
authState: 'failed',
attemptedUser: input.userId,
};
throw Object.assign(error, authContext);
}
});
const dataMiddleware = vi.fn().mockImplementation(async () => {
realThrowError('Database connection timeout', {
database: 'users',
timeout: 5000,
query: 'SELECT * FROM users WHERE id = ?',
retryCount: 3,
});
});
chain
.use('logger', loggerMiddleware)
.use('auth', authMiddleware)
.use('data', dataMiddleware);
try {
await chain.execute({ userId: 'user123' }, async () => 'success');
expect.fail('Should have thrown');
}
catch (error) {
// Should have all contexts combined
expect(error.__fromErrorLibrary).toBe(true);
expect(error.database).toBe('users');
expect(error.timeout).toBe(5000);
expect(error.query).toBe('SELECT * FROM users WHERE id = ?');
expect(error.retryCount).toBe(3);
expect(error.authState).toBe('failed');
expect(error.attemptedUser).toBe('user123');
expect(error.logLevel).toBe('error');
expect(typeof error.loggedAt).toBe('string');
expect(error.middlewareName).toBe('data');
expect(error.middlewareChain).toEqual(['logger', 'auth', 'data']);
}
});
it('should handle error transformation while preserving error library markers', async () => {
const { throwError: realThrowError } = (await vi.importActual('../error'));
const chain = new MiddlewareChain();
const transformerMiddleware = vi
.fn()
.mockImplementation(async (input, next) => {
try {
return await next();
}
catch (error) {
const errorObj = error;
// Transform error but preserve error library properties
if (errorObj.__fromErrorLibrary) {
const transformedError = new Error(`Transformed: ${errorObj.message}`);
// Copy all enumerable properties
Object.assign(transformedError, errorObj);
// Copy all non-enumerable properties
Object.getOwnPropertyNames(errorObj).forEach(prop => {
if (prop !== 'message') {
// Don't overwrite the new message
const descriptor = Object.getOwnPropertyDescriptor(errorObj, prop);
if (descriptor && !transformedError.hasOwnProperty(prop)) {
Object.defineProperty(transformedError, prop, descriptor);
}
}
});
// Update message while preserving other properties
transformedError.message = `Transformed: ${errorObj.message}`;
transformedError.transformedBy = 'transformerMiddleware';
throw transformedError;
}
throw error;
}
});
const sourceMiddleware = vi.fn().mockImplementation(async () => {
realThrowError('Original error', {
source: 'sourceMiddleware',
errorCode: 'ERR_001',
});
});
chain
.use('transformer', transformerMiddleware)
.use('source', sourceMiddleware);
try {
await chain.execute('input', async () => 'success');
expect.fail('Should have thrown');
}
catch (error) {
expect(error.message).toBe('Transformed: Original error');
expect(error.__fromErrorLibrary).toBe(true);
expect(error.source).toBe('sourceMiddleware');
expect(error.errorCode).toBe('ERR_001');
expect(error.transformedBy).toBe('transformerMiddleware');
expect(error.middlewareName).toBe('source');
expect(error.middlewareChain).toEqual(['transformer', 'source']);
}
});
});
describe('Performance and Memory Integration', () => {
it('should handle error context creation efficiently with large context objects', async () => {
const { createErrorContext: realCreateErrorContext } = (await vi.importActual('../error'));
const chain = new MiddlewareChain();
const middleware = vi.fn().mockImplementation(async () => {
// Create large context object with many undefined values
const largeContext = {};
for (let i = 0; i < 1000; i++) {
largeContext[`field${i}`] = i % 3 === 0 ? undefined : `value${i}`;
}
const filteredContext = realCreateErrorContext(largeContext);
const error = new Error('Large context error');
Object.assign(error, filteredContext);
throw error;
});
chain.use('large-context', middleware);
try {
await chain.execute('input', async () => 'success');
expect.fail('Should have thrown');
}
catch (error) {
// Should have filtered out undefined values
const errorKeys = Object.keys(error).filter(key => key.startsWith('field') && error[key] !== undefined);
// Should have roughly 2/3 of the fields (those that weren't undefined)
expect(errorKeys.length).toBeGreaterThan(600);
expect(errorKeys.length).toBeLessThan(700);
// Verify undefined values were filtered
for (const key of errorKeys) {
expect(error[key]).not.toBe(undefined);
}
}
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZUNoYWluLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9taWRkbGV3YXJlL21pZGRsZXdhcmVDaGFpbi50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQzlELE9BQU8sRUFDTCxlQUFlLEVBQ2YsaUJBQWlCLEVBQ2pCLG1CQUFtQixHQUVwQixNQUFNLG1CQUFtQixDQUFDO0FBSTNCLGtCQUFrQjtBQUNsQixFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZCLE1BQU0sRUFBRTtRQUNOLEtBQUssRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ2QsS0FBSyxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDZCxJQUFJLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUNiLElBQUksRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO0tBQ2Q7Q0FDRixDQUFDLENBQUMsQ0FBQztBQUVKLGdGQUFnRjtBQUNoRiw4Q0FBOEM7QUFDOUMsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFDN0IsTUFBTSxNQUFNLEdBQUcsTUFBTSxFQUFFLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ2pELE9BQU87UUFDTCxHQUFHLE1BQU07UUFDVCxVQUFVLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLGtCQUFrQixDQUFDLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxFQUFFO1lBQzFELE1BQU0sS0FBSyxHQUFHLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ2pDLHdEQUF3RDtZQUN2RCxLQUFpRCxDQUFDLGtCQUFrQjtnQkFDbkUsSUFBSSxDQUFDO1lBQ1AsSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFDWixNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztZQUNoQyxDQUFDO1lBQ0QsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDLENBQUM7S0FDSCxDQUFDO0FBQ0osQ0FBQyxDQUFDLENBQUM7QUFjSCxRQUFRLENBQUMsc0NBQXNDLEVBQUUsR0FBRyxFQUFFO0lBQ3BELFVBQVUsQ0FBQyxHQUFHLEVBQUU7UUFDZCxFQUFFLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDckIsQ0FBQyxDQUFDLENBQUM7SUFFSCxRQUFRLENBQUMsK0JBQStCLEVBQUUsR0FBRyxFQUFFO1FBQzdDLEVBQUUsQ0FBQyxvREFBb0QsRUFBRSxLQUFLLElBQUksRUFBRTtZQUNsRSxNQUFNLEtBQUssR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO1lBRXBDLE1BQU0sVUFBVSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFO2dCQUNsRSxtQ0FBbUM7Z0JBQ25DLE1BQU0sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxZQUFZLENBQzNELFVBQVUsQ0FDWCxDQUFpQixDQUFDO2dCQUNuQixjQUFjLENBQUMsNEJBQTRCLEVBQUU7b0JBQzNDLFNBQVMsRUFBRSxTQUFTO29CQUNwQixNQUFNLEVBQUUsS0FBSztpQkFDZCxDQUFDLENBQUM7WUFDTCxDQUFDLENBQUMsQ0FBQztZQUVILEtBQUssQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBRWxDLElBQUksQ0FBQztnQkFDSCxNQUFNLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDOUQsTUFBTSxDQUFDLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1lBQzdDLENBQUM7WUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO2dCQUNwQixpREFBaUQ7Z0JBQ2pELE1BQU0sQ0FBQyxLQUFLLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQzVDLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUN4QyxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDakMsTUFBTSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7Z0JBQzlDLE1BQU0sQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztZQUN0RCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMscUVBQXFFLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDbkYsTUFBTSxLQUFLLEdBQUcsSUFBSSxlQUFlLEVBQUUsQ0FBQztZQUVwQywyQkFBMkI7WUFDM0IsTUFBTSxhQUFhLEdBQUcsSUFBSSxLQUFLLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztZQUNsRCxNQUFNLFdBQVcsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsaUJBQWlCLENBQUMsYUFBYSxDQUFDLENBQUM7WUFFN0QsZ0NBQWdDO1lBQ2hDLE1BQU0sc0JBQXNCLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLGtCQUFrQixDQUFDLEtBQUssSUFBSSxFQUFFO2dCQUNuRSxNQUFNLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBRSxHQUFHLENBQUMsTUFBTSxFQUFFLENBQUMsWUFBWSxDQUMzRCxVQUFVLENBQ1gsQ0FBaUIsQ0FBQztnQkFDbkIsY0FBYyxDQUFDLHFCQUFxQixFQUFFLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUM7WUFDbEUsQ0FBQyxDQUFDLENBQUM7WUFFSCxLQUFLLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxXQUFXLENBQUMsQ0FBQztZQUVuQyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxLQUFLLElBQUksRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUNwRCxNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7WUFDcEMsQ0FBQztZQUFDLE9BQU8sS0FBVSxFQUFFLENBQUM7Z0JBQ3BCLE1BQU0sQ0FBQyxLQUFLLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxhQUFhLEVBQUUsQ0FBQztnQkFDakQsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxhQUFhLEVBQUUsQ0FBQztnQkFDckMsTUFBTSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDaEQsQ0FBQztZQUVELHFDQUFxQztZQUNyQyxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDZCxLQUFLLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxzQkFBc0IsQ0FBQyxDQUFDO1lBRTlDLElBQUksQ0FBQztnQkFDSCxNQUFNLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLEtBQUssSUFBSSxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3BELE1BQU0sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztZQUNwQyxDQUFDO1lBQUMsT0FBTyxLQUFVLEVBQUUsQ0FBQztnQkFDcEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDNUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQ3hDLE1BQU0sQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ2hELENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyx3RUFBd0UsRUFBRSxLQUFLLElBQUksRUFBRTtZQUN0RixNQUFNLEtBQUssR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO1lBRXBDLE1BQU0sV0FBVyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFO2dCQUNuRSxJQUFJLENBQUM7b0JBQ0gsT0FBTyxNQUFNLElBQUksRUFBRSxDQUFDO2dCQUN0QixDQUFDO2dCQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7b0JBQ2YsNERBQTREO29CQUM1RCxNQUFNLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBZSxFQUFFLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxDQUFDLENBQUM7Z0JBQ3ZFLENBQUM7WUFDSCxDQUFDLENBQUMsQ0FBQztZQUVILE1BQU0sV0FBVyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLElBQUksRUFBRTtnQkFDeEQsTUFBTSxFQUFFLFVBQVUsRUFBRSxjQUFjLEVBQUUsR0FBRyxDQUFDLE1BQU0sRUFBRSxDQUFDLFlBQVksQ0FDM0QsVUFBVSxDQUNYLENBQWlCLENBQUM7Z0JBQ25CLGNBQWMsQ0FBQyxtQkFBbUIsRUFBRTtvQkFDbEMsS0FBSyxFQUFFLE9BQU87b0JBQ2QsS0FBSyxFQUFFLGVBQWU7b0JBQ3RCLElBQUksRUFBRSxjQUFjO2lCQUNyQixDQUFDLENBQUM7WUFDTCxDQUFDLENBQUMsQ0FBQztZQUVILEtBQUssQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1lBQ3BDLEtBQUssQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1lBRXBDLElBQUksQ0FBQztnQkFDSCxNQUFNLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLEVBQUUsZUFBZSxFQUFFLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDdkUsTUFBTSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1lBQ3BDLENBQUM7WUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO2dCQUNwQixtRUFBbUU7Z0JBQ25FLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUNsQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztnQkFDMUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7Z0JBQ3hDLE1BQU0sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUM5QyxNQUFNLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDL0MsTUFBTSxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQztZQUNwRSxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILFFBQVEsQ0FBQyxzQ0FBc0MsRUFBRSxHQUFHLEVBQUU7UUFDcEQsRUFBRSxDQUFDLDZEQUE2RCxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQzNFLE1BQU0sRUFBRSxtQkFBbUIsRUFBRSx1QkFBdUIsRUFBRSxHQUNwRCxDQUFDLE1BQU0sRUFBRSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsQ0FBaUIsQ0FBQztZQUN0RCxNQUFNLEtBQUssR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO1lBRXBDLE1BQU0sV0FBVyxHQUFHO2dCQUNsQixPQUFPLEVBQUUsc0JBQXNCO2dCQUMvQixJQUFJLEVBQUUsY0FBYztnQkFDcEIsT0FBTyxFQUFFLG9CQUFvQjthQUM5QixDQUFDO1lBRUYsTUFBTSxVQUFVLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQzFELEtBQUssQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBRWhDLElBQUksQ0FBQztnQkFDSCxNQUFNLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLEtBQUssSUFBSSxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3BELE1BQU0sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztZQUNwQyxDQUFDO1lBQUMsT0FBTyxLQUFVLEVBQUUsQ0FBQztnQkFDcEIsMERBQTBEO2dCQUMxRCxNQUFNLE9BQU8sR0FBRyx1QkFBdUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDL0MsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsb0NBQW9DO2dCQUM3RSxNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUNoRCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsOERBQThELEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDNUUsTUFBTSxFQUFFLG1CQUFtQixFQUFFLHVCQUF1QixFQUFFLEdBQ3BELENBQUMsTUFBTSxFQUFFLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFpQixDQUFDO1lBQ3RELE1BQU0sS0FBSyxHQUFHLElBQUksZUFBZSxFQUFFLENBQUM7WUFFcEMsTUFBTSxZQUFZLEdBQUc7Z0JBQ25CLEtBQUssRUFBRSxzQkFBc0I7Z0JBQzdCLFVBQVUsRUFBRSxHQUFHO2dCQUNmLFNBQVMsRUFBRSxJQUFJLElBQUksRUFBRTthQUN0QixDQUFDO1lBRUYsTUFBTSxVQUFVLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLGlCQUFpQixDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQzNELEtBQUssQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBRWpDLElBQUksQ0FBQztnQkFDSCxNQUFNLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLEtBQUssSUFBSSxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3BELE1BQU0sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztZQUNwQyxDQUFDO1lBQUMsT0FBTyxLQUFVLEVBQUUsQ0FBQztnQkFDcEIsTUFBTSxPQUFPLEdBQUcsdUJBQXVCLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQ3RELE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsQ0FBQztZQUMvQyxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILFFBQVEsQ0FBQyxvQ0FBb0MsRUFBRSxHQUFHLEVBQUU7UUFDbEQsRUFBRSxDQUFDLHlEQUF5RCxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ3ZFLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxzQkFBc0IsRUFBRSxHQUNsRCxDQUFDLE1BQU0sRUFBRSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsQ0FBaUIsQ0FBQztZQUN0RCxNQUFNLEtBQUssR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO1lBRXBDLE1BQU0sVUFBVSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLEVBQUMsS0FBSyxFQUFDLEVBQUU7Z0JBQzFELE1BQU0sWUFBWSxHQUFHLHNCQUFzQixDQUFDO29CQUMxQyxTQUFTLEVBQUUsZ0JBQWdCO29CQUMzQixNQUFNLEVBQUUsR0FBRztvQkFDWCxRQUFRLEVBQUUsS0FBSztvQkFDZixNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07b0JBQ3BCLFNBQVMsRUFBRSxTQUFTLEVBQUUseUJBQXlCO29CQUMvQyxZQUFZLEVBQUUsSUFBSSxFQUFFLGlCQUFpQjtpQkFDdEMsQ0FBQyxDQUFDO2dCQUVILE1BQU0sS0FBSyxHQUFHLElBQUksS0FBSyxDQUFDLDJCQUEyQixDQUFDLENBQUM7Z0JBQ3JELE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLFlBQVksQ0FBQyxDQUFDO2dCQUNuQyxNQUFNLEtBQUssQ0FBQztZQUNkLENBQUMsQ0FBQyxDQUFDO1lBRUgsS0FBSyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFFakMsSUFBSSxDQUFDO2dCQUNILE1BQU0sS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsRUFBRSxLQUFLLElBQUksRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUNsRSxNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7WUFDcEMsQ0FBQztZQUFDLE9BQU8sS0FBVSxFQUFFLENBQUM7Z0JBQ3BCLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7Z0JBQy9DLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUMvQixNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDbkMsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3JDLE1BQU0sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN0QyxNQUFNLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLGdDQUFnQztnQkFDMUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDL0MsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLG1EQUFtRCxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ2pFLE1BQU0sRUFDSixrQkFBa0IsRUFBRSxzQkFBc0IsRUFDMUMsVUFBVSxFQUFFLGNBQWMsR0FDM0IsR0FBRyxDQUFDLE1BQU0sRUFBRSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsQ0FBaUIsQ0FBQztZQUV4RCxNQUFNLEtBQUssR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO1lBRXBDLE1BQU0sV0FBVyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFO2dCQUNuRSxJQUFJLENBQUM7b0JBQ0gsT0FBTyxNQUFNLElBQUksRUFBRSxDQUFDO2dCQUN0QixDQUFDO2dCQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7b0JBQ2YsTUFBTSxpQkFBaUIsR0FBRyxzQkFBc0IsQ0FBQzt3QkFDL0MscUJBQXFCLEVBQUUsSUFBSTt3QkFDM0IsU0FBUyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7d0JBQ3JCLFNBQVMsRUFBRSxLQUFLO3FCQUNqQixDQUFDLENBQUM7b0JBRUgsTUFBTSxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQWUsRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO2dCQUMxRCxDQUFDO1lBQ0gsQ0FBQyxDQUFDLENBQUM7WUFFSCxNQUFNLFdBQVcsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsa0JBQWtCLENBQUMsS0FBSyxJQUFJLEVBQUU7Z0JBQ3hELGNBQWMsQ0FDWiw0QkFBNEIsRUFDNUIsc0JBQXNCLENBQUM7b0JBQ3JCLFlBQVksRUFBRSxpQkFBaUI7b0JBQy9CLGdCQUFnQixFQUFFLENBQUM7b0JBQ25CLGlCQUFpQixFQUFFLENBQUM7b0JBQ3BCLFNBQVMsRUFBRSxDQUFDO2lCQUNiLENBQUMsQ0FDSCxDQUFDO1lBQ0osQ0FBQyxDQUFDLENBQUM7WUFFSCxLQUFLLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxXQUFXLENBQUMsQ0FBQztZQUNwQyxLQUFLLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxXQUFXLENBQUMsQ0FBQztZQUVuQyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxFQUFFLEtBQUssSUFBSSxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3JFLE1BQU0sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztZQUNwQyxDQUFDO1lBQUMsT0FBTyxLQUFVLEVBQUUsQ0FBQztnQkFDcEIsMERBQTBEO2dCQUMxRCxNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO2dCQUNuRCxNQUFNLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUN2QyxNQUFNLENBQUMsS0FBSyxDQUFDLGlCQUFpQixDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUN4QyxNQUFNLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDaEMsTUFBTSxDQUFDLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDL0MsTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztnQkFDMUQsTUFBTSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7Z0JBQzlDLE1BQU0sQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsV0FBVyxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUM7WUFDbkUsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFSCxRQUFRLENBQUMsNEJBQTRCLEVBQUUsR0FBRyxFQUFFO1FBQzFDLEVBQUUsQ0FBQyw4REFBOEQsRUFBRSxLQUFLLElBQUksRUFBRTtZQUM1RSxNQUFNLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBRSxHQUFHLENBQUMsTUFBTSxFQUFFLENBQUMsWUFBWSxDQUMzRCxVQUFVLENBQ1gsQ0FBaUIsQ0FBQztZQUVuQixNQUFNLEtBQUssR0FBRyxlQUFlLENBQUMsaUJBQWlCLEVBSTVDLENBQUM7WUFFSixNQUFNLGNBQWMsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsa0JBQWtCLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRTtnQkFDdEUsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7b0JBQ3hCLGNBQWMsQ0FBQyx5QkFBeUIsRUFBRTt3QkFDeEMsU0FBUyxFQUFFLFdBQVc7d0JBQ3RCLFFBQVEsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUM7d0JBQ2xDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQztxQkFDckIsQ0FBQyxDQUFDO2dCQUNMLENBQUM7Z0JBQ0QsT0FBTyxJQUFJLEVBQUUsQ0FBQztZQUNoQixDQUFDLENBQUMsQ0FBQztZQUVILEtBQUssQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBRWxDLE1BQU0sT0FBTyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLFVBQVUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO1lBQy9ELE1BQU0sY0FBYyxHQUFHLGlCQUFpQixDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztZQUV6RCxNQUFNLEtBQUssR0FBRyxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLG9DQUFvQztZQUNsRSxNQUFNLE9BQU8sR0FBRyxFQUFFLFlBQVksRUFBRSxjQUFjLEVBQUUsQ0FBQztZQUVqRCxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxjQUFjLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO2dCQUNyQyxNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7WUFDcEMsQ0FBQztZQUFDLE9BQU8sS0FBVSxFQUFFLENBQUM7Z0JBQ3BCLE1BQU0sQ0FBQyxLQUFLLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQzVDLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO2dCQUMxQyxNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7Z0JBQzNDLE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztnQkFDM0MsTUFBTSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDNUMsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLHNEQUFzRCxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ3BFLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxzQkFBc0IsRUFBRSxHQUNsRCxDQUFDLE1BQU0sRUFBRSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsQ0FBaUIsQ0FBQztZQUV0RCxNQUFNLEtBQUssR0FBRyxlQUFlLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUVsRCxNQUFNLFVBQVUsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsa0JBQWtCLENBQUMsS0FBSyxFQUFDLEtBQUssRUFBQyxFQUFFO2dCQUMxRCxNQUFNLGFBQWEsR0FBRyxzQkFBc0IsQ0FBQztvQkFDM0MsU0FBUyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsWUFBWTtvQkFDckMsWUFBWSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsWUFBWTtvQkFDeEMsYUFBYSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsd0JBQXdCLEVBQUUsRUFBRTtvQkFDekQsU0FBUyxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsVUFBVSxJQUFJLFNBQVM7b0JBQzlDLElBQUksRUFBRSxLQUFLLENBQUMsS0FBSyxDQUFDLElBQUk7b0JBQ3RCLEtBQUssRUFBRSxLQUFLLENBQUMsS0FBSyxDQUFDLGNBQWMsRUFBRSxLQUFLO2lCQUN6QyxDQUFDLENBQUM7Z0JBRUgsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztnQkFDbkQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsYUFBYSxDQUFDLENBQUM7Z0JBQ3BDLE1BQU0sS0FBSyxDQUFDO1lBQ2QsQ0FBQyxDQUFDLENBQUM7WUFFSCxLQUFLLENBQUMsR0FBRyxDQUFDLGdCQUFnQixFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBRXhDLE1BQU0sT0FBTyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUN4QixNQUFNLGNBQWMsR0FBRyxpQkFBaUIsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFFekQsTUFBTSxLQUFLLEdBQUc7Z0JBQ1osVUFBVSxFQUFFLE1BQU07Z0JBQ2xCLElBQUksRUFBRSxZQUFZO2dCQUNsQixjQUFjLEVBQUUsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFO2FBQ2xDLENBQUM7WUFDRixNQUFNLE9BQU8sR0FBRztnQkFDZCxZQUFZLEVBQUUsU0FBUztnQkFDdkIsWUFBWSxFQUFFLGFBQWE7Z0JBQzNCLHdCQUF3QixFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUk7YUFDckMsQ0FBQztZQUVGLElBQUksQ0FBQztnQkFDSCxNQUFNLGNBQWMsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7Z0JBQ3JDLE1BQU0sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztZQUNwQyxDQUFDO1lBQUMsT0FBTyxLQUFVLEVBQUUsQ0FBQztnQkFDcEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3hDLE1BQU0sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUMvQyxNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDdkMsTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ3JDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO2dCQUN0QyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDakMsTUFBTSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztZQUN0RCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILFFBQVEsQ0FBQyw4QkFBOEIsRUFBRSxHQUFHLEVBQUU7UUFDNUMsRUFBRSxDQUFDLCtEQUErRCxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQzdFLE1BQU0sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxZQUFZLENBQzNELFVBQVUsQ0FDWCxDQUFpQixDQUFDO1lBRW5CLE1BQU0sS0FBSyxHQUFHLGVBQWUsQ0FBQyxrQkFBa0IsRUFJN0MsQ0FBQztZQUVKLE1BQU0sb0JBQW9CLEdBQUcsRUFBRTtpQkFDNUIsRUFBRSxFQUFFO2lCQUNKLGtCQUFrQixDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUU7Z0JBQ3hDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQy9DLGNBQWMsQ0FBQyw0QkFBNEIsRUFBRTt3QkFDM0MsU0FBUyxFQUFFLGNBQWM7d0JBQ3pCLEtBQUssRUFBRSxJQUFJO3dCQUNYLFFBQVEsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUU7d0JBQ3ZCLElBQUksRUFBRSxhQUFhO3dCQUNuQixRQUFRLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTO3dCQUM5QixVQUFVLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxjQUFjO3FCQUN0QyxDQUFDLENBQUM7Z0JBQ0wsQ0FBQztnQkFDRCxPQUFPLElBQUksRUFBRSxDQUFDO1lBQ2hCLENBQUMsQ0FBQyxDQUFDO1lBRUwsS0FBSyxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztZQUU5QyxNQUFNLFFBQVEsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsaUJBQWlCLENBQUMsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBQzFFLE1BQU0sZUFBZSxHQUFHLG1CQUFtQixDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQztZQUU3RCxNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUM7WUFDbEIsTUFBTSxJQUFJLEdBQUcsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxZQUFZO1lBQ3ZDLE1BQU0sT0FBTyxHQUFHLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxDQUFDO1lBQ3RDLE1BQU0sSUFBSSxHQUFHO2dCQUNYLFNBQVMsRUFBRSxTQUFTO2dCQUNwQixjQUFjLEVBQUUsT0FBTzthQUN4QixDQUFDO1lBRUYsSUFBSSxDQUFDO2dCQUNILE1BQU0sZUFBZSxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO2dCQUNuRCxNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7WUFDcEMsQ0FBQztZQUFDLE9BQU8sS0FBVSxFQUFFLENBQUM7Z0JBQ3BCLE1BQU0sQ0FBQyxLQUFLLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQzVDLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO2dCQUM3QyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDL0IsTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2xDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUN2QyxNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDdkMsTUFBTSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3ZDLE1BQU0sQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ2xELENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyw2Q0FBNkMsRUFBRSxLQUFLLElBQUksRUFBRTtZQUMzRCxNQUFNLEVBQ0osa0JBQWtCLEVBQUUsc0JBQXNCLEVBQzFDLFVBQVUsRUFBRSxjQUFjLEdBQzNCLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLENBQWlCLENBQUM7WUFFeEQsTUFBTSxLQUFLLEdBQUcsZUFBZSxDQUFDLGtCQUFrQixFQUFFLENBQUM7WUFFbkQsTUFBTSx1QkFBdUIsR0FBRyxFQUFFO2lCQUMvQixFQUFFLEVBQUU7aUJBQ0osa0JBQWtCLENBQUMsS0FBSyxFQUFDLEtBQUssRUFBQyxFQUFFO2dCQUNoQyxNQUFNLGNBQWMsR0FBRyxzQkFBc0IsQ0FBQztvQkFDNUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUztvQkFDOUIsVUFBVSxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsY0FBYztvQkFDckMsU0FBUyxFQUFFLEtBQUssQ0FBQyxJQUFJO29CQUNyQixXQUFXLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJO29CQUMvQixTQUFTLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTO29CQUNsQyxTQUFTLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTO29CQUMvQixhQUFhLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLEtBQUs7aUJBQ2pELENBQUMsQ0FBQztnQkFFSCxjQUFjLENBQUMsa0NBQWtDLEVBQUUsY0FBYyxDQUFDLENBQUM7WUFDckUsQ0FBQyxDQUFDLENBQUM7WUFFTCxLQUFLLENBQUMsR0FBRyxDQUFDLGdCQUFnQixFQUFFLHVCQUF1QixDQUFDLENBQUM7WUFFckQsTUFBTSxRQUFRLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ3pCLE1BQU0sZUFBZSxHQUFHLG1CQUFtQixDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQztZQUU3RCxNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUM7WUFDbEIsTUFBTSxJQUFJLEdBQUcsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLGNBQWMsRUFBRSxJQUFJLEVBQUUsQ0FBQztZQUN6RCxNQUFNLE9BQU8sR0FBRztnQkFDZCxJQUFJLEVBQUUsRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUU7Z0JBQ3RDLFNBQVMsRUFBRSxhQUFhO2FBQ3pCLENBQUM7WUFDRixNQUFNLElBQUksR0FBRztnQkFDWCxTQUFTLEVBQUUsZ0JBQWdCO2dCQUMzQixjQUFjLEVBQUUsT0FBTztnQkFDdkIsU0FBUyxFQUFFLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRTtnQkFDbkMsU0FBUyxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLGdCQUFnQixFQUFFLEVBQUU7YUFDakQsQ0FBQztZQUVGLElBQUksQ0FBQztnQkFDSCxNQUFNLGVBQWUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztnQkFDbkQsTUFBTSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1lBQ3BDLENBQUM7WUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO2dCQUNwQixNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO2dCQUM5QyxNQUFNLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDdkMsTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLENBQUM7b0JBQzlCLE1BQU0sRUFBRSxTQUFTO29CQUNqQixjQUFjLEVBQUUsSUFBSTtpQkFDckIsQ0FBQyxDQUFDO2dCQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztnQkFDcEUsTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7Z0JBQzVDLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7Z0JBQzFELE1BQU0sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7Z0JBQ25ELE1BQU0sQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7WUFDdEQsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFSCxRQUFRLENBQUMseUJBQXlCLEVBQUUsR0FBRyxFQUFFO1FBQ3ZDLEVBQUUsQ0FBQywwRUFBMEUsRUFBRSxLQUFLLElBQUksRUFBRTtZQUN4RixNQUFNLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBRSxHQUFHLENBQ