import { BlockNumber, CheckpointNumber, type EpochNumber, type SlotNumber } from '@aztec/foundation/branded-types'; import type { Fr } from '@aztec/foundation/curves/bn254'; import type { EthAddress } from '@aztec/foundation/eth-address'; import type { TypedEventEmitter } from '@aztec/foundation/types'; import { z } from 'zod'; import type { Checkpoint } from '../checkpoint/checkpoint.js'; import type { CheckpointData } from '../checkpoint/checkpoint_data.js'; import type { PublishedCheckpoint } from '../checkpoint/published_checkpoint.js'; import type { L1RollupConstants } from '../epoch-helpers/index.js'; import type { BlockHeader } from '../tx/block_header.js'; import type { IndexedTxEffect } from '../tx/indexed_tx_effect.js'; import type { TxHash } from '../tx/tx_hash.js'; import type { TxReceipt } from '../tx/tx_receipt.js'; import type { BlockData } from './block_data.js'; import type { BlockHash } from './block_hash.js'; import type { CheckpointedL2Block } from './checkpointed_l2_block.js'; import type { L2Block } from './l2_block.js'; import type { ValidateCheckpointNegativeResult, ValidateCheckpointResult } from './validate_block_result.js'; /** * Interface of classes allowing for the retrieval of L2 blocks. */ export interface L2BlockSource { /** * Method to fetch the rollup contract address at the base-layer. * @returns The rollup address. */ getRollupAddress(): Promise; /** * Method to fetch the registry contract address at the base-layer. * @returns The registry address. */ getRegistryAddress(): Promise; /** * Gets the number of the latest L2 block processed by the block source implementation. * @returns The number of the latest L2 block processed by the block source implementation. */ getBlockNumber(): Promise; /** * Gets the number of the latest L2 checkpoint processed by the block source implementation. * @returns The number of the latest L2 checkpoint processed by the block source implementation. */ getCheckpointNumber(): Promise; /** * Gets the number of the latest L2 block proven seen by the block source implementation. * @returns The number of the latest L2 block proven seen by the block source implementation. */ getProvenBlockNumber(): Promise; /** * Gets the number of the latest L2 block checkpointed seen by the block source implementation. * @returns The number of the latest L2 block checkpointed seen by the block source implementation. */ getCheckpointedL2BlockNumber(): Promise; /** * Returns the finalized L2 block number. A block is finalized when it was proven * in an L1 block that has itself been finalized on Ethereum. * @returns The finalized block number. */ getFinalizedL2BlockNumber(): Promise; /** * Gets an l2 block header. * @param number - The block number to return or 'latest' for the most recent one. * @returns The requested L2 block header. */ getBlockHeader(number: BlockNumber | 'latest'): Promise; /** * Gets a checkpointed L2 block by block number. * Returns undefined if the block doesn't exist or hasn't been checkpointed yet. * @param number - The block number to retrieve. * @returns The requested checkpointed L2 block (or undefined if not found or not checkpointed). */ getCheckpointedBlock(number: BlockNumber): Promise; getCheckpointedBlocks(from: BlockNumber, limit: number): Promise; /** * Retrieves a collection of checkpoints. * @param checkpointNumber The first checkpoint to be retrieved. * @param limit The number of checkpoints to be retrieved. * @returns The collection of complete checkpoints. */ getCheckpoints(checkpointNumber: CheckpointNumber, limit: number): Promise; /** * Gets the checkpoints for a given epoch * @param epochNumber - Epoch for which we want checkpoint data */ getCheckpointsForEpoch(epochNumber: EpochNumber): Promise; /** * Gets lightweight checkpoint metadata for a given epoch, without fetching full block data. * @param epochNumber - Epoch for which we want checkpoint data */ getCheckpointsDataForEpoch(epochNumber: EpochNumber): Promise; /** * Gets a block header by its hash. * @param blockHash - The block hash to retrieve. * @returns The requested block header (or undefined if not found). */ getBlockHeaderByHash(blockHash: BlockHash): Promise; /** * Gets a block header by its archive root. * @param archive - The archive root to retrieve. * @returns The requested block header (or undefined if not found). */ getBlockHeaderByArchive(archive: Fr): Promise; /** * Gets block metadata (without tx data) by block number. * @param number - The block number to retrieve. * @returns The requested block data (or undefined if not found). */ getBlockData(number: BlockNumber): Promise; /** * Gets block metadata (without tx data) by archive root. * @param archive - The archive root to retrieve. * @returns The requested block data (or undefined if not found). */ getBlockDataByArchive(archive: Fr): Promise; /** * Gets an L2 block by block number. * @param number - The block number to return. * @returns The requested L2 block (or undefined if not found). */ getL2Block(number: BlockNumber): Promise; /** * Gets an L2 block by its hash. * @param blockHash - The block hash to retrieve. * @returns The requested L2 block (or undefined if not found). */ getL2BlockByHash(blockHash: BlockHash): Promise; /** * Gets an L2 block by its archive root. * @param archive - The archive root to retrieve. * @returns The requested L2 block (or undefined if not found). */ getL2BlockByArchive(archive: Fr): Promise; /** * Gets a tx effect. * @param txHash - The hash of the tx corresponding to the tx effect. * @returns The requested tx effect with block info (or undefined if not found). */ getTxEffect(txHash: TxHash): Promise; /** * Gets a receipt of a settled tx. * @param txHash - The hash of a tx we try to get the receipt for. * @returns The requested tx receipt (or undefined if not found). */ getSettledTxReceipt(txHash: TxHash): Promise; /** * Returns the last L2 slot number for which we have all L1 data needed to build the next checkpoint. * Determined by the max of two signals: L1 block sync progress and latest synced checkpoint slot. * The checkpoint signal handles missed L1 blocks, since a published checkpoint seals the message tree * for the next checkpoint via the inbox LAG mechanism. */ getSyncedL2SlotNumber(): Promise; /** * Returns the last L2 epoch number that has been fully synchronized from L1. * An epoch is fully synced when all its L2 slots have been fully synced. */ getSyncedL2EpochNumber(): Promise; /** * Returns all checkpointed block headers for a given epoch. * @dev Use this method only with recent epochs, since it walks the block list backwards. * @param epochNumber - The epoch number to return headers for. */ getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise; /** * Returns whether the given epoch is completed on L1, based on the current L1 and L2 block numbers. * @param epochNumber - The epoch number to check. */ isEpochComplete(epochNumber: EpochNumber): Promise; /** * Returns the tips of the L2 chain. */ getL2Tips(): Promise; /** * Returns the rollup constants for the current chain. */ getL1Constants(): Promise; /** Returns values for the genesis block */ getGenesisValues(): Promise<{ genesisArchiveRoot: Fr; }>; /** Latest synced L1 timestamp. */ getL1Timestamp(): Promise; /** * Returns whether the latest block in the pending chain on L1 is invalid (ie its attestations are incorrect). * Note that invalid blocks do not get synced, so the latest block returned by the block source is always a valid one. */ isPendingChainInvalid(): Promise; /** * Returns the status of the pending chain validation. If the chain is invalid, reports the earliest consecutive * checkpoint that is invalid, along with the reason for being invalid, which can be used to trigger an invalidation. */ getPendingChainValidationStatus(): Promise; /** Force a sync. */ syncImmediate(): Promise; /** * Gets an l2 block. If a negative number is passed, the block returned is the most recent. * @param number - The block number to return (inclusive). * @returns The requested L2 block. */ getBlock(number: BlockNumber): Promise; /** * Returns all checkpointed blocks for a given epoch. * @dev Use this method only with recent epochs, since it walks the block list backwards. * @param epochNumber - The epoch number to return blocks for. */ getCheckpointedBlocksForEpoch(epochNumber: EpochNumber): Promise; /** * Returns all blocks for a given slot. * @dev Use this method only with recent slots, since it walks the block list backwards. * @param slotNumber - The slot number to return blocks for. */ getBlocksForSlot(slotNumber: SlotNumber): Promise; /** * Gets a checkpointed block by its block hash. * @param blockHash - The block hash to retrieve. * @returns The requested block (or undefined if not found). */ getCheckpointedBlockByHash(blockHash: BlockHash): Promise; /** * Gets a checkpointed block by its archive root. * @param archive - The archive root to retrieve. * @returns The requested block (or undefined if not found). */ getCheckpointedBlockByArchive(archive: Fr): Promise; /** * Gets up to `limit` amount of L2 blocks starting from `from`. * @param from - Number of the first block to return (inclusive). * @param limit - The maximum number of blocks to return. * @returns The requested L2 blocks. */ getBlocks(from: BlockNumber, limit: number): Promise; } /** * Interface for classes that can receive and store L2 blocks. */ export interface L2BlockSink { /** * Adds a block to the store. * @param block - The L2 block to add. * @throws If block number is not incremental (i.e., not exactly one more than the last stored block). */ addBlock(block: L2Block): Promise; } /** * L2BlockSource that emits events upon pending / proven chain changes. * see L2BlockSourceEvents for the events emitted. */ export type ArchiverEmitter = TypedEventEmitter<{ [L2BlockSourceEvents.L2PruneUnproven]: (args: L2PruneUnprovenEvent) => void; [L2BlockSourceEvents.L2PruneUncheckpointed]: (args: L2PruneUncheckpointedEvent) => void; [L2BlockSourceEvents.L2BlockProven]: (args: L2BlockProvenEvent) => void; [L2BlockSourceEvents.InvalidAttestationsCheckpointDetected]: (args: InvalidCheckpointDetectedEvent) => void; [L2BlockSourceEvents.L2BlocksCheckpointed]: (args: L2CheckpointEvent) => void; }>; export interface L2BlockSourceEventEmitter extends L2BlockSource { events: ArchiverEmitter; } /** * Identifier for L2 block tags. * - proposed: Latest block proposed on L2. * - checkpointed: Checkpointed block on L1. * - proven: Proven block on L1. * - finalized: Proven block on a finalized L1 block (not implemented, set to proven for now). */ export type L2BlockTag = 'proposed' | 'checkpointed' | 'proven' | 'finalized'; /** Tips of the L2 chain. */ export type L2Tips = { proposed: L2BlockId; checkpointed: L2TipId; proven: L2TipId; finalized: L2TipId; }; export declare const GENESIS_CHECKPOINT_HEADER_HASH: Fr; /** Identifies a block by number and hash. */ export type L2BlockId = { number: BlockNumber; hash: string; }; export type CheckpointId = { number: CheckpointNumber; hash: string; }; export type L2TipId = { block: L2BlockId; checkpoint: CheckpointId; }; /** Creates an L2 block id */ export declare function makeL2BlockId(number: BlockNumber, hash?: string): L2BlockId; /** Creates an L2 checkpoint id */ export declare function makeL2CheckpointId(number: CheckpointNumber, hash: string): CheckpointId; export declare const L2TipsSchema: z.ZodObject<{ proposed: z.ZodObject<{ number: z.ZodEffects, z.ZodNumber>, BlockNumber, string | number | bigint>; hash: z.ZodString; }, "strip", z.ZodTypeAny, { number: number & { _branding: "BlockNumber"; }; hash: string; }, { number: string | number | bigint; hash: string; }>; checkpointed: z.ZodObject<{ block: z.ZodObject<{ number: z.ZodEffects, z.ZodNumber>, BlockNumber, string | number | bigint>; hash: z.ZodString; }, "strip", z.ZodTypeAny, { number: number & { _branding: "BlockNumber"; }; hash: string; }, { number: string | number | bigint; hash: string; }>; checkpoint: z.ZodObject<{ number: z.ZodEffects, z.ZodNumber>, CheckpointNumber, string | number | bigint>; hash: z.ZodString; }, "strip", z.ZodTypeAny, { number: number & { _branding: "CheckpointNumber"; }; hash: string; }, { number: string | number | bigint; hash: string; }>; }, "strip", z.ZodTypeAny, { block: { number: number & { _branding: "BlockNumber"; }; hash: string; }; checkpoint: { number: number & { _branding: "CheckpointNumber"; }; hash: string; }; }, { block: { number: string | number | bigint; hash: string; }; checkpoint: { number: string | number | bigint; hash: string; }; }>; proven: z.ZodObject<{ block: z.ZodObject<{ number: z.ZodEffects, z.ZodNumber>, BlockNumber, string | number | bigint>; hash: z.ZodString; }, "strip", z.ZodTypeAny, { number: number & { _branding: "BlockNumber"; }; hash: string; }, { number: string | number | bigint; hash: string; }>; checkpoint: z.ZodObject<{ number: z.ZodEffects, z.ZodNumber>, CheckpointNumber, string | number | bigint>; hash: z.ZodString; }, "strip", z.ZodTypeAny, { number: number & { _branding: "CheckpointNumber"; }; hash: string; }, { number: string | number | bigint; hash: string; }>; }, "strip", z.ZodTypeAny, { block: { number: number & { _branding: "BlockNumber"; }; hash: string; }; checkpoint: { number: number & { _branding: "CheckpointNumber"; }; hash: string; }; }, { block: { number: string | number | bigint; hash: string; }; checkpoint: { number: string | number | bigint; hash: string; }; }>; finalized: z.ZodObject<{ block: z.ZodObject<{ number: z.ZodEffects, z.ZodNumber>, BlockNumber, string | number | bigint>; hash: z.ZodString; }, "strip", z.ZodTypeAny, { number: number & { _branding: "BlockNumber"; }; hash: string; }, { number: string | number | bigint; hash: string; }>; checkpoint: z.ZodObject<{ number: z.ZodEffects, z.ZodNumber>, CheckpointNumber, string | number | bigint>; hash: z.ZodString; }, "strip", z.ZodTypeAny, { number: number & { _branding: "CheckpointNumber"; }; hash: string; }, { number: string | number | bigint; hash: string; }>; }, "strip", z.ZodTypeAny, { block: { number: number & { _branding: "BlockNumber"; }; hash: string; }; checkpoint: { number: number & { _branding: "CheckpointNumber"; }; hash: string; }; }, { block: { number: string | number | bigint; hash: string; }; checkpoint: { number: string | number | bigint; hash: string; }; }>; }, "strip", z.ZodTypeAny, { proposed: { number: number & { _branding: "BlockNumber"; }; hash: string; }; checkpointed: { block: { number: number & { _branding: "BlockNumber"; }; hash: string; }; checkpoint: { number: number & { _branding: "CheckpointNumber"; }; hash: string; }; }; proven: { block: { number: number & { _branding: "BlockNumber"; }; hash: string; }; checkpoint: { number: number & { _branding: "CheckpointNumber"; }; hash: string; }; }; finalized: { block: { number: number & { _branding: "BlockNumber"; }; hash: string; }; checkpoint: { number: number & { _branding: "CheckpointNumber"; }; hash: string; }; }; }, { proposed: { number: string | number | bigint; hash: string; }; checkpointed: { block: { number: string | number | bigint; hash: string; }; checkpoint: { number: string | number | bigint; hash: string; }; }; proven: { block: { number: string | number | bigint; hash: string; }; checkpoint: { number: string | number | bigint; hash: string; }; }; finalized: { block: { number: string | number | bigint; hash: string; }; checkpoint: { number: string | number | bigint; hash: string; }; }; }>; export declare enum L2BlockSourceEvents { L2PruneUnproven = "l2PruneUnproven", L2PruneUncheckpointed = "l2PruneUncheckpointed", L2BlockProven = "l2BlockProven", L2BlocksCheckpointed = "l2BlocksCheckpointed", InvalidAttestationsCheckpointDetected = "invalidCheckpointDetected" } export type L2BlockProvenEvent = { type: 'l2BlockProven'; blockNumber: BlockNumber; slotNumber: SlotNumber; epochNumber: EpochNumber; }; export type L2PruneUnprovenEvent = { type: 'l2PruneUnproven'; epochNumber: EpochNumber; blocks: L2Block[]; }; export type L2PruneUncheckpointedEvent = { type: 'l2PruneUncheckpointed'; slotNumber: SlotNumber; blocks: L2Block[]; }; export type L2CheckpointEvent = { type: 'l2BlocksCheckpointed'; checkpoint: PublishedCheckpoint; }; export type InvalidCheckpointDetectedEvent = { type: 'invalidCheckpointDetected'; validationResult: ValidateCheckpointNegativeResult; }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibDJfYmxvY2tfc291cmNlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYmxvY2svbDJfYmxvY2tfc291cmNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxXQUFXLEVBRVgsZ0JBQWdCLEVBRWhCLEtBQUssV0FBVyxFQUNoQixLQUFLLFVBQVUsRUFDaEIsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN6RCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRWpFLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFFeEIsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDOUQsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDdkUsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUNqRixPQUFPLEtBQUssRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRW5FLE9BQU8sS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3pELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2xFLE9BQU8sS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQy9DLE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3JELE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ2pELE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ2pELE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDdEUsT0FBTyxLQUFLLEVBQUUsT0FBTyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzdDLE9BQU8sS0FBSyxFQUFFLGdDQUFnQyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFN0c7O0dBRUc7QUFDSCxNQUFNLFdBQVcsYUFBYTtJQUM1Qjs7O09BR0c7SUFDSCxnQkFBZ0IsSUFBSSxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7SUFFeEM7OztPQUdHO0lBQ0gsa0JBQWtCLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBRTFDOzs7T0FHRztJQUNILGNBQWMsSUFBSSxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUM7SUFFdkM7OztPQUdHO0lBQ0gsbUJBQW1CLElBQUksT0FBTyxDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFFakQ7OztPQUdHO0lBQ0gsb0JBQW9CLElBQUksT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBRTdDOzs7T0FHRztJQUNILDRCQUE0QixJQUFJLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUVyRDs7OztPQUlHO0lBQ0gseUJBQXlCLElBQUksT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBRWxEOzs7O09BSUc7SUFDSCxjQUFjLENBQUMsTUFBTSxFQUFFLFdBQVcsR0FBRyxRQUFRLEdBQUcsT0FBTyxDQUFDLFdBQVcsR0FBRyxTQUFTLENBQUMsQ0FBQztJQUVqRjs7Ozs7T0FLRztJQUNILG9CQUFvQixDQUFDLE1BQU0sRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBRXBGLHFCQUFxQixDQUFDLElBQUksRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsbUJBQW1CLEVBQUUsQ0FBQyxDQUFDO0lBRXhGOzs7OztPQUtHO0lBQ0gsY0FBYyxDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLEtBQUssRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixFQUFFLENBQUMsQ0FBQztJQUVsRzs7O09BR0c7SUFDSCxzQkFBc0IsQ0FBQyxXQUFXLEVBQUUsV0FBVyxHQUFHLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO0lBRXhFOzs7T0FHRztJQUNILDBCQUEwQixDQUFDLFdBQVcsRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUM7SUFFaEY7Ozs7T0FJRztJQUNILG9CQUFvQixDQUFDLFNBQVMsRUFBRSxTQUFTLEdBQUcsT0FBTyxDQUFDLFdBQVcsR0FBRyxTQUFTLENBQUMsQ0FBQztJQUU3RTs7OztPQUlHO0lBQ0gsdUJBQXVCLENBQUMsT0FBTyxFQUFFLEVBQUUsR0FBRyxPQUFPLENBQUMsV0FBVyxHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBRXZFOzs7O09BSUc7SUFDSCxZQUFZLENBQUMsTUFBTSxFQUFFLFdBQVcsR0FBRyxPQUFPLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBRWxFOzs7O09BSUc7SUFDSCxxQkFBcUIsQ0FBQyxPQUFPLEVBQUUsRUFBRSxHQUFHLE9BQU8sQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDLENBQUM7SUFFbkU7Ozs7T0FJRztJQUNILFVBQVUsQ0FBQyxNQUFNLEVBQUUsV0FBVyxHQUFHLE9BQU8sQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDLENBQUM7SUFFOUQ7Ozs7T0FJRztJQUNILGdCQUFnQixDQUFDLFNBQVMsRUFBRSxTQUFTLEdBQUcsT0FBTyxDQUFDLE9BQU8sR0FBRyxTQUFTLENBQUMsQ0FBQztJQUVyRTs7OztPQUlHO0lBQ0gsbUJBQW1CLENBQUMsT0FBTyxFQUFFLEVBQUUsR0FBRyxPQUFPLENBQUMsT0FBTyxHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBRS9EOzs7O09BSUc7SUFDSCxXQUFXLENBQUMsTUFBTSxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsZUFBZSxHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBRWxFOzs7O09BSUc7SUFDSCxtQkFBbUIsQ0FBQyxNQUFNLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDLENBQUM7SUFFcEU7Ozs7O09BS0c7SUFDSCxxQkFBcUIsSUFBSSxPQUFPLENBQUMsVUFBVSxHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBRXpEOzs7T0FHRztJQUNILHNCQUFzQixJQUFJLE9BQU8sQ0FBQyxXQUFXLEdBQUcsU0FBUyxDQUFDLENBQUM7SUFFM0Q7Ozs7T0FJRztJQUNILG1DQUFtQyxDQUFDLFdBQVcsRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFFdEY7OztPQUdHO0lBQ0gsZUFBZSxDQUFDLFdBQVcsRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBRTVEOztPQUVHO0lBQ0gsU0FBUyxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUU3Qjs7T0FFRztJQUNILGNBQWMsSUFBSSxPQUFPLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUU3QywyQ0FBMkM7SUFDM0MsZ0JBQWdCLElBQUksT0FBTyxDQUFDO1FBQUUsa0JBQWtCLEVBQUUsRUFBRSxDQUFBO0tBQUUsQ0FBQyxDQUFDO0lBRXhELGtDQUFrQztJQUNsQyxjQUFjLElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUMsQ0FBQztJQUU5Qzs7O09BR0c7SUFDSCxxQkFBcUIsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFMUM7OztPQUdHO0lBQ0gsK0JBQStCLElBQUksT0FBTyxDQUFDLHdCQUF3QixDQUFDLENBQUM7SUFFckUsb0JBQW9CO0lBQ3BCLGFBQWEsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFJL0I7Ozs7T0FJRztJQUNILFFBQVEsQ0FBQyxNQUFNLEVBQUUsV0FBVyxHQUFHLE9BQU8sQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDLENBQUM7SUFFNUQ7Ozs7T0FJRztJQUNILDZCQUE2QixDQUFDLFdBQVcsRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixFQUFFLENBQUMsQ0FBQztJQUV4Rjs7OztPQUlHO0lBQ0gsZ0JBQWdCLENBQUMsVUFBVSxFQUFFLFVBQVUsR0FBRyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUU3RDs7OztPQUlHO0lBQ0gsMEJBQTBCLENBQUMsU0FBUyxFQUFFLFNBQVMsR0FBRyxPQUFPLENBQUMsbUJBQW1CLEdBQUcsU0FBUyxDQUFDLENBQUM7SUFFM0Y7Ozs7T0FJRztJQUNILDZCQUE2QixDQUFDLE9BQU8sRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBRXJGOzs7OztPQUtHO0lBQ0gsU0FBUyxDQUFDLElBQUksRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztDQUNqRTtBQUVEOztHQUVHO0FBQ0gsTUFBTSxXQUFXLFdBQVc7SUFDMUI7Ozs7T0FJRztJQUNILFFBQVEsQ0FBQyxLQUFLLEVBQUUsT0FBTyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztDQUN6QztBQUVEOzs7R0FHRztBQUNILE1BQU0sTUFBTSxlQUFlLEdBQUcsaUJBQWlCLENBQUM7SUFDOUMsQ0FBQyxtQkFBbUIsQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxvQkFBb0IsS0FBSyxJQUFJLENBQUM7SUFDNUUsQ0FBQyxtQkFBbUIsQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLDBCQUEwQixLQUFLLElBQUksQ0FBQztJQUN4RixDQUFDLG1CQUFtQixDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLGtCQUFrQixLQUFLLElBQUksQ0FBQztJQUN4RSxDQUFDLG1CQUFtQixDQUFDLHFDQUFxQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsOEJBQThCLEtBQUssSUFBSSxDQUFDO0lBQzVHLENBQUMsbUJBQW1CLENBQUMsb0JBQW9CLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxpQkFBaUIsS0FBSyxJQUFJLENBQUM7Q0FDL0UsQ0FBQyxDQUFDO0FBQ0gsTUFBTSxXQUFXLHlCQUEwQixTQUFRLGFBQWE7SUFDOUQsTUFBTSxFQUFFLGVBQWUsQ0FBQztDQUN6QjtBQUVEOzs7Ozs7R0FNRztBQUNILE1BQU0sTUFBTSxVQUFVLEdBQUcsVUFBVSxHQUFHLGNBQWMsR0FBRyxRQUFRLEdBQUcsV0FBVyxDQUFDO0FBRTlFLDRCQUE0QjtBQUM1QixNQUFNLE1BQU0sTUFBTSxHQUFHO0lBQ25CLFFBQVEsRUFBRSxTQUFTLENBQUM7SUFDcEIsWUFBWSxFQUFFLE9BQU8sQ0FBQztJQUN0QixNQUFNLEVBQUUsT0FBTyxDQUFDO0lBQ2hCLFNBQVMsRUFBRSxPQUFPLENBQUM7Q0FDcEIsQ0FBQztBQUVGLGVBQU8sTUFBTSw4QkFBOEIsSUFBa0MsQ0FBQztBQUU5RSw2Q0FBNkM7QUFDN0MsTUFBTSxNQUFNLFNBQVMsR0FBRztJQUFFLE1BQU0sRUFBRSxXQUFXLENBQUM7SUFBQyxJQUFJLEVBQUUsTUFBTSxDQUFBO0NBQUUsQ0FBQztBQUU5RCxNQUFNLE1BQU0sWUFBWSxHQUFHO0lBQUUsTUFBTSxFQUFFLGdCQUFnQixDQUFDO0lBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQTtDQUFFLENBQUM7QUFFdEUsTUFBTSxNQUFNLE9BQU8sR0FBRztJQUFFLEtBQUssRUFBRSxTQUFTLENBQUM7SUFBQyxVQUFVLEVBQUUsWUFBWSxDQUFBO0NBQUUsQ0FBQztBQUVyRSw2QkFBNkI7QUFDN0Isd0JBQWdCLGFBQWEsQ0FBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxFQUFFLE1BQU0sR0FBRyxTQUFTLENBSzNFO0FBRUQsa0NBQWtDO0FBQ2xDLHdCQUFnQixrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsZ0JBQWdCLEVBQUUsSUFBSSxFQUFFLE1BQU0sR0FBRyxZQUFZLENBRXZGO0FBaUJELGVBQU8sTUFBTSxZQUFZOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBS3ZCLENBQUM7QUFFSCxvQkFBWSxtQkFBbUI7SUFDN0IsZUFBZSxvQkFBb0I7SUFDbkMscUJBQXFCLDBCQUEwQjtJQUMvQyxhQUFhLGtCQUFrQjtJQUMvQixvQkFBb0IseUJBQXlCO0lBQzdDLHFDQUFxQyw4QkFBOEI7Q0FDcEU7QUFFRCxNQUFNLE1BQU0sa0JBQWtCLEdBQUc7SUFDL0IsSUFBSSxFQUFFLGVBQWUsQ0FBQztJQUN0QixXQUFXLEVBQUUsV0FBVyxDQUFDO0lBQ3pCLFVBQVUsRUFBRSxVQUFVLENBQUM7SUFDdkIsV0FBVyxFQUFFLFdBQVcsQ0FBQztDQUMxQixDQUFDO0FBRUYsTUFBTSxNQUFNLG9CQUFvQixHQUFHO0lBQ2pDLElBQUksRUFBRSxpQkFBaUIsQ0FBQztJQUN4QixXQUFXLEVBQUUsV0FBVyxDQUFDO0lBQ3pCLE1BQU0sRUFBRSxPQUFPLEVBQUUsQ0FBQztDQUNuQixDQUFDO0FBRUYsTUFBTSxNQUFNLDBCQUEwQixHQUFHO0lBQ3ZDLElBQUksRUFBRSx1QkFBdUIsQ0FBQztJQUM5QixVQUFVLEVBQUUsVUFBVSxDQUFDO0lBQ3ZCLE1BQU0sRUFBRSxPQUFPLEVBQUUsQ0FBQztDQUNuQixDQUFDO0FBRUYsTUFBTSxNQUFNLGlCQUFpQixHQUFHO0lBQzlCLElBQUksRUFBRSxzQkFBc0IsQ0FBQztJQUM3QixVQUFVLEVBQUUsbUJBQW1CLENBQUM7Q0FDakMsQ0FBQztBQUVGLE1BQU0sTUFBTSw4QkFBOEIsR0FBRztJQUMzQyxJQUFJLEVBQUUsMkJBQTJCLENBQUM7SUFDbEMsZ0JBQWdCLEVBQUUsZ0NBQWdDLENBQUM7Q0FDcEQsQ0FBQyJ9