Overview
ETH Balance
0.000003602392113149 ETH
Eth Value
$0.01 (@ $3,265.20/ETH)Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 60,513 transactions
(More than 25 Pending Txns)
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
15559066 | 677 days ago | 0.00001229 ETH | ||||
15382708 | 705 days ago | 0.038 ETH | ||||
15246638 | 726 days ago | 0.00300612 ETH | ||||
15246609 | 726 days ago | 0.00771718 ETH | ||||
14333179 | 873 days ago | 0.01 ETH | ||||
13835263 | 950 days ago | 0.02 ETH | ||||
13776495 | 959 days ago | 0.25 ETH | ||||
13758369 | 962 days ago | 0.015 ETH | ||||
13707092 | 970 days ago | 0.29 ETH | ||||
13706931 | 970 days ago | 0.13 ETH | ||||
13706660 | 970 days ago | 0.67 ETH | ||||
13702533 | 971 days ago | 0.2 ETH | ||||
13699577 | 971 days ago | 0.03 ETH | ||||
13694969 | 972 days ago | 0.15619741 ETH | ||||
13675746 | 975 days ago | 0.01818531 ETH | ||||
13673133 | 975 days ago | 0.24 ETH | ||||
13672630 | 975 days ago | 0.641 ETH | ||||
13645526 | 980 days ago | 0.03 ETH | ||||
13644362 | 980 days ago | 0.9 ETH | ||||
13643278 | 980 days ago | 0.2 ETH | ||||
13639769 | 981 days ago | 0.4 ETH | ||||
13639680 | 981 days ago | 0.03 ETH | ||||
13629248 | 982 days ago | 0.15568504 ETH | ||||
13628375 | 982 days ago | 0.02 ETH | ||||
13628285 | 982 days ago | 0.04 ETH |
Loading...
Loading
Contract Name:
Exchange
Compiler Version
v0.6.8+commit.0bbfe453
Contract Source Code (Solidity Multiple files format)
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.6.8; pragma experimental ABIEncoderV2; import { Address } from './Address.sol'; import { ECDSA } from './ECDSA.sol'; import { SafeMath as SafeMath256 } from './SafeMath.sol'; import { AssetRegistry } from './AssetRegistry.sol'; import { AssetTransfers } from './AssetTransfers.sol'; import { AssetUnitConversions } from './AssetUnitConversions.sol'; import { Owned } from './Owned.sol'; import { SafeMath64 } from './SafeMath64.sol'; import { Signatures } from './Signatures.sol'; import { Enums, ICustodian, IERC20, IExchange, Structs } from './Interfaces.sol'; import { UUID } from './UUID.sol'; /** * @notice The Exchange contract. Implements all deposit, trade, and withdrawal logic and associated balance tracking * * @dev The term `asset` refers collectively to ETH and ERC-20 tokens, the term `token` refers only to the latter * @dev Events with indexed string parameters (Deposited and TradeExecuted) only log the hash values for those * parameters, from which the original raw string values cannot be retrieved. For convenience these events contain * the un-indexed string parameter values in addition to the indexed values */ contract Exchange is IExchange, Owned { using SafeMath64 for uint64; using SafeMath256 for uint256; using AssetRegistry for AssetRegistry.Storage; // Events // /** * @notice Emitted when an admin changes the Chain Propagation Period tunable parameter with `setChainPropagationPeriod` */ event ChainPropagationPeriodChanged(uint256 previousValue, uint256 newValue); /** * @notice Emitted when a user deposits ETH with `depositEther` or a token with `depositAsset` or `depositAssetBySymbol` */ event Deposited( uint64 index, address indexed wallet, address indexed assetAddress, string indexed assetSymbolIndex, string assetSymbol, uint64 quantityInPips, uint64 newExchangeBalanceInPips, uint256 newExchangeBalanceInAssetUnits ); /** * @notice Emitted when an admin changes the Dispatch Wallet tunable parameter with `setDispatcher` */ event DispatcherChanged(address previousValue, address newValue); /** * @notice Emitted when an admin changes the Fee Wallet tunable parameter with `setFeeWallet` */ event FeeWalletChanged(address previousValue, address newValue); /** * @notice Emitted when a user invalidates an order nonce with `invalidateOrderNonce` */ event OrderNonceInvalidated( address indexed wallet, uint128 nonce, uint128 timestampInMs, uint256 effectiveBlockNumber ); /** * @notice Emitted when an admin initiates the token registration process with `registerToken` */ event TokenRegistered( IERC20 indexed assetAddress, string assetSymbol, uint8 decimals ); /** * @notice Emitted when an admin finalizes the token registration process with `confirmAssetRegistration`, after * which it can be deposited, traded, or withdrawn */ event TokenRegistrationConfirmed( IERC20 indexed assetAddress, string assetSymbol, uint8 decimals ); /** * @notice Emitted when an admin adds a symbol to a previously registered and confirmed token * via `addTokenSymbol` */ event TokenSymbolAdded(IERC20 indexed assetAddress, string assetSymbol); /** * @notice Emitted when the Dispatcher Wallet submits a trade for execution with `executeTrade` */ event TradeExecuted( address buyWallet, address sellWallet, string indexed baseAssetSymbolIndex, string indexed quoteAssetSymbolIndex, string baseAssetSymbol, string quoteAssetSymbol, uint64 baseQuantityInPips, uint64 quoteQuantityInPips, uint64 tradePriceInPips, bytes32 buyOrderHash, bytes32 sellOrderHash ); /** * @notice Emitted when a user invokes the Exit Wallet mechanism with `exitWallet` */ event WalletExited(address indexed wallet, uint256 effectiveBlockNumber); /** * @notice Emitted when a user withdraws an asset balance through the Exit Wallet mechanism with `withdrawExit` */ event WalletExitWithdrawn( address indexed wallet, address indexed assetAddress, string assetSymbol, uint64 quantityInPips, uint64 newExchangeBalanceInPips, uint256 newExchangeBalanceInAssetUnits ); /** * @notice Emitted when a user clears the exited status of a wallet previously exited with `exitWallet` */ event WalletExitCleared(address indexed wallet); /** * @notice Emitted when the Dispatcher Wallet submits a withdrawal with `withdraw` */ event Withdrawn( address indexed wallet, address indexed assetAddress, string assetSymbol, uint64 quantityInPips, uint64 newExchangeBalanceInPips, uint256 newExchangeBalanceInAssetUnits ); // Internally used structs // struct NonceInvalidation { bool exists; uint64 timestampInMs; uint256 effectiveBlockNumber; } struct WalletExit { bool exists; uint256 effectiveBlockNumber; } // Storage // // Asset registry data AssetRegistry.Storage _assetRegistry; // Mapping of order wallet hash => isComplete mapping(bytes32 => bool) _completedOrderHashes; // Mapping of withdrawal wallet hash => isComplete mapping(bytes32 => bool) _completedWithdrawalHashes; address payable _custodian; uint64 _depositIndex; // Mapping of wallet => asset => balance mapping(address => mapping(address => uint64)) _balancesInPips; // Mapping of wallet => last invalidated timestampInMs mapping(address => NonceInvalidation) _nonceInvalidations; // Mapping of order hash => filled quantity in pips mapping(bytes32 => uint64) _partiallyFilledOrderQuantitiesInPips; mapping(address => WalletExit) _walletExits; // Tunable parameters uint256 _chainPropagationPeriod; address _dispatcherWallet; address _feeWallet; // Constant values // uint256 constant _maxChainPropagationPeriod = (7 * 24 * 60 * 60) / 15; // 1 week at 15s/block uint64 constant _maxTradeFeeBasisPoints = 20 * 100; // 20%; uint64 constant _maxWithdrawalFeeBasisPoints = 20 * 100; // 20%; /** * @notice Instantiate a new `Exchange` contract * * @dev Sets `_owner` and `_admin` to `msg.sender` */ constructor() public Owned() {} /** * @notice Sets the address of the `Custodian` contract * * @dev The `Custodian` accepts `Exchange` and `Governance` addresses in its constructor, after * which they can only be changed by the `Governance` contract itself. Therefore the `Custodian` * must be deployed last and its address set here on an existing `Exchange` contract. This value * is immutable once set and cannot be changed again * * @param newCustodian The address of the `Custodian` contract deployed against this `Exchange` * contract's address */ function setCustodian(address payable newCustodian) external onlyAdmin { require(_custodian == address(0x0), 'Custodian can only be set once'); require(Address.isContract(newCustodian), 'Invalid address'); _custodian = newCustodian; } /*** Tunable parameters ***/ /** * @notice Sets a new Chain Propagation Period - the block delay after which order nonce invalidations * are respected by `executeTrade` and wallet exits are respected by `executeTrade` and `withdraw` * * @param newChainPropagationPeriod The new Chain Propagation Period expressed as a number of blocks. Must * be less than `_maxChainPropagationPeriod` */ function setChainPropagationPeriod(uint256 newChainPropagationPeriod) external onlyAdmin { require( newChainPropagationPeriod < _maxChainPropagationPeriod, 'Must be less than 1 week' ); uint256 oldChainPropagationPeriod = _chainPropagationPeriod; _chainPropagationPeriod = newChainPropagationPeriod; emit ChainPropagationPeriodChanged( oldChainPropagationPeriod, newChainPropagationPeriod ); } /** * @notice Sets the address of the Fee wallet * * @dev Trade and Withdraw fees will accrue in the `_balancesInPips` mappings for this wallet * * @param newFeeWallet The new Fee wallet. Must be different from the current one */ function setFeeWallet(address newFeeWallet) external onlyAdmin { require(newFeeWallet != address(0x0), 'Invalid wallet address'); require( newFeeWallet != _feeWallet, 'Must be different from current fee wallet' ); address oldFeeWallet = _feeWallet; _feeWallet = newFeeWallet; emit FeeWalletChanged(oldFeeWallet, newFeeWallet); } // Accessors // /** * @notice Load a wallet's balance by asset address, in asset units * * @param wallet The wallet address to load the balance for. Can be different from `msg.sender` * @param assetAddress The asset address to load the wallet's balance for * * @return The quantity denominated in asset units of asset at `assetAddress` currently * deposited by `wallet` */ function loadBalanceInAssetUnitsByAddress( address wallet, address assetAddress ) external view returns (uint256) { require(wallet != address(0x0), 'Invalid wallet address'); Structs.Asset memory asset = _assetRegistry.loadAssetByAddress( assetAddress ); return AssetUnitConversions.pipsToAssetUnits( _balancesInPips[wallet][assetAddress], asset.decimals ); } /** * @notice Load a wallet's balance by asset address, in asset units * * @param wallet The wallet address to load the balance for. Can be different from `msg.sender` * @param assetSymbol The asset symbol to load the wallet's balance for * * @return The quantity denominated in asset units of asset `assetSymbol` currently deposited * by `wallet` */ function loadBalanceInAssetUnitsBySymbol( address wallet, string calldata assetSymbol ) external view returns (uint256) { require(wallet != address(0x0), 'Invalid wallet address'); Structs.Asset memory asset = _assetRegistry.loadAssetBySymbol( assetSymbol, getCurrentTimestampInMs() ); return AssetUnitConversions.pipsToAssetUnits( _balancesInPips[wallet][asset.assetAddress], asset.decimals ); } /** * @notice Load a wallet's balance by asset address, in pips * * @param wallet The wallet address to load the balance for. Can be different from `msg.sender` * @param assetAddress The asset address to load the wallet's balance for * * @return The quantity denominated in pips of asset at `assetAddress` currently deposited by `wallet` */ function loadBalanceInPipsByAddress(address wallet, address assetAddress) external view returns (uint64) { require(wallet != address(0x0), 'Invalid wallet address'); return _balancesInPips[wallet][assetAddress]; } /** * @notice Load a wallet's balance by asset symbol, in pips * * @param wallet The wallet address to load the balance for. Can be different from `msg.sender` * @param assetSymbol The asset symbol to load the wallet's balance for * * @return The quantity denominated in pips of asset with `assetSymbol` currently deposited by `wallet` */ function loadBalanceInPipsBySymbol( address wallet, string calldata assetSymbol ) external view returns (uint64) { require(wallet != address(0x0), 'Invalid wallet address'); address assetAddress = _assetRegistry .loadAssetBySymbol(assetSymbol, getCurrentTimestampInMs()) .assetAddress; return _balancesInPips[wallet][assetAddress]; } /** * @notice Load the address of the Fee wallet * * @return The address of the Fee wallet */ function loadFeeWallet() external view returns (address) { return _feeWallet; } /** * @notice Load the quantity filled so far for a partially filled orders * @dev Invalidating an order nonce will not clear partial fill quantities for earlier orders because * the gas cost would potentially be unbound * * @param orderHash The order hash as originally signed by placing wallet that uniquely identifies an order * * @return For partially filled orders, the amount filled so far in pips. For orders in all other states, 0 */ function loadPartiallyFilledOrderQuantityInPips(bytes32 orderHash) external view returns (uint64) { return _partiallyFilledOrderQuantitiesInPips[orderHash]; } // Depositing // /** * @notice Deposit ETH */ function depositEther() external payable { deposit(msg.sender, address(0x0), msg.value); } /** * @notice Deposit `IERC20` compliant tokens * * @param tokenAddress The token contract address * @param quantityInAssetUnits The quantity to deposit. The sending wallet must first call the `approve` method on * the token contract for at least this quantity first */ function depositTokenByAddress( IERC20 tokenAddress, uint256 quantityInAssetUnits ) external { require( address(tokenAddress) != address(0x0), 'Use depositEther to deposit Ether' ); deposit(msg.sender, address(tokenAddress), quantityInAssetUnits); } /** * @notice Deposit `IERC20` compliant tokens * * @param assetSymbol The case-sensitive symbol string for the token * @param quantityInAssetUnits The quantity to deposit. The sending wallet must first call the `approve` method on * the token contract for at least this quantity first */ function depositTokenBySymbol( string calldata assetSymbol, uint256 quantityInAssetUnits ) external { IERC20 tokenAddress = IERC20( _assetRegistry .loadAssetBySymbol(assetSymbol, getCurrentTimestampInMs()) .assetAddress ); require( address(tokenAddress) != address(0x0), 'Use depositEther to deposit ETH' ); deposit(msg.sender, address(tokenAddress), quantityInAssetUnits); } function deposit( address payable wallet, address assetAddress, uint256 quantityInAssetUnits ) private { // Calling exitWallet disables deposits immediately on mining, in contrast to withdrawals and // trades which respect the Chain Propagation Period given by `effectiveBlockNumber` via // `isWalletExitFinalized` require(!_walletExits[wallet].exists, 'Wallet exited'); Structs.Asset memory asset = _assetRegistry.loadAssetByAddress( assetAddress ); uint64 quantityInPips = AssetUnitConversions.assetUnitsToPips( quantityInAssetUnits, asset.decimals ); require(quantityInPips > 0, 'Quantity is too low'); // Convert from pips back into asset units to remove any fractional amount that is too small // to express in pips. If the asset is ETH, this leftover fractional amount accumulates as dust // in the `Exchange` contract. If the asset is a token the `Exchange` will call `transferFrom` // without this fractional amount and there will be no dust uint256 quantityInAssetUnitsWithoutFractionalPips = AssetUnitConversions .pipsToAssetUnits(quantityInPips, asset.decimals); // If the asset is ETH then the funds were already assigned to this contract via msg.value. If // the asset is a token, additionally call the transferFrom function on the token contract for // the pre-approved asset quantity if (assetAddress != address(0x0)) { AssetTransfers.transferFrom( wallet, IERC20(assetAddress), quantityInAssetUnitsWithoutFractionalPips ); } // Forward the funds to the `Custodian` AssetTransfers.transferTo( _custodian, assetAddress, quantityInAssetUnitsWithoutFractionalPips ); uint64 newExchangeBalanceInPips = _balancesInPips[wallet][assetAddress].add( quantityInPips ); uint256 newExchangeBalanceInAssetUnits = AssetUnitConversions .pipsToAssetUnits(newExchangeBalanceInPips, asset.decimals); // Update balance with actual transferred quantity _balancesInPips[wallet][assetAddress] = newExchangeBalanceInPips; _depositIndex++; emit Deposited( _depositIndex, wallet, assetAddress, asset.symbol, asset.symbol, quantityInPips, newExchangeBalanceInPips, newExchangeBalanceInAssetUnits ); } // Invalidation // /** * @notice Invalidate all order nonces with a timestampInMs lower than the one provided * * @param nonce A Version 1 UUID. After calling and once the Chain Propagation Period has elapsed, * `executeTrade` will reject order nonces from this wallet with a timestampInMs component lower than * the one provided */ function invalidateOrderNonce(uint128 nonce) external { uint64 timestampInMs = UUID.getTimestampInMsFromUuidV1(nonce); // Enforce a maximum skew for invalidating nonce timestamps in the future so the user doesn't // lock their wallet from trades indefinitely require( timestampInMs < getOneDayFromNowInMs(), 'Nonce timestamp too far in future' ); if (_nonceInvalidations[msg.sender].exists) { require( _nonceInvalidations[msg.sender].timestampInMs < timestampInMs, 'Nonce timestamp already invalidated' ); require( _nonceInvalidations[msg.sender].effectiveBlockNumber <= block.number, 'Previous invalidation awaiting chain propagation' ); } // Changing the Chain Propagation Period will not affect the effectiveBlockNumber for this invalidation uint256 effectiveBlockNumber = block.number + _chainPropagationPeriod; _nonceInvalidations[msg.sender] = NonceInvalidation( true, timestampInMs, effectiveBlockNumber ); emit OrderNonceInvalidated( msg.sender, nonce, timestampInMs, effectiveBlockNumber ); } // Withdrawing // /** * @notice Settles a user withdrawal submitted off-chain. Calls restricted to currently whitelisted Dispatcher wallet * * @param withdrawal A `Structs.Withdrawal` struct encoding the parameters of the withdrawal */ function withdraw(Structs.Withdrawal memory withdrawal) public override onlyDispatcher { // Validations require(!isWalletExitFinalized(withdrawal.walletAddress), 'Wallet exited'); require( getFeeBasisPoints(withdrawal.gasFeeInPips, withdrawal.quantityInPips) <= _maxWithdrawalFeeBasisPoints, 'Excessive withdrawal fee' ); bytes32 withdrawalHash = validateWithdrawalSignature(withdrawal); require( !_completedWithdrawalHashes[withdrawalHash], 'Hash already withdrawn' ); // If withdrawal is by asset symbol (most common) then resolve to asset address Structs.Asset memory asset = withdrawal.withdrawalType == Enums.WithdrawalType.BySymbol ? _assetRegistry.loadAssetBySymbol( withdrawal.assetSymbol, UUID.getTimestampInMsFromUuidV1(withdrawal.nonce) ) : _assetRegistry.loadAssetByAddress(withdrawal.assetAddress); // SafeMath reverts if balance is overdrawn uint64 netAssetQuantityInPips = withdrawal.quantityInPips.sub( withdrawal.gasFeeInPips ); uint256 netAssetQuantityInAssetUnits = AssetUnitConversions .pipsToAssetUnits(netAssetQuantityInPips, asset.decimals); uint64 newExchangeBalanceInPips = _balancesInPips[withdrawal .walletAddress][asset.assetAddress] .sub(withdrawal.quantityInPips); uint256 newExchangeBalanceInAssetUnits = AssetUnitConversions .pipsToAssetUnits(newExchangeBalanceInPips, asset.decimals); _balancesInPips[withdrawal.walletAddress][asset .assetAddress] = newExchangeBalanceInPips; _balancesInPips[_feeWallet][asset .assetAddress] = _balancesInPips[_feeWallet][asset.assetAddress].add( withdrawal.gasFeeInPips ); ICustodian(_custodian).withdraw( withdrawal.walletAddress, asset.assetAddress, netAssetQuantityInAssetUnits ); _completedWithdrawalHashes[withdrawalHash] = true; emit Withdrawn( withdrawal.walletAddress, asset.assetAddress, asset.symbol, withdrawal.quantityInPips, newExchangeBalanceInPips, newExchangeBalanceInAssetUnits ); } // Wallet exits // /** * @notice Flags the sending wallet as exited, immediately disabling deposits upon mining. * After the Chain Propagation Period passes trades and withdrawals are also disabled for the wallet, * and assets may then be withdrawn one at a time via `withdrawExit` */ function exitWallet() external { require(!_walletExits[msg.sender].exists, 'Wallet already exited'); _walletExits[msg.sender] = WalletExit( true, block.number + _chainPropagationPeriod ); emit WalletExited(msg.sender, block.number + _chainPropagationPeriod); } /** * @notice Withdraw the entire balance of an asset for an exited wallet. The Chain Propagation Period must * have already passed since calling `exitWallet` on `assetAddress` * * @param assetAddress The address of the asset to withdraw */ function withdrawExit(address assetAddress) external { require(isWalletExitFinalized(msg.sender), 'Wallet exit not finalized'); Structs.Asset memory asset = _assetRegistry.loadAssetByAddress( assetAddress ); uint64 balanceInPips = _balancesInPips[msg.sender][assetAddress]; uint256 balanceInAssetUnits = AssetUnitConversions.pipsToAssetUnits( balanceInPips, asset.decimals ); require(balanceInAssetUnits > 0, 'No balance for asset'); _balancesInPips[msg.sender][assetAddress] = 0; ICustodian(_custodian).withdraw( msg.sender, assetAddress, balanceInAssetUnits ); emit WalletExitWithdrawn( msg.sender, assetAddress, asset.symbol, balanceInPips, 0, 0 ); } /** * @notice Clears exited status of sending wallet. Upon mining immediately enables * deposits, trades, and withdrawals by sending wallet */ function clearWalletExit() external { require(_walletExits[msg.sender].exists, 'Wallet not exited'); delete _walletExits[msg.sender]; emit WalletExitCleared(msg.sender); } function isWalletExitFinalized(address wallet) internal view returns (bool) { WalletExit storage exit = _walletExits[wallet]; return exit.exists && exit.effectiveBlockNumber <= block.number; } // Trades // /** * @notice Settles a trade between two orders submitted and matched off-chain * * @dev As a gas optimization, base and quote symbols are passed in separately and combined to verify * the wallet hash, since this is cheaper than splitting the market symbol into its two constituent asset symbols * @dev Stack level too deep if declared external * * @param buy A `Structs.Order` struct encoding the parameters of the buy-side order (receiving base, giving quote) * @param sell A `Structs.Order` struct encoding the parameters of the sell-side order (giving base, receiving quote) * @param trade A `Structs.Trade` struct encoding the parameters of this trade execution of the counterparty orders */ function executeTrade( Structs.Order memory buy, Structs.Order memory sell, Structs.Trade memory trade ) public override onlyDispatcher { require( !isWalletExitFinalized(buy.walletAddress), 'Buy wallet exit finalized' ); require( !isWalletExitFinalized(sell.walletAddress), 'Sell wallet exit finalized' ); require( buy.walletAddress != sell.walletAddress, 'Self-trading not allowed' ); validateAssetPair(buy, sell, trade); validateLimitPrices(buy, sell, trade); validateOrderNonces(buy, sell); (bytes32 buyHash, bytes32 sellHash) = validateOrderSignatures( buy, sell, trade ); validateTradeFees(trade); updateOrderFilledQuantities(buy, buyHash, sell, sellHash, trade); updateBalancesForTrade(buy, sell, trade); emit TradeExecuted( buy.walletAddress, sell.walletAddress, trade.baseAssetSymbol, trade.quoteAssetSymbol, trade.baseAssetSymbol, trade.quoteAssetSymbol, trade.grossBaseQuantityInPips, trade.grossQuoteQuantityInPips, trade.priceInPips, buyHash, sellHash ); } // Updates buyer, seller, and fee wallet balances for both assets in trade pair according to trade parameters function updateBalancesForTrade( Structs.Order memory buy, Structs.Order memory sell, Structs.Trade memory trade ) private { // Seller gives base asset including fees _balancesInPips[sell.walletAddress][trade .baseAssetAddress] = _balancesInPips[sell.walletAddress][trade .baseAssetAddress] .sub(trade.grossBaseQuantityInPips); // Buyer receives base asset minus fees _balancesInPips[buy.walletAddress][trade .baseAssetAddress] = _balancesInPips[buy.walletAddress][trade .baseAssetAddress] .add(trade.netBaseQuantityInPips); // Buyer gives quote asset including fees _balancesInPips[buy.walletAddress][trade .quoteAssetAddress] = _balancesInPips[buy.walletAddress][trade .quoteAssetAddress] .sub(trade.grossQuoteQuantityInPips); // Seller receives quote asset minus fees _balancesInPips[sell.walletAddress][trade .quoteAssetAddress] = _balancesInPips[sell.walletAddress][trade .quoteAssetAddress] .add(trade.netQuoteQuantityInPips); // Maker and taker fees to fee wallet _balancesInPips[_feeWallet][trade .makerFeeAssetAddress] = _balancesInPips[_feeWallet][trade .makerFeeAssetAddress] .add(trade.makerFeeQuantityInPips); _balancesInPips[_feeWallet][trade .takerFeeAssetAddress] = _balancesInPips[_feeWallet][trade .takerFeeAssetAddress] .add(trade.takerFeeQuantityInPips); } function updateOrderFilledQuantities( Structs.Order memory buyOrder, bytes32 buyOrderHash, Structs.Order memory sellOrder, bytes32 sellOrderHash, Structs.Trade memory trade ) private { updateOrderFilledQuantity(buyOrder, buyOrderHash, trade); updateOrderFilledQuantity(sellOrder, sellOrderHash, trade); } // Update filled quantities tracking for order to prevent over- or double-filling orders function updateOrderFilledQuantity( Structs.Order memory order, bytes32 orderHash, Structs.Trade memory trade ) private { require(!_completedOrderHashes[orderHash], 'Order double filled'); // Total quantity of above filled as a result of all trade executions, including this one uint64 newFilledQuantityInPips; // Market orders can express quantity in quote terms, and can be partially filled by multiple // limit maker orders necessitating tracking partially filled amounts in quote terms to // determine completion if (order.isQuantityInQuote) { require( isMarketOrderType(order.orderType), 'Order quote quantity only valid for market orders' ); newFilledQuantityInPips = trade.grossQuoteQuantityInPips.add( _partiallyFilledOrderQuantitiesInPips[orderHash] ); } else { // All other orders track partially filled quantities in base terms newFilledQuantityInPips = trade.grossBaseQuantityInPips.add( _partiallyFilledOrderQuantitiesInPips[orderHash] ); } require( newFilledQuantityInPips <= order.quantityInPips, 'Order overfilled' ); if (newFilledQuantityInPips < order.quantityInPips) { // If the order was partially filled, track the new filled quantity _partiallyFilledOrderQuantitiesInPips[orderHash] = newFilledQuantityInPips; } else { // If the order was completed, delete any partial fill tracking and instead track its completion // to prevent future double fills delete _partiallyFilledOrderQuantitiesInPips[orderHash]; _completedOrderHashes[orderHash] = true; } } // Validations // function validateAssetPair( Structs.Order memory buy, Structs.Order memory sell, Structs.Trade memory trade ) private view { require( trade.baseAssetAddress != trade.quoteAssetAddress, 'Base and quote assets must be different' ); // Buy order market pair Structs.Asset memory buyBaseAsset = _assetRegistry.loadAssetBySymbol( trade.baseAssetSymbol, UUID.getTimestampInMsFromUuidV1(buy.nonce) ); Structs.Asset memory buyQuoteAsset = _assetRegistry.loadAssetBySymbol( trade.quoteAssetSymbol, UUID.getTimestampInMsFromUuidV1(buy.nonce) ); require( buyBaseAsset.assetAddress == trade.baseAssetAddress && buyQuoteAsset.assetAddress == trade.quoteAssetAddress, 'Buy order market symbol address resolution mismatch' ); // Sell order market pair Structs.Asset memory sellBaseAsset = _assetRegistry.loadAssetBySymbol( trade.baseAssetSymbol, UUID.getTimestampInMsFromUuidV1(sell.nonce) ); Structs.Asset memory sellQuoteAsset = _assetRegistry.loadAssetBySymbol( trade.quoteAssetSymbol, UUID.getTimestampInMsFromUuidV1(sell.nonce) ); require( sellBaseAsset.assetAddress == trade.baseAssetAddress && sellQuoteAsset.assetAddress == trade.quoteAssetAddress, 'Sell order market symbol address resolution mismatch' ); // Fee asset validation require( trade.makerFeeAssetAddress == trade.baseAssetAddress || trade.makerFeeAssetAddress == trade.quoteAssetAddress, 'Maker fee asset is not in trade pair' ); require( trade.takerFeeAssetAddress == trade.baseAssetAddress || trade.takerFeeAssetAddress == trade.quoteAssetAddress, 'Taker fee asset is not in trade pair' ); require( trade.makerFeeAssetAddress != trade.takerFeeAssetAddress, 'Maker and taker fee assets must be different' ); } function validateLimitPrices( Structs.Order memory buy, Structs.Order memory sell, Structs.Trade memory trade ) private pure { require( trade.grossBaseQuantityInPips > 0, 'Base quantity must be greater than zero' ); require( trade.grossQuoteQuantityInPips > 0, 'Quote quantity must be greater than zero' ); if (isLimitOrderType(buy.orderType)) { require( getImpliedQuoteQuantityInPips( trade.grossBaseQuantityInPips, buy.limitPriceInPips ) >= trade.grossQuoteQuantityInPips, 'Buy order limit price exceeded' ); } if (isLimitOrderType(sell.orderType)) { require( getImpliedQuoteQuantityInPips( trade.grossBaseQuantityInPips, sell.limitPriceInPips ) <= trade.grossQuoteQuantityInPips, 'Sell order limit price exceeded' ); } } function validateTradeFees(Structs.Trade memory trade) private pure { uint64 makerTotalQuantityInPips = trade.makerFeeAssetAddress == trade.baseAssetAddress ? trade.grossBaseQuantityInPips : trade.grossQuoteQuantityInPips; require( getFeeBasisPoints( trade.makerFeeQuantityInPips, makerTotalQuantityInPips ) <= _maxTradeFeeBasisPoints, 'Excessive maker fee' ); uint64 takerTotalQuantityInPips = trade.takerFeeAssetAddress == trade.baseAssetAddress ? trade.grossBaseQuantityInPips : trade.grossQuoteQuantityInPips; require( getFeeBasisPoints( trade.takerFeeQuantityInPips, takerTotalQuantityInPips ) <= _maxTradeFeeBasisPoints, 'Excessive taker fee' ); require( trade.netBaseQuantityInPips.add( trade.makerFeeAssetAddress == trade.baseAssetAddress ? trade.makerFeeQuantityInPips : trade.takerFeeQuantityInPips ) == trade.grossBaseQuantityInPips, 'Net base plus fee is not equal to gross' ); require( trade.netQuoteQuantityInPips.add( trade.makerFeeAssetAddress == trade.quoteAssetAddress ? trade.makerFeeQuantityInPips : trade.takerFeeQuantityInPips ) == trade.grossQuoteQuantityInPips, 'Net quote plus fee is not equal to gross' ); } function validateOrderSignatures( Structs.Order memory buy, Structs.Order memory sell, Structs.Trade memory trade ) private pure returns (bytes32, bytes32) { bytes32 buyOrderHash = validateOrderSignature(buy, trade); bytes32 sellOrderHash = validateOrderSignature(sell, trade); return (buyOrderHash, sellOrderHash); } function validateOrderSignature( Structs.Order memory order, Structs.Trade memory trade ) private pure returns (bytes32) { bytes32 orderHash = Signatures.getOrderWalletHash( order, trade.baseAssetSymbol, trade.quoteAssetSymbol ); require( Signatures.isSignatureValid( orderHash, order.walletSignature, order.walletAddress ), order.side == Enums.OrderSide.Buy ? 'Invalid wallet signature for buy order' : 'Invalid wallet signature for sell order' ); return orderHash; } function validateOrderNonces( Structs.Order memory buy, Structs.Order memory sell ) private view { require( UUID.getTimestampInMsFromUuidV1(buy.nonce) > getLastInvalidatedTimestamp(buy.walletAddress), 'Buy order nonce timestamp too low' ); require( UUID.getTimestampInMsFromUuidV1(sell.nonce) > getLastInvalidatedTimestamp(sell.walletAddress), 'Sell order nonce timestamp too low' ); } function validateWithdrawalSignature(Structs.Withdrawal memory withdrawal) private pure returns (bytes32) { bytes32 withdrawalHash = Signatures.getWithdrawalWalletHash(withdrawal); require( Signatures.isSignatureValid( withdrawalHash, withdrawal.walletSignature, withdrawal.walletAddress ), 'Invalid wallet signature' ); return withdrawalHash; } // Asset registry // /** * @notice Initiate registration process for a token asset. Only `IERC20` compliant tokens can be * added - ETH is hardcoded in the registry * * @param tokenAddress The address of the `IERC20` compliant token contract to add * @param symbol The symbol identifying the token asset * @param decimals The decimal precision of the token */ function registerToken( IERC20 tokenAddress, string calldata symbol, uint8 decimals ) external onlyAdmin { _assetRegistry.registerToken(tokenAddress, symbol, decimals); emit TokenRegistered(tokenAddress, symbol, decimals); } /** * @notice Finalize registration process for a token asset. All parameters must exactly match a previous * call to `registerToken` * * @param tokenAddress The address of the `IERC20` compliant token contract to add * @param symbol The symbol identifying the token asset * @param decimals The decimal precision of the token */ function confirmTokenRegistration( IERC20 tokenAddress, string calldata symbol, uint8 decimals ) external onlyAdmin { _assetRegistry.confirmTokenRegistration(tokenAddress, symbol, decimals); emit TokenRegistrationConfirmed(tokenAddress, symbol, decimals); } /** * @notice Add a symbol to a token that has already been registered and confirmed * * @param tokenAddress The address of the `IERC20` compliant token contract the symbol will identify * @param symbol The symbol identifying the token asset */ function addTokenSymbol(IERC20 tokenAddress, string calldata symbol) external onlyAdmin { _assetRegistry.addTokenSymbol(tokenAddress, symbol); emit TokenSymbolAdded(tokenAddress, symbol); } /** * @notice Loads an asset descriptor struct by its symbol and timestamp * * @dev Since multiple token addresses can potentially share the same symbol (in case of a token * swap/contract upgrade) the provided `timestampInMs` is compared against each asset's * `confirmedTimestampInMs` to uniquely determine the newest asset for the symbol at that point in time * * @param assetSymbol The asset's symbol * @param timestampInMs Point in time used to disambiguate multiple tokens with same symbol * * @return A `Structs.Asset` record describing the asset */ function loadAssetBySymbol(string calldata assetSymbol, uint64 timestampInMs) external view returns (Structs.Asset memory) { return _assetRegistry.loadAssetBySymbol(assetSymbol, timestampInMs); } // Dispatcher whitelisting // /** * @notice Sets the wallet whitelisted to dispatch transactions calling the `executeTrade` and `withdraw` functions * * @param newDispatcherWallet The new whitelisted dispatcher wallet. Must be different from the current one */ function setDispatcher(address newDispatcherWallet) external onlyAdmin { require(newDispatcherWallet != address(0x0), 'Invalid wallet address'); require( newDispatcherWallet != _dispatcherWallet, 'Must be different from current dispatcher' ); address oldDispatcherWallet = _dispatcherWallet; _dispatcherWallet = newDispatcherWallet; emit DispatcherChanged(oldDispatcherWallet, newDispatcherWallet); } /** * @notice Clears the currently set whitelisted dispatcher wallet, effectively disabling calling the * `executeTrade` and `withdraw` functions until a new wallet is set with `setDispatcher` */ function removeDispatcher() external onlyAdmin { emit DispatcherChanged(_dispatcherWallet, address(0x0)); _dispatcherWallet = address(0x0); } modifier onlyDispatcher() { require(msg.sender == _dispatcherWallet, 'Caller is not dispatcher'); _; } // Utils // function isLimitOrderType(Enums.OrderType orderType) private pure returns (bool) { return orderType == Enums.OrderType.Limit || orderType == Enums.OrderType.LimitMaker || orderType == Enums.OrderType.StopLossLimit || orderType == Enums.OrderType.TakeProfitLimit; } function isMarketOrderType(Enums.OrderType orderType) private pure returns (bool) { return orderType == Enums.OrderType.Market || orderType == Enums.OrderType.StopLoss || orderType == Enums.OrderType.TakeProfit; } function getCurrentTimestampInMs() private view returns (uint64) { uint64 msInOneSecond = 1000; return uint64(block.timestamp) * msInOneSecond; } function getFeeBasisPoints(uint64 fee, uint64 total) private pure returns (uint64) { uint64 basisPointsInTotal = 100 * 100; // 100 basis points/percent * 100 percent/total return fee.mul(basisPointsInTotal).div(total); } function getImpliedQuoteQuantityInPips( uint64 baseQuantityInPips, uint64 limitPriceInPips ) private pure returns (uint64) { // To convert a fractional price to integer pips, shift right by the pip precision of 8 decimals uint256 pipsMultiplier = 10**8; uint256 impliedQuoteQuantityInPips = uint256(baseQuantityInPips) .mul(uint256(limitPriceInPips)) .div(pipsMultiplier); require( impliedQuoteQuantityInPips < 2**64, 'Implied quote pip quantity overflows uint64' ); return uint64(impliedQuoteQuantityInPips); } function getLastInvalidatedTimestamp(address walletAddress) private view returns (uint64) { if ( _nonceInvalidations[walletAddress].exists && _nonceInvalidations[walletAddress].effectiveBlockNumber <= block.number ) { return _nonceInvalidations[walletAddress].timestampInMs; } return 0; } function getOneDayFromNowInMs() private view returns (uint64) { uint64 secondsInOneDay = 24 * 60 * 60; // 24 hours/day * 60 min/hour * 60 seconds/min uint64 msInOneSecond = 1000; return (uint64(block.timestamp) + secondsInOneDay) * msInOneSecond; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.8; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.6.8; pragma experimental ABIEncoderV2; import { Address } from './Address.sol'; import { IERC20, Structs } from './Interfaces.sol'; /** * @notice Library helper functions for managing a registry of asset descriptors indexed by address and symbol */ library AssetRegistry { struct Storage { mapping(address => Structs.Asset) assetsByAddress; // Mapping value is array since the same symbol can be re-used for a different address // (usually as a result of a token swap or upgrade) mapping(string => Structs.Asset[]) assetsBySymbol; } function registerToken( Storage storage self, IERC20 tokenAddress, string memory symbol, uint8 decimals ) internal { require(decimals <= 32, 'Token cannot have more than 32 decimals'); require( tokenAddress != IERC20(0x0) && Address.isContract(address(tokenAddress)), 'Invalid token address' ); // The string type does not have a length property so cast to bytes to check for empty string require(bytes(symbol).length > 0, 'Invalid token symbol'); require( !self.assetsByAddress[address(tokenAddress)].isConfirmed, 'Token already finalized' ); self.assetsByAddress[address(tokenAddress)] = Structs.Asset({ exists: true, assetAddress: address(tokenAddress), symbol: symbol, decimals: decimals, isConfirmed: false, confirmedTimestampInMs: 0 }); } function confirmTokenRegistration( Storage storage self, IERC20 tokenAddress, string memory symbol, uint8 decimals ) internal { Structs.Asset memory asset = self.assetsByAddress[address(tokenAddress)]; require(asset.exists, 'Unknown token'); require(!asset.isConfirmed, 'Token already finalized'); require(isStringEqual(asset.symbol, symbol), 'Symbols do not match'); require(asset.decimals == decimals, 'Decimals do not match'); asset.isConfirmed = true; asset.confirmedTimestampInMs = uint64(block.timestamp * 1000); // Block timestamp is in seconds, store ms self.assetsByAddress[address(tokenAddress)] = asset; self.assetsBySymbol[symbol].push(asset); } function addTokenSymbol( Storage storage self, IERC20 tokenAddress, string memory symbol ) internal { Structs.Asset memory asset = self.assetsByAddress[address(tokenAddress)]; require( asset.exists && asset.isConfirmed, 'Registration of token not finalized' ); require(!isStringEqual(symbol, 'ETH'), 'ETH symbol reserved for Ether'); // This will prevent swapping assets for previously existing orders uint64 msInOneSecond = 1000; asset.confirmedTimestampInMs = uint64(block.timestamp * msInOneSecond); self.assetsBySymbol[symbol].push(asset); } /** * @dev Resolves an asset address into corresponding Asset struct * * @param assetAddress Ethereum address of asset */ function loadAssetByAddress(Storage storage self, address assetAddress) internal view returns (Structs.Asset memory) { if (assetAddress == address(0x0)) { return getEthAsset(); } Structs.Asset memory asset = self.assetsByAddress[assetAddress]; require( asset.exists && asset.isConfirmed, 'No confirmed asset found for address' ); return asset; } /** * @dev Resolves a asset symbol into corresponding Asset struct * * @param symbol Asset symbol, e.g. 'IDEX' * @param timestampInMs Milliseconds since Unix epoch, usually parsed from a UUID v1 order nonce. * Constrains symbol resolution to the asset most recently confirmed prior to timestampInMs. Reverts * if no such asset exists */ function loadAssetBySymbol( Storage storage self, string memory symbol, uint64 timestampInMs ) internal view returns (Structs.Asset memory) { if (isStringEqual('ETH', symbol)) { return getEthAsset(); } Structs.Asset memory asset; if (self.assetsBySymbol[symbol].length > 0) { for (uint8 i = 0; i < self.assetsBySymbol[symbol].length; i++) { if ( self.assetsBySymbol[symbol][i].confirmedTimestampInMs <= timestampInMs ) { asset = self.assetsBySymbol[symbol][i]; } } } require( asset.exists && asset.isConfirmed, 'No confirmed asset found for symbol' ); return asset; } /** * @dev ETH is modeled as an always-confirmed Asset struct for programmatic consistency */ function getEthAsset() private pure returns (Structs.Asset memory) { return Structs.Asset(true, address(0x0), 'ETH', 18, true, 0); } // See https://solidity.readthedocs.io/en/latest/types.html#bytes-and-strings-as-arrays function isStringEqual(string memory a, string memory b) private pure returns (bool) { return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.6.8; pragma experimental ABIEncoderV2; import { SafeMath as SafeMath256 } from './SafeMath.sol'; import { IERC20 } from './Interfaces.sol'; /** * @notice This library provides helper utilities for transfering assets in and out of contracts. * It further validates ERC-20 compliant balance updates in the case of token assets */ library AssetTransfers { using SafeMath256 for uint256; /** * @dev Transfers tokens from a wallet into a contract during deposits. `wallet` must already * have called `approve` on the token contract for at least `tokenQuantity`. Note this only * applies to tokens since ETH is sent in the deposit transaction via `msg.value` */ function transferFrom( address wallet, IERC20 tokenAddress, uint256 quantityInAssetUnits ) internal { uint256 balanceBefore = tokenAddress.balanceOf(address(this)); // Because we check for the expected balance change we can safely ignore the return value of transferFrom tokenAddress.transferFrom(wallet, address(this), quantityInAssetUnits); uint256 balanceAfter = tokenAddress.balanceOf(address(this)); require( balanceAfter.sub(balanceBefore) == quantityInAssetUnits, 'Token contract returned transferFrom success without expected balance change' ); } /** * @dev Transfers ETH or token assets from a contract to 1) another contract, when `Exchange` * forwards funds to `Custodian` during deposit or 2) a wallet, when withdrawing */ function transferTo( address payable walletOrContract, address asset, uint256 quantityInAssetUnits ) internal { if (asset == address(0x0)) { require( walletOrContract.send(quantityInAssetUnits), 'ETH transfer failed' ); } else { uint256 balanceBefore = IERC20(asset).balanceOf(walletOrContract); // Because we check for the expected balance change we can safely ignore the return value of transfer IERC20(asset).transfer(walletOrContract, quantityInAssetUnits); uint256 balanceAfter = IERC20(asset).balanceOf(walletOrContract); require( balanceAfter.sub(balanceBefore) == quantityInAssetUnits, 'Token contract returned transfer success without expected balance change' ); } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.6.8; pragma experimental ABIEncoderV2; import { SafeMath as SafeMath256 } from './SafeMath.sol'; /** * @notice Library helpers for converting asset quantities between asset units and pips */ library AssetUnitConversions { using SafeMath256 for uint256; function pipsToAssetUnits(uint64 quantityInPips, uint8 assetDecimals) internal pure returns (uint256) { require(assetDecimals <= 32, 'Asset cannot have more than 32 decimals'); // Exponents cannot be negative, so divide or multiply based on exponent signedness if (assetDecimals > 8) { return uint256(quantityInPips).mul(uint256(10)**(assetDecimals - 8)); } return uint256(quantityInPips).div(uint256(10)**(8 - assetDecimals)); } function assetUnitsToPips(uint256 quantityInAssetUnits, uint8 assetDecimals) internal pure returns (uint64) { require(assetDecimals <= 32, 'Asset cannot have more than 32 decimals'); uint256 quantityInPips; // Exponents cannot be negative, so divide or multiply based on exponent signedness if (assetDecimals > 8) { quantityInPips = quantityInAssetUnits.div( uint256(10)**(assetDecimals - 8) ); } else { quantityInPips = quantityInAssetUnits.mul( uint256(10)**(8 - assetDecimals) ); } require(quantityInPips < 2**64, 'Pip quantity overflows uint64'); return uint64(quantityInPips); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.8; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { revert("ECDSA: invalid signature length"); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { revert("ECDSA: invalid signature 's' value"); } if (v != 27 && v != 28) { revert("ECDSA: invalid signature 'v' value"); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); require(signer != address(0), "ECDSA: invalid signature"); return signer; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.6.8; pragma experimental ABIEncoderV2; /** * @notice Enums used in `Order` and `Withdrawal` structs */ contract Enums { enum OrderSelfTradePrevention { // Decrement and cancel dc, // Cancel oldest co, // Cancel newest cn, // Cancel both cb } enum OrderSide { Buy, Sell } enum OrderTimeInForce { // Good until cancelled gtc, // Good until time gtt, // Immediate or cancel ioc, // Fill or kill fok } enum OrderType { Market, Limit, LimitMaker, StopLoss, StopLossLimit, TakeProfit, TakeProfitLimit } enum WithdrawalType { BySymbol, ByAddress } } /** * @notice Struct definitions */ contract Structs { /** * @notice Argument type for `Exchange.executeTrade` and `Signatures.getOrderWalletHash` */ struct Order { // Not currently used but reserved for future use. Must be 1 uint8 signatureHashVersion; // UUIDv1 unique to wallet uint128 nonce; // Wallet address that placed order and signed hash address walletAddress; // Type of order Enums.OrderType orderType; // Order side wallet is on Enums.OrderSide side; // Order quantity in base or quote asset terms depending on isQuantityInQuote flag uint64 quantityInPips; // Is quantityInPips in quote terms bool isQuantityInQuote; // For limit orders, price in decimal pips * 10^8 in quote terms uint64 limitPriceInPips; // For stop orders, stop loss or take profit price in decimal pips * 10^8 in quote terms uint64 stopPriceInPips; // Optional custom client order ID string clientOrderId; // TIF option specified by wallet for order Enums.OrderTimeInForce timeInForce; // STP behavior specified by wallet for order Enums.OrderSelfTradePrevention selfTradePrevention; // Cancellation time specified by wallet for GTT TIF order uint64 cancelAfter; // The ECDSA signature of the order hash as produced by Signatures.getOrderWalletHash bytes walletSignature; } /** * @notice Return type for `Exchange.loadAssetBySymbol`, and `Exchange.loadAssetByAddress`; also * used internally by `AssetRegistry` */ struct Asset { // Flag to distinguish from empty struct bool exists; // The asset's address address assetAddress; // The asset's symbol string symbol; // The asset's decimal precision uint8 decimals; // Flag set when asset registration confirmed. Asset deposits, trades, or withdrawals only allowed if true bool isConfirmed; // Timestamp as ms since Unix epoch when isConfirmed was asserted uint64 confirmedTimestampInMs; } /** * @notice Argument type for `Exchange.executeTrade` specifying execution parameters for matching orders */ struct Trade { // Base asset symbol string baseAssetSymbol; // Quote asset symbol string quoteAssetSymbol; // Base asset address address baseAssetAddress; // Quote asset address address quoteAssetAddress; // Gross amount including fees of base asset executed uint64 grossBaseQuantityInPips; // Gross amount including fees of quote asset executed uint64 grossQuoteQuantityInPips; // Net amount of base asset received by buy side wallet after fees uint64 netBaseQuantityInPips; // Net amount of quote asset received by sell side wallet after fees uint64 netQuoteQuantityInPips; // Asset address for liquidity maker's fee address makerFeeAssetAddress; // Asset address for liquidity taker's fee address takerFeeAssetAddress; // Fee paid by liquidity maker uint64 makerFeeQuantityInPips; // Fee paid by liquidity taker uint64 takerFeeQuantityInPips; // Execution price of trade in decimal pips * 10^8 in quote terms uint64 priceInPips; // Which side of the order (buy or sell) the liquidity maker was on Enums.OrderSide makerSide; } /** * @notice Argument type for `Exchange.withdraw` and `Signatures.getWithdrawalWalletHash` */ struct Withdrawal { // Distinguishes between withdrawals by asset symbol or address Enums.WithdrawalType withdrawalType; // UUIDv1 unique to wallet uint128 nonce; // Address of wallet to which funds will be returned address payable walletAddress; // Asset symbol string assetSymbol; // Asset address address assetAddress; // Used when assetSymbol not specified // Withdrawal quantity uint64 quantityInPips; // Gas fee deducted from withdrawn quantity to cover dispatcher tx costs uint64 gasFeeInPips; // Not currently used but reserved for future use. Must be true bool autoDispatchEnabled; // The ECDSA signature of the withdrawal hash as produced by Signatures.getWithdrawalWalletHash bytes walletSignature; } } /** * @notice Interface of the ERC20 standard as defined in the EIP, but with no return values for * transfer and transferFrom. By asserting expected balance changes when calling these two methods * we can safely ignore their return values. This allows support of non-compliant tokens that do not * return a boolean. See https://github.com/ethereum/solidity/issues/4116 */ interface IERC20 { /** * @notice Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @notice Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @notice Moves `amount` tokens from the caller's account to `recipient`. * * Most implementing contracts return a boolean value indicating whether the operation succeeded, but * we ignore this and rely on asserting balance changes instead * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external; /** * @notice Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @notice Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @notice Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Most implementing contracts return a boolean value indicating whether the operation succeeded, but * we ignore this and rely on asserting balance changes instead * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external; /** * @notice Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @notice Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } /** * @notice Interface to Custodian contract. Used by Exchange and Governance contracts for internal * delegate calls */ interface ICustodian { /** * @notice ETH can only be sent by the Exchange */ receive() external payable; /** * @notice Withdraw any asset and amount to a target wallet * * @dev No balance checking performed * * @param wallet The wallet to which assets will be returned * @param asset The address of the asset to withdraw (ETH or ERC-20 contract) * @param quantityInAssetUnits The quantity in asset units to withdraw */ function withdraw( address payable wallet, address asset, uint256 quantityInAssetUnits ) external; /** * @notice Load address of the currently whitelisted Exchange contract * * @return The address of the currently whitelisted Exchange contract */ function loadExchange() external view returns (address); /** * @notice Sets a new Exchange contract address * * @param newExchange The address of the new whitelisted Exchange contract */ function setExchange(address newExchange) external; /** * @notice Load address of the currently whitelisted Governance contract * * @return The address of the currently whitelisted Governance contract */ function loadGovernance() external view returns (address); /** * @notice Sets a new Governance contract address * * @param newGovernance The address of the new whitelisted Governance contract */ function setGovernance(address newGovernance) external; } /** * @notice Interface to Exchange contract. Provided only to document struct usage */ interface IExchange { /** * @notice Settles a trade between two orders submitted and matched off-chain * * @param buy A `Structs.Order` struct encoding the parameters of the buy-side order (receiving base, giving quote) * @param sell A `Structs.Order` struct encoding the parameters of the sell-side order (giving base, receiving quote) * @param trade A `Structs.Trade` struct encoding the parameters of this trade execution of the counterparty orders */ function executeTrade( Structs.Order calldata buy, Structs.Order calldata sell, Structs.Trade calldata trade ) external; /** * @notice Settles a user withdrawal submitted off-chain. Calls restricted to currently whitelisted Dispatcher wallet * * @param withdrawal A `Structs.Withdrawal` struct encoding the parameters of the withdrawal */ function withdraw(Structs.Withdrawal calldata withdrawal) external; }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.6.8; /** * @notice Mixin that provide separate owner and admin roles for RBAC */ abstract contract Owned { address immutable _owner; address _admin; modifier onlyOwner { require(msg.sender == _owner, 'Caller must be owner'); _; } modifier onlyAdmin { require(msg.sender == _admin, 'Caller must be admin'); _; } /** * @notice Sets both the owner and admin roles to the contract creator */ constructor() public { _owner = msg.sender; _admin = msg.sender; } /** * @notice Sets a new whitelisted admin wallet * * @param newAdmin The new whitelisted admin wallet. Must be different from the current one */ function setAdmin(address newAdmin) external onlyOwner { require(newAdmin != address(0x0), 'Invalid wallet address'); require(newAdmin != _admin, 'Must be different from current admin'); _admin = newAdmin; } /** * @notice Clears the currently whitelisted admin wallet, effectively disabling any functions requiring * the admin role */ function removeAdmin() external onlyOwner { _admin = address(0x0); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.8; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.6.8; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath64 { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint64 a, uint64 b) internal pure returns (uint64) { uint64 c = a + b; require(c >= a, 'SafeMath: addition overflow'); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint64 a, uint64 b) internal pure returns (uint64) { return sub(a, b, 'SafeMath: subtraction overflow'); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub( uint64 a, uint64 b, string memory errorMessage ) internal pure returns (uint64) { require(b <= a, errorMessage); uint64 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint64 a, uint64 b) internal pure returns (uint64) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint64 c = a * b; require(c / a == b, 'SafeMath: multiplication overflow'); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint64 a, uint64 b) internal pure returns (uint64) { return div(a, b, 'SafeMath: division by zero'); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div( uint64 a, uint64 b, string memory errorMessage ) internal pure returns (uint64) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint64 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.6.8; pragma experimental ABIEncoderV2; import { ECDSA } from './ECDSA.sol'; import { Enums, Structs } from './Interfaces.sol'; /** * Library helpers for building hashes and verifying wallet signatures on `Order` and `Withdrawal` structs */ library Signatures { function isSignatureValid( bytes32 hash, bytes memory signature, address signer ) internal pure returns (bool) { return ECDSA.recover(ECDSA.toEthSignedMessageHash(hash), signature) == signer; } function getOrderWalletHash( Structs.Order memory order, string memory baseSymbol, string memory quoteSymbol ) internal pure returns (bytes32) { require( order.signatureHashVersion == 1, 'Signature hash version must be 1' ); return keccak256( // Placing all the fields in a single `abi.encodePacked` call causes a `stack too deep` error abi.encodePacked( abi.encodePacked( order.signatureHashVersion, order.nonce, order.walletAddress, getMarketSymbol(baseSymbol, quoteSymbol), uint8(order.orderType), uint8(order.side), // Ledger qtys and prices are in pip, but order was signed by wallet owner with decimal values pipToDecimal(order.quantityInPips) ), abi.encodePacked( order.isQuantityInQuote, order.limitPriceInPips > 0 ? pipToDecimal(order.limitPriceInPips) : '', order.stopPriceInPips > 0 ? pipToDecimal(order.stopPriceInPips) : '', order.clientOrderId, uint8(order.timeInForce), uint8(order.selfTradePrevention), order.cancelAfter ) ) ); } function getWithdrawalWalletHash(Structs.Withdrawal memory withdrawal) internal pure returns (bytes32) { return keccak256( abi.encodePacked( withdrawal.nonce, withdrawal.walletAddress, // Ternary branches must resolve to the same type, so wrap in idempotent encodePacked withdrawal.withdrawalType == Enums.WithdrawalType.BySymbol ? abi.encodePacked(withdrawal.assetSymbol) : abi.encodePacked(withdrawal.assetAddress), pipToDecimal(withdrawal.quantityInPips), withdrawal.autoDispatchEnabled ) ); } /** * @dev Combines base and quote asset symbols into the market symbol originally signed by the * wallet. For example if base is 'IDEX' and quote is 'ETH', the resulting market symbol is * 'IDEX-ETH'. This approach is used rather than passing in the market symbol and splitting it * since the latter incurs a higher gas cost */ function getMarketSymbol(string memory baseSymbol, string memory quoteSymbol) private pure returns (string memory) { bytes memory baseSymbolBytes = bytes(baseSymbol); bytes memory hyphenBytes = bytes('-'); bytes memory quoteSymbolBytes = bytes(quoteSymbol); bytes memory marketSymbolBytes = bytes( new string( baseSymbolBytes.length + quoteSymbolBytes.length + hyphenBytes.length ) ); uint256 i; uint256 j; for (i = 0; i < baseSymbolBytes.length; i++) { marketSymbolBytes[j++] = baseSymbolBytes[i]; } // Hyphen is one byte marketSymbolBytes[j++] = hyphenBytes[0]; for (i = 0; i < quoteSymbolBytes.length; i++) { marketSymbolBytes[j++] = quoteSymbolBytes[i]; } return string(marketSymbolBytes); } /** * @dev Converts an integer pip quantity back into the fixed-precision decimal pip string * originally signed by the wallet. For example, 1234567890 becomes '12.34567890' */ function pipToDecimal(uint256 pips) private pure returns (string memory) { // Inspired by https://github.com/provable-things/ethereum-api/blob/831f4123816f7a3e57ebea171a3cdcf3b528e475/oraclizeAPI_0.5.sol#L1045-L1062 uint256 copy = pips; uint256 length; while (copy != 0) { length++; copy /= 10; } if (length < 9) { length = 9; // a zero before the decimal point plus 8 decimals } length++; // for the decimal point bytes memory decimal = new bytes(length); for (uint256 i = length; i > 0; i--) { if (length - i == 8) { decimal[i - 1] = bytes1(uint8(46)); // period } else { decimal[i - 1] = bytes1(uint8(48 + (pips % 10))); pips /= 10; } } return string(decimal); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.6.8; import { SafeMath64 } from './SafeMath64.sol'; /** * Library helper for extracting timestamp component of Version 1 UUIDs */ library UUID { using SafeMath64 for uint64; /** * Extracts the timestamp component of a Version 1 UUID. Used to make time-based assertions * against a wallet-privided nonce */ function getTimestampInMsFromUuidV1(uint128 uuid) internal pure returns (uint64 msSinceUnixEpoch) { // https://tools.ietf.org/html/rfc4122#section-4.1.2 uint128 version = (uuid >> 76) & 0x0000000000000000000000000000000F; require(version == 1, 'Must be v1 UUID'); // Time components are in reverse order so shift+mask each to reassemble uint128 timeHigh = (uuid >> 16) & 0x00000000000000000FFF000000000000; uint128 timeMid = (uuid >> 48) & 0x00000000000000000000FFFF00000000; uint128 timeLow = (uuid >> 96) & 0x000000000000000000000000FFFFFFFF; uint128 nsSinceGregorianEpoch = (timeHigh | timeMid | timeLow); // Gregorian offset given in seconds by https://www.wolframalpha.com/input/?i=convert+1582-10-15+UTC+to+unix+time msSinceUnixEpoch = uint64(nsSinceGregorianEpoch / 10000).sub( 12219292800000 ); return msSinceUnixEpoch; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"ChainPropagationPeriodChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"index","type":"uint64"},{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":true,"internalType":"string","name":"assetSymbolIndex","type":"string"},{"indexed":false,"internalType":"string","name":"assetSymbol","type":"string"},{"indexed":false,"internalType":"uint64","name":"quantityInPips","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newExchangeBalanceInPips","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"newExchangeBalanceInAssetUnits","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"DispatcherChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"FeeWalletChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint128","name":"nonce","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"timestampInMs","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"effectiveBlockNumber","type":"uint256"}],"name":"OrderNonceInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"assetAddress","type":"address"},{"indexed":false,"internalType":"string","name":"assetSymbol","type":"string"},{"indexed":false,"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"TokenRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"assetAddress","type":"address"},{"indexed":false,"internalType":"string","name":"assetSymbol","type":"string"},{"indexed":false,"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"TokenRegistrationConfirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"assetAddress","type":"address"},{"indexed":false,"internalType":"string","name":"assetSymbol","type":"string"}],"name":"TokenSymbolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"buyWallet","type":"address"},{"indexed":false,"internalType":"address","name":"sellWallet","type":"address"},{"indexed":true,"internalType":"string","name":"baseAssetSymbolIndex","type":"string"},{"indexed":true,"internalType":"string","name":"quoteAssetSymbolIndex","type":"string"},{"indexed":false,"internalType":"string","name":"baseAssetSymbol","type":"string"},{"indexed":false,"internalType":"string","name":"quoteAssetSymbol","type":"string"},{"indexed":false,"internalType":"uint64","name":"baseQuantityInPips","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"quoteQuantityInPips","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"tradePriceInPips","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"buyOrderHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"sellOrderHash","type":"bytes32"}],"name":"TradeExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"WalletExitCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":false,"internalType":"string","name":"assetSymbol","type":"string"},{"indexed":false,"internalType":"uint64","name":"quantityInPips","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newExchangeBalanceInPips","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"newExchangeBalanceInAssetUnits","type":"uint256"}],"name":"WalletExitWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"effectiveBlockNumber","type":"uint256"}],"name":"WalletExited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":false,"internalType":"string","name":"assetSymbol","type":"string"},{"indexed":false,"internalType":"uint64","name":"quantityInPips","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newExchangeBalanceInPips","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"newExchangeBalanceInAssetUnits","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"contract IERC20","name":"tokenAddress","type":"address"},{"internalType":"string","name":"symbol","type":"string"}],"name":"addTokenSymbol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"clearWalletExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenAddress","type":"address"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"confirmTokenRegistration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositEther","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"quantityInAssetUnits","type":"uint256"}],"name":"depositTokenByAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"assetSymbol","type":"string"},{"internalType":"uint256","name":"quantityInAssetUnits","type":"uint256"}],"name":"depositTokenBySymbol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"signatureHashVersion","type":"uint8"},{"internalType":"uint128","name":"nonce","type":"uint128"},{"internalType":"address","name":"walletAddress","type":"address"},{"internalType":"enum Enums.OrderType","name":"orderType","type":"uint8"},{"internalType":"enum Enums.OrderSide","name":"side","type":"uint8"},{"internalType":"uint64","name":"quantityInPips","type":"uint64"},{"internalType":"bool","name":"isQuantityInQuote","type":"bool"},{"internalType":"uint64","name":"limitPriceInPips","type":"uint64"},{"internalType":"uint64","name":"stopPriceInPips","type":"uint64"},{"internalType":"string","name":"clientOrderId","type":"string"},{"internalType":"enum Enums.OrderTimeInForce","name":"timeInForce","type":"uint8"},{"internalType":"enum Enums.OrderSelfTradePrevention","name":"selfTradePrevention","type":"uint8"},{"internalType":"uint64","name":"cancelAfter","type":"uint64"},{"internalType":"bytes","name":"walletSignature","type":"bytes"}],"internalType":"struct Structs.Order","name":"buy","type":"tuple"},{"components":[{"internalType":"uint8","name":"signatureHashVersion","type":"uint8"},{"internalType":"uint128","name":"nonce","type":"uint128"},{"internalType":"address","name":"walletAddress","type":"address"},{"internalType":"enum Enums.OrderType","name":"orderType","type":"uint8"},{"internalType":"enum Enums.OrderSide","name":"side","type":"uint8"},{"internalType":"uint64","name":"quantityInPips","type":"uint64"},{"internalType":"bool","name":"isQuantityInQuote","type":"bool"},{"internalType":"uint64","name":"limitPriceInPips","type":"uint64"},{"internalType":"uint64","name":"stopPriceInPips","type":"uint64"},{"internalType":"string","name":"clientOrderId","type":"string"},{"internalType":"enum Enums.OrderTimeInForce","name":"timeInForce","type":"uint8"},{"internalType":"enum Enums.OrderSelfTradePrevention","name":"selfTradePrevention","type":"uint8"},{"internalType":"uint64","name":"cancelAfter","type":"uint64"},{"internalType":"bytes","name":"walletSignature","type":"bytes"}],"internalType":"struct Structs.Order","name":"sell","type":"tuple"},{"components":[{"internalType":"string","name":"baseAssetSymbol","type":"string"},{"internalType":"string","name":"quoteAssetSymbol","type":"string"},{"internalType":"address","name":"baseAssetAddress","type":"address"},{"internalType":"address","name":"quoteAssetAddress","type":"address"},{"internalType":"uint64","name":"grossBaseQuantityInPips","type":"uint64"},{"internalType":"uint64","name":"grossQuoteQuantityInPips","type":"uint64"},{"internalType":"uint64","name":"netBaseQuantityInPips","type":"uint64"},{"internalType":"uint64","name":"netQuoteQuantityInPips","type":"uint64"},{"internalType":"address","name":"makerFeeAssetAddress","type":"address"},{"internalType":"address","name":"takerFeeAssetAddress","type":"address"},{"internalType":"uint64","name":"makerFeeQuantityInPips","type":"uint64"},{"internalType":"uint64","name":"takerFeeQuantityInPips","type":"uint64"},{"internalType":"uint64","name":"priceInPips","type":"uint64"},{"internalType":"enum Enums.OrderSide","name":"makerSide","type":"uint8"}],"internalType":"struct Structs.Trade","name":"trade","type":"tuple"}],"name":"executeTrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exitWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"nonce","type":"uint128"}],"name":"invalidateOrderNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"assetSymbol","type":"string"},{"internalType":"uint64","name":"timestampInMs","type":"uint64"}],"name":"loadAssetBySymbol","outputs":[{"components":[{"internalType":"bool","name":"exists","type":"bool"},{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"bool","name":"isConfirmed","type":"bool"},{"internalType":"uint64","name":"confirmedTimestampInMs","type":"uint64"}],"internalType":"struct Structs.Asset","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"assetAddress","type":"address"}],"name":"loadBalanceInAssetUnitsByAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"string","name":"assetSymbol","type":"string"}],"name":"loadBalanceInAssetUnitsBySymbol","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"assetAddress","type":"address"}],"name":"loadBalanceInPipsByAddress","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"string","name":"assetSymbol","type":"string"}],"name":"loadBalanceInPipsBySymbol","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"loadFeeWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"loadPartiallyFilledOrderQuantityInPips","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenAddress","type":"address"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"registerToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"removeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"removeDispatcher","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainPropagationPeriod","type":"uint256"}],"name":"setChainPropagationPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newCustodian","type":"address"}],"name":"setCustodian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newDispatcherWallet","type":"address"}],"name":"setDispatcher","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeWallet","type":"address"}],"name":"setFeeWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum Enums.WithdrawalType","name":"withdrawalType","type":"uint8"},{"internalType":"uint128","name":"nonce","type":"uint128"},{"internalType":"address payable","name":"walletAddress","type":"address"},{"internalType":"string","name":"assetSymbol","type":"string"},{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"uint64","name":"quantityInPips","type":"uint64"},{"internalType":"uint64","name":"gasFeeInPips","type":"uint64"},{"internalType":"bool","name":"autoDispatchEnabled","type":"bool"},{"internalType":"bytes","name":"walletSignature","type":"bytes"}],"internalType":"struct Structs.Withdrawal","name":"withdrawal","type":"tuple"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"}],"name":"withdrawExit","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a060405234801561001057600080fd5b5033606081901b608052600080546001600160a01b03191682178155615ff99062000049903980610f2952806113685250615ff96000f3fe6080604052600436106101415760003560e01c806372e8f08d116100b157806372e8f08d146102ea578063869af2121461030a57806390d49b9d14610337578063985c4af51461035757806398ea5fca146103775780639a202d471461037f578063ae0e969e14610394578063ba22bd76146103c1578063d7a6aec7146103e1578063dbb3653514610401578063dcc6349014610421578063eb5068f214610441578063ef3b9d4a1461045657610141565b80630226b70e1461014657806302ca6002146101685780630c187a721461019357806313cfda2c146101a85780631abb5832146101d557806320e6a8e3146101f5578063403f3731146102155780634196818214610235578063457aa3c6146102555780634a284ef91461027557806365fce5b71461028a5780636bb509f2146102aa578063704b6c02146102ca575b600080fd5b34801561015257600080fd5b50610166610161366004614559565b610476565b005b34801561017457600080fd5b5061017d610540565b60405161018a9190614c10565b60405180910390f35b34801561019f57600080fd5b50610166610550565b3480156101b457600080fd5b506101c86101c33660046144b7565b6105d4565b60405161018a9190615ea2565b3480156101e157600080fd5b506101c86101f03660046144ef565b610662565b34801561020157600080fd5b50610166610210366004614541565b610736565b34801561022157600080fd5b5061016661023036600461449b565b6107c7565b34801561024157600080fd5b506101666102503660046145e9565b610861565b34801561026157600080fd5b50610166610270366004614559565b6108e3565b34801561028157600080fd5b50610166610996565b34801561029657600080fd5b506101666102a536600461468d565b610a0a565b3480156102b657600080fd5b506101666102c5366004614850565b610bb1565b3480156102d657600080fd5b506101666102e536600461449b565b610f1e565b3480156102f657600080fd5b506101666103053660046144ef565b610fdc565b34801561031657600080fd5b5061032a610325366004614632565b611099565b60405161018a9190615e07565b34801561034357600080fd5b5061016661035236600461449b565b6110f3565b34801561036357600080fd5b5061016661037236600461449b565b6111c4565b61016661134f565b34801561038b57600080fd5b5061016661135d565b3480156103a057600080fd5b506103b46103af366004614541565b6113b7565b60405161018a9190615eb9565b3480156103cd57600080fd5b506101666103dc36600461449b565b6113d5565b3480156103ed57600080fd5b506101666103fc366004614962565b6114a6565b34801561040d57600080fd5b506103b461041c3660046144b7565b61161e565b34801561042d57600080fd5b5061016661043c3660046145be565b61167b565b34801561044d57600080fd5b506101666116b0565b34801561046257600080fd5b506103b46104713660046144ef565b611762565b6000546001600160a01b031633146104a95760405162461bcd60e51b81526004016104a0906159ba565b60405180910390fd5b6104f58484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001949392508691505063ffffffff61180c16565b836001600160a01b03167fa8968236dc4afb2c189afeb69c91b02445e6bd09f0ffe27256b62838edc99edb84848460405161053293929190614d25565b60405180910390a250505050565b600c546001600160a01b03165b90565b6000546001600160a01b0316331461057a5760405162461bcd60e51b81526004016104a0906159ba565b600b546040517fddb86df2d5262dd7b44067db5962cc7875e9db409cb21c88adfe3c5760315e39916105ba916001600160a01b0390911690600090614c61565b60405180910390a1600b80546001600160a01b0319169055565b60006001600160a01b0383166105fc5760405162461bcd60e51b81526004016104a090615c07565b610604614140565b61061560018463ffffffff611b6216565b6001600160a01b038086166000908152600660209081526040808320938816835292905220546060820151919250610658916001600160401b0390911690611cbb565b9150505b92915050565b60006001600160a01b03841661068a5760405162461bcd60e51b81526004016104a090615c07565b610692614140565b6106e484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506106d59250611d33915050565b6001919063ffffffff611d3b16565b6001600160a01b0380871660009081526006602090815260408083208286015190941683529290522054606082015191925061072b916001600160401b0390911690611cbb565b9150505b9392505050565b6000546001600160a01b031633146107605760405162461bcd60e51b81526004016104a0906159ba565b619d8081106107815760405162461bcd60e51b81526004016104a0906155ab565b600a8054908290556040517f9a22227d6c0251a79ef8b846202ddcbe9d682ee5482e84abeec6dda096398a6f906107bb9083908590615eab565b60405180910390a15050565b6000546001600160a01b031633146107f15760405162461bcd60e51b81526004016104a0906159ba565b6005546001600160a01b03161561081a5760405162461bcd60e51b81526004016104a0906157f0565b61082381611fa5565b61083f5760405162461bcd60e51b81526004016104a090614ee0565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b60006108a684848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506106d59250611d33915050565b6020015190506001600160a01b0381166108d25760405162461bcd60e51b81526004016104a090615574565b6108dd338284611fab565b50505050565b6000546001600160a01b0316331461090d5760405162461bcd60e51b81526004016104a0906159ba565b6109598484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001949392508691505063ffffffff6121d016565b836001600160a01b03167fcf66acda7673c71cd9458c59067eb30a473eeaf2fa05d008acf47616cbbbe01c84848460405161053293929190614d25565b3360009081526009602052604090205460ff166109c55760405162461bcd60e51b81526004016104a090615bdc565b33600081815260096020526040808220805460ff19168155600101829055517fb771d4b2a83beca38f442c8903629e0e8ab1a07cf76e94eb2977153167e209369190a2565b600b546001600160a01b03163314610a345760405162461bcd60e51b81526004016104a090614df9565b610a41836040015161237a565b15610a5e5760405162461bcd60e51b81526004016104a090615cf0565b610a6b826040015161237a565b15610a885760405162461bcd60e51b81526004016104a0906150fd565b81604001516001600160a01b031683604001516001600160a01b03161415610ac25760405162461bcd60e51b81526004016104a090615455565b610acd8383836123ab565b610ad8838383612620565b610ae28383612731565b600080610af08585856127c3565b91509150610afd836127ee565b610b0a85838684876129e8565b610b15858585612a05565b8260200151604051610b279190614ac2565b60405190819003812084519091610b3e9190614ac2565b60405180910390207fbd75b2e24c3d43ec9f10f3583265606c0a7d8b67d147f9dc48376b81456823a1876040015187604001518760000151886020015189608001518a60a001518b61018001518b8b604051610ba299989796959493929190614c7b565b60405180910390a35050505050565b600b546001600160a01b03163314610bdb5760405162461bcd60e51b81526004016104a090614df9565b610be8816040015161237a565b15610c055760405162461bcd60e51b81526004016104a090615d6b565b6107d06001600160401b0316610c238260c001518360a00151612cff565b6001600160401b03161115610c4a5760405162461bcd60e51b81526004016104a0906156cf565b6000610c5582612d36565b60008181526004602052604090205490915060ff1615610c875760405162461bcd60e51b81526004016104a090615827565b610c8f614140565b600083516001811115610c9e57fe5b14610cbf576080830151610cba9060019063ffffffff611b6216565b610cd4565b610cd483606001516106d58560200151612d74565b90506000610cfc8460c001518560a001516001600160401b0316612e0190919063ffffffff16565b90506000610d0e828460600151611cbb565b60a08601516040808801516001600160a01b03908116600090815260066020908152838220898201519093168252919091529081205492935091610d63916001600160401b039091169063ffffffff612e0116565b90506000610d75828660600151611cbb565b6040888101516001600160a01b039081166000908152600660208181528483208b820180518616855290825285842080546001600160401b0319166001600160401b038b81169190911790915560c08f0151600c548716865293835286852091519095168452905292902054929350610def921690612e43565b600c546001600160a01b0390811660009081526006602090815260408083208a830180518616855292529182902080546001600160401b0319166001600160401b0395909516949094179093556005548a82015193519151636ce5768960e11b815292169263d9caed1292610e6992908890600401614c24565b600060405180830381600087803b158015610e8357600080fd5b505af1158015610e97573d6000803e3d6000fd5b505050600087815260046020908152604091829020805460ff19166001179055870151898201518883015160a08c015193516001600160a01b03938416955091909216927f6960a1f64ecf9da0d1d1bcbfa3dd27f8c1c60de69b13faa28127dafa36c111e492610f0d9290919088908890614d5f565b60405180910390a350505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f665760405162461bcd60e51b81526004016104a090615779565b6001600160a01b038116610f8c5760405162461bcd60e51b81526004016104a090615c07565b6000546001600160a01b0382811691161415610fba5760405162461bcd60e51b81526004016104a09061502e565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146110065760405162461bcd60e51b81526004016104a0906159ba565b6110518383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001949392505063ffffffff612e74169050565b826001600160a01b03167f7f63a63f4a2ea318da0b031794d0b5a3183a1b2de54e053ceb17cabdba031735838360405161108c929190614d11565b60405180910390a2505050565b6110a1614140565b6110eb84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019392508691505063ffffffff611d3b16565b949350505050565b6000546001600160a01b0316331461111d5760405162461bcd60e51b81526004016104a0906159ba565b6001600160a01b0381166111435760405162461bcd60e51b81526004016104a090615c07565b600c546001600160a01b03828116911614156111715760405162461bcd60e51b81526004016104a0906157a7565b600c80546001600160a01b038381166001600160a01b03198316179092556040519116907f9f4f5dce3c4d197b5d7496cb96e25f0a89809167195964b0daa3ef5fed63c00a906107bb9083908590614c61565b6111cd3361237a565b6111e95760405162461bcd60e51b81526004016104a0906153f3565b6111f1614140565b61120260018363ffffffff611b6216565b3360009081526006602090815260408083206001600160a01b038716845290915281205460608301519293506001600160401b031691611243908390611cbb565b9050600081116112655760405162461bcd60e51b81526004016104a090615d92565b3360008181526006602090815260408083206001600160a01b03898116855292529182902080546001600160401b03191690556005549151636ce5768960e11b815291169163d9caed12916112c1919088908690600401614c24565b600060405180830381600087803b1580156112db57600080fd5b505af11580156112ef573d6000803e3d6000fd5b50505050836001600160a01b0316336001600160a01b03167f02e03f232c88c87047c5a9cfbad1213b842503fee6a002ec2eec9f5a64725bf48560400151856000806040516113419493929190614d5f565b60405180910390a350505050565b61135b33600034611fab565b565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146113a55760405162461bcd60e51b81526004016104a090615779565b600080546001600160a01b0319169055565b6000818152600860205260409020546001600160401b03165b919050565b6000546001600160a01b031633146113ff5760405162461bcd60e51b81526004016104a0906159ba565b6001600160a01b0381166114255760405162461bcd60e51b81526004016104a090615c07565b600b546001600160a01b03828116911614156114535760405162461bcd60e51b81526004016104a090615888565b600b80546001600160a01b038381166001600160a01b03198316179092556040519116907fddb86df2d5262dd7b44067db5962cc7875e9db409cb21c88adfe3c5760315e39906107bb9083908590614c61565b60006114b182612d74565b90506114bb613089565b6001600160401b0316816001600160401b0316106114eb5760405162461bcd60e51b81526004016104a0906153b2565b3360009081526007602052604090205460ff161561157457336000908152600760205260409020546001600160401b0380831661010090920416106115425760405162461bcd60e51b81526004016104a090614e9d565b336000908152600760205260409020600101544310156115745760405162461bcd60e51b81526004016104a090615adf565b600a546040805160608101825260018082526001600160401b0385811660208085019182524390960184860181815233600081815260079099529787902095518654935160ff199094169015151768ffffffffffffffff001916610100939094169290920292909217845551929091019190915590519091907f10cf19671b43c88b1f02d4e94932d7ffaa89c7278bc5b8868fa7b7676210809b9061108c90869086908690615e78565b60006001600160a01b0383166116465760405162461bcd60e51b81526004016104a090615c07565b506001600160a01b0391821660009081526006602090815260408083209390941682529190915220546001600160401b031690565b6001600160a01b0382166116a15760405162461bcd60e51b81526004016104a090615738565b6116ac338383611fab565b5050565b3360009081526009602052604090205460ff16156116e05760405162461bcd60e51b81526004016104a090615503565b6040805180820182526001808252600a80544390810160208086019182523360008181526009909252908790209551865460ff19169015151786559051949093019390935554925190927fd60f9f7b2f1a208268475a927bd727c4e198fc8b40aab3004ebcc2bc78ca84809261175892910190615ea2565b60405180910390a2565b60006001600160a01b03841661178a5760405162461bcd60e51b81526004016104a090615c07565b60006117cf84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506106d59250611d33915050565b6020908101516001600160a01b03808816600090815260068452604080822092909316815292529020546001600160401b03169150509392505050565b611814614140565b6001600160a01b0384811660009081526020878152604091829020825160c081018452815460ff8116151582526101009081900490951681840152600180830180548651600293821615909802600019011691909104601f81018590048502870185018652808752919592948601939091908301828280156118d75780601f106118ac576101008083540402835291602001916118d7565b820191906000526020600020905b8154815290600101906020018083116118ba57829003601f168201915b50505091835250506002919091015460ff8082166020840152610100820416151560408301526201000090046001600160401b031660609091015280519091506119335760405162461bcd60e51b81526004016104a09061522b565b8060800151156119555760405162461bcd60e51b81526004016104a090615857565b611963816040015184613096565b61197f5760405162461bcd60e51b81526004016104a090614f09565b8160ff16816060015160ff16146119a85760405162461bcd60e51b81526004016104a090615426565b6001608082018190526001600160401b036103e842021660a08301526001600160a01b0380861660009081526020888152604091829020855181548388015190951661010002610100600160a81b031991151560ff1990961695909517169390931783559084015180518594611a2393908501920190614176565b50606082015160029091018054608084015160a0909401516001600160401b0316620100000262010000600160501b03199415156101000261ff001960ff90951660ff19909316929092179390931617929092161790556040516001860190611a8d908590614ac2565b9081526040805191829003602090810190922080546001818101835560009283529184902085516003909202018054868601516001600160a01b031661010002610100600160a81b031993151560ff1990921691909117929092169190911781559184015180518594611b04938501920190614176565b50606082015160029091018054608084015160a0909401516001600160401b0316620100000262010000600160501b03199415156101000261ff001960ff90951660ff19909316929092179390931617929092161790555050505050565b611b6a614140565b6001600160a01b038216611b8757611b806130ef565b905061065c565b611b8f614140565b6001600160a01b0383811660009081526020868152604091829020825160c081018452815460ff8116151582526101009081900490951681840152600180830180548651600293821615909802600019011691909104601f8101859004850287018501865280875291959294860193909190830182828015611c525780601f10611c2757610100808354040283529160200191611c52565b820191906000526020600020905b815481529060010190602001808311611c3557829003601f168201915b50505091835250506002919091015460ff8082166020840152610100820416151560408301526201000090046001600160401b031660609091015280519091508015611c9f575080608001515b61072f5760405162461bcd60e51b81526004016104a090615976565b600060208260ff161115611ce15760405162461bcd60e51b81526004016104a090615a15565b60088260ff161115611d1057611b806001600160401b03841660ff600719850116600a0a63ffffffff61314816565b61072f6001600160401b03841660ff600885900316600a0a63ffffffff61318216565b426103e80290565b611d43614140565b611d686040518060400160405280600381526020016208aa8960eb1b81525084613096565b15611d7c57611d756130ef565b905061072f565b611d84614140565b60008560010185604051611d989190614ac2565b908152604051908190036020019020541115611f7a5760005b8560010185604051611dc39190614ac2565b9081526040519081900360200190205460ff82161015611f7857836001600160401b03168660010186604051611df99190614ac2565b90815260200160405180910390208260ff1681548110611e1557fe5b60009182526020909120600390910201600201546201000090046001600160401b031611611f70578560010185604051611e4f9190614ac2565b90815260200160405180910390208160ff1681548110611e6b57fe5b60009182526020918290206040805160c081018252600393909302909101805460ff811615158452610100908190046001600160a01b031684860152600180830180548551600293821615909402600019011691909104601f8101879004870283018701855280835294959294938601939192909190830182828015611f325780601f10611f0757610100808354040283529160200191611f32565b820191906000526020600020905b815481529060010190602001808311611f1557829003601f168201915b50505091835250506002919091015460ff8082166020840152610100820416151560408301526201000090046001600160401b031660609091015291505b600101611db1565b505b80518015611f89575080608001515b6110eb5760405162461bcd60e51b81526004016104a090615621565b3b151590565b6001600160a01b03831660009081526009602052604090205460ff1615611fe45760405162461bcd60e51b81526004016104a090615d6b565b611fec614140565b611ffd60018463ffffffff611b6216565b9050600061200f8383606001516131c1565b90506000816001600160401b03161161203a5760405162461bcd60e51b81526004016104a090615168565b600061204a828460600151611cbb565b90506001600160a01b0385161561206657612066868683613256565b60055461207d906001600160a01b031686836133e9565b6001600160a01b0380871660009081526006602090815260408083209389168352929052908120546120be906001600160401b03168463ffffffff612e4316565b905060006120d0828660600151611cbb565b6001600160a01b038981166000908152600660209081526040808320938c16835292905281902080546001600160401b0319166001600160401b03868116919091179091556005805467ffffffffffffffff60a01b198116600160a01b9182900484166001019093160291909117905586810151905191925061215291614ac2565b6040518091039020876001600160a01b0316896001600160a01b03167fc2813a84168de59cf710030ba2acb13031b567b8ba76f70e8ab0782aa9469a7a600560149054906101000a90046001600160401b031689604001518988886040516121be959493929190615ecd565b60405180910390a45050505050505050565b60208160ff1611156121f45760405162461bcd60e51b81526004016104a09061536b565b6001600160a01b03831615801590612210575061221083611fa5565b61222c5760405162461bcd60e51b81526004016104a090615ab0565b600082511161224d5760405162461bcd60e51b81526004016104a090615bae565b6001600160a01b038316600090815260208590526040902060020154610100900460ff161561228e5760405162461bcd60e51b81526004016104a090615857565b6040805160c08101825260018082526001600160a01b03868116602080850182815285870189815260ff8916606088015260006080880181905260a088018190529384528b83529690922085518154935160ff1990941690151517610100600160a81b03191661010093909416929092029290921781559351805193949361231d938501929190910190614176565b50606082015160029091018054608084015160a0909401516001600160401b0316620100000262010000600160501b03199415156101000261ff001960ff90951660ff199093169290921793909316179290921617905550505050565b6001600160a01b0381166000908152600960205260408120805460ff16801561072f57506001015443101592915050565b80606001516001600160a01b031681604001516001600160a01b031614156123e55760405162461bcd60e51b81526004016104a090615487565b6123ed614140565b61240282600001516106d58660200151612d74565b905061240c614140565b61242183602001516106d58760200151612d74565b905082604001516001600160a01b031682602001516001600160a01b0316148015612465575082606001516001600160a01b031681602001516001600160a01b0316145b6124815760405162461bcd60e51b81526004016104a090615195565b612489614140565b61249e84600001516106d58760200151612d74565b90506124a8614140565b6124bd85602001516106d58860200151612d74565b905084604001516001600160a01b031682602001516001600160a01b0316148015612501575084606001516001600160a01b031681602001516001600160a01b0316145b61251d5760405162461bcd60e51b81526004016104a090615a5c565b84604001516001600160a01b03168561010001516001600160a01b03161480612560575084606001516001600160a01b03168561010001516001600160a01b0316145b61257c5760405162461bcd60e51b81526004016104a090615327565b84604001516001600160a01b03168561012001516001600160a01b031614806125bf575084606001516001600160a01b03168561012001516001600160a01b0316145b6125db5760405162461bcd60e51b81526004016104a0906155dd565b8461012001516001600160a01b03168561010001516001600160a01b031614156126175760405162461bcd60e51b81526004016104a090614fe2565b50505050505050565b600081608001516001600160401b03161161264d5760405162461bcd60e51b81526004016104a090615dc0565b60008160a001516001600160401b03161161267a5760405162461bcd60e51b81526004016104a090615d23565b61268783606001516135ce565b156126d3578060a001516001600160401b03166126ac82608001518560e00151613627565b6001600160401b031610156126d35760405162461bcd60e51b81526004016104a0906158d1565b6126e082606001516135ce565b1561272c578060a001516001600160401b031661270582608001518460e00151613627565b6001600160401b0316111561272c5760405162461bcd60e51b81526004016104a090615b77565b505050565b61273e8260400151613680565b6001600160401b03166127548360200151612d74565b6001600160401b03161161277a5760405162461bcd60e51b81526004016104a090615935565b6127878160400151613680565b6001600160401b031661279d8260200151612d74565b6001600160401b0316116116ac5760405162461bcd60e51b81526004016104a090615252565b60008060006127d286856136fd565b905060006127e086866136fd565b919791965090945050505050565b600081604001516001600160a01b03168261010001516001600160a01b03161461281c578160a00151612822565b81608001515b90506107d06001600160401b031661283f83610140015183612cff565b6001600160401b031611156128665760405162461bcd60e51b81526004016104a09061509b565b600082604001516001600160a01b03168361012001516001600160a01b031614612894578260a0015161289a565b82608001515b90506107d06001600160401b03166128b784610160015183612cff565b6001600160401b031611156128de5760405162461bcd60e51b81526004016104a090614f6e565b82608001516001600160401b031661293d84604001516001600160a01b03168561010001516001600160a01b03161461291c57846101600151612923565b8461014001515b60c08601516001600160401b03169063ffffffff612e4316565b6001600160401b0316146129635760405162461bcd60e51b81526004016104a090614f9b565b8260a001516001600160401b03166129c284606001516001600160a01b03168561010001516001600160a01b0316146129a1578461016001516129a8565b8461014001515b60e08601516001600160401b03169063ffffffff612e4316565b6001600160401b03161461272c5760405162461bcd60e51b81526004016104a090615b2f565b6129f385858361379e565b6129fe83838361379e565b5050505050565b60808101516040808401516001600160a01b03908116600090815260066020908152838220848701519093168252919091522054612a54916001600160401b039091169063ffffffff612e0116565b6040838101516001600160a01b0390811660009081526006602081815284832087860180518616855290825285842080546001600160401b0319166001600160401b0398891617905560c08801518a8701518616855292825285842090519094168352929092529190912054612acb921690612e43565b604084810180516001600160a01b039081166000908152600660208181528583208887015185168452815285832080546001600160401b0319166001600160401b0398891617905560a088015194518416835290815284822060608801519093168252919091529190912054612b42921690612e01565b6040848101516001600160a01b039081166000908152600660208181528483206060880180518616855290825285842080546001600160401b0319166001600160401b0398891617905560e0880151898701518616855292825285842090519094168352929092529190912054612bba921690612e43565b6040838101516001600160a01b03908116600090815260066020818152848320606088015185168452815284832080546001600160401b0319166001600160401b03978816179055610140870151600c54851684529181528483206101008801519094168352929092529190912054612c34921690612e43565b600c80546001600160a01b03908116600090815260066020818152604080842061010089015186168552825280842080546001600160401b0319166001600160401b039889161790556101608801519554851684529181528183206101208801519094168352929092522054612cab921690612e43565b600c546001600160a01b039081166000908152600660209081526040808320610120969096015190931682529390935290912080546001600160401b0319166001600160401b039092169190911790555050565b600061271061065883612d216001600160401b0387168463ffffffff61392216565b6001600160401b03169063ffffffff61397d16565b600080612d42836139bc565b9050612d58818461010001518560400151613a77565b61065c5760405162461bcd60e51b81526004016104a090614dc7565b6000600f604c83901c1660018114612d9e5760405162461bcd60e51b81526004016104a090615072565b610fff60301b601084901c1665ffff00000000603085901c1663ffffffff606086901c168183178117612df6650b1d069b54006127106001600160801b038416046001600160401b0316612e0190919063ffffffff16565b979650505050505050565b600061072f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613aa7565b60008282016001600160401b03808516908216101561072f5760405162461bcd60e51b81526004016104a0906150c8565b612e7c614140565b6001600160a01b0383811660009081526020868152604091829020825160c081018452815460ff8116151582526101009081900490951681840152600180830180548651600293821615909802600019011691909104601f8101859004850287018501865280875291959294860193909190830182828015612f3f5780601f10612f1457610100808354040283529160200191612f3f565b820191906000526020600020905b815481529060010190602001808311612f2257829003601f168201915b50505091835250506002919091015460ff8082166020840152610100820416151560408301526201000090046001600160401b031660609091015280519091508015612f8c575080608001515b612fa85760405162461bcd60e51b81526004016104a0906151e8565b612fcd826040518060400160405280600381526020016208aa8960eb1b815250613096565b15612fea5760405162461bcd60e51b81526004016104a090615131565b426103e89081026001600160401b031660a08301526040516001860190613012908590614ac2565b9081526040805191829003602090810190922080546001818101835560009283529184902086516003909202018054878601516001600160a01b031661010002610100600160a81b031993151560ff1990921691909117929092169190911781559185015180518694611b04938501920190614176565b4262015180016103e80290565b6000816040516020016130a99190614ac2565b60405160208183030381529060405280519060200120836040516020016130d09190614ac2565b6040516020818303038152906040528051906020012014905092915050565b6130f7614140565b506040805160c08101825260018082526000602080840182905284518086018652600381526208aa8960eb1b918101919091529383019390935260126060830152608082015260a081019190915290565b6000826131575750600061065c565b8282028284828161316457fe5b041461072f5760405162461bcd60e51b81526004016104a09061568e565b600061072f83836040518060400160405280601a815260200179536166654d6174683a206469766973696f6e206279207a65726f60301b815250613ae6565b600060208260ff1611156131e75760405162461bcd60e51b81526004016104a090615a15565b600060088360ff1611156132165761320f8460ff600719860116600a0a63ffffffff61318216565b9050613233565b6132308460ff600886900316600a0a63ffffffff61314816565b90505b600160401b811061072f5760405162461bcd60e51b81526004016104a090615701565b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190613285903090600401614c10565b60206040518083038186803b15801561329d57600080fd5b505afa1580156132b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d5919061497d565b6040516323b872dd60e01b81529091506001600160a01b038416906323b872dd9061330890879030908790600401614c24565b600060405180830381600087803b15801561332257600080fd5b505af1158015613336573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03861691506370a0823190613369903090600401614c10565b60206040518083038186803b15801561338157600080fd5b505afa158015613395573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b9919061497d565b9050826133cc828463ffffffff613b1d16565b146129fe5760405162461bcd60e51b81526004016104a090614e2b565b6001600160a01b03821661343d576040516001600160a01b0384169082156108fc029083906000818181858888f193505050506134385760405162461bcd60e51b81526004016104a0906159e8565b61272c565b6040516370a0823160e01b81526000906001600160a01b038416906370a082319061346c908790600401614c10565b60206040518083038186803b15801561348457600080fd5b505afa158015613498573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134bc919061497d565b60405163a9059cbb60e01b81529091506001600160a01b0384169063a9059cbb906134ed9087908690600401614c48565b600060405180830381600087803b15801561350757600080fd5b505af115801561351b573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03861691506370a082319061354e908890600401614c10565b60206040518083038186803b15801561356657600080fd5b505afa15801561357a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061359e919061497d565b9050826135b1828463ffffffff613b1d16565b146129fe5760405162461bcd60e51b81526004016104a090615c82565b600060018260068111156135de57fe5b14806135f5575060028260068111156135f357fe5b145b8061360b5750600482600681111561360957fe5b145b8061065c575060065b82600681111561362057fe5b1492915050565b60006305f5e1008161365b8261364f6001600160401b0388811690881663ffffffff61314816565b9063ffffffff61318216565b9050600160401b81106106585760405162461bcd60e51b81526004016104a090615c37565b6001600160a01b03811660009081526007602052604081205460ff1680156136c357506001600160a01b0382166000908152600760205260409020600101544310155b156136f557506001600160a01b03811660009081526007602052604090205461010090046001600160401b03166113d0565b506000919050565b6000806137138484600001518560200151613b5f565b905061372981856101a001518660400151613a77565b60008560800151600181111561373b57fe5b1461375e57604051806060016040528060278152602001615f9d60279139613778565b604051806060016040528060268152602001615f77602691395b906137965760405162461bcd60e51b81526004016104a09190614d4c565b509392505050565b60008281526003602052604090205460ff16156137cd5760405162461bcd60e51b81526004016104a090615908565b60008360c0015115613839576137e68460600151613d01565b6138025760405162461bcd60e51b81526004016104a090615294565b60008381526008602052604090205460a0830151613832916001600160401b03918216911663ffffffff612e4316565b905061386c565b6000838152600860205260409020546080830151613869916001600160401b03918216911663ffffffff612e4316565b90505b8360a001516001600160401b0316816001600160401b031611156138a25760405162461bcd60e51b81526004016104a090615664565b8360a001516001600160401b0316816001600160401b031610156138ec57600083815260086020526040902080546001600160401b0319166001600160401b0383161790556108dd565b5050600090815260086020908152604080832080546001600160401b031916905560039091529020805460ff1916600117905550565b60006001600160401b03831661393a5750600061065c565b8282026001600160401b03808416908086169083168161395657fe5b046001600160401b03161461072f5760405162461bcd60e51b81526004016104a09061568e565b600061072f83836040518060400160405280601a815260200179536166654d6174683a206469766973696f6e206279207a65726f60301b815250613d34565b602081015160408201516000919082845160018111156139d857fe5b14613a065783608001516040516020016139f291906149eb565b604051602081830303815290604052613a2b565b8360600151604051602001613a1b9190614ac2565b6040516020818303038152906040525b613a418560a001516001600160401b0316613d7c565b8560e00151604051602001613a5a959493929190614b0f565b604051602081830303815290604052805190602001209050919050565b6000816001600160a01b0316613a95613a8f86613e78565b85613e8b565b6001600160a01b031614949350505050565b6000836001600160401b0316836001600160401b031611158290613ade5760405162461bcd60e51b81526004016104a09190614d4c565b505050900390565b60008183613b075760405162461bcd60e51b81526004016104a09190614d4c565b506000838581613b1357fe5b0495945050505050565b600061072f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613faf565b6000836000015160ff16600114613b885760405162461bcd60e51b81526004016104a0906154ce565b835160208501516040860151613b9e8686613fd3565b87606001516006811115613bae57fe5b88608001516001811115613bbe57fe5b613bd48a60a001516001600160401b0316613d7c565b604051602001613bea9796959493929190614b7d565b6040516020818303038152906040528460c0015160008660e001516001600160401b031611613c285760405180602001604052806000815250613c3e565b613c3e8660e001516001600160401b0316613d7c565b60008761010001516001600160401b031611613c695760405180602001604052806000815250613c80565b613c808761010001516001600160401b0316613d7c565b8761012001518861014001516003811115613c9757fe5b8961016001516003811115613ca857fe5b8a6101800151604051602001613cc49796959493929190614a03565b60408051601f1981840301815290829052613ce29291602001614a94565b6040516020818303038152906040528051906020012090509392505050565b600080826006811115613d1057fe5b1480613d2757506003826006811115613d2557fe5b145b8061065c57506005613614565b6000816001600160401b038416613d5e5760405162461bcd60e51b81526004016104a09190614d4c565b506000836001600160401b0316856001600160401b031681613b1357fe5b60608160005b8115613d9657600101600a82049150613d82565b6009811015613da3575060095b6001016060816001600160401b0381118015613dbe57600080fd5b506040519080825280601f01601f191660200182016040528015613de9576020820181803683370190505b509050815b8015613e6f5780830360081415613e2f57602e60f81b826001830381518110613e1357fe5b60200101906001600160f81b031916908160001a905350613e66565b600a860660300160f81b826001830381518110613e4857fe5b60200101906001600160f81b031916908160001a905350600a860495505b60001901613dee565b50949350505050565b600081604051602001613a5a9190614ade565b60008151604114613eae5760405162461bcd60e51b81526004016104a090614f37565b60208201516040830151606084015160001a6fa2a8918ca85bafe22016d0b997e4df60600160ff1b03821115613ef65760405162461bcd60e51b81526004016104a0906152e5565b8060ff16601b14158015613f0e57508060ff16601c14155b15613f2b5760405162461bcd60e51b81526004016104a090615532565b600060018783868660405160008152602001604052604051613f509493929190614cf3565b6020604051602081039080840390855afa158015613f72573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613fa55760405162461bcd60e51b81526004016104a090614d95565b9695505050505050565b60008184841115613ade5760405162461bcd60e51b81526004016104a09190614d4c565b604080518082019091526001808252602d60f81b60208301528251845160609386939092869286929101016001600160401b038111801561401357600080fd5b506040519080825280601f01601f19166020018201604052801561403e576020820181803683370190505b5090506000805b85518210156140995785828151811061405a57fe5b602001015160f81c60f81b83828060010193508151811061407757fe5b60200101906001600160f81b031916908160001a905350600190910190614045565b846000815181106140a657fe5b602001015160f81c60f81b8382806001019350815181106140c357fe5b60200101906001600160f81b031916908160001a905350600091505b8351821015614133578382815181106140f457fe5b602001015160f81c60f81b83828060010193508151811061411157fe5b60200101906001600160f81b031916908160001a9053506001909101906140df565b5090979650505050505050565b6040805160c08101825260008082526020820181905260609282018390529181018290526080810182905260a081019190915290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106141b757805160ff19168380011785556141e4565b828001600101855582156141e4579182015b828111156141e45782518255916020019190600101906141c9565b506141f09291506141f4565b5090565b61054d91905b808211156141f057600081556001016141fa565b803561065c81615f5e565b8035801515811461065c57600080fd5b600082601f830112614239578081fd5b81356001600160401b0381111561424e578182fd5b614261601f8201601f1916602001615f0c565b915080825283602082850101111561427857600080fd5b8060208401602084013760009082016020015292915050565b80356004811061065c57600080fd5b80356002811061065c57600080fd5b80356007811061065c57600080fd5b60008083601f8401126142cf578182fd5b5081356001600160401b038111156142e5578182fd5b6020830191508360208285010111156142fd57600080fd5b9250929050565b60006101c0808385031215614317578182fd5b61432081615f0c565b91505061432d838361448a565b815261433c836020840161445c565b602082015261434e836040840161420e565b604082015261436083606084016142af565b606082015261437283608084016142a0565b60808201526143848360a08401614473565b60a08201526143968360c08401614219565b60c08201526143a88360e08401614473565b60e08201526101006143bc84828501614473565b90820152610120828101356001600160401b03808211156143dc57600080fd5b6143e886838701614229565b8385015261014092506143fd86848701614291565b83850152610160925061441286848701614291565b83850152610180925061442786848701614473565b838501526101a092508285013591508082111561444357600080fd5b5061445085828601614229565b82840152505092915050565b80356001600160801b038116811461065c57600080fd5b80356001600160401b038116811461065c57600080fd5b803560ff8116811461065c57600080fd5b6000602082840312156144ac578081fd5b813561072f81615f5e565b600080604083850312156144c9578081fd5b82356144d481615f5e565b915060208301356144e481615f5e565b809150509250929050565b600080600060408486031215614503578081fd5b833561450e81615f5e565b925060208401356001600160401b03811115614528578182fd5b614534868287016142be565b9497909650939450505050565b600060208284031215614552578081fd5b5035919050565b6000806000806060858703121561456e578182fd5b843561457981615f5e565b935060208501356001600160401b03811115614593578283fd5b61459f878288016142be565b90945092506145b39050866040870161448a565b905092959194509250565b600080604083850312156145d0578182fd5b82356145db81615f5e565b946020939093013593505050565b6000806000604084860312156145fd578081fd5b83356001600160401b03811115614612578182fd5b61461e868287016142be565b909790965060209590950135949350505050565b600080600060408486031215614646578081fd5b83356001600160401b038082111561465c578283fd5b614668878388016142be565b9095509350602086013591508082168214614681578283fd5b50809150509250925092565b6000806000606084860312156146a1578081fd5b83356001600160401b03808211156146b7578283fd5b6146c387838801614304565b945060208601359150808211156146d8578283fd5b6146e487838801614304565b935060408601359150808211156146f9578283fd5b6101c091860180880383131561470d578384fd5b61471683615f0c565b8135935082841115614726578485fd5b61473289858401614229565b81526020820135935082841115614747578485fd5b61475389858401614229565b6020820152614765896040840161420e565b6040820152614777896060840161420e565b60608201526147898960808401614473565b608082015261479b8960a08401614473565b60a08201526147ad8960c08401614473565b60c08201526147bf8960e08401614473565b60e082015261010093506147d58985840161420e565b8482015261012093506147ea8985840161420e565b8482015261014093506147ff89858401614473565b84820152610160935061481489858401614473565b84820152610180935061482989858401614473565b848201526101a0935061483e898584016142a0565b84820152809450505050509250925092565b600060208284031215614861578081fd5b81356001600160401b0380821115614877578283fd5b61012091840180860383131561488b578384fd5b61489483615f0c565b61489e87836142a0565b81526148ad876020840161445c565b60208201526148bf876040840161420e565b604082015260608201359350828411156148d7578485fd5b6148e387858401614229565b60608201526148f5876080840161420e565b60808201526149078760a08401614473565b60a08201526149198760c08401614473565b60c082015261492b8760e08401614219565b60e082015261010093508382013583811115614945578586fd5b61495188828501614229565b948201949094529695505050505050565b600060208284031215614973578081fd5b61072f838361445c565b60006020828403121561498e578081fd5b5051919050565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b600081518084526149d7816020860160208601615f32565b601f01601f19169290920160200192915050565b60609190911b6001600160601b031916815260140190565b600088151560f81b82528751614a20816001850160208c01615f32565b8751908301614a36826001830160208c01615f32565b8751918101614a4c836001830160208c01615f32565b60f897881b6001600160f81b0319908116600192909401918201939093529590961b166002850152505060c01b6001600160c01b0319166003820152600b0195945050505050565b60008351614aa6818460208801615f32565b8351908301614ab9828260208801615f32565b01949350505050565b60008251614ad4818460208701615f32565b9190910192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b608086901b6001600160801b0319168152606085901b6001600160601b03191660108201528351600090614b4a816024850160208901615f32565b8451908301614b60826024830160208901615f32565b93151560f81b602494909101938401525050602501949350505050565b6001600160f81b031960f889901b811682526001600160801b0319608089901b1660018301526001600160601b0319606088901b166011830152855160009190614bce816025860160208b01615f32565b808401828860f81b166025820152828760f81b16602682015285519250614bfc836027830160208901615f32565b9091016027019a9950505050505050505050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b038a811682528916602082015261012060408201819052600090614ca88382018b6149bf565b8381036060850152614cba818b6149bf565b6001600160401b03998a16608086015297891660a08501525050509290941660c083015260e08201526101000191909152949350505050565b93845260ff9290921660208401526040830152606082015260800190565b6000602082526110eb602083018486614995565b600060408252614d39604083018587614995565b905060ff83166020830152949350505050565b60006020825261072f60208301846149bf565b600060808252614d7260808301876149bf565b6001600160401b0395861660208401529390941660408201526060015292915050565b60208082526018908201527745434453413a20696e76616c6964207369676e617475726560401b604082015260600190565b602080825260189082015277496e76616c69642077616c6c6574207369676e617475726560401b604082015260600190565b60208082526018908201527721b0b63632b91034b9903737ba103234b9b830ba31b432b960411b604082015260600190565b6020808252604c908201527f546f6b656e20636f6e74726163742072657475726e6564207472616e7366657260408201527f46726f6d207375636365737320776974686f757420657870656374656420626160608201526b6c616e6365206368616e676560a01b608082015260a00190565b60208082526023908201527f4e6f6e63652074696d657374616d7020616c726561647920696e76616c6964616040820152621d195960ea1b606082015260800190565b6020808252600f908201526e496e76616c6964206164647265737360881b604082015260600190565b6020808252601490820152730a6f2dac4ded8e640c8de40dcdee840dac2e8c6d60631b604082015260600190565b6020808252601f908201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604082015260600190565b6020808252601390820152724578636573736976652074616b65722066656560681b604082015260600190565b60208082526027908201527f4e6574206261736520706c757320666565206973206e6f7420657175616c20746040820152666f2067726f737360c81b606082015260800190565b6020808252602c908201527f4d616b657220616e642074616b65722066656520617373657473206d7573742060408201526b189948191a5999995c995b9d60a21b606082015260800190565b60208082526024908201527f4d75737420626520646966666572656e742066726f6d2063757272656e7420616040820152633236b4b760e11b606082015260800190565b6020808252600f908201526e135d5cdd081899481d8c4815555251608a1b604082015260600190565b602080825260139082015272457863657373697665206d616b65722066656560681b604082015260600190565b6020808252601b908201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604082015260600190565b6020808252601a908201527914d95b1b081dd85b1b195d08195e1a5d08199a5b985b1a5e995960321b604082015260600190565b6020808252601d908201527f4554482073796d626f6c20726573657276656420666f72204574686572000000604082015260600190565b6020808252601390820152725175616e7469747920697320746f6f206c6f7760681b604082015260600190565b60208082526033908201527f427579206f72646572206d61726b65742073796d626f6c2061646472657373206040820152720e4cae6ded8eae8d2dedc40dad2e6dac2e8c6d606b1b606082015260800190565b60208082526023908201527f526567697374726174696f6e206f6620746f6b656e206e6f742066696e616c696040820152621e995960ea1b606082015260800190565b6020808252600d908201526c2ab735b737bbb7103a37b5b2b760991b604082015260600190565b60208082526022908201527f53656c6c206f72646572206e6f6e63652074696d657374616d7020746f6f206c6040820152616f7760f01b606082015260800190565b60208082526031908201527f4f726465722071756f7465207175616e74697479206f6e6c792076616c696420604082015270666f72206d61726b6574206f726465727360781b606082015260800190565b60208082526022908201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604082015261756560f01b606082015260800190565b60208082526024908201527f4d616b657220666565206173736574206973206e6f7420696e207472616465206040820152633830b4b960e11b606082015260800190565b60208082526027908201527f546f6b656e2063616e6e6f742068617665206d6f7265207468616e20333220646040820152666563696d616c7360c81b606082015260800190565b60208082526021908201527f4e6f6e63652074696d657374616d7020746f6f2066617220696e2066757475726040820152606560f81b606082015260800190565b60208082526019908201527815d85b1b195d08195e1a5d081b9bdd08199a5b985b1a5e9959603a1b604082015260600190565b602080825260159082015274088cac6d2dac2d8e640c8de40dcdee840dac2e8c6d605b1b604082015260600190565b60208082526018908201527714d95b198b5d1c98591a5b99c81b9bdd08185b1b1bddd95960421b604082015260600190565b60208082526027908201527f4261736520616e642071756f746520617373657473206d7573742062652064696040820152661999995c995b9d60ca1b606082015260800190565b6020808252818101527f5369676e617475726520686173682076657273696f6e206d7573742062652031604082015260600190565b60208082526015908201527415d85b1b195d08185b1c9958591e48195e1a5d1959605a1b604082015260600190565b60208082526022908201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604082015261756560f01b606082015260800190565b6020808252601f908201527f557365206465706f736974457468657220746f206465706f7369742045544800604082015260600190565b6020808252601890820152774d757374206265206c657373207468616e2031207765656b60401b604082015260600190565b60208082526024908201527f54616b657220666565206173736574206973206e6f7420696e207472616465206040820152633830b4b960e11b606082015260800190565b60208082526023908201527f4e6f20636f6e6669726d656420617373657420666f756e6420666f722073796d604082015262189bdb60ea1b606082015260800190565b60208082526010908201526f13dc99195c881bdd995c999a5b1b195960821b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b602080825260189082015277457863657373697665207769746864726177616c2066656560401b604082015260600190565b6020808252601d908201527f506970207175616e74697479206f766572666c6f77732075696e743634000000604082015260600190565b60208082526021908201527f557365206465706f736974457468657220746f206465706f73697420457468656040820152603960f91b606082015260800190565b60208082526014908201527321b0b63632b91036bab9ba1031329037bbb732b960611b604082015260600190565b60208082526029908201527f4d75737420626520646966666572656e742066726f6d2063757272656e7420666040820152681959481dd85b1b195d60ba1b606082015260800190565b6020808252601e908201527f437573746f6469616e2063616e206f6e6c7920626520736574206f6e63650000604082015260600190565b6020808252601690820152752430b9b41030b63932b0b23c903bb4ba34323930bbb760511b604082015260600190565b602080825260179082015276151bdad95b88185b1c9958591e48199a5b985b1a5e9959604a1b604082015260600190565b60208082526029908201527f4d75737420626520646966666572656e742066726f6d2063757272656e74206460408201526834b9b830ba31b432b960b91b606082015260800190565b6020808252601e908201527f427579206f72646572206c696d69742070726963652065786365656465640000604082015260600190565b60208082526013908201527213dc99195c88191bdd589b1948199a5b1b1959606a1b604082015260600190565b60208082526021908201527f427579206f72646572206e6f6e63652074696d657374616d7020746f6f206c6f6040820152607760f81b606082015260800190565b60208082526024908201527f4e6f20636f6e6669726d656420617373657420666f756e6420666f72206164646040820152637265737360e01b606082015260800190565b60208082526014908201527321b0b63632b91036bab9ba1031329030b236b4b760611b604082015260600190565b602080825260139082015272115512081d1c985b9cd9995c8819985a5b1959606a1b604082015260600190565b60208082526027908201527f41737365742063616e6e6f742068617665206d6f7265207468616e20333220646040820152666563696d616c7360c81b606082015260800190565b60208082526034908201527f53656c6c206f72646572206d61726b65742073796d626f6c2061646472657373604082015273040e4cae6ded8eae8d2dedc40dad2e6dac2e8c6d60631b606082015260800190565b602080825260159082015274496e76616c696420746f6b656e206164647265737360581b604082015260600190565b60208082526030908201527f50726576696f757320696e76616c69646174696f6e206177616974696e67206360408201526f3430b4b710383937b830b3b0ba34b7b760811b606082015260800190565b60208082526028908201527f4e65742071756f746520706c757320666565206973206e6f7420657175616c20604082015267746f2067726f737360c01b606082015260800190565b6020808252601f908201527f53656c6c206f72646572206c696d697420707269636520657863656564656400604082015260600190565b602080825260149082015273125b9d985b1a59081d1bdad95b881cde5b589bdb60621b604082015260600190565b60208082526011908201527015d85b1b195d081b9bdd08195e1a5d1959607a1b604082015260600190565b602080825260169082015275496e76616c69642077616c6c6574206164647265737360501b604082015260600190565b6020808252602b908201527f496d706c6965642071756f746520706970207175616e74697479206f7665726660408201526a1b1bdddcc81d5a5b9d0d8d60aa1b606082015260800190565b60208082526048908201527f546f6b656e20636f6e74726163742072657475726e6564207472616e7366657260408201527f207375636365737320776974686f75742065787065637465642062616c616e6360608201526765206368616e676560c01b608082015260a00190565b602080825260199082015278109d5e481dd85b1b195d08195e1a5d08199a5b985b1a5e9959603a1b604082015260600190565b60208082526028908201527f51756f7465207175616e74697479206d7573742062652067726561746572207460408201526768616e207a65726f60c01b606082015260800190565b6020808252600d908201526c15d85b1b195d08195e1a5d1959609a1b604082015260600190565b602080825260149082015273139bc818985b185b98d948199bdc88185cdcd95d60621b604082015260600190565b60208082526027908201527f42617365207175616e74697479206d7573742062652067726561746572207468604082015266616e207a65726f60c81b606082015260800190565b60006020825282511515602083015260018060a01b036020840151166040830152604083015160c06060840152615e4160e08401826149bf565b60ff60608601511660808501526080850151151560a08501526001600160401b0360a08601511660c0850152809250505092915050565b6001600160801b039390931683526001600160401b03919091166020830152604082015260600190565b90815260200190565b918252602082015260400190565b6001600160401b0391909116815260200190565b60006001600160401b03808816835260a06020840152615ef060a08401886149bf565b9581166040840152939093166060820152608001525092915050565b6040518181016001600160401b0381118282101715615f2a57600080fd5b604052919050565b60005b83811015615f4d578181015183820152602001615f35565b838111156108dd5750506000910152565b6001600160a01b0381168114615f7357600080fd5b5056fe496e76616c69642077616c6c6574207369676e617475726520666f7220627579206f72646572496e76616c69642077616c6c6574207369676e617475726520666f722073656c6c206f72646572a26469706673582212205dd7ac35c5f7c6f5ec79f4ba79633e7c75138d994328bbe33fa2efc0d21be22d64736f6c63430006080033
Deployed Bytecode
0x6080604052600436106101415760003560e01c806372e8f08d116100b157806372e8f08d146102ea578063869af2121461030a57806390d49b9d14610337578063985c4af51461035757806398ea5fca146103775780639a202d471461037f578063ae0e969e14610394578063ba22bd76146103c1578063d7a6aec7146103e1578063dbb3653514610401578063dcc6349014610421578063eb5068f214610441578063ef3b9d4a1461045657610141565b80630226b70e1461014657806302ca6002146101685780630c187a721461019357806313cfda2c146101a85780631abb5832146101d557806320e6a8e3146101f5578063403f3731146102155780634196818214610235578063457aa3c6146102555780634a284ef91461027557806365fce5b71461028a5780636bb509f2146102aa578063704b6c02146102ca575b600080fd5b34801561015257600080fd5b50610166610161366004614559565b610476565b005b34801561017457600080fd5b5061017d610540565b60405161018a9190614c10565b60405180910390f35b34801561019f57600080fd5b50610166610550565b3480156101b457600080fd5b506101c86101c33660046144b7565b6105d4565b60405161018a9190615ea2565b3480156101e157600080fd5b506101c86101f03660046144ef565b610662565b34801561020157600080fd5b50610166610210366004614541565b610736565b34801561022157600080fd5b5061016661023036600461449b565b6107c7565b34801561024157600080fd5b506101666102503660046145e9565b610861565b34801561026157600080fd5b50610166610270366004614559565b6108e3565b34801561028157600080fd5b50610166610996565b34801561029657600080fd5b506101666102a536600461468d565b610a0a565b3480156102b657600080fd5b506101666102c5366004614850565b610bb1565b3480156102d657600080fd5b506101666102e536600461449b565b610f1e565b3480156102f657600080fd5b506101666103053660046144ef565b610fdc565b34801561031657600080fd5b5061032a610325366004614632565b611099565b60405161018a9190615e07565b34801561034357600080fd5b5061016661035236600461449b565b6110f3565b34801561036357600080fd5b5061016661037236600461449b565b6111c4565b61016661134f565b34801561038b57600080fd5b5061016661135d565b3480156103a057600080fd5b506103b46103af366004614541565b6113b7565b60405161018a9190615eb9565b3480156103cd57600080fd5b506101666103dc36600461449b565b6113d5565b3480156103ed57600080fd5b506101666103fc366004614962565b6114a6565b34801561040d57600080fd5b506103b461041c3660046144b7565b61161e565b34801561042d57600080fd5b5061016661043c3660046145be565b61167b565b34801561044d57600080fd5b506101666116b0565b34801561046257600080fd5b506103b46104713660046144ef565b611762565b6000546001600160a01b031633146104a95760405162461bcd60e51b81526004016104a0906159ba565b60405180910390fd5b6104f58484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001949392508691505063ffffffff61180c16565b836001600160a01b03167fa8968236dc4afb2c189afeb69c91b02445e6bd09f0ffe27256b62838edc99edb84848460405161053293929190614d25565b60405180910390a250505050565b600c546001600160a01b03165b90565b6000546001600160a01b0316331461057a5760405162461bcd60e51b81526004016104a0906159ba565b600b546040517fddb86df2d5262dd7b44067db5962cc7875e9db409cb21c88adfe3c5760315e39916105ba916001600160a01b0390911690600090614c61565b60405180910390a1600b80546001600160a01b0319169055565b60006001600160a01b0383166105fc5760405162461bcd60e51b81526004016104a090615c07565b610604614140565b61061560018463ffffffff611b6216565b6001600160a01b038086166000908152600660209081526040808320938816835292905220546060820151919250610658916001600160401b0390911690611cbb565b9150505b92915050565b60006001600160a01b03841661068a5760405162461bcd60e51b81526004016104a090615c07565b610692614140565b6106e484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506106d59250611d33915050565b6001919063ffffffff611d3b16565b6001600160a01b0380871660009081526006602090815260408083208286015190941683529290522054606082015191925061072b916001600160401b0390911690611cbb565b9150505b9392505050565b6000546001600160a01b031633146107605760405162461bcd60e51b81526004016104a0906159ba565b619d8081106107815760405162461bcd60e51b81526004016104a0906155ab565b600a8054908290556040517f9a22227d6c0251a79ef8b846202ddcbe9d682ee5482e84abeec6dda096398a6f906107bb9083908590615eab565b60405180910390a15050565b6000546001600160a01b031633146107f15760405162461bcd60e51b81526004016104a0906159ba565b6005546001600160a01b03161561081a5760405162461bcd60e51b81526004016104a0906157f0565b61082381611fa5565b61083f5760405162461bcd60e51b81526004016104a090614ee0565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b60006108a684848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506106d59250611d33915050565b6020015190506001600160a01b0381166108d25760405162461bcd60e51b81526004016104a090615574565b6108dd338284611fab565b50505050565b6000546001600160a01b0316331461090d5760405162461bcd60e51b81526004016104a0906159ba565b6109598484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001949392508691505063ffffffff6121d016565b836001600160a01b03167fcf66acda7673c71cd9458c59067eb30a473eeaf2fa05d008acf47616cbbbe01c84848460405161053293929190614d25565b3360009081526009602052604090205460ff166109c55760405162461bcd60e51b81526004016104a090615bdc565b33600081815260096020526040808220805460ff19168155600101829055517fb771d4b2a83beca38f442c8903629e0e8ab1a07cf76e94eb2977153167e209369190a2565b600b546001600160a01b03163314610a345760405162461bcd60e51b81526004016104a090614df9565b610a41836040015161237a565b15610a5e5760405162461bcd60e51b81526004016104a090615cf0565b610a6b826040015161237a565b15610a885760405162461bcd60e51b81526004016104a0906150fd565b81604001516001600160a01b031683604001516001600160a01b03161415610ac25760405162461bcd60e51b81526004016104a090615455565b610acd8383836123ab565b610ad8838383612620565b610ae28383612731565b600080610af08585856127c3565b91509150610afd836127ee565b610b0a85838684876129e8565b610b15858585612a05565b8260200151604051610b279190614ac2565b60405190819003812084519091610b3e9190614ac2565b60405180910390207fbd75b2e24c3d43ec9f10f3583265606c0a7d8b67d147f9dc48376b81456823a1876040015187604001518760000151886020015189608001518a60a001518b61018001518b8b604051610ba299989796959493929190614c7b565b60405180910390a35050505050565b600b546001600160a01b03163314610bdb5760405162461bcd60e51b81526004016104a090614df9565b610be8816040015161237a565b15610c055760405162461bcd60e51b81526004016104a090615d6b565b6107d06001600160401b0316610c238260c001518360a00151612cff565b6001600160401b03161115610c4a5760405162461bcd60e51b81526004016104a0906156cf565b6000610c5582612d36565b60008181526004602052604090205490915060ff1615610c875760405162461bcd60e51b81526004016104a090615827565b610c8f614140565b600083516001811115610c9e57fe5b14610cbf576080830151610cba9060019063ffffffff611b6216565b610cd4565b610cd483606001516106d58560200151612d74565b90506000610cfc8460c001518560a001516001600160401b0316612e0190919063ffffffff16565b90506000610d0e828460600151611cbb565b60a08601516040808801516001600160a01b03908116600090815260066020908152838220898201519093168252919091529081205492935091610d63916001600160401b039091169063ffffffff612e0116565b90506000610d75828660600151611cbb565b6040888101516001600160a01b039081166000908152600660208181528483208b820180518616855290825285842080546001600160401b0319166001600160401b038b81169190911790915560c08f0151600c548716865293835286852091519095168452905292902054929350610def921690612e43565b600c546001600160a01b0390811660009081526006602090815260408083208a830180518616855292529182902080546001600160401b0319166001600160401b0395909516949094179093556005548a82015193519151636ce5768960e11b815292169263d9caed1292610e6992908890600401614c24565b600060405180830381600087803b158015610e8357600080fd5b505af1158015610e97573d6000803e3d6000fd5b505050600087815260046020908152604091829020805460ff19166001179055870151898201518883015160a08c015193516001600160a01b03938416955091909216927f6960a1f64ecf9da0d1d1bcbfa3dd27f8c1c60de69b13faa28127dafa36c111e492610f0d9290919088908890614d5f565b60405180910390a350505050505050565b336001600160a01b037f000000000000000000000000b2d3731fd28309c399774fb26f993697c174f4511614610f665760405162461bcd60e51b81526004016104a090615779565b6001600160a01b038116610f8c5760405162461bcd60e51b81526004016104a090615c07565b6000546001600160a01b0382811691161415610fba5760405162461bcd60e51b81526004016104a09061502e565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146110065760405162461bcd60e51b81526004016104a0906159ba565b6110518383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001949392505063ffffffff612e74169050565b826001600160a01b03167f7f63a63f4a2ea318da0b031794d0b5a3183a1b2de54e053ceb17cabdba031735838360405161108c929190614d11565b60405180910390a2505050565b6110a1614140565b6110eb84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019392508691505063ffffffff611d3b16565b949350505050565b6000546001600160a01b0316331461111d5760405162461bcd60e51b81526004016104a0906159ba565b6001600160a01b0381166111435760405162461bcd60e51b81526004016104a090615c07565b600c546001600160a01b03828116911614156111715760405162461bcd60e51b81526004016104a0906157a7565b600c80546001600160a01b038381166001600160a01b03198316179092556040519116907f9f4f5dce3c4d197b5d7496cb96e25f0a89809167195964b0daa3ef5fed63c00a906107bb9083908590614c61565b6111cd3361237a565b6111e95760405162461bcd60e51b81526004016104a0906153f3565b6111f1614140565b61120260018363ffffffff611b6216565b3360009081526006602090815260408083206001600160a01b038716845290915281205460608301519293506001600160401b031691611243908390611cbb565b9050600081116112655760405162461bcd60e51b81526004016104a090615d92565b3360008181526006602090815260408083206001600160a01b03898116855292529182902080546001600160401b03191690556005549151636ce5768960e11b815291169163d9caed12916112c1919088908690600401614c24565b600060405180830381600087803b1580156112db57600080fd5b505af11580156112ef573d6000803e3d6000fd5b50505050836001600160a01b0316336001600160a01b03167f02e03f232c88c87047c5a9cfbad1213b842503fee6a002ec2eec9f5a64725bf48560400151856000806040516113419493929190614d5f565b60405180910390a350505050565b61135b33600034611fab565b565b336001600160a01b037f000000000000000000000000b2d3731fd28309c399774fb26f993697c174f45116146113a55760405162461bcd60e51b81526004016104a090615779565b600080546001600160a01b0319169055565b6000818152600860205260409020546001600160401b03165b919050565b6000546001600160a01b031633146113ff5760405162461bcd60e51b81526004016104a0906159ba565b6001600160a01b0381166114255760405162461bcd60e51b81526004016104a090615c07565b600b546001600160a01b03828116911614156114535760405162461bcd60e51b81526004016104a090615888565b600b80546001600160a01b038381166001600160a01b03198316179092556040519116907fddb86df2d5262dd7b44067db5962cc7875e9db409cb21c88adfe3c5760315e39906107bb9083908590614c61565b60006114b182612d74565b90506114bb613089565b6001600160401b0316816001600160401b0316106114eb5760405162461bcd60e51b81526004016104a0906153b2565b3360009081526007602052604090205460ff161561157457336000908152600760205260409020546001600160401b0380831661010090920416106115425760405162461bcd60e51b81526004016104a090614e9d565b336000908152600760205260409020600101544310156115745760405162461bcd60e51b81526004016104a090615adf565b600a546040805160608101825260018082526001600160401b0385811660208085019182524390960184860181815233600081815260079099529787902095518654935160ff199094169015151768ffffffffffffffff001916610100939094169290920292909217845551929091019190915590519091907f10cf19671b43c88b1f02d4e94932d7ffaa89c7278bc5b8868fa7b7676210809b9061108c90869086908690615e78565b60006001600160a01b0383166116465760405162461bcd60e51b81526004016104a090615c07565b506001600160a01b0391821660009081526006602090815260408083209390941682529190915220546001600160401b031690565b6001600160a01b0382166116a15760405162461bcd60e51b81526004016104a090615738565b6116ac338383611fab565b5050565b3360009081526009602052604090205460ff16156116e05760405162461bcd60e51b81526004016104a090615503565b6040805180820182526001808252600a80544390810160208086019182523360008181526009909252908790209551865460ff19169015151786559051949093019390935554925190927fd60f9f7b2f1a208268475a927bd727c4e198fc8b40aab3004ebcc2bc78ca84809261175892910190615ea2565b60405180910390a2565b60006001600160a01b03841661178a5760405162461bcd60e51b81526004016104a090615c07565b60006117cf84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506106d59250611d33915050565b6020908101516001600160a01b03808816600090815260068452604080822092909316815292529020546001600160401b03169150509392505050565b611814614140565b6001600160a01b0384811660009081526020878152604091829020825160c081018452815460ff8116151582526101009081900490951681840152600180830180548651600293821615909802600019011691909104601f81018590048502870185018652808752919592948601939091908301828280156118d75780601f106118ac576101008083540402835291602001916118d7565b820191906000526020600020905b8154815290600101906020018083116118ba57829003601f168201915b50505091835250506002919091015460ff8082166020840152610100820416151560408301526201000090046001600160401b031660609091015280519091506119335760405162461bcd60e51b81526004016104a09061522b565b8060800151156119555760405162461bcd60e51b81526004016104a090615857565b611963816040015184613096565b61197f5760405162461bcd60e51b81526004016104a090614f09565b8160ff16816060015160ff16146119a85760405162461bcd60e51b81526004016104a090615426565b6001608082018190526001600160401b036103e842021660a08301526001600160a01b0380861660009081526020888152604091829020855181548388015190951661010002610100600160a81b031991151560ff1990961695909517169390931783559084015180518594611a2393908501920190614176565b50606082015160029091018054608084015160a0909401516001600160401b0316620100000262010000600160501b03199415156101000261ff001960ff90951660ff19909316929092179390931617929092161790556040516001860190611a8d908590614ac2565b9081526040805191829003602090810190922080546001818101835560009283529184902085516003909202018054868601516001600160a01b031661010002610100600160a81b031993151560ff1990921691909117929092169190911781559184015180518594611b04938501920190614176565b50606082015160029091018054608084015160a0909401516001600160401b0316620100000262010000600160501b03199415156101000261ff001960ff90951660ff19909316929092179390931617929092161790555050505050565b611b6a614140565b6001600160a01b038216611b8757611b806130ef565b905061065c565b611b8f614140565b6001600160a01b0383811660009081526020868152604091829020825160c081018452815460ff8116151582526101009081900490951681840152600180830180548651600293821615909802600019011691909104601f8101859004850287018501865280875291959294860193909190830182828015611c525780601f10611c2757610100808354040283529160200191611c52565b820191906000526020600020905b815481529060010190602001808311611c3557829003601f168201915b50505091835250506002919091015460ff8082166020840152610100820416151560408301526201000090046001600160401b031660609091015280519091508015611c9f575080608001515b61072f5760405162461bcd60e51b81526004016104a090615976565b600060208260ff161115611ce15760405162461bcd60e51b81526004016104a090615a15565b60088260ff161115611d1057611b806001600160401b03841660ff600719850116600a0a63ffffffff61314816565b61072f6001600160401b03841660ff600885900316600a0a63ffffffff61318216565b426103e80290565b611d43614140565b611d686040518060400160405280600381526020016208aa8960eb1b81525084613096565b15611d7c57611d756130ef565b905061072f565b611d84614140565b60008560010185604051611d989190614ac2565b908152604051908190036020019020541115611f7a5760005b8560010185604051611dc39190614ac2565b9081526040519081900360200190205460ff82161015611f7857836001600160401b03168660010186604051611df99190614ac2565b90815260200160405180910390208260ff1681548110611e1557fe5b60009182526020909120600390910201600201546201000090046001600160401b031611611f70578560010185604051611e4f9190614ac2565b90815260200160405180910390208160ff1681548110611e6b57fe5b60009182526020918290206040805160c081018252600393909302909101805460ff811615158452610100908190046001600160a01b031684860152600180830180548551600293821615909402600019011691909104601f8101879004870283018701855280835294959294938601939192909190830182828015611f325780601f10611f0757610100808354040283529160200191611f32565b820191906000526020600020905b815481529060010190602001808311611f1557829003601f168201915b50505091835250506002919091015460ff8082166020840152610100820416151560408301526201000090046001600160401b031660609091015291505b600101611db1565b505b80518015611f89575080608001515b6110eb5760405162461bcd60e51b81526004016104a090615621565b3b151590565b6001600160a01b03831660009081526009602052604090205460ff1615611fe45760405162461bcd60e51b81526004016104a090615d6b565b611fec614140565b611ffd60018463ffffffff611b6216565b9050600061200f8383606001516131c1565b90506000816001600160401b03161161203a5760405162461bcd60e51b81526004016104a090615168565b600061204a828460600151611cbb565b90506001600160a01b0385161561206657612066868683613256565b60055461207d906001600160a01b031686836133e9565b6001600160a01b0380871660009081526006602090815260408083209389168352929052908120546120be906001600160401b03168463ffffffff612e4316565b905060006120d0828660600151611cbb565b6001600160a01b038981166000908152600660209081526040808320938c16835292905281902080546001600160401b0319166001600160401b03868116919091179091556005805467ffffffffffffffff60a01b198116600160a01b9182900484166001019093160291909117905586810151905191925061215291614ac2565b6040518091039020876001600160a01b0316896001600160a01b03167fc2813a84168de59cf710030ba2acb13031b567b8ba76f70e8ab0782aa9469a7a600560149054906101000a90046001600160401b031689604001518988886040516121be959493929190615ecd565b60405180910390a45050505050505050565b60208160ff1611156121f45760405162461bcd60e51b81526004016104a09061536b565b6001600160a01b03831615801590612210575061221083611fa5565b61222c5760405162461bcd60e51b81526004016104a090615ab0565b600082511161224d5760405162461bcd60e51b81526004016104a090615bae565b6001600160a01b038316600090815260208590526040902060020154610100900460ff161561228e5760405162461bcd60e51b81526004016104a090615857565b6040805160c08101825260018082526001600160a01b03868116602080850182815285870189815260ff8916606088015260006080880181905260a088018190529384528b83529690922085518154935160ff1990941690151517610100600160a81b03191661010093909416929092029290921781559351805193949361231d938501929190910190614176565b50606082015160029091018054608084015160a0909401516001600160401b0316620100000262010000600160501b03199415156101000261ff001960ff90951660ff199093169290921793909316179290921617905550505050565b6001600160a01b0381166000908152600960205260408120805460ff16801561072f57506001015443101592915050565b80606001516001600160a01b031681604001516001600160a01b031614156123e55760405162461bcd60e51b81526004016104a090615487565b6123ed614140565b61240282600001516106d58660200151612d74565b905061240c614140565b61242183602001516106d58760200151612d74565b905082604001516001600160a01b031682602001516001600160a01b0316148015612465575082606001516001600160a01b031681602001516001600160a01b0316145b6124815760405162461bcd60e51b81526004016104a090615195565b612489614140565b61249e84600001516106d58760200151612d74565b90506124a8614140565b6124bd85602001516106d58860200151612d74565b905084604001516001600160a01b031682602001516001600160a01b0316148015612501575084606001516001600160a01b031681602001516001600160a01b0316145b61251d5760405162461bcd60e51b81526004016104a090615a5c565b84604001516001600160a01b03168561010001516001600160a01b03161480612560575084606001516001600160a01b03168561010001516001600160a01b0316145b61257c5760405162461bcd60e51b81526004016104a090615327565b84604001516001600160a01b03168561012001516001600160a01b031614806125bf575084606001516001600160a01b03168561012001516001600160a01b0316145b6125db5760405162461bcd60e51b81526004016104a0906155dd565b8461012001516001600160a01b03168561010001516001600160a01b031614156126175760405162461bcd60e51b81526004016104a090614fe2565b50505050505050565b600081608001516001600160401b03161161264d5760405162461bcd60e51b81526004016104a090615dc0565b60008160a001516001600160401b03161161267a5760405162461bcd60e51b81526004016104a090615d23565b61268783606001516135ce565b156126d3578060a001516001600160401b03166126ac82608001518560e00151613627565b6001600160401b031610156126d35760405162461bcd60e51b81526004016104a0906158d1565b6126e082606001516135ce565b1561272c578060a001516001600160401b031661270582608001518460e00151613627565b6001600160401b0316111561272c5760405162461bcd60e51b81526004016104a090615b77565b505050565b61273e8260400151613680565b6001600160401b03166127548360200151612d74565b6001600160401b03161161277a5760405162461bcd60e51b81526004016104a090615935565b6127878160400151613680565b6001600160401b031661279d8260200151612d74565b6001600160401b0316116116ac5760405162461bcd60e51b81526004016104a090615252565b60008060006127d286856136fd565b905060006127e086866136fd565b919791965090945050505050565b600081604001516001600160a01b03168261010001516001600160a01b03161461281c578160a00151612822565b81608001515b90506107d06001600160401b031661283f83610140015183612cff565b6001600160401b031611156128665760405162461bcd60e51b81526004016104a09061509b565b600082604001516001600160a01b03168361012001516001600160a01b031614612894578260a0015161289a565b82608001515b90506107d06001600160401b03166128b784610160015183612cff565b6001600160401b031611156128de5760405162461bcd60e51b81526004016104a090614f6e565b82608001516001600160401b031661293d84604001516001600160a01b03168561010001516001600160a01b03161461291c57846101600151612923565b8461014001515b60c08601516001600160401b03169063ffffffff612e4316565b6001600160401b0316146129635760405162461bcd60e51b81526004016104a090614f9b565b8260a001516001600160401b03166129c284606001516001600160a01b03168561010001516001600160a01b0316146129a1578461016001516129a8565b8461014001515b60e08601516001600160401b03169063ffffffff612e4316565b6001600160401b03161461272c5760405162461bcd60e51b81526004016104a090615b2f565b6129f385858361379e565b6129fe83838361379e565b5050505050565b60808101516040808401516001600160a01b03908116600090815260066020908152838220848701519093168252919091522054612a54916001600160401b039091169063ffffffff612e0116565b6040838101516001600160a01b0390811660009081526006602081815284832087860180518616855290825285842080546001600160401b0319166001600160401b0398891617905560c08801518a8701518616855292825285842090519094168352929092529190912054612acb921690612e43565b604084810180516001600160a01b039081166000908152600660208181528583208887015185168452815285832080546001600160401b0319166001600160401b0398891617905560a088015194518416835290815284822060608801519093168252919091529190912054612b42921690612e01565b6040848101516001600160a01b039081166000908152600660208181528483206060880180518616855290825285842080546001600160401b0319166001600160401b0398891617905560e0880151898701518616855292825285842090519094168352929092529190912054612bba921690612e43565b6040838101516001600160a01b03908116600090815260066020818152848320606088015185168452815284832080546001600160401b0319166001600160401b03978816179055610140870151600c54851684529181528483206101008801519094168352929092529190912054612c34921690612e43565b600c80546001600160a01b03908116600090815260066020818152604080842061010089015186168552825280842080546001600160401b0319166001600160401b039889161790556101608801519554851684529181528183206101208801519094168352929092522054612cab921690612e43565b600c546001600160a01b039081166000908152600660209081526040808320610120969096015190931682529390935290912080546001600160401b0319166001600160401b039092169190911790555050565b600061271061065883612d216001600160401b0387168463ffffffff61392216565b6001600160401b03169063ffffffff61397d16565b600080612d42836139bc565b9050612d58818461010001518560400151613a77565b61065c5760405162461bcd60e51b81526004016104a090614dc7565b6000600f604c83901c1660018114612d9e5760405162461bcd60e51b81526004016104a090615072565b610fff60301b601084901c1665ffff00000000603085901c1663ffffffff606086901c168183178117612df6650b1d069b54006127106001600160801b038416046001600160401b0316612e0190919063ffffffff16565b979650505050505050565b600061072f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613aa7565b60008282016001600160401b03808516908216101561072f5760405162461bcd60e51b81526004016104a0906150c8565b612e7c614140565b6001600160a01b0383811660009081526020868152604091829020825160c081018452815460ff8116151582526101009081900490951681840152600180830180548651600293821615909802600019011691909104601f8101859004850287018501865280875291959294860193909190830182828015612f3f5780601f10612f1457610100808354040283529160200191612f3f565b820191906000526020600020905b815481529060010190602001808311612f2257829003601f168201915b50505091835250506002919091015460ff8082166020840152610100820416151560408301526201000090046001600160401b031660609091015280519091508015612f8c575080608001515b612fa85760405162461bcd60e51b81526004016104a0906151e8565b612fcd826040518060400160405280600381526020016208aa8960eb1b815250613096565b15612fea5760405162461bcd60e51b81526004016104a090615131565b426103e89081026001600160401b031660a08301526040516001860190613012908590614ac2565b9081526040805191829003602090810190922080546001818101835560009283529184902086516003909202018054878601516001600160a01b031661010002610100600160a81b031993151560ff1990921691909117929092169190911781559185015180518694611b04938501920190614176565b4262015180016103e80290565b6000816040516020016130a99190614ac2565b60405160208183030381529060405280519060200120836040516020016130d09190614ac2565b6040516020818303038152906040528051906020012014905092915050565b6130f7614140565b506040805160c08101825260018082526000602080840182905284518086018652600381526208aa8960eb1b918101919091529383019390935260126060830152608082015260a081019190915290565b6000826131575750600061065c565b8282028284828161316457fe5b041461072f5760405162461bcd60e51b81526004016104a09061568e565b600061072f83836040518060400160405280601a815260200179536166654d6174683a206469766973696f6e206279207a65726f60301b815250613ae6565b600060208260ff1611156131e75760405162461bcd60e51b81526004016104a090615a15565b600060088360ff1611156132165761320f8460ff600719860116600a0a63ffffffff61318216565b9050613233565b6132308460ff600886900316600a0a63ffffffff61314816565b90505b600160401b811061072f5760405162461bcd60e51b81526004016104a090615701565b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190613285903090600401614c10565b60206040518083038186803b15801561329d57600080fd5b505afa1580156132b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d5919061497d565b6040516323b872dd60e01b81529091506001600160a01b038416906323b872dd9061330890879030908790600401614c24565b600060405180830381600087803b15801561332257600080fd5b505af1158015613336573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03861691506370a0823190613369903090600401614c10565b60206040518083038186803b15801561338157600080fd5b505afa158015613395573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b9919061497d565b9050826133cc828463ffffffff613b1d16565b146129fe5760405162461bcd60e51b81526004016104a090614e2b565b6001600160a01b03821661343d576040516001600160a01b0384169082156108fc029083906000818181858888f193505050506134385760405162461bcd60e51b81526004016104a0906159e8565b61272c565b6040516370a0823160e01b81526000906001600160a01b038416906370a082319061346c908790600401614c10565b60206040518083038186803b15801561348457600080fd5b505afa158015613498573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134bc919061497d565b60405163a9059cbb60e01b81529091506001600160a01b0384169063a9059cbb906134ed9087908690600401614c48565b600060405180830381600087803b15801561350757600080fd5b505af115801561351b573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03861691506370a082319061354e908890600401614c10565b60206040518083038186803b15801561356657600080fd5b505afa15801561357a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061359e919061497d565b9050826135b1828463ffffffff613b1d16565b146129fe5760405162461bcd60e51b81526004016104a090615c82565b600060018260068111156135de57fe5b14806135f5575060028260068111156135f357fe5b145b8061360b5750600482600681111561360957fe5b145b8061065c575060065b82600681111561362057fe5b1492915050565b60006305f5e1008161365b8261364f6001600160401b0388811690881663ffffffff61314816565b9063ffffffff61318216565b9050600160401b81106106585760405162461bcd60e51b81526004016104a090615c37565b6001600160a01b03811660009081526007602052604081205460ff1680156136c357506001600160a01b0382166000908152600760205260409020600101544310155b156136f557506001600160a01b03811660009081526007602052604090205461010090046001600160401b03166113d0565b506000919050565b6000806137138484600001518560200151613b5f565b905061372981856101a001518660400151613a77565b60008560800151600181111561373b57fe5b1461375e57604051806060016040528060278152602001615f9d60279139613778565b604051806060016040528060268152602001615f77602691395b906137965760405162461bcd60e51b81526004016104a09190614d4c565b509392505050565b60008281526003602052604090205460ff16156137cd5760405162461bcd60e51b81526004016104a090615908565b60008360c0015115613839576137e68460600151613d01565b6138025760405162461bcd60e51b81526004016104a090615294565b60008381526008602052604090205460a0830151613832916001600160401b03918216911663ffffffff612e4316565b905061386c565b6000838152600860205260409020546080830151613869916001600160401b03918216911663ffffffff612e4316565b90505b8360a001516001600160401b0316816001600160401b031611156138a25760405162461bcd60e51b81526004016104a090615664565b8360a001516001600160401b0316816001600160401b031610156138ec57600083815260086020526040902080546001600160401b0319166001600160401b0383161790556108dd565b5050600090815260086020908152604080832080546001600160401b031916905560039091529020805460ff1916600117905550565b60006001600160401b03831661393a5750600061065c565b8282026001600160401b03808416908086169083168161395657fe5b046001600160401b03161461072f5760405162461bcd60e51b81526004016104a09061568e565b600061072f83836040518060400160405280601a815260200179536166654d6174683a206469766973696f6e206279207a65726f60301b815250613d34565b602081015160408201516000919082845160018111156139d857fe5b14613a065783608001516040516020016139f291906149eb565b604051602081830303815290604052613a2b565b8360600151604051602001613a1b9190614ac2565b6040516020818303038152906040525b613a418560a001516001600160401b0316613d7c565b8560e00151604051602001613a5a959493929190614b0f565b604051602081830303815290604052805190602001209050919050565b6000816001600160a01b0316613a95613a8f86613e78565b85613e8b565b6001600160a01b031614949350505050565b6000836001600160401b0316836001600160401b031611158290613ade5760405162461bcd60e51b81526004016104a09190614d4c565b505050900390565b60008183613b075760405162461bcd60e51b81526004016104a09190614d4c565b506000838581613b1357fe5b0495945050505050565b600061072f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613faf565b6000836000015160ff16600114613b885760405162461bcd60e51b81526004016104a0906154ce565b835160208501516040860151613b9e8686613fd3565b87606001516006811115613bae57fe5b88608001516001811115613bbe57fe5b613bd48a60a001516001600160401b0316613d7c565b604051602001613bea9796959493929190614b7d565b6040516020818303038152906040528460c0015160008660e001516001600160401b031611613c285760405180602001604052806000815250613c3e565b613c3e8660e001516001600160401b0316613d7c565b60008761010001516001600160401b031611613c695760405180602001604052806000815250613c80565b613c808761010001516001600160401b0316613d7c565b8761012001518861014001516003811115613c9757fe5b8961016001516003811115613ca857fe5b8a6101800151604051602001613cc49796959493929190614a03565b60408051601f1981840301815290829052613ce29291602001614a94565b6040516020818303038152906040528051906020012090509392505050565b600080826006811115613d1057fe5b1480613d2757506003826006811115613d2557fe5b145b8061065c57506005613614565b6000816001600160401b038416613d5e5760405162461bcd60e51b81526004016104a09190614d4c565b506000836001600160401b0316856001600160401b031681613b1357fe5b60608160005b8115613d9657600101600a82049150613d82565b6009811015613da3575060095b6001016060816001600160401b0381118015613dbe57600080fd5b506040519080825280601f01601f191660200182016040528015613de9576020820181803683370190505b509050815b8015613e6f5780830360081415613e2f57602e60f81b826001830381518110613e1357fe5b60200101906001600160f81b031916908160001a905350613e66565b600a860660300160f81b826001830381518110613e4857fe5b60200101906001600160f81b031916908160001a905350600a860495505b60001901613dee565b50949350505050565b600081604051602001613a5a9190614ade565b60008151604114613eae5760405162461bcd60e51b81526004016104a090614f37565b60208201516040830151606084015160001a6fa2a8918ca85bafe22016d0b997e4df60600160ff1b03821115613ef65760405162461bcd60e51b81526004016104a0906152e5565b8060ff16601b14158015613f0e57508060ff16601c14155b15613f2b5760405162461bcd60e51b81526004016104a090615532565b600060018783868660405160008152602001604052604051613f509493929190614cf3565b6020604051602081039080840390855afa158015613f72573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613fa55760405162461bcd60e51b81526004016104a090614d95565b9695505050505050565b60008184841115613ade5760405162461bcd60e51b81526004016104a09190614d4c565b604080518082019091526001808252602d60f81b60208301528251845160609386939092869286929101016001600160401b038111801561401357600080fd5b506040519080825280601f01601f19166020018201604052801561403e576020820181803683370190505b5090506000805b85518210156140995785828151811061405a57fe5b602001015160f81c60f81b83828060010193508151811061407757fe5b60200101906001600160f81b031916908160001a905350600190910190614045565b846000815181106140a657fe5b602001015160f81c60f81b8382806001019350815181106140c357fe5b60200101906001600160f81b031916908160001a905350600091505b8351821015614133578382815181106140f457fe5b602001015160f81c60f81b83828060010193508151811061411157fe5b60200101906001600160f81b031916908160001a9053506001909101906140df565b5090979650505050505050565b6040805160c08101825260008082526020820181905260609282018390529181018290526080810182905260a081019190915290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106141b757805160ff19168380011785556141e4565b828001600101855582156141e4579182015b828111156141e45782518255916020019190600101906141c9565b506141f09291506141f4565b5090565b61054d91905b808211156141f057600081556001016141fa565b803561065c81615f5e565b8035801515811461065c57600080fd5b600082601f830112614239578081fd5b81356001600160401b0381111561424e578182fd5b614261601f8201601f1916602001615f0c565b915080825283602082850101111561427857600080fd5b8060208401602084013760009082016020015292915050565b80356004811061065c57600080fd5b80356002811061065c57600080fd5b80356007811061065c57600080fd5b60008083601f8401126142cf578182fd5b5081356001600160401b038111156142e5578182fd5b6020830191508360208285010111156142fd57600080fd5b9250929050565b60006101c0808385031215614317578182fd5b61432081615f0c565b91505061432d838361448a565b815261433c836020840161445c565b602082015261434e836040840161420e565b604082015261436083606084016142af565b606082015261437283608084016142a0565b60808201526143848360a08401614473565b60a08201526143968360c08401614219565b60c08201526143a88360e08401614473565b60e08201526101006143bc84828501614473565b90820152610120828101356001600160401b03808211156143dc57600080fd5b6143e886838701614229565b8385015261014092506143fd86848701614291565b83850152610160925061441286848701614291565b83850152610180925061442786848701614473565b838501526101a092508285013591508082111561444357600080fd5b5061445085828601614229565b82840152505092915050565b80356001600160801b038116811461065c57600080fd5b80356001600160401b038116811461065c57600080fd5b803560ff8116811461065c57600080fd5b6000602082840312156144ac578081fd5b813561072f81615f5e565b600080604083850312156144c9578081fd5b82356144d481615f5e565b915060208301356144e481615f5e565b809150509250929050565b600080600060408486031215614503578081fd5b833561450e81615f5e565b925060208401356001600160401b03811115614528578182fd5b614534868287016142be565b9497909650939450505050565b600060208284031215614552578081fd5b5035919050565b6000806000806060858703121561456e578182fd5b843561457981615f5e565b935060208501356001600160401b03811115614593578283fd5b61459f878288016142be565b90945092506145b39050866040870161448a565b905092959194509250565b600080604083850312156145d0578182fd5b82356145db81615f5e565b946020939093013593505050565b6000806000604084860312156145fd578081fd5b83356001600160401b03811115614612578182fd5b61461e868287016142be565b909790965060209590950135949350505050565b600080600060408486031215614646578081fd5b83356001600160401b038082111561465c578283fd5b614668878388016142be565b9095509350602086013591508082168214614681578283fd5b50809150509250925092565b6000806000606084860312156146a1578081fd5b83356001600160401b03808211156146b7578283fd5b6146c387838801614304565b945060208601359150808211156146d8578283fd5b6146e487838801614304565b935060408601359150808211156146f9578283fd5b6101c091860180880383131561470d578384fd5b61471683615f0c565b8135935082841115614726578485fd5b61473289858401614229565b81526020820135935082841115614747578485fd5b61475389858401614229565b6020820152614765896040840161420e565b6040820152614777896060840161420e565b60608201526147898960808401614473565b608082015261479b8960a08401614473565b60a08201526147ad8960c08401614473565b60c08201526147bf8960e08401614473565b60e082015261010093506147d58985840161420e565b8482015261012093506147ea8985840161420e565b8482015261014093506147ff89858401614473565b84820152610160935061481489858401614473565b84820152610180935061482989858401614473565b848201526101a0935061483e898584016142a0565b84820152809450505050509250925092565b600060208284031215614861578081fd5b81356001600160401b0380821115614877578283fd5b61012091840180860383131561488b578384fd5b61489483615f0c565b61489e87836142a0565b81526148ad876020840161445c565b60208201526148bf876040840161420e565b604082015260608201359350828411156148d7578485fd5b6148e387858401614229565b60608201526148f5876080840161420e565b60808201526149078760a08401614473565b60a08201526149198760c08401614473565b60c082015261492b8760e08401614219565b60e082015261010093508382013583811115614945578586fd5b61495188828501614229565b948201949094529695505050505050565b600060208284031215614973578081fd5b61072f838361445c565b60006020828403121561498e578081fd5b5051919050565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b600081518084526149d7816020860160208601615f32565b601f01601f19169290920160200192915050565b60609190911b6001600160601b031916815260140190565b600088151560f81b82528751614a20816001850160208c01615f32565b8751908301614a36826001830160208c01615f32565b8751918101614a4c836001830160208c01615f32565b60f897881b6001600160f81b0319908116600192909401918201939093529590961b166002850152505060c01b6001600160c01b0319166003820152600b0195945050505050565b60008351614aa6818460208801615f32565b8351908301614ab9828260208801615f32565b01949350505050565b60008251614ad4818460208701615f32565b9190910192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b608086901b6001600160801b0319168152606085901b6001600160601b03191660108201528351600090614b4a816024850160208901615f32565b8451908301614b60826024830160208901615f32565b93151560f81b602494909101938401525050602501949350505050565b6001600160f81b031960f889901b811682526001600160801b0319608089901b1660018301526001600160601b0319606088901b166011830152855160009190614bce816025860160208b01615f32565b808401828860f81b166025820152828760f81b16602682015285519250614bfc836027830160208901615f32565b9091016027019a9950505050505050505050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b038a811682528916602082015261012060408201819052600090614ca88382018b6149bf565b8381036060850152614cba818b6149bf565b6001600160401b03998a16608086015297891660a08501525050509290941660c083015260e08201526101000191909152949350505050565b93845260ff9290921660208401526040830152606082015260800190565b6000602082526110eb602083018486614995565b600060408252614d39604083018587614995565b905060ff83166020830152949350505050565b60006020825261072f60208301846149bf565b600060808252614d7260808301876149bf565b6001600160401b0395861660208401529390941660408201526060015292915050565b60208082526018908201527745434453413a20696e76616c6964207369676e617475726560401b604082015260600190565b602080825260189082015277496e76616c69642077616c6c6574207369676e617475726560401b604082015260600190565b60208082526018908201527721b0b63632b91034b9903737ba103234b9b830ba31b432b960411b604082015260600190565b6020808252604c908201527f546f6b656e20636f6e74726163742072657475726e6564207472616e7366657260408201527f46726f6d207375636365737320776974686f757420657870656374656420626160608201526b6c616e6365206368616e676560a01b608082015260a00190565b60208082526023908201527f4e6f6e63652074696d657374616d7020616c726561647920696e76616c6964616040820152621d195960ea1b606082015260800190565b6020808252600f908201526e496e76616c6964206164647265737360881b604082015260600190565b6020808252601490820152730a6f2dac4ded8e640c8de40dcdee840dac2e8c6d60631b604082015260600190565b6020808252601f908201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604082015260600190565b6020808252601390820152724578636573736976652074616b65722066656560681b604082015260600190565b60208082526027908201527f4e6574206261736520706c757320666565206973206e6f7420657175616c20746040820152666f2067726f737360c81b606082015260800190565b6020808252602c908201527f4d616b657220616e642074616b65722066656520617373657473206d7573742060408201526b189948191a5999995c995b9d60a21b606082015260800190565b60208082526024908201527f4d75737420626520646966666572656e742066726f6d2063757272656e7420616040820152633236b4b760e11b606082015260800190565b6020808252600f908201526e135d5cdd081899481d8c4815555251608a1b604082015260600190565b602080825260139082015272457863657373697665206d616b65722066656560681b604082015260600190565b6020808252601b908201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604082015260600190565b6020808252601a908201527914d95b1b081dd85b1b195d08195e1a5d08199a5b985b1a5e995960321b604082015260600190565b6020808252601d908201527f4554482073796d626f6c20726573657276656420666f72204574686572000000604082015260600190565b6020808252601390820152725175616e7469747920697320746f6f206c6f7760681b604082015260600190565b60208082526033908201527f427579206f72646572206d61726b65742073796d626f6c2061646472657373206040820152720e4cae6ded8eae8d2dedc40dad2e6dac2e8c6d606b1b606082015260800190565b60208082526023908201527f526567697374726174696f6e206f6620746f6b656e206e6f742066696e616c696040820152621e995960ea1b606082015260800190565b6020808252600d908201526c2ab735b737bbb7103a37b5b2b760991b604082015260600190565b60208082526022908201527f53656c6c206f72646572206e6f6e63652074696d657374616d7020746f6f206c6040820152616f7760f01b606082015260800190565b60208082526031908201527f4f726465722071756f7465207175616e74697479206f6e6c792076616c696420604082015270666f72206d61726b6574206f726465727360781b606082015260800190565b60208082526022908201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604082015261756560f01b606082015260800190565b60208082526024908201527f4d616b657220666565206173736574206973206e6f7420696e207472616465206040820152633830b4b960e11b606082015260800190565b60208082526027908201527f546f6b656e2063616e6e6f742068617665206d6f7265207468616e20333220646040820152666563696d616c7360c81b606082015260800190565b60208082526021908201527f4e6f6e63652074696d657374616d7020746f6f2066617220696e2066757475726040820152606560f81b606082015260800190565b60208082526019908201527815d85b1b195d08195e1a5d081b9bdd08199a5b985b1a5e9959603a1b604082015260600190565b602080825260159082015274088cac6d2dac2d8e640c8de40dcdee840dac2e8c6d605b1b604082015260600190565b60208082526018908201527714d95b198b5d1c98591a5b99c81b9bdd08185b1b1bddd95960421b604082015260600190565b60208082526027908201527f4261736520616e642071756f746520617373657473206d7573742062652064696040820152661999995c995b9d60ca1b606082015260800190565b6020808252818101527f5369676e617475726520686173682076657273696f6e206d7573742062652031604082015260600190565b60208082526015908201527415d85b1b195d08185b1c9958591e48195e1a5d1959605a1b604082015260600190565b60208082526022908201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604082015261756560f01b606082015260800190565b6020808252601f908201527f557365206465706f736974457468657220746f206465706f7369742045544800604082015260600190565b6020808252601890820152774d757374206265206c657373207468616e2031207765656b60401b604082015260600190565b60208082526024908201527f54616b657220666565206173736574206973206e6f7420696e207472616465206040820152633830b4b960e11b606082015260800190565b60208082526023908201527f4e6f20636f6e6669726d656420617373657420666f756e6420666f722073796d604082015262189bdb60ea1b606082015260800190565b60208082526010908201526f13dc99195c881bdd995c999a5b1b195960821b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b602080825260189082015277457863657373697665207769746864726177616c2066656560401b604082015260600190565b6020808252601d908201527f506970207175616e74697479206f766572666c6f77732075696e743634000000604082015260600190565b60208082526021908201527f557365206465706f736974457468657220746f206465706f73697420457468656040820152603960f91b606082015260800190565b60208082526014908201527321b0b63632b91036bab9ba1031329037bbb732b960611b604082015260600190565b60208082526029908201527f4d75737420626520646966666572656e742066726f6d2063757272656e7420666040820152681959481dd85b1b195d60ba1b606082015260800190565b6020808252601e908201527f437573746f6469616e2063616e206f6e6c7920626520736574206f6e63650000604082015260600190565b6020808252601690820152752430b9b41030b63932b0b23c903bb4ba34323930bbb760511b604082015260600190565b602080825260179082015276151bdad95b88185b1c9958591e48199a5b985b1a5e9959604a1b604082015260600190565b60208082526029908201527f4d75737420626520646966666572656e742066726f6d2063757272656e74206460408201526834b9b830ba31b432b960b91b606082015260800190565b6020808252601e908201527f427579206f72646572206c696d69742070726963652065786365656465640000604082015260600190565b60208082526013908201527213dc99195c88191bdd589b1948199a5b1b1959606a1b604082015260600190565b60208082526021908201527f427579206f72646572206e6f6e63652074696d657374616d7020746f6f206c6f6040820152607760f81b606082015260800190565b60208082526024908201527f4e6f20636f6e6669726d656420617373657420666f756e6420666f72206164646040820152637265737360e01b606082015260800190565b60208082526014908201527321b0b63632b91036bab9ba1031329030b236b4b760611b604082015260600190565b602080825260139082015272115512081d1c985b9cd9995c8819985a5b1959606a1b604082015260600190565b60208082526027908201527f41737365742063616e6e6f742068617665206d6f7265207468616e20333220646040820152666563696d616c7360c81b606082015260800190565b60208082526034908201527f53656c6c206f72646572206d61726b65742073796d626f6c2061646472657373604082015273040e4cae6ded8eae8d2dedc40dad2e6dac2e8c6d60631b606082015260800190565b602080825260159082015274496e76616c696420746f6b656e206164647265737360581b604082015260600190565b60208082526030908201527f50726576696f757320696e76616c69646174696f6e206177616974696e67206360408201526f3430b4b710383937b830b3b0ba34b7b760811b606082015260800190565b60208082526028908201527f4e65742071756f746520706c757320666565206973206e6f7420657175616c20604082015267746f2067726f737360c01b606082015260800190565b6020808252601f908201527f53656c6c206f72646572206c696d697420707269636520657863656564656400604082015260600190565b602080825260149082015273125b9d985b1a59081d1bdad95b881cde5b589bdb60621b604082015260600190565b60208082526011908201527015d85b1b195d081b9bdd08195e1a5d1959607a1b604082015260600190565b602080825260169082015275496e76616c69642077616c6c6574206164647265737360501b604082015260600190565b6020808252602b908201527f496d706c6965642071756f746520706970207175616e74697479206f7665726660408201526a1b1bdddcc81d5a5b9d0d8d60aa1b606082015260800190565b60208082526048908201527f546f6b656e20636f6e74726163742072657475726e6564207472616e7366657260408201527f207375636365737320776974686f75742065787065637465642062616c616e6360608201526765206368616e676560c01b608082015260a00190565b602080825260199082015278109d5e481dd85b1b195d08195e1a5d08199a5b985b1a5e9959603a1b604082015260600190565b60208082526028908201527f51756f7465207175616e74697479206d7573742062652067726561746572207460408201526768616e207a65726f60c01b606082015260800190565b6020808252600d908201526c15d85b1b195d08195e1a5d1959609a1b604082015260600190565b602080825260149082015273139bc818985b185b98d948199bdc88185cdcd95d60621b604082015260600190565b60208082526027908201527f42617365207175616e74697479206d7573742062652067726561746572207468604082015266616e207a65726f60c81b606082015260800190565b60006020825282511515602083015260018060a01b036020840151166040830152604083015160c06060840152615e4160e08401826149bf565b60ff60608601511660808501526080850151151560a08501526001600160401b0360a08601511660c0850152809250505092915050565b6001600160801b039390931683526001600160401b03919091166020830152604082015260600190565b90815260200190565b918252602082015260400190565b6001600160401b0391909116815260200190565b60006001600160401b03808816835260a06020840152615ef060a08401886149bf565b9581166040840152939093166060820152608001525092915050565b6040518181016001600160401b0381118282101715615f2a57600080fd5b604052919050565b60005b83811015615f4d578181015183820152602001615f35565b838111156108dd5750506000910152565b6001600160a01b0381168114615f7357600080fd5b5056fe496e76616c69642077616c6c6574207369676e617475726520666f7220627579206f72646572496e76616c69642077616c6c6574207369676e617475726520666f722073656c6c206f72646572a26469706673582212205dd7ac35c5f7c6f5ec79f4ba79633e7c75138d994328bbe33fa2efc0d21be22d64736f6c63430006080033
Deployed Bytecode Sourcemap
1220:38806:5:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;9;2:12;35081:281:5;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;35081:281:5;;;;;;;;:::i;:::-;;11712:85;;5:9:-1;2:2;;;27:1;24;17:12;2:2;11712:85:5;;;:::i;:::-;;;;;;;;;;;;;;;;37580:151;;5:9:-1;2:2;;;27:1;24;17:12;2:2;37580:151:5;;;:::i;8990:422::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;8990:422:5;;;;;;;;:::i;:::-;;;;;;;;9793:465;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;9793:465:5;;;;;;;;:::i;7507:455::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;7507:455:5;;;;;;;;:::i;6843:249::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;6843:249:5;;;;;;;;:::i;13497:442::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;13497:442:5;;;;;;;;:::i;34477:248::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;34477:248:5;;;;;;;;:::i;22047:187::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;22047:187:5;;;:::i;23190:1171::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;23190:1171:5;;;;;;;;:::i;18097:2154::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;18097:2154:5;;;;;;;;:::i;733:222:7:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;733:222:7;;;;;;;;:::i;35628:209:5:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;35628:209:5;;;;;;;;:::i;36433:215::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;36433:215:5;;;;;;;;:::i;:::-;;;;;;;;8216:368;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;8216:368:5;;;;;;;;:::i;21111:778::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;21111:778:5;;;;;;;;:::i;12509:96::-;;;:::i;1097:74:7:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1097:74:7;;;:::i;12270:178:5:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;12270:178:5;;;;;;;;:::i;:::-;;;;;;;;36930:439;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;36930:439:5;;;;;;;;:::i;16672:1168::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;16672:1168:5;;;;;;;;:::i;10626:238::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;10626:238:5;;;;;;;;:::i;12899:285::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;12899:285:5;;;;;;;;:::i;20557:292::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;20557:292:5;;;:::i;11230:370::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;-1:-1;11230:370:5;;;;;;;;:::i;35081:281::-;361:6:7;;-1:-1:-1;;;;;361:6:7;347:10;:20;339:53;;;;-1:-1:-1;;;339:53:7;;;;;;;;;;;;;;;;;35217:71:5::1;35257:12;35271:6;;35217:71;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16:::0;::::1;74:27:::0;;;;-1:-1;35217:14:5::1;::::0;:71;;-1:-1:-1;35279:8:5;;-1:-1:-1;;35217:71:5::1;:39;:71;:::i;:::-;35326:12;-1:-1:-1::0;;;;;35299:58:5::1;;35340:6;;35348:8;35299:58;;;;;;;;;;;;;;;;;35081:281:::0;;;;:::o;11712:85::-;11782:10;;-1:-1:-1;;;;;11782:10:5;11712:85;;:::o;37580:151::-;361:6:7;;-1:-1:-1;;;;;361:6:7;347:10;:20;339:53;;;;-1:-1:-1;;;339:53:7;;;;;;;;;37656:17:5::1;::::0;37638:50:::1;::::0;::::1;::::0;::::1;::::0;-1:-1:-1;;;;;37656:17:5;;::::1;::::0;::::1;::::0;37638:50:::1;;;;;;;;;;37694:17;:32:::0;;-1:-1:-1;;;;;;37694:32:5::1;::::0;;37580:151::o;8990:422::-;9105:7;-1:-1:-1;;;;;9128:22:5;;9120:57;;;;-1:-1:-1;;;9120:57:5;;;;;;;;;9184:26;;:::i;:::-;9213:59;:14;9254:12;9213:59;:33;:59;:::i;:::-;-1:-1:-1;;;;;9338:23:5;;;;;;;:15;:23;;;;;;;;:37;;;;;;;;;;9385:14;;;;9184:88;;-1:-1:-1;9291:116:5;;-1:-1:-1;;;;;9338:37:5;;;;9291;:116::i;:::-;9278:129;;;8990:422;;;;;:::o;9793:465::-;9914:7;-1:-1:-1;;;;;9937:22:5;;9929:57;;;;-1:-1:-1;;;9929:57:5;;;;;;;;;9993:26;;:::i;:::-;10022:90;10062:11;;10022:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;10081:25:5;;-1:-1:-1;10081:23:5;;-1:-1:-1;;10081:25:5:i;:::-;10022:14;;:90;;:32;:90;:::i;:::-;-1:-1:-1;;;;;10178:23:5;;;;;;;:15;:23;;;;;;;;10202:18;;;;10178:43;;;;;;;;;;10231:14;;;;9993:119;;-1:-1:-1;10131:122:5;;-1:-1:-1;;;;;10178:43:5;;;;10131:37;:122::i;:::-;10118:135;;;9793:465;;;;;;:::o;7507:455::-;361:6:7;;-1:-1:-1;;;;;361:6:7;347:10;:20;339:53;;;;-1:-1:-1;;;339:53:7;;;;;;;;;5957:23:5::1;7627:25;:54;7612:109;;;;-1:-1:-1::0;;;7612:109:5::1;;;;;;;;;7764:23;::::0;;7793:51;;;;7856:101:::1;::::0;::::1;::::0;::::1;::::0;7764:23;;7819:25;;7856:101:::1;;;;;;;;;;398:1:7;7507:455:5::0;:::o;6843:249::-;361:6:7;;-1:-1:-1;;;;;361:6:7;347:10;:20;339:53;;;;-1:-1:-1;;;339:53:7;;;;;;;;;6928:10:5::1;::::0;-1:-1:-1;;;;;6928:10:5::1;:26:::0;6920:69:::1;;;;-1:-1:-1::0;;;6920:69:5::1;;;;;;;;;7003:32;7022:12;7003:18;:32::i;:::-;6995:60;;;;-1:-1:-1::0;;;6995:60:5::1;;;;;;;;;7062:10;:25:::0;;-1:-1:-1;;;;;;7062:25:5::1;-1:-1:-1::0;;;;;7062:25:5;;;::::1;::::0;;;::::1;::::0;;6843:249::o;13497:442::-;13613:19;13649:81;13691:11;;13649:81;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;13704:25:5;;-1:-1:-1;13704:23:5;;-1:-1:-1;;13704:25:5:i;13649:81::-;:103;;;;-1:-1:-1;;;;;;13779:37:5;;13764:99;;;;-1:-1:-1;;;13764:99:5;;;;;;;;;13870:64;13878:10;13898:12;13913:20;13870:7;:64::i;:::-;13497:442;;;;:::o;34477:248::-;361:6:7;;-1:-1:-1;;;;;361:6:7;347:10;:20;339:53;;;;-1:-1:-1;;;339:53:7;;;;;;;;;34602:60:5::1;34631:12;34645:6;;34602:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16:::0;::::1;74:27:::0;;;;-1:-1;34602:14:5::1;::::0;:60;;-1:-1:-1;34653:8:5;;-1:-1:-1;;34602:60:5::1;:28;:60;:::i;:::-;34689:12;-1:-1:-1::0;;;;;34673:47:5::1;;34703:6;;34711:8;34673:47;;;;;;;;;22047:187:::0;22110:10;22097:24;;;;:12;:24;;;;;:31;;;22089:61;;;;-1:-1:-1;;;22089:61:5;;;;;;;;;22177:10;22164:24;;;;:12;:24;;;;;;22157:31;;-1:-1:-1;;22157:31:5;;;;;;;;22200:29;;;22164:24;22200:29;22047:187::o;23190:1171::-;37789:17;;-1:-1:-1;;;;;37789:17:5;37775:10;:31;37767:68;;;;-1:-1:-1;;;37767:68:5;;;;;;;;;23362:40:::1;23384:3;:17;;;23362:21;:40::i;:::-;23361:41;23346:97;;;;-1:-1:-1::0;;;23346:97:5::1;;;;;;;;;23465:41;23487:4;:18;;;23465:21;:41::i;:::-;23464:42;23449:99;;;;-1:-1:-1::0;;;23449:99:5::1;;;;;;;;;23590:4;:18;;;-1:-1:-1::0;;;;;23569:39:5::1;:3;:17;;;-1:-1:-1::0;;;;;23569:39:5::1;;;23554:94;;;;-1:-1:-1::0;;;23554:94:5::1;;;;;;;;;23655:35;23673:3;23678:4;23684:5;23655:17;:35::i;:::-;23696:37;23716:3;23721:4;23727:5;23696:19;:37::i;:::-;23739:30;23759:3;23764:4;23739:19;:30::i;:::-;23776:15;23793:16:::0;23813:65:::1;23844:3;23855:4;23867:5;23813:23;:65::i;:::-;23775:103;;;;23884:24;23902:5;23884:17;:24::i;:::-;23915:64;23943:3;23948:7;23957:4;23963:8;23973:5;23915:27;:64::i;:::-;23985:40;24008:3;24013:4;24019:5;23985:22;:40::i;:::-;24138:5;:22;;;24037:319;;;;;;;;;::::0;;;;::::1;::::0;;24109:21;;24037:319;;::::1;::::0;24109:21;24037:319:::1;;;;;;;;;;;24058:3;:17;;;24083:4;:18;;;24168:5;:21;;;24197:5;:22;;;24227:5;:29;;;24264:5;:30;;;24302:5;:17;;;24327:7;24342:8;24037:319;;;;;;;;;;;;;;;;;;;;;;;37841:1;;23190:1171:::0;;;:::o;18097:2154::-;37789:17;;-1:-1:-1;;;;;37789:17:5;37775:10;:31;37767:68;;;;-1:-1:-1;;;37767:68:5;;;;;;;;;18232:47:::1;18254:10;:24;;;18232:21;:47::i;:::-;18231:48;18223:74;;;;-1:-1:-1::0;;;18223:74:5::1;;;;;;;;;6116:8;-1:-1:-1::0;;;;;18318:109:5::1;:69;18336:10;:23;;;18361:10;:25;;;18318:17;:69::i;:::-;-1:-1:-1::0;;;;;18318:109:5::1;;;18303:164;;;;-1:-1:-1::0;;;18303:164:5::1;;;;;;;;;18473:22;18498:39;18526:10;18498:27;:39::i;:::-;18559:42;::::0;;;:26:::1;:42;::::0;;;;;18473:64;;-1:-1:-1;18559:42:5::1;;18558:43;18543:96;;;;-1:-1:-1::0;;;18543:96:5::1;;;;;;;;;18730:26;;:::i;:::-;18794:29;18759:25:::0;;:64:::1;::::0;::::1;;;;;;;:271;;19006:23;::::0;::::1;::::0;18972:58:::1;::::0;:14:::1;::::0;:58:::1;:33;:58;:::i;:::-;18759:271;;;18832:131;18874:10;:22;;;18906:49;18938:10;:16;;;18906:31;:49::i;18832:131::-;18730:300;;19085:29;19117:66;19154:10;:23;;;19117:10;:25;;;-1:-1:-1::0;;;;;19117:29:5::1;;;:66;;;;:::i;:::-;19085:98;;19189:36;19228:84;19273:22;19297:5;:14;;;19228:44;:84::i;:::-;19432:25;::::0;::::1;::::0;19368:31:::1;::::0;;::::1;::::0;-1:-1:-1;;;;;19352:48:5;;::::1;19318:31;19352:48:::0;;;:15:::1;:48;::::0;;;;;;19401:18;;::::1;::::0;19352:68;;::::1;::::0;;;;;;;;;;19189:123;;-1:-1:-1;19318:31:5;19352:106:::1;::::0;-1:-1:-1;;;;;19352:68:5;;::::1;::::0;:106:::1;:79;:106;:::i;:::-;19318:140;;19464:38;19505:86;19550:24;19576:5;:14;;;19505:44;:86::i;:::-;19614:24;::::0;;::::1;::::0;-1:-1:-1;;;;;19598:41:5;;::::1;;::::0;;;:15:::1;:41;::::0;;;;;;19640:25;;::::1;::::0;;19598:68;::::1;::::0;;;;;;;;:95;;-1:-1:-1;;;;;;19598:95:5::1;-1:-1:-1::0;;;;;19598:95:5;;::::1;::::0;;;::::1;::::0;;;19815:23:::1;::::0;::::1;::::0;19772:10:::1;::::0;;::::1;19756:27:::0;;;;;;;;19784:18;;19756:47;;::::1;::::0;;;;;;;;19464:127;;-1:-1:-1;19756:88:5::1;::::0;:47:::1;::::0;:51:::1;:88::i;:::-;19715:10;::::0;-1:-1:-1;;;;;19715:10:5;;::::1;19699:27;::::0;;;:15:::1;:27;::::0;;;;;;;19727:25;;::::1;::::0;;19699:54;::::1;::::0;;;;;;;;:145;;-1:-1:-1;;;;;;19699:145:5::1;-1:-1:-1::0;;;;;19699:145:5;;;::::1;::::0;;;::::1;::::0;;;19862:10:::1;::::0;19890:24;;::::1;::::0;19922:18;;19851:131;;-1:-1:-1;;;19851:131:5;;19862:10;::::1;::::0;19851:31:::1;::::0;:131:::1;::::0;19922:18;19948:28;;19851:131:::1;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;2:2;19851:131:5;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;-1:-1:::0;;;19989:42:5::1;::::0;;;:26:::1;:42;::::0;;;;;;;;:49;;-1:-1:-1;;19989:49:5::1;20034:4;19989:49;::::0;;20099:18;::::1;::::0;20067:24;;::::1;::::0;20125:12;;::::1;::::0;20145:25:::1;::::0;::::1;::::0;20050:196;;-1:-1:-1;;;;;20050:196:5;;::::1;::::0;-1:-1:-1;20050:196:5;;;::::1;::::0;::::1;::::0;::::1;::::0;20125:12;;20145:25;20178:24;;20210:30;;20050:196:::1;;;;;;;;;;37841:1;;;;;;18097:2154:::0;:::o;733:222:7:-;254:10;-1:-1:-1;;;;;268:6:7;254:20;;246:53;;;;-1:-1:-1;;;246:53:7;;;;;;;;;-1:-1:-1;;;;;802:24:7;::::1;794:59;;;;-1:-1:-1::0;;;794:59:7::1;;;;;;;;;879:6;::::0;-1:-1:-1;;;;;867:18:7;;::::1;879:6:::0;::::1;867:18;;859:67;;;;-1:-1:-1::0;;;859:67:7::1;;;;;;;;;933:6;:17:::0;;-1:-1:-1;;;;;;933:17:7::1;-1:-1:-1::0;;;;;933:17:7;;;::::1;::::0;;;::::1;::::0;;733:222::o;35628:209:5:-;361:6:7;;-1:-1:-1;;;;;361:6:7;347:10;:20;339:53;;;;-1:-1:-1;;;339:53:7;;;;;;;;;35732:51:5::1;35762:12;35776:6;;35732:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16:::0;::::1;74:27:::0;;;;-1:-1;35732:14:5::1;::::0;:51;;-1:-1:-1;;35732:51:5::1;:29;:51;::::0;-1:-1:-1;35732:51:5:i:1;:::-;35811:12;-1:-1:-1::0;;;;;35794:38:5::1;;35825:6;;35794:38;;;;;;;;;;;;;;;;35628:209:::0;;;:::o;36433:215::-;36546:20;;:::i;:::-;36583:60;36616:11;;36583:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;36583:14:5;;:60;-1:-1:-1;36629:13:5;;-1:-1:-1;;36583:60:5;:32;:60;:::i;:::-;36576:67;36433:215;-1:-1:-1;;;;36433:215:5:o;8216:368::-;361:6:7;;-1:-1:-1;;;;;361:6:7;347:10;:20;339:53;;;;-1:-1:-1;;;339:53:7;;;;;;;;;-1:-1:-1;;;;;8293:28:5;::::1;8285:63;;;;-1:-1:-1::0;;;8285:63:5::1;;;;;;;;;8385:10;::::0;-1:-1:-1;;;;;8369:26:5;;::::1;8385:10:::0;::::1;8369:26;;8354:98;;;;-1:-1:-1::0;;;8354:98:5::1;;;;;;;;;8482:10;::::0;;-1:-1:-1;;;;;8498:25:5;;::::1;-1:-1:-1::0;;;;;;8498:25:5;::::1;;::::0;;;8535:44:::1;::::0;8482:10;::::1;::::0;8535:44:::1;::::0;::::1;::::0;8482:10;;8511:12;;8535:44:::1;;21111:778:::0;21178:33;21200:10;21178:21;:33::i;:::-;21170:71;;;;-1:-1:-1;;;21170:71:5;;;;;;;;;21248:26;;:::i;:::-;21277:59;:14;21318:12;21277:59;:33;:59;:::i;:::-;21381:10;21342:20;21365:27;;;:15;:27;;;;;;;;-1:-1:-1;;;;;21365:41:5;;;;;;;;;;21508:14;;;;21248:88;;-1:-1:-1;;;;;;21365:41:5;;21442:86;;21365:41;;21442:37;:86::i;:::-;21412:116;;21565:1;21543:19;:23;21535:56;;;;-1:-1:-1;;;21535:56:5;;;;;;;;;21613:10;21641:1;21597:27;;;:15;:27;;;;;;;;-1:-1:-1;;;;;21597:41:5;;;;;;;;;;;:45;;-1:-1:-1;;;;;;21597:45:5;;;21659:10;;21648:102;;-1:-1:-1;;;21648:102:5;;21659:10;;;21648:31;;:102;;21613:10;21625:12;;21725:19;;21648:102;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;21648:102:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;21648:102:5;;;;21807:12;-1:-1:-1;;;;;21762:122:5;21789:10;-1:-1:-1;;;;;21762:122:5;;21827:5;:12;;;21847:13;21868:1;21877;21762:122;;;;;;;;;;;;;;;;;;21111:778;;;;:::o;12509:96::-;12556:44;12564:10;12584:3;12590:9;12556:7;:44::i;:::-;12509:96::o;1097:74:7:-;254:10;-1:-1:-1;;;;;268:6:7;254:20;;246:53;;;;-1:-1:-1;;;246:53:7;;;;;;;;;1162:3:::1;1145:21:::0;;-1:-1:-1;;;;;;1145:21:7::1;::::0;;1097:74::o;12270:178:5:-;12372:6;12395:48;;;:37;:48;;;;;;-1:-1:-1;;;;;12395:48:5;12270:178;;;;:::o;36930:439::-;361:6:7;;-1:-1:-1;;;;;361:6:7;347:10;:20;339:53;;;;-1:-1:-1;;;339:53:7;;;;;;;;;-1:-1:-1;;;;;37015:35:5;::::1;37007:70;;;;-1:-1:-1::0;;;37007:70:5::1;;;;;;;;;37121:17;::::0;-1:-1:-1;;;;;37098:40:5;;::::1;37121:17:::0;::::1;37098:40;;37083:112;;;;-1:-1:-1::0;;;37083:112:5::1;;;;;;;;;37231:17;::::0;;-1:-1:-1;;;;;37254:39:5;;::::1;-1:-1:-1::0;;;;;;37254:39:5;::::1;;::::0;;;37305:59:::1;::::0;37231:17;::::1;::::0;37305:59:::1;::::0;::::1;::::0;37231:17;;37274:19;;37305:59:::1;;16672:1168:::0;16732:20;16755:38;16787:5;16755:31;:38::i;:::-;16732:61;;16978:22;:20;:22::i;:::-;-1:-1:-1;;;;;16962:38:5;:13;-1:-1:-1;;;;;16962:38:5;;16947:102;;;;-1:-1:-1;;;16947:102:5;;;;;;;;;17080:10;17060:31;;;;:19;:31;;;;;:38;;;17056:353;;;17145:10;17125:31;;;;:19;:31;;;;;:45;-1:-1:-1;;;;;17125:61:5;;;:45;;;;;:61;17108:133;;;;-1:-1:-1;;;17108:133:5;;;;;;;;;17286:10;17266:31;;;;:19;:31;;;;;:52;;;17322:12;-1:-1:-1;17266:68:5;17249:153;;;;-1:-1:-1;;;17249:153:5;;;;;;;;;17569:23;;17632:84;;;;;;;;17657:4;17632:84;;;-1:-1:-1;;;;;17632:84:5;;;;;;;;;;17554:12;:38;;;17632:84;;;;;;17618:10;-1:-1:-1;17598:31:5;;;:19;:31;;;;;;;:118;;;;;;-1:-1:-1;;17598:118:5;;;;;;;-1:-1:-1;;17598:118:5;;;;;;;;;;;;;;;;;;;;;;;;;17728:107;;17554:38;;17618:10;17728:107;;;;17775:5;;17632:84;;17554:38;;17728:107;;10626:238;10735:6;-1:-1:-1;;;;;10759:22:5;;10751:57;;;;-1:-1:-1;;;10751:57:5;;;;;;;;;-1:-1:-1;;;;;;10822:23:5;;;;;;;:15;:23;;;;;;;;:37;;;;;;;;;;;;-1:-1:-1;;;;;10822:37:5;;10626:238::o;12899:285::-;-1:-1:-1;;;;;13023:37:5;;13008:101;;;;-1:-1:-1;;;13008:101:5;;;;;;;;;13115:64;13123:10;13143:12;13158:20;13115:7;:64::i;:::-;12899:285;;:::o;20557:292::-;20616:10;20603:24;;;;:12;:24;;;;;:31;;;20602:32;20594:66;;;;-1:-1:-1;;;20594:66:5;;;;;;;;;20694:74;;;;;;;;20712:4;20694:74;;;20739:23;;;20724:12;:38;;;20694:74;;;;;;;20680:10;-1:-1:-1;20667:24:5;;;:12;:24;;;;;;;:101;;;;-1:-1:-1;;20667:101:5;;;;;;;;;;;;;;;;;20820:23;20780:64;;20680:10;;20780:64;;;;20805:38;;;20780:64;;;;;;;;;;20557:292::o;11230:370::-;11345:6;-1:-1:-1;;;;;11367:22:5;;11359:57;;;;-1:-1:-1;;;11359:57:5;;;;;;;;;11423:20;11446:79;11486:11;;11446:79;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;11499:25:5;;-1:-1:-1;11499:23:5;;-1:-1:-1;;11499:25:5:i;11446:79::-;:99;;;;;-1:-1:-1;;;;;11558:23:5;;;;;;;:15;:23;;;;;;:37;;;;;;;;;;;-1:-1:-1;;;;;11558:37:5;;-1:-1:-1;;11230:370:5;;;;;:::o;1488:714:1:-;1638:26;;:::i;:::-;-1:-1:-1;;;;;1667:43:1;;;:20;:43;;;;;;;;;;;;1638:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1638:72:1;;;;;;;;;;;;;;;;;;;;;;;;;1667:43;;1638:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1638:72:1;;;-1:-1:-1;;1638:72:1;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1638:72:1;;;;;;1724:12;;;;-1:-1:-1;1716:38:1;;;;-1:-1:-1;;;1716:38:1;;;;;;;;;1769:5;:17;;;1768:18;1760:54;;;;-1:-1:-1;;;1760:54:1;;;;;;;;;1828:35;1842:5;:12;;;1856:6;1828:13;:35::i;:::-;1820:68;;;;-1:-1:-1;;;1820:68:1;;;;;;;;;1920:8;1902:26;;:5;:14;;;:26;;;1894:60;;;;-1:-1:-1;;;1894:60:1;;;;;;;;;1981:4;1961:17;;;:24;;;-1:-1:-1;;;;;2047:4:1;2029:15;:22;1991:61;:28;;;:61;-1:-1:-1;;;;;2101:43:1;;;1961:24;2101:43;;;;;;;;;;;;:51;;;;;;;;;;;;;-1:-1:-1;;;;;;2101:51:1;;;-1:-1:-1;;2101:51:1;;;;;;;;;;;;;;;;;;;;1961:5;;2101:51;;;;;;;;;:::i;:::-;-1:-1:-1;2101:51:1;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2101:51:1;;;-1:-1:-1;;;;;;2101:51:1;;;;;-1:-1:-1;;2101:51:1;;;;-1:-1:-1;;2101:51:1;;;;;;;;;;;;;;;;;;;2158:27;;2101:51;2158:19;;;:27;;2178:6;;2158:27;;;;;;;;;;;;;;;;;;;;27:10:-1;;39:1;23:18;;;45:23;;-1:-1;2158:39:1;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2158:39:1;;;-1:-1:-1;;;;;;2158:39:1;;;-1:-1:-1;;2158:39:1;;;;;;;;;;;;;;;;;;;;;;;2191:5;;2158:39;;;;;;;;:::i;:::-;-1:-1:-1;2158:39:1;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2158:39:1;;;-1:-1:-1;;;;;;2158:39:1;;;;;-1:-1:-1;;2158:39:1;;;;-1:-1:-1;;2158:39:1;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1488:714:1:o;2953:405::-;3060:20;;:::i;:::-;-1:-1:-1;;;;;3094:28:1;;3090:69;;3139:13;:11;:13::i;:::-;3132:20;;;;3090:69;3165:26;;:::i;:::-;-1:-1:-1;;;;;3194:34:1;;;:20;:34;;;;;;;;;;;;3165:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3165:63:1;;;;;;;;;;;;;;;;;;;;;;;;;3194:34;;3165:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;3165:63:1;;;-1:-1:-1;;3165:63:1;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3165:63:1;;;;;;3249:12;;;;-1:-1:-1;3249:33:1;;;;;3265:5;:17;;;3249:33;3234:100;;;;-1:-1:-1;;;3234:100:1;;;;;;;;326:472:3;431:7;473:2;456:13;:19;;;;448:71;;;;-1:-1:-1;;;448:71:3;;;;;;;;;634:1;618:13;:17;;;614:106;;;652:61;-1:-1:-1;;;;;652:23:3;;680:32;-1:-1:-1;;694:17:3;;680:32;688:2;680:32;652:61;:27;:61;:::i;614:106::-;732:61;-1:-1:-1;;;;;732:23:3;;760:32;774:1;:17;;;760:32;768:2;760:32;732:61;:27;:61;:::i;38433:156:5:-;38552:15;38527:4;38545:39;38433:156;:::o;3722:691:1:-;3854:20;;:::i;:::-;3886:28;;;;;;;;;;;;;;-1:-1:-1;;;3886:28:1;;;3907:6;3886:13;:28::i;:::-;3882:69;;;3931:13;:11;:13::i;:::-;3924:20;;;;3882:69;3957:26;;:::i;:::-;4030:1;3993:4;:19;;4013:6;3993:27;;;;;;;;;;;;;;;;;;;;;:34;:38;3989:296;;;4046:7;4041:238;4063:4;:19;;4083:6;4063:27;;;;;;;;;;;;;;;;;;;;;:34;4059:38;;;;4041:238;;;4186:13;-1:-1:-1;;;;;4129:70:1;:4;:19;;4149:6;4129:27;;;;;;;;;;;;;;;;;;;;4157:1;4129:30;;;;;;;;;;;;;;;;;;;;;;;:53;;;;;;-1:-1:-1;;;;;4129:53:1;:70;4114:157;;4230:4;:19;;4250:6;4230:27;;;;;;;;;;;;;;;;;;;;4258:1;4230:30;;;;;;;;;;;;;;;;;;;4222:38;;;;;;;;4230:30;;;;;;;;4222:38;;;;;;;;;;;;;;-1:-1:-1;;;;;4222:38:1;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4222:38:1;;;;;;;;;;;;;;;;;;;;;;;;;4230:30;;4222:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;4222:38:1;;;-1:-1:-1;;4222:38:1;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;4222:38:1;;;;;;;-1:-1:-1;4114:157:1;4099:3;;4041:238;;;;3989:296;4305:12;;:33;;;;;4321:5;:17;;;4305:33;4290:99;;;;-1:-1:-1;;;4290:99:1;;;;;;;;718:413:0;1078:20;1116:8;;;718:413::o;13943:2369:5:-;-1:-1:-1;;;;;14297:20:5;;;;;;:12;:20;;;;;:27;;;14296:28;14288:54;;;;-1:-1:-1;;;14288:54:5;;;;;;;;;14349:26;;:::i;:::-;14378:59;:14;14419:12;14378:59;:33;:59;:::i;:::-;14349:88;;14443:21;14467:93;14512:20;14540:5;:14;;;14467:37;:93::i;:::-;14443:117;;14591:1;14574:14;-1:-1:-1;;;;;14574:18:5;;14566:50;;;;-1:-1:-1;;;14566:50:5;;;;;;;;;14983:49;15035:76;15080:14;15096:5;:14;;;15035:44;:76::i;:::-;14983:128;-1:-1:-1;;;;;;15359:28:5;;;15355:181;;15397:132;15434:6;15457:12;15480:41;15397:27;:132::i;:::-;15618:10;;15585:118;;-1:-1:-1;;;;;15618:10:5;15636:12;15656:41;15585:25;:118::i;:::-;-1:-1:-1;;;;;15744:23:5;;;15710:31;15744:23;;;:15;:23;;;;;;;;:37;;;;;;;;;;;;:69;;-1:-1:-1;;;;;15744:37:5;15793:14;15744:69;:41;:69;:::i;:::-;15710:103;;15819:38;15860:86;15905:24;15931:5;:14;;;15860:44;:86::i;:::-;-1:-1:-1;;;;;16008:23:5;;;;;;;:15;:23;;;;;;;;:37;;;;;;;;;;;:64;;-1:-1:-1;;;;;;16008:64:5;-1:-1:-1;;;;;16008:64:5;;;;;;;;;;16078:13;:15;;-1:-1:-1;;;;16078:15:5;;-1:-1:-1;;;16078:15:5;;;;;;-1:-1:-1;16078:15:5;;;;;;;;;;;16177:12;;;;16105:202;;15819:127;;-1:-1:-1;16105:202:5;;;;;;;;;;;;16157:12;-1:-1:-1;;;;;16105:202:5;16143:6;-1:-1:-1;;;;;16105:202:5;;16122:13;;;;;;;;;-1:-1:-1;;;;;16122:13:5;16197:5;:12;;;16217:14;16239:24;16271:30;16105:202;;;;;;;;;;;;;;;;;;;13943:2369;;;;;;;;:::o;623:861:1:-;782:2;770:8;:14;;;;762:66;;;;-1:-1:-1;;;762:66:1;;;;;;;;;-1:-1:-1;;;;;849:27:1;;;;;;:72;;;880:41;907:12;880:18;:41::i;:::-;834:124;;;;-1:-1:-1;;;834:124:1;;;;;;;;;1093:1;1076:6;1070:20;:24;1062:57;;;;-1:-1:-1;;;1062:57:1;;;;;;;;;-1:-1:-1;;;;;1141:43:1;;:20;:43;;;;;;;;;;:55;;;;;;;;1140:56;1125:110;;;;-1:-1:-1;;;1125:110:1;;;;;;;;;1288:191;;;;;;;;1318:4;1288:191;;;-1:-1:-1;;;;;1288:191:1;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1288:191:1;;;;;;;;;;;;1242:43;;;;;;;;;;:237;;;;;;-1:-1:-1;;1242:237:1;;;;;;;-1:-1:-1;;;;;;1242:237:1;;;;;;;;;;;;;;;;;;;;1288:191;;1242:43;:237;;;;;;;;;;;:::i;:::-;-1:-1:-1;1242:237:1;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1242:237:1;;;-1:-1:-1;;;;;;1242:237:1;;;;;-1:-1:-1;;1242:237:1;;;;-1:-1:-1;;1242:237:1;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;623:861:1:o;22238:202:5:-;-1:-1:-1;;;;;22346:20:5;;22308:4;22346:20;;;:12;:20;;;;;22379:11;;;;:56;;;;-1:-1:-1;22394:25:5;;;22423:12;-1:-1:-1;22394:41:5;;22372:63;-1:-1:-1;;22238:202:5:o;28054:1929::-;28238:5;:23;;;-1:-1:-1;;;;;28212:49:5;:5;:22;;;-1:-1:-1;;;;;28212:49:5;;;28197:119;;;;-1:-1:-1;;;28197:119:5;;;;;;;;;28352:33;;:::i;:::-;28388:117;28428:5;:21;;;28457:42;28489:3;:9;;;28457:31;:42::i;28388:117::-;28352:153;;28511:34;;:::i;:::-;28548:118;28588:5;:22;;;28618:42;28650:3;:9;;;28618:31;:42::i;28548:118::-;28511:155;;28716:5;:22;;;-1:-1:-1;;;;;28687:51:5;:12;:25;;;-1:-1:-1;;;;;28687:51:5;;:116;;;;;28780:5;:23;;;-1:-1:-1;;;;;28750:53:5;:13;:26;;;-1:-1:-1;;;;;28750:53:5;;28687:116;28672:198;;;;-1:-1:-1;;;28672:198:5;;;;;;;;;28907:34;;:::i;:::-;28944:118;28984:5;:21;;;29013:43;29045:4;:10;;;29013:31;:43::i;28944:118::-;28907:155;;29068:35;;:::i;:::-;29106:119;29146:5;:22;;;29176:43;29208:4;:10;;;29176:31;:43::i;29106:119::-;29068:157;;29276:5;:22;;;-1:-1:-1;;;;;29246:52:5;:13;:26;;;-1:-1:-1;;;;;29246:52:5;;:118;;;;;29341:5;:23;;;-1:-1:-1;;;;;29310:54:5;:14;:27;;;-1:-1:-1;;;;;29310:54:5;;29246:118;29231:201;;;;-1:-1:-1;;;29231:201:5;;;;;;;;;29512:5;:22;;;-1:-1:-1;;;;;29482:52:5;:5;:26;;;-1:-1:-1;;;;;29482:52:5;;:117;;;;29576:5;:23;;;-1:-1:-1;;;;;29546:53:5;:5;:26;;;-1:-1:-1;;;;;29546:53:5;;29482:117;29467:184;;;;-1:-1:-1;;;29467:184:5;;;;;;;;;29702:5;:22;;;-1:-1:-1;;;;;29672:52:5;:5;:26;;;-1:-1:-1;;;;;29672:52:5;;:117;;;;29766:5;:23;;;-1:-1:-1;;;;;29736:53:5;:5;:26;;;-1:-1:-1;;;;;29736:53:5;;29672:117;29657:184;;;;-1:-1:-1;;;29657:184:5;;;;;;;;;29892:5;:26;;;-1:-1:-1;;;;;29862:56:5;:5;:26;;;-1:-1:-1;;;;;29862:56:5;;;29847:131;;;;-1:-1:-1;;;29847:131:5;;;;;;;;;28054:1929;;;;;;;:::o;29987:909::-;30179:1;30147:5;:29;;;-1:-1:-1;;;;;30147:33:5;;30132:103;;;;-1:-1:-1;;;30132:103:5;;;;;;;;;30289:1;30256:5;:30;;;-1:-1:-1;;;;;30256:34:5;;30241:105;;;;-1:-1:-1;;;30241:105:5;;;;;;;;;30357:31;30374:3;:13;;;30357:16;:31::i;:::-;30353:265;;;30531:5;:30;;;-1:-1:-1;;;;;30415:146:5;:112;30456:5;:29;;;30497:3;:20;;;30415:29;:112::i;:::-;-1:-1:-1;;;;;30415:146:5;;;30398:213;;;;-1:-1:-1;;;30398:213:5;;;;;;;;;30628:32;30645:4;:14;;;30628:16;:32::i;:::-;30624:268;;;30804:5;:30;;;-1:-1:-1;;;;;30687:147:5;:113;30728:5;:29;;;30769:4;:21;;;30687:29;:113::i;:::-;-1:-1:-1;;;;;30687:147:5;;;30670:215;;;;-1:-1:-1;;;30670:215:5;;;;;;;;;29987:909;;;:::o;33209:453::-;33390:46;33418:3;:17;;;33390:27;:46::i;:::-;-1:-1:-1;;;;;33337:99:5;:42;33369:3;:9;;;33337:31;:42::i;:::-;-1:-1:-1;;;;;33337:99:5;;33322:163;;;;-1:-1:-1;;;33322:163:5;;;;;;;;;33560:47;33588:4;:18;;;33560:27;:47::i;:::-;-1:-1:-1;;;;;33506:101:5;:43;33538:4;:10;;;33506:31;:43::i;:::-;-1:-1:-1;;;;;33506:101:5;;33491:166;;;;-1:-1:-1;;;33491:166:5;;;;;;;;32277:346;32429:7;32438;32453:20;32476:34;32499:3;32504:5;32476:22;:34::i;:::-;32453:57;;32516:21;32540:35;32563:4;32569:5;32540:22;:35::i;:::-;32590:12;;;;-1:-1:-1;32277:346:5;;-1:-1:-1;;;;;32277:346:5:o;30900:1373::-;30974:31;31044:5;:22;;;-1:-1:-1;;;;;31008:58:5;:5;:26;;;-1:-1:-1;;;;;31008:58:5;;:135;;31113:5;:30;;;31008:135;;;31075:5;:29;;;31008:135;30974:169;;6049:8;-1:-1:-1;;;;;31164:124:5;:97;31191:5;:28;;;31229:24;31164:17;:97::i;:::-;-1:-1:-1;;;;;31164:124:5;;;31149:174;;;;-1:-1:-1;;;31149:174:5;;;;;;;;;31330:31;31400:5;:22;;;-1:-1:-1;;;;;31364:58:5;:5;:26;;;-1:-1:-1;;;;;31364:58:5;;:135;;31469:5;:30;;;31364:135;;;31431:5;:29;;;31364:135;31330:169;;6049:8;-1:-1:-1;;;;;31520:124:5;:97;31547:5;:28;;;31585:24;31520:17;:97::i;:::-;-1:-1:-1;;;;;31520:124:5;;;31505:174;;;;-1:-1:-1;;;31505:174:5;;;;;;;;;31888:5;:29;;;-1:-1:-1;;;;;31701:216:5;:183;31772:5;:22;;;-1:-1:-1;;;;;31742:52:5;:5;:26;;;-1:-1:-1;;;;;31742:52:5;;:134;;31848:5;:28;;;31742:134;;;31807:5;:28;;;31742:134;31701:27;;;;-1:-1:-1;;;;;31701:31:5;;:183;:31;:183;:::i;:::-;-1:-1:-1;;;;;31701:216:5;;31686:286;;;;-1:-1:-1;;;31686:286:5;;;;;;;;;32182:5;:30;;;-1:-1:-1;;;;;31993:219:5;:185;32065:5;:23;;;-1:-1:-1;;;;;32035:53:5;:5;:26;;;-1:-1:-1;;;;;32035:53:5;;:135;;32142:5;:28;;;32035:135;;;32101:5;:28;;;32035:135;31993:28;;;;-1:-1:-1;;;;;31993:32:5;;:185;:32;:185;:::i;:::-;-1:-1:-1;;;;;31993:219:5;;31978:290;;;;-1:-1:-1;;;31978:290:5;;;;;;;;25927:336;26138:56;26164:8;26174:12;26188:5;26138:25;:56::i;:::-;26200:58;26226:9;26237:13;26252:5;26200:25;:58::i;:::-;25927:336;;;;;:::o;24477:1446::-;24813:29;;;;24751:18;;;;;-1:-1:-1;;;;;24735:35:5;;;;;;;:15;:35;;;;;;;24771:29;;;;24735:66;;;;;;;;;;;:108;;-1:-1:-1;;;;;24735:66:5;;;;:108;:77;:108;:::i;:::-;24682:18;;;;;-1:-1:-1;;;;;24666:35:5;;;;;;;:15;:35;;;;;;;24702:29;;;;;24666:66;;;;;;;;;;:177;;-1:-1:-1;;;;;;24666:177:5;-1:-1:-1;;;;;24666:177:5;;;;;;25038:27;;;;24977:17;;;;24961:34;;;;;;;;;;24996:29;;24961:65;;;;;;;;;;;;;;:105;;:65;;:76;:105::i;:::-;24909:17;;;;;;-1:-1:-1;;;;;24893:34:5;;;;;;;:15;:34;;;;;;;24928:29;;;;24893:65;;;;;;;;;:173;;-1:-1:-1;;;;;;24893:173:5;-1:-1:-1;;;;;24893:173:5;;;;;;25266:30;;;;25204:17;;25188:34;;;;;;;;;;25223:30;;;;25188:66;;;;;;;;;;;;;;:109;;:66;;:77;:109::i;:::-;25135:17;;;;;-1:-1:-1;;;;;25119:34:5;;;;;;;:15;:34;;;;;;;25154:30;;;;;25119:66;;;;;;;;;;:178;;-1:-1:-1;;;;;;25119:178:5;-1:-1:-1;;;;;25119:178:5;;;;;;25498:28;;;;25435:18;;;;25419:35;;;;;;;;;;25455:30;;25419:67;;;;;;;;;;;;;;:108;;:67;;:78;:108::i;:::-;25365:18;;;;;-1:-1:-1;;;;;25349:35:5;;;;;;;:15;:35;;;;;;;25385:30;;;;25349:67;;;;;;;;;:178;;-1:-1:-1;;;;;;25349:178:5;-1:-1:-1;;;;;25349:178:5;;;;;;25715:28;;;;25657:10;;;;25641:27;;;;;;;;25349:178;25669:33;;;25641:62;;;;;;;;;;;;;;:103;;:62;;:73;:103::i;:::-;25592:10;;;-1:-1:-1;;;;;25592:10:5;;;25576:27;;;;:15;:27;;;;;;;;25592:10;25604:33;;;25576:62;;;;;;;;;:168;;-1:-1:-1;;;;;;25576:168:5;-1:-1:-1;;;;;25576:168:5;;;;;;25889:28;;;;25831:10;;;;25815:27;;;;;;;;25843:33;;;;25815:62;;;;;;;;;;;:103;;:62;;:73;:103::i;:::-;25766:10;;-1:-1:-1;;;;;25766:10:5;;;25750:27;;;;:15;:27;;;;;;;;25778:33;;;;;;25750:62;;;;;;;;;;;;:168;;-1:-1:-1;;;;;;25750:168:5;-1:-1:-1;;;;;25750:168:5;;;;;;;;;-1:-1:-1;;24477:1446:5:o;38593:244::-;38680:6;38724:9;38794:38;38826:5;38794:27;-1:-1:-1;;;;;38794:7:5;;38724:9;38794:27;:7;:27;:::i;:::-;-1:-1:-1;;;;;38794:31:5;;:38;:31;:38;:::i;33666:421::-;33775:7;33792:22;33817:46;33852:10;33817:34;:46::i;:::-;33792:71;;33885:129;33922:14;33946:10;:26;;;33982:10;:24;;;33885:27;:129::i;:::-;33870:184;;;;-1:-1:-1;;;33870:184:5;;;;;;;;388:901:11;473:23;596:34;590:2;582:10;;;581:49;655:1;644:12;;636:40;;;;-1:-1:-1;;;636:40:11;;;;;;;;;-1:-1:-1;;;788:2:11;780:10;;;779:49;867:34;861:2;853:10;;;852:49;926:10;934:2;926:10;;;;1013:18;;;:28;;1185:69;1234:14;1216:5;-1:-1:-1;;;;;1192:29:11;;;-1:-1:-1;;;;;1185:41:11;;;:69;;;;:::i;:::-;1166:88;388:901;-1:-1:-1;;;;;;;388:901:11:o;1261:125:9:-;1317:6;1338:43;1342:1;1345;1338:43;;;;;;;;;;;;;;;;;:3;:43::i;859:158::-;915:6;940:5;;;-1:-1:-1;;;;;959:6:9;;;;;;;;951:46;;;;-1:-1:-1;;;951:46:9;;;;;;;;2206:607:1;2326:26;;:::i;:::-;-1:-1:-1;;;;;2355:43:1;;;:20;:43;;;;;;;;;;;;2326:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2326:72:1;;;;;;;;;;;;;;;;;;;;;;;;;2355:43;;2326:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;2326:72:1;;;-1:-1:-1;;2326:72:1;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2326:72:1;;;;;;2419:12;;;;-1:-1:-1;2419:33:1;;;;;2435:5;:17;;;2419:33;2404:99;;;;-1:-1:-1;;;2404:99:1;;;;;;;;;2518:28;2532:6;2518:28;;;;;;;;;;;;;-1:-1:-1;;;2518:28:1;;;:13;:28::i;:::-;2517:29;2509:71;;;;-1:-1:-1;;;2509:71:1;;;;;;;;;2730:15;2682:4;2730:31;;;-1:-1:-1;;;;;2692:70:1;:28;;;:70;2769:27;;:19;;;;:27;;2789:6;;2769:27;;;;;;;;;;;;;;;;;;;;27:10:-1;;39:1;23:18;;;45:23;;-1:-1;2769:39:1;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2769:39:1;;;-1:-1:-1;;;;;;2769:39:1;;;-1:-1:-1;;2769:39:1;;;;;;;;;;;;;;;;;;;;;;;2802:5;;2769:39;;;;;;;;:::i;39761:263:5:-;39968:15;39854:12;39961:41;39942:4;39960:59;39761:263;:::o;4751:181:1:-;4842:4;4924:1;4907:19;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;4907:19:1;;;4897:30;;;;;;4890:1;4873:19;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;4873:19:1;;;4863:30;;;;;;:64;4856:71;;4751:181;;;;:::o;4519:138::-;4564:20;;:::i;:::-;-1:-1:-1;4599:53:1;;;;;;;;4613:4;4599:53;;;-1:-1:-1;4599:53:1;;;;;;;;;;;;;;;;;-1:-1:-1;;;4599:53:1;;;;;;;;;;;;;;4640:2;4599:53;;;;;;;;;;;;;;;4519:138;:::o;2180:459:8:-;2238:7;2479:6;2475:45;;-1:-1:-1;2508:1:8;2501:8;;2475:45;2542:5;;;2546:1;2542;:5;:1;2565:5;;;;;:10;2557:56;;;;-1:-1:-1;;;2557:56:8;;;;;;;;3101:130;3159:7;3185:39;3189:1;3192;3185:39;;;;;;;;;;;;;-1:-1:-1;;;3185:39:8;;;:3;:39::i;802:673:3:-;914:6;955:2;938:13;:19;;;;930:71;;;;-1:-1:-1;;;930:71:3;;;;;;;;;1008:22;1144:1;1128:13;:17;;;1124:241;;;1172:74;:20;1206:32;-1:-1:-1;;1220:17:3;;1206:32;1214:2;1206:32;1172:74;:24;:74;:::i;:::-;1155:91;;1124:241;;;1284:74;:20;1318:32;1332:1;:17;;;1318:32;1326:2;1318:32;1284:74;:24;:74;:::i;:::-;1267:91;;1124:241;-1:-1:-1;;;1378:14:3;:22;1370:64;;;;-1:-1:-1;;;1370:64:3;;;;;;;;745:608:2;889:37;;-1:-1:-1;;;889:37:2;;865:21;;-1:-1:-1;;;;;889:22:2;;;;;:37;;920:4;;889:37;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;889:37:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;889:37:2;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;889:37:2;;;;;;;;;1043:70;;-1:-1:-1;;;1043:70:2;;865:61;;-1:-1:-1;;;;;;1043:25:2;;;;;:70;;1069:6;;1085:4;;1092:20;;1043:70;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1043:70:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;1143:37:2;;-1:-1:-1;;;1143:37:2;;1120:20;;-1:-1:-1;;;;;;1143:22:2;;;-1:-1:-1;1143:22:2;;:37;;1174:4;;1143:37;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1143:37:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1143:37:2;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1143:37:2;;;;;;;;;1120:60;-1:-1:-1;1236:20:2;1201:31;1120:60;1218:13;1201:31;:16;:31;:::i;:::-;:55;1186:162;;;;-1:-1:-1;;;1186:162:2;;;;;;;;1548:785;-1:-1:-1;;;;;1682:21:2;;1678:651;;1730:43;;-1:-1:-1;;;;;1730:21:2;;;:43;;;;;1752:20;;1730:43;;;;1752:20;1730:21;:43;;;;;;;1713:99;;;;-1:-1:-1;;;1713:99:2;;;;;;;;;1678:651;;;1857:41;;-1:-1:-1;;;1857:41:2;;1833:21;;-1:-1:-1;;;;;1857:23:2;;;;;:41;;1881:16;;1857:41;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1857:41:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1857:41:2;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1857:41:2;;;;;;;;;2015:62;;-1:-1:-1;;;2015:62:2;;1833:65;;-1:-1:-1;;;;;;2015:22:2;;;;;:62;;2038:16;;2056:20;;2015:62;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2015:62:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;2109:41:2;;-1:-1:-1;;;2109:41:2;;2086:20;;-1:-1:-1;;;;;;2109:23:2;;;-1:-1:-1;2109:23:2;;:41;;2133:16;;2109:41;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2109:41:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;2109:41:2;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;2109:41:2;;;;;;;;;2086:64;-1:-1:-1;2210:20:2;2175:31;2086:64;2192:13;2175:31;:16;:31;:::i;:::-;:55;2158:164;;;;-1:-1:-1;;;2158:164:2;;;;;;;;37866:308:5;37953:4;37993:21;37980:9;:34;;;;;;;;;:83;;;-1:-1:-1;38037:26:5;38024:9;:39;;;;;;;;;37980:83;:135;;;-1:-1:-1;38086:29:5;38073:9;:42;;;;;;;;;37980:135;:189;;;-1:-1:-1;38138:31:5;38125:44;:9;:44;;;;;;;;;37967:202;37866:308;-1:-1:-1;;37866:308:5:o;38841:573::-;38966:6;39106:5;38966:6;39155:92;39106:5;39155:65;-1:-1:-1;;;;;39155:27:5;;;;39194:25;;39155:65;:38;:65;:::i;:::-;:76;:92;:76;:92;:::i;:::-;39118:129;;-1:-1:-1;;;39268:26:5;:34;39253:108;;;;-1:-1:-1;;;39253:108:5;;;;;;;;39418:339;-1:-1:-1;;;;;39539:34:5;;39512:6;39539:34;;;:19;:34;;;;;:41;;;:122;;;;-1:-1:-1;;;;;;39590:34:5;;;;;;:19;:34;;;;;:55;;;39649:12;-1:-1:-1;39590:71:5;39539:122;39528:210;;;-1:-1:-1;;;;;;39683:34:5;;;;;;:19;:34;;;;;:48;;;;-1:-1:-1;;;;;39683:48:5;39676:55;;39528:210;-1:-1:-1;39751:1:5;39418:339;;;:::o;32627:578::-;32749:7;32764:17;32784:107;32821:5;32834;:21;;;32863:5;:22;;;32784:29;:107::i;:::-;32764:127;;32913:114;32950:9;32969:5;:21;;;33000:5;:19;;;32913:27;:114::i;:::-;33049:19;33035:5;:10;;;:33;;;;;;;;;:136;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;32898:279;;;;;-1:-1:-1;;;32898:279:5;;;;;;;;;;-1:-1:-1;33191:9:5;32627:578;-1:-1:-1;;;32627:578:5:o;26358:1671::-;26507:32;;;;:21;:32;;;;;;;;26506:33;26498:65;;;;-1:-1:-1;;;26498:65:5;;;;;;;;;26664:30;26923:5;:23;;;26919:518;;;26973:34;26991:5;:15;;;26973:17;:34::i;:::-;26956:120;;;;-1:-1:-1;;;26956:120:5;;;;;;;;;27154:48;;;;:37;:48;;;;;;27110:30;;;;:100;;-1:-1:-1;;;;;27110:34:5;;;;27154:48;27110:100;:34;:100;:::i;:::-;27084:126;;26919:518;;;27374:48;;;;:37;:48;;;;;;27331:29;;;;:99;;-1:-1:-1;;;;;27331:33:5;;;;27374:48;27331:99;:33;:99;:::i;:::-;27305:125;;26919:518;27485:5;:20;;;-1:-1:-1;;;;;27458:47:5;:23;-1:-1:-1;;;;;27458:47:5;;;27443:94;;;;-1:-1:-1;;;27443:94:5;;;;;;;;;27574:5;:20;;;-1:-1:-1;;;;;27548:46:5;:23;-1:-1:-1;;;;;27548:46:5;;27544:481;;;27678:48;;;;:37;:48;;;;;:74;;-1:-1:-1;;;;;;27678:74:5;-1:-1:-1;;;;;27678:74:5;;;;;27544:481;;;-1:-1:-1;;27923:48:5;;;;:37;:48;;;;;;;;27916:55;;-1:-1:-1;;;;;;27916:55:5;;;27979:21;:32;;;;;:39;;-1:-1:-1;;27979:39:5;-1:-1:-1;27979:39:5;;;-1:-1:-1;26358:1671:5:o;2091:415:9:-;2147:6;-1:-1:-1;;;;;2371:6:9;;2367:35;;-1:-1:-1;2394:1:9;2387:8;;2367:35;2419:5;;;-1:-1:-1;;;;;2438:10:9;;;;:5;;;;;;;;;;;;-1:-1:-1;;;;;2438:10:9;;2430:56;;;;-1:-1:-1;;;2430:56:9;;;;;;;;2937:121;2993:6;3014:39;3018:1;3021;3014:39;;;;;;;;;;;;;-1:-1:-1;;;3014:39:9;;;:3;:39::i;1854:628:10:-;2037:16;;;;2065:24;;;;1960:7;;2037:16;1960:7;2197:25;;:58;;;;;;;;;:169;;2342:10;:23;;;2325:41;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;2325:41:10;;;2197:169;;;2287:10;:22;;;2270:40;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;2270:40:10;;;2197:169;2378:39;2391:10;:25;;;-1:-1:-1;;;;;2378:39:10;:12;:39::i;:::-;2429:10;:30;;;2009:460;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;2009:460:10;;;1990:487;;;;;;1977:500;;1854:628;;;:::o;330:219::-;449:4;538:6;-1:-1:-1;;;;;474:70:10;:60;488:34;517:4;488:28;:34::i;:::-;524:9;474:13;:60::i;:::-;-1:-1:-1;;;;;474:70:10;;;330:219;-1:-1:-1;;;;330:219:10:o;1686:185:9:-;1786:6;1813:1;-1:-1:-1;;;;;1808:6:9;:1;-1:-1:-1;;;;;1808:6:9;;;1816:12;1800:29;;;;;-1:-1:-1;;;1800:29:9;;;;;;;;;;-1:-1:-1;;;1846:5:9;;;1686:185::o;3713:272:8:-;3799:7;3833:12;3826:5;3818:28;;;;-1:-1:-1;;;3818:28:8;;;;;;;;;;;3856:9;3872:1;3868;:5;;;;;;;3713:272;-1:-1:-1;;;;;3713:272:8:o;1321:134::-;1379:7;1405:43;1409:1;1412;1405:43;;;;;;;;;;;;;;;;;:3;:43::i;553:1297:10:-;701:7;731:5;:26;;;:31;;761:1;731:31;716:94;;;;-1:-1:-1;;;716:94:10;;;;;;;;;1008:26;;1048:11;;;;1073:19;;;;1106:40;1122:10;1134:11;1106:15;:40::i;:::-;1166:5;:15;;;1160:22;;;;;;;;1202:5;:10;;;1196:17;;;;;;;;1334:34;1347:5;:20;;;-1:-1:-1;;;;;1334:34:10;:12;:34::i;:::-;978:402;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;978:402:10;;;1422:5;:23;;;1484:1;1459:5;:22;;;-1:-1:-1;;;;;1459:26:10;;:98;;;;;;;;;;;;;;;;;1502:36;1515:5;:22;;;-1:-1:-1;;;;;1502:36:10;:12;:36::i;:::-;1595:1;1571:5;:21;;;-1:-1:-1;;;;;1571:25:10;;:96;;;;;;;;;;;;;;;;;1613:35;1626:5;:21;;;-1:-1:-1;;;;;1613:35:10;:12;:35::i;:::-;1681:5;:19;;;1720:5;:17;;;1714:24;;;;;;;;1758:5;:25;;;1752:32;;;;;;;;1798:5;:17;;;1392:435;;;;;;;;;;;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;1392:435:10;;;;950:887;;;49:4:-1;950:887:10;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;950:887:10;;;829:1016;;;;;;816:1029;;553:1297;;;;;:::o;38178:251:5:-;38266:4;;38293:9;:35;;;;;;;;;:82;;;-1:-1:-1;38351:24:5;38338:9;:37;;;;;;;;;38293:82;:131;;;-1:-1:-1;38398:26:5;38385:39;;3545:328:9;3645:6;3736:12;-1:-1:-1;;;;;3729:5:9;;3721:28;;;;-1:-1:-1;;;3721:28:9;;;;;;;;;;;3755:8;3770:1;-1:-1:-1;;;;;3766:5:9;:1;-1:-1:-1;;;;;3766:5:9;;;;;3829:776:10;3887:13;4068:4;4053:12;4098:59;4105:9;;4098:59;;4124:8;;4148:2;4140:10;;;;4098:59;;;4175:1;4166:6;:10;4162:92;;;-1:-1:-1;4195:1:10;4162:92;4259:8;;4299:20;4259:8;-1:-1:-1;;;;;4322:17:10;;2:2:-1;;;;27:1;24;17:12;2:2;4322:17:10;;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;108:14;4322:17:10;87:42:-1;143:17;;-1:-1;4322:17:10;-1:-1:-1;4299:40:10;-1:-1:-1;4362:6:10;4345:228;4370:5;;4345:228;;4403:1;4394:6;:10;4408:1;4394:15;4390:177;;;4451:2;4438:17;;4421:7;4433:1;4429;:5;4421:14;;;;;;;;;;;:34;-1:-1:-1;;;;;4421:34:10;;;;;;;;;4390:177;;;4533:2;4526:4;:9;4520:2;:16;4507:31;;4490:7;4502:1;4498;:5;4490:14;;;;;;;;;;;:48;-1:-1:-1;;;;;4490:48:10;;;;;;;;-1:-1:-1;4556:2:10;4548:10;;;;4390:177;-1:-1:-1;;4377:3:10;4345:228;;;-1:-1:-1;4592:7:10;3829:776;-1:-1:-1;;;;3829:776:10:o;3396:265:4:-;3465:7;3648:4;3595:58;;;;;;;;;1064:2068;1142:7;1203:9;:16;1223:2;1203:22;1199:94;;1241:41;;-1:-1:-1;;;1241:41:4;;;;;;;;1199:94;1643:4;1628:20;;1622:27;1688:4;1673:20;;1667:27;1741:4;1726:20;;1720:27;1359:9;1712:36;-1:-1:-1;;;;;2646:79:4;;2642:154;;;2741:44;;-1:-1:-1;;;2741:44:4;;;;;;;;2642:154;2810:1;:7;;2815:2;2810:7;;:18;;;;;2821:1;:7;;2826:2;2821:7;;2810:18;2806:93;;;2844:44;;-1:-1:-1;;;2844:44:4;;;;;;;;2806:93;2993:14;3010:24;3020:4;3026:1;3029;3032;3010:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;3010:24:4;;-1:-1:-1;;3010:24:4;;;-1:-1:-1;;;;;;;3052:20:4;;3044:57;;;;-1:-1:-1;;;3044:57:4;;;;;;;;;3119:6;1064:2068;-1:-1:-1;;;;;;1064:2068:4:o;1746:187:8:-;1832:7;1867:12;1859:6;;;;1851:29;;;;-1:-1:-1;;;1851:29:8;;;;;;;;;2832:805:10;3048:10;;;;;;;;;;;;;-1:-1:-1;;;3048:10:10;;;;3212:23;;3187:22;;2944:13;;3004:10;;3048;;3102:11;;2944:13;;3187:48;;:69;-1:-1:-1;;;;;3167:97:10;;2:2:-1;;;;27:1;24;17:12;2:2;3167:97:10;;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;108:14;3167:97:10;87:42:-1;143:17;;-1:-1;3167:97:10;-1:-1:-1;3121:149:10;-1:-1:-1;3277:9:10;;3308:103;3324:15;:22;3320:1;:26;3308:103;;;3386:15;3402:1;3386:18;;;;;;;;;;;;;;;;3361:17;3379:3;;;;;;3361:22;;;;;;;;;;;:43;-1:-1:-1;;;;;3361:43:10;;;;;;;;-1:-1:-1;3348:3:10;;;;;3308:103;;;3468:11;3480:1;3468:14;;;;;;;;;;;;;;;;3443:17;3461:3;;;;;;3443:22;;;;;;;;;;;:39;-1:-1:-1;;;;;3443:39:10;;;;;;;;;3498:1;3494:5;;3489:105;3505:16;:23;3501:1;:27;3489:105;;;3568:16;3585:1;3568:19;;;;;;;;;;;;;;;;3543:17;3561:3;;;;;;3543:22;;;;;;;;;;;:44;-1:-1:-1;;;;;3543:44:10;;;;;;;;-1:-1:-1;3530:3:10;;;;;3489:105;;;-1:-1:-1;3614:17:10;;2832:805;-1:-1:-1;;;;;;;2832:805:10:o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;5:130;72:20;;97:33;72:20;97:33;;295:124;359:20;;94476:13;;94469:21;97992:32;;97982:2;;98038:1;;98028:12;564:440;;665:3;658:4;650:6;646:17;642:27;632:2;;-1:-1;;673:12;632:2;720:6;707:20;-1:-1;;;;;92786:6;92783:30;92780:2;;;-1:-1;;92816:12;92780:2;742:64;92889:9;92870:17;;-1:-1;;92866:33;92957:4;92947:15;742:64;;;733:73;;826:6;819:5;812:21;930:3;92957:4;921:6;854;912:16;;909:25;906:2;;;947:1;;937:12;906:2;96030:6;92957:4;854:6;850:17;92957:4;888:5;884:16;96007:30;96086:1;96068:16;;;92957:4;96068:16;96061:27;888:5;625:379;-1:-1;;625:379;1179:188;1275:20;;98430:1;98420:12;;98410:2;;98446:1;;98436:12;1374:158;1455:20;;98545:1;98535:12;;98525:2;;98561:1;;98551:12;1718:158;1799:20;;98782:1;98772:12;;98762:2;;98798:1;;98788:12;2073:337;;;2188:3;2181:4;2173:6;2169:17;2165:27;2155:2;;-1:-1;;2196:12;2155:2;-1:-1;2226:20;;-1:-1;;;;;2255:30;;2252:2;;;-1:-1;;2288:12;2252:2;2332:4;2324:6;2320:17;2308:29;;2383:3;2332:4;2363:17;2324:6;2349:32;;2346:41;2343:2;;;2400:1;;2390:12;2343:2;2148:262;;;;;;2896:2605;;3008:6;;2996:9;2991:3;2987:19;2983:32;2980:2;;;-1:-1;;3018:12;2980:2;3046:22;3008:6;3046:22;;;3037:31;;;3166:47;3209:3;3185:22;3166:47;;;3148:16;3141:73;3309:49;3354:3;3276:2;3334:9;3330:22;3309:49;;;3276:2;3295:5;3291:16;3284:75;3462:49;3507:3;3429:2;3487:9;3483:22;3462:49;;;3429:2;3448:5;3444:16;3437:75;3611:63;3670:3;3578:2;3650:9;3646:22;3611:63;;;3578:2;3597:5;3593:16;3586:89;3770:63;3829:3;3736;3809:9;3805:22;3770:63;;;3736:3;3756:5;3752:16;3745:89;3939:48;3983:3;3905;3963:9;3959:22;3939:48;;;3905:3;3925:5;3921:16;3914:74;4096:46;4138:3;4062;4118:9;4114:22;4096:46;;;4062:3;4082:5;4078:16;4071:72;4250:48;4294:3;4216;4274:9;4270:22;4250:48;;;4216:3;4236:5;4232:16;4225:74;4371:3;4407:48;4451:3;4371;4431:9;4427:22;4407:48;;;4387:18;;;4380:76;4554:3;4539:19;;;4526:33;-1:-1;;;;;4568:30;;;4565:2;;;3134:1;;4601:12;4565:2;4648:59;4703:3;4694:6;4683:9;4679:22;4648:59;;;4554:3;4632:5;4628:18;4621:87;4776:3;;;4812:70;4878:3;4776;4858:9;4854:22;4812:70;;;4776:3;4796:5;4792:18;4785:98;4959:3;;;4995:78;5069:3;4959;5049:9;5045:22;4995:78;;;4959:3;4979:5;4975:18;4968:106;5142:3;;;5178:48;5222:3;5142;5202:9;5198:22;5178:48;;;5142:3;5162:5;5158:18;5151:76;5327:3;;;;5316:9;5312:19;5299:33;5285:47;;4579:18;5344:6;5341:30;5338:2;;;3134:1;;5374:12;5338:2;;5421:58;5475:3;5466:6;5455:9;5451:22;5421:58;;;5327:3;5405:5;5401:18;5394:86;;;2974:2527;;;;;9982:130;10049:20;;-1:-1;;;;;94756:46;;98993:35;;98983:2;;99042:1;;99032:12;10397:128;10463:20;;-1:-1;;;;;95082:30;;99240:34;;99230:2;;99288:1;;99278:12;10532:126;10597:20;;95195:4;95184:16;;99361:33;;99351:2;;99408:1;;99398:12;10665:241;;10769:2;10757:9;10748:7;10744:23;10740:32;10737:2;;;-1:-1;;10775:12;10737:2;85:6;72:20;97:33;124:5;97:33;;11177:366;;;11298:2;11286:9;11277:7;11273:23;11269:32;11266:2;;;-1:-1;;11304:12;11266:2;85:6;72:20;97:33;124:5;97:33;;;11356:63;-1:-1;11456:2;11495:22;;72:20;97:33;72:20;97:33;;;11464:63;;;;11260:283;;;;;;11550:492;;;;11691:2;11679:9;11670:7;11666:23;11662:32;11659:2;;;-1:-1;;11697:12;11659:2;85:6;72:20;97:33;124:5;97:33;;;11749:63;-1:-1;11877:2;11862:18;;11849:32;-1:-1;;;;;11890:30;;11887:2;;;-1:-1;;11923:12;11887:2;11961:65;12018:7;12009:6;11998:9;11994:22;11961:65;;;11653:389;;11951:75;;-1:-1;11951:75;;-1:-1;;;;11653:389;12049:241;;12153:2;12141:9;12132:7;12128:23;12124:32;12121:2;;;-1:-1;;12159:12;12121:2;-1:-1;493:20;;12115:175;-1:-1;12115:175;12826:643;;;;;12997:2;12985:9;12976:7;12972:23;12968:32;12965:2;;;-1:-1;;13003:12;12965:2;1107:6;1094:20;1119:48;1161:5;1119:48;;;13055:78;-1:-1;13198:2;13183:18;;13170:32;-1:-1;;;;;13211:30;;13208:2;;;-1:-1;;13244:12;13208:2;13282:65;13339:7;13330:6;13319:9;13315:22;13282:65;;;13272:75;;-1:-1;13272:75;-1:-1;13402:51;;-1:-1;13445:7;13384:2;13421:22;;13402:51;;;13392:61;;12959:510;;;;;;;;13476:396;;;13612:2;13600:9;13591:7;13587:23;13583:32;13580:2;;;-1:-1;;13618:12;13580:2;1107:6;1094:20;1119:48;1161:5;1119:48;;;13670:78;13785:2;13824:22;;;;10186:20;;-1:-1;;;13574:298;13879:492;;;;14020:2;14008:9;13999:7;13995:23;13991:32;13988:2;;;-1:-1;;14026:12;13988:2;14084:17;14071:31;-1:-1;;;;;14114:6;14111:30;14108:2;;;-1:-1;;14144:12;14108:2;14182:65;14239:7;14230:6;14219:9;14215:22;14182:65;;;14172:75;;;;-1:-1;14284:2;14323:22;;;;10186:20;;13982:389;-1:-1;;;;13982:389;14378:490;;;;14518:2;14506:9;14497:7;14493:23;14489:32;14486:2;;;-1:-1;;14524:12;14486:2;14582:17;14569:31;-1:-1;;;;;14620:18;14612:6;14609:30;14606:2;;;-1:-1;;14642:12;14606:2;14680:65;14737:7;14728:6;14717:9;14713:22;14680:65;;;14670:75;;-1:-1;14670:75;-1:-1;14782:2;14820:22;;10463:20;;-1:-1;95082:30;;;99240:34;;99230:2;;-1:-1;;99278:12;99230:2;;14790:62;;;;14480:388;;;;;;14875:887;;;;15082:2;15070:9;15061:7;15057:23;15053:32;15050:2;;;-1:-1;;15088:12;15050:2;15146:17;15133:31;-1:-1;;;;;15184:18;15176:6;15173:30;15170:2;;;-1:-1;;15206:12;15170:2;15236:76;15304:7;15295:6;15284:9;15280:22;15236:76;;;15226:86;;15377:2;15366:9;15362:18;15349:32;15335:46;;15184:18;15393:6;15390:30;15387:2;;;-1:-1;;15423:12;15387:2;15453:76;15521:7;15512:6;15501:9;15497:22;15453:76;;;15443:86;;15594:2;15583:9;15579:18;15566:32;15552:46;;15184:18;15610:6;15607:30;15604:2;;;-1:-1;;15640:12;15604:2;5647:6;;15714:22;;5626:19;;;5622:32;-1:-1;5619:2;;;-1:-1;;5657:12;5619:2;5685:22;5647:6;5685:22;;;5781:17;5768:31;5754:45;;15184:18;5811:6;5808:30;5805:2;;;-1:-1;;5841:12;5805:2;5886:59;5941:3;5932:6;5921:9;5917:22;5886:59;;;5868:16;5861:85;15377:2;6036:9;6032:18;6019:32;6005:46;;15184:18;6063:6;6060:30;6057:2;;;-1:-1;;6093:12;6057:2;6138:59;6193:3;6184:6;6173:9;6169:22;6138:59;;;15377:2;6124:5;6120:16;6113:85;6304:49;6349:3;15594:2;6329:9;6325:22;6304:49;;;15594:2;6290:5;6286:16;6279:75;6461:49;6506:3;15082:2;6486:9;6482:22;6461:49;;;15082:2;6447:5;6443:16;6436:75;6625:48;6669:3;6591;6649:9;6645:22;6625:48;;;6591:3;6611:5;6607:16;6600:74;6789:48;6833:3;6755;6813:9;6809:22;6789:48;;;6755:3;6775:5;6771:16;6764:74;6950:48;6994:3;6916;6974:9;6970:22;6950:48;;;6916:3;6936:5;6932:16;6925:74;7112:48;7156:3;7078;7136:9;7132:22;7112:48;;;7078:3;7098:5;7094:16;7087:74;7238:3;;;7274:49;7319:3;7238;7299:9;7295:22;7274:49;;;7238:3;7258:5;7254:18;7247:77;7401:3;;;7437:49;7482:3;7401;7462:9;7458:22;7437:49;;;7401:3;7421:5;7417:18;7410:77;7566:3;;;7602:48;7646:3;7566;7626:9;7622:22;7602:48;;;7566:3;7586:5;7582:18;7575:76;7730:3;;;7766:48;7810:3;7730;7790:9;7786:22;7766:48;;;7730:3;7750:5;7746:18;7739:76;7883:3;;;7919:48;7963:3;7883;7943:9;7939:22;7919:48;;;7883:3;7903:5;7899:18;7892:76;8034:3;;;8070:63;8129:3;8034;8109:9;8105:22;8070:63;;;8034:3;8054:5;8050:18;8043:91;15660:86;;;;;;;15044:718;;;;;;15769:383;;15901:2;15889:9;15880:7;15876:23;15872:32;15869:2;;;-1:-1;;15907:12;15869:2;15965:17;15952:31;-1:-1;;;;;16003:18;15995:6;15992:30;15989:2;;;-1:-1;;16025:12;15989:2;8311:6;;16104:22;;8290:19;;;8286:32;-1:-1;8283:2;;;-1:-1;;8321:12;8283:2;8349:22;8311:6;8349:22;;;8463:68;8527:3;8503:22;8463:68;;;8445:16;8438:94;8627:49;8672:3;15901:2;8652:9;8648:22;8627:49;;;15901:2;8613:5;8609:16;8602:75;8780:57;8833:3;8747:2;8813:9;8809:22;8780:57;;;8747:2;8766:5;8762:16;8755:83;8934:2;8923:9;8919:18;8906:32;8892:46;;16003:18;8950:6;8947:30;8944:2;;;-1:-1;;8980:12;8944:2;9025:59;9080:3;9071:6;9060:9;9056:22;9025:59;;;8934:2;9011:5;9007:16;9000:85;9188:49;9233:3;9154;9213:9;9209:22;9188:49;;;9154:3;9174:5;9170:16;9163:75;9343:48;9387:3;9309;9367:9;9363:22;9343:48;;;9309:3;9329:5;9325:16;9318:74;9495:48;9539:3;9461;9519:9;9515:22;9495:48;;;9461:3;9481:5;9477:16;9470:74;9654:46;9696:3;9620;9676:9;9672:22;9654:46;;;9620:3;9640:5;9636:16;9629:72;9801:3;;;;9790:9;9786:19;9773:33;16003:18;9818:6;9815:30;9812:2;;;-1:-1;;9848:12;9812:2;9895:58;9949:3;9940:6;9929:9;9925:22;9895:58;;;9875:18;;;9868:86;;;;9879:5;15863:289;-1:-1;;;;;;15863:289;16159:241;;16263:2;16251:9;16242:7;16238:23;16234:32;16231:2;;;-1:-1;;16269:12;16231:2;16331:53;16376:7;16352:22;16331:53;;16655:263;;16770:2;16758:9;16749:7;16745:23;16741:32;16738:2;;;-1:-1;;16776:12;16738:2;-1:-1;10334:13;;16732:186;-1:-1;16732:186;19009:300;;93824:6;93819:3;93812:19;96030:6;96025:3;93861:4;93856:3;93852:14;96007:30;-1:-1;93861:4;96077:6;93856:3;96068:16;;96061:27;93861:4;92889:9;;97241:2;19295:6;97221:14;97217:28;93856:3;19264:39;;19257:46;;19111:198;;;;;;19317:327;;19452:5;93395:12;93824:6;93819:3;93812:19;19536:52;19581:6;93861:4;93856:3;93852:14;93861:4;19562:5;19558:16;19536:52;;;92889:9;97221:14;-1:-1;;97217:28;19600:39;;;;93861:4;19600:39;;19399:245;-1:-1;;19399:245;48662:253;97640:14;;;;;-1:-1;;;;;;97640:14;17323:74;;48887:2;48878:12;;48778:137;48922:1117;;18026:5;94476:13;94469:21;97541:3;97537:15;17989:3;17982:52;18485:5;93395:12;18596:52;18641:6;49353:1;49348:3;49344:11;18629:4;18622:5;18618:16;18596:52;;;93395:12;;;18660:16;;18596:52;93395:12;49353:1;18660:16;;18629:4;18618:16;;18596:52;;;93395:12;;;18660:16;;18596:52;93395:12;49353:1;18660:16;;18629:4;18618:16;;18596:52;;;97537:15;;;;-1:-1;;;;;;97537:15;;;49353:1;18660:16;;;;;;;48596:54;;;;97537:15;;;;;49789:11;;;48596:54;-1:-1;;97433:15;;-1:-1;;;;;;97433:15;49895:11;;;48225:56;50003:11;;;49250:789;-1:-1;;;;;49250:789;50046:428;;18485:5;93395:12;18596:52;18641:6;18636:3;18629:4;18622:5;18618:16;18596:52;;;93395:12;;;18660:16;;18596:52;93395:12;18660:16;18629:4;18618:16;;18596:52;;;18660:16;;50226:248;-1:-1;;;;50226:248;50481:275;;18485:5;93395:12;18596:52;18641:6;18636:3;18629:4;18622:5;18618:16;18596:52;;;18660:16;;;;;50617:139;-1:-1;;50617:139;50763:520;23501:66;23481:87;;23465:2;23587:12;;18117:37;;;;51246:12;;;50980:303;51290:868;94767:34;97329:15;;;-1:-1;;;;;;97329:15;47593:58;;97640:14;;;;-1:-1;;;;;;97640:14;51675:2;51666:12;;17323:74;93395:12;;51290:868;;18596:52;93395:12;51793;;;18629:4;18618:16;;18596:52;;;93395:12;;;18660:16;;18596:52;93395:12;51793;18660:16;;18629:4;18618:16;;18596:52;;;94476:13;;94469:21;97541:3;97537:15;51793:12;18660:16;;;;;;;17982:52;-1:-1;;52122:11;;;51566:592;-1:-1;;;;51566:592;52165:1104;-1:-1;;;;;;97537:15;;;;;;48596:54;;-1:-1;;;;;;94767:34;97329:15;;;;92794:18;52573:11;;47593:58;-1:-1;;;;;;97640:14;;;;;52683:12;;;17323:74;93395:12;;-1:-1;;97537:15;18596:52;93395:12;52794;;;18629:4;18618:16;;18596:52;;;18669:6;52577:3;18660:16;97537:15;48642:5;97541:3;97537:15;;52794:12;18660:16;;48596:54;97537:15;48642:5;97541:3;97537:15;;53014:11;18660:16;53014:11;48596:54;18485:5;93395:12;18439:52;;18596;18641:6;53120:11;18660:16;53120:11;18629:4;18622:5;18618:16;18596:52;;;18660:16;;;53120:11;18660:16;;52477:792;-1:-1;;;;;;;;;;52477:792;53276:222;-1:-1;;;;;94876:54;;;;17161:45;;53403:2;53388:18;;53374:124;53750:476;-1:-1;;;;;94876:54;;;17161:45;;94876:54;;;;54129:2;54114:18;;17161:45;54212:2;54197:18;;18117:37;;;;53949:2;53934:18;;53920:306;54233:349;-1:-1;;;;;94876:54;;;;17004:58;;54568:2;54553:18;;18117:37;54396:2;54381:18;;54367:215;54589:333;-1:-1;;;;;94876:54;;;17161:45;;94876:54;;54908:2;54893:18;;17161:45;54744:2;54729:18;;54715:207;55285:1280;-1:-1;;;;;94876:54;;;17161:45;;94876:54;;55835:2;55820:18;;17161:45;55670:3;55872:2;55857:18;;55850:48;;;55285:1280;;55912:78;55655:19;;;55976:6;55912:78;;;56038:9;56032:4;56028:20;56023:2;56012:9;56008:18;56001:48;56063:78;56136:4;56127:6;56063:78;;;-1:-1;;;;;95082:30;;;56218:3;56203:19;;47973:36;95082:30;;;56300:3;56285:19;;47973:36;-1:-1;;;95082:30;;;;56382:3;56367:19;;47973:36;56466:3;56451:19;;18117:37;56550:3;56535:19;18117:37;;;;56055:86;55641:924;-1:-1;;;;55641:924;57023:548;18117:37;;;95195:4;95184:16;;;;57391:2;57376:18;;48350:35;57474:2;57459:18;;18117:37;57557:2;57542:18;;18117:37;57230:3;57215:19;;57201:370;57578:330;;57735:2;57756:17;57749:47;57810:88;57735:2;57724:9;57720:18;57884:6;57876;57810:88;;57915:433;;58096:2;58117:17;58110:47;58171:88;58096:2;58085:9;58081:18;58245:6;58237;58171:88;;;58163:96;;95195:4;48378:5;95184:16;58334:2;58323:9;58319:18;48350:35;58067:281;;;;;;;58355:310;;58502:2;58523:17;58516:47;58577:78;58502:2;58491:9;58487:18;58641:6;58577:78;;58672:670;;58916:3;58938:17;58931:47;58992:78;58916:3;58905:9;58901:19;59056:6;58992:78;;;-1:-1;;;;;95082:30;;;59147:2;59132:18;;47973:36;95082:30;;;;59237:2;59222:18;;18915:57;59328:2;59313:18;18767:58;58984:86;58887:455;-1:-1;;58887:455;59992:416;60192:2;60206:47;;;20597:2;60177:18;;;93812:19;-1:-1;;;93852:14;;;20613:47;20679:12;;;60163:245;60415:416;60615:2;60629:47;;;20930:2;60600:18;;;93812:19;-1:-1;;;93852:14;;;20946:47;21012:12;;;60586:245;60838:416;61038:2;61052:47;;;21263:2;61023:18;;;93812:19;-1:-1;;;93852:14;;;21279:47;21345:12;;;61009:245;61261:416;61461:2;61475:47;;;21596:2;61446:18;;;93812:19;21632:34;93852:14;;;21612:55;21701:34;21687:12;;;21680:56;-1:-1;;;21756:12;;;21749:36;21804:12;;;61432:245;61684:416;61884:2;61898:47;;;22055:2;61869:18;;;93812:19;22091:34;93852:14;;;22071:55;-1:-1;;;22146:12;;;22139:27;22185:12;;;61855:245;62107:416;62307:2;62321:47;;;22436:2;62292:18;;;93812:19;-1:-1;;;93852:14;;;22452:38;22509:12;;;62278:245;62530:416;62730:2;62744:47;;;22760:2;62715:18;;;93812:19;-1:-1;;;93852:14;;;22776:43;22838:12;;;62701:245;62953:416;63153:2;63167:47;;;23089:2;63138:18;;;93812:19;23125:33;93852:14;;;23105:54;23178:12;;;63124:245;63376:416;63576:2;63590:47;;;23838:2;63561:18;;;93812:19;-1:-1;;;93852:14;;;23854:42;23915:12;;;63547:245;63799:416;63999:2;64013:47;;;24166:2;63984:18;;;93812:19;24202:34;93852:14;;;24182:55;-1:-1;;;24257:12;;;24250:31;24300:12;;;63970:245;64222:416;64422:2;64436:47;;;24551:2;64407:18;;;93812:19;24587:34;93852:14;;;24567:55;-1:-1;;;24642:12;;;24635:36;24690:12;;;64393:245;64645:416;64845:2;64859:47;;;24941:2;64830:18;;;93812:19;24977:34;93852:14;;;24957:55;-1:-1;;;25032:12;;;25025:28;25072:12;;;64816:245;65068:416;65268:2;65282:47;;;25323:2;65253:18;;;93812:19;-1:-1;;;93852:14;;;25339:38;25396:12;;;65239:245;65491:416;65691:2;65705:47;;;25647:2;65676:18;;;93812:19;-1:-1;;;93852:14;;;25663:42;25724:12;;;65662:245;65914:416;66114:2;66128:47;;;25975:2;66099:18;;;93812:19;-1:-1;;;93852:14;;;25991:50;26060:12;;;66085:245;66337:416;66537:2;66551:47;;;26311:2;66522:18;;;93812:19;-1:-1;;;93852:14;;;26327:49;26395:12;;;66508:245;66760:416;66960:2;66974:47;;;26646:2;66945:18;;;93812:19;26682:31;93852:14;;;26662:52;26733:12;;;66931:245;67183:416;67383:2;67397:47;;;26984:2;67368:18;;;93812:19;-1:-1;;;93852:14;;;27000:42;27061:12;;;67354:245;67606:416;67806:2;67820:47;;;27312:2;67791:18;;;93812:19;27348:34;93852:14;;;27328:55;-1:-1;;;27403:12;;;27396:43;27458:12;;;67777:245;68029:416;68229:2;68243:47;;;27709:2;68214:18;;;93812:19;27745:34;93852:14;;;27725:55;-1:-1;;;27800:12;;;27793:27;27839:12;;;68200:245;68452:416;68652:2;68666:47;;;28090:2;68637:18;;;93812:19;-1:-1;;;93852:14;;;28106:36;28161:12;;;68623:245;68875:416;69075:2;69089:47;;;28412:2;69060:18;;;93812:19;28448:34;93852:14;;;28428:55;-1:-1;;;28503:12;;;28496:26;28541:12;;;69046:245;69298:416;69498:2;69512:47;;;28792:2;69483:18;;;93812:19;28828:34;93852:14;;;28808:55;-1:-1;;;28883:12;;;28876:41;28936:12;;;69469:245;69721:416;69921:2;69935:47;;;29187:2;69906:18;;;93812:19;29223:34;93852:14;;;29203:55;-1:-1;;;29278:12;;;29271:26;29316:12;;;69892:245;70144:416;70344:2;70358:47;;;29567:2;70329:18;;;93812:19;29603:34;93852:14;;;29583:55;-1:-1;;;29658:12;;;29651:28;29698:12;;;70315:245;70567:416;70767:2;70781:47;;;29949:2;70752:18;;;93812:19;29985:34;93852:14;;;29965:55;-1:-1;;;30040:12;;;30033:31;30083:12;;;70738:245;70990:416;71190:2;71204:47;;;30334:2;71175:18;;;93812:19;30370:34;93852:14;;;30350:55;-1:-1;;;30425:12;;;30418:25;30462:12;;;71161:245;71413:416;71613:2;71627:47;;;30713:2;71598:18;;;93812:19;-1:-1;;;93852:14;;;30729:48;30796:12;;;71584:245;71836:416;72036:2;72050:47;;;31047:2;72021:18;;;93812:19;-1:-1;;;93852:14;;;31063:44;31126:12;;;72007:245;72259:416;72459:2;72473:47;;;31377:2;72444:18;;;93812:19;-1:-1;;;93852:14;;;31393:47;31459:12;;;72430:245;72682:416;72882:2;72896:47;;;31710:2;72867:18;;;93812:19;31746:34;93852:14;;;31726:55;-1:-1;;;31801:12;;;31794:31;31844:12;;;72853:245;73105:416;73305:2;73319:47;;;73290:18;;;93812:19;32131:34;93852:14;;;32111:55;32185:12;;;73276:245;73528:416;73728:2;73742:47;;;32436:2;73713:18;;;93812:19;-1:-1;;;93852:14;;;32452:44;32515:12;;;73699:245;73951:416;74151:2;74165:47;;;32766:2;74136:18;;;93812:19;32802:34;93852:14;;;32782:55;-1:-1;;;32857:12;;;32850:26;32895:12;;;74122:245;74374:416;74574:2;74588:47;;;33146:2;74559:18;;;93812:19;33182:33;93852:14;;;33162:54;33235:12;;;74545:245;74797:416;74997:2;75011:47;;;33486:2;74982:18;;;93812:19;-1:-1;;;93852:14;;;33502:47;33568:12;;;74968:245;75220:416;75420:2;75434:47;;;33819:2;75405:18;;;93812:19;33855:34;93852:14;;;33835:55;-1:-1;;;33910:12;;;33903:28;33950:12;;;75391:245;75643:416;75843:2;75857:47;;;34201:2;75828:18;;;93812:19;34237:34;93852:14;;;34217:55;-1:-1;;;34292:12;;;34285:27;34331:12;;;75814:245;76066:416;76266:2;76280:47;;;34582:2;76251:18;;;93812:19;-1:-1;;;93852:14;;;34598:39;34656:12;;;76237:245;76489:416;76689:2;76703:47;;;34907:2;76674:18;;;93812:19;34943:34;93852:14;;;34923:55;-1:-1;;;34998:12;;;34991:25;35035:12;;;76660:245;76912:416;77112:2;77126:47;;;35286:2;77097:18;;;93812:19;-1:-1;;;93852:14;;;35302:47;35368:12;;;77083:245;77335:416;77535:2;77549:47;;;35619:2;77520:18;;;93812:19;35655:31;93852:14;;;35635:52;35706:12;;;77506:245;77758:416;77958:2;77972:47;;;35957:2;77943:18;;;93812:19;35993:34;93852:14;;;35973:55;-1:-1;;;36048:12;;;36041:25;36085:12;;;77929:245;78181:416;78381:2;78395:47;;;36336:2;78366:18;;;93812:19;-1:-1;;;93852:14;;;36352:43;36414:12;;;78352:245;78604:416;78804:2;78818:47;;;36665:2;78789:18;;;93812:19;36701:34;93852:14;;;36681:55;-1:-1;;;36756:12;;;36749:33;36801:12;;;78775:245;79027:416;79227:2;79241:47;;;37052:2;79212:18;;;93812:19;37088:32;93852:14;;;37068:53;37140:12;;;79198:245;79450:416;79650:2;79664:47;;;37391:2;79635:18;;;93812:19;-1:-1;;;93852:14;;;37407:45;37471:12;;;79621:245;79873:416;80073:2;80087:47;;;37722:2;80058:18;;;93812:19;-1:-1;;;93852:14;;;37738:46;37803:12;;;80044:245;80296:416;80496:2;80510:47;;;38054:2;80481:18;;;93812:19;38090:34;93852:14;;;38070:55;-1:-1;;;38145:12;;;38138:33;38190:12;;;80467:245;80719:416;80919:2;80933:47;;;38441:2;80904:18;;;93812:19;38477:32;93852:14;;;38457:53;38529:12;;;80890:245;81142:416;81342:2;81356:47;;;38780:2;81327:18;;;93812:19;-1:-1;;;93852:14;;;38796:42;38857:12;;;81313:245;81565:416;81765:2;81779:47;;;39108:2;81750:18;;;93812:19;39144:34;93852:14;;;39124:55;-1:-1;;;39199:12;;;39192:25;39236:12;;;81736:245;81988:416;82188:2;82202:47;;;39487:2;82173:18;;;93812:19;39523:34;93852:14;;;39503:55;-1:-1;;;39578:12;;;39571:28;39618:12;;;82159:245;82411:416;82611:2;82625:47;;;39869:2;82596:18;;;93812:19;-1:-1;;;93852:14;;;39885:43;39947:12;;;82582:245;82834:416;83034:2;83048:47;;;40198:2;83019:18;;;93812:19;-1:-1;;;93852:14;;;40214:42;40275:12;;;83005:245;83257:416;83457:2;83471:47;;;40526:2;83442:18;;;93812:19;40562:34;93852:14;;;40542:55;-1:-1;;;40617:12;;;40610:31;40660:12;;;83428:245;83680:416;83880:2;83894:47;;;40911:2;83865:18;;;93812:19;40947:34;93852:14;;;40927:55;-1:-1;;;41002:12;;;40995:44;41058:12;;;83851:245;84103:416;84303:2;84317:47;;;41309:2;84288:18;;;93812:19;-1:-1;;;93852:14;;;41325:44;41388:12;;;84274:245;84526:416;84726:2;84740:47;;;41639:2;84711:18;;;93812:19;41675:34;93852:14;;;41655:55;-1:-1;;;41730:12;;;41723:40;41782:12;;;84697:245;84949:416;85149:2;85163:47;;;42033:2;85134:18;;;93812:19;42069:34;93852:14;;;42049:55;-1:-1;;;42124:12;;;42117:32;42168:12;;;85120:245;85372:416;85572:2;85586:47;;;42419:2;85557:18;;;93812:19;42455:33;93852:14;;;42435:54;42508:12;;;85543:245;85795:416;85995:2;86009:47;;;42759:2;85980:18;;;93812:19;-1:-1;;;93852:14;;;42775:43;42837:12;;;85966:245;86218:416;86418:2;86432:47;;;43088:2;86403:18;;;93812:19;-1:-1;;;93852:14;;;43104:40;43163:12;;;86389:245;86641:416;86841:2;86855:47;;;43414:2;86826:18;;;93812:19;-1:-1;;;93852:14;;;43430:45;43494:12;;;86812:245;87064:416;87264:2;87278:47;;;43745:2;87249:18;;;93812:19;43781:34;93852:14;;;43761:55;-1:-1;;;43836:12;;;43829:35;43883:12;;;87235:245;87487:416;87687:2;87701:47;;;44134:2;87672:18;;;93812:19;44170:34;93852:14;;;44150:55;44239:34;44225:12;;;44218:56;-1:-1;;;44294:12;;;44287:32;44338:12;;;87658:245;87910:416;88110:2;88124:47;;;44589:2;88095:18;;;93812:19;-1:-1;;;93852:14;;;44605:48;44672:12;;;88081:245;88333:416;88533:2;88547:47;;;44923:2;88518:18;;;93812:19;44959:34;93852:14;;;44939:55;-1:-1;;;45014:12;;;45007:32;45058:12;;;88504:245;88756:416;88956:2;88970:47;;;45309:2;88941:18;;;93812:19;-1:-1;;;93852:14;;;45325:36;45380:12;;;88927:245;89179:416;89379:2;89393:47;;;45631:2;89364:18;;;93812:19;-1:-1;;;93852:14;;;45647:43;45709:12;;;89350:245;89602:416;89802:2;89816:47;;;45960:2;89787:18;;;93812:19;45996:34;93852:14;;;45976:55;-1:-1;;;46051:12;;;46044:31;46094:12;;;89773:245;90025:362;;90198:2;90219:17;90212:47;46392:16;46386:23;94476:13;94469:21;90198:2;90187:9;90183:18;17853:34;92794:18;;97640:14;;;90198:2;46552:5;46548:16;46542:23;94876:54;46619:14;90187:9;46619:14;17161:45;46619:14;46708:5;46704:16;46698:23;46318:4;46741:14;90187:9;46741:14;46734:38;46787:73;46309:14;90187:9;46309:14;46841:12;46787:73;;;95195:4;46741:14;46942:5;46938:16;46932:23;95184:16;47005:14;90187:9;47005:14;48350:35;47005:14;47099:5;47095:16;47089:23;94476:13;94469:21;47160:14;90187:9;47160:14;17853:34;-1:-1;;;;;47160:14;47265:5;47261:16;47255:23;95082:30;46318:4;90187:9;47330:14;47973:36;90265:112;;;;;90169:218;;;;;90394:442;-1:-1;;;;;94756:46;;;;47455:37;;-1:-1;;;;;95082:30;;;;90739:2;90724:18;;18915:57;90822:2;90807:18;;18117:37;90576:2;90561:18;;90547:289;90843:222;18117:37;;;90970:2;90955:18;;90941:124;91072:333;18117:37;;;91391:2;91376:18;;18117:37;91227:2;91212:18;;91198:207;91412:218;-1:-1;;;;;95082:30;;;;47973:36;;91537:2;91522:18;;91508:122;91637:744;;-1:-1;;;;;95093:18;48002:5;95082:30;47980:3;47973:36;91890:3;92007:2;91996:9;91992:18;91985:48;92047:78;91890:3;91879:9;91875:19;92111:6;92047:78;;;95082:30;;;92202:2;92187:18;;47973:36;95082:30;;;;92283:2;92268:18;;47973:36;92366:3;92351:19;18117:37;-1:-1;92039:86;91861:520;-1:-1;;91861:520;92388:256;92450:2;92444:9;92476:17;;;-1:-1;;;;;92536:34;;92572:22;;;92533:62;92530:2;;;92608:1;;92598:12;92530:2;92450;92617:22;92428:216;;-1:-1;92428:216;96103:268;96168:1;96175:101;96189:6;96186:1;96183:13;96175:101;;;96256:11;;;96250:18;96237:11;;;96230:39;96211:2;96204:10;96175:101;;;96291:6;96288:1;96285:13;96282:2;;;-1:-1;;96168:1;96338:16;;96331:27;96152:219;97672:117;-1:-1;;;;;94876:54;;97731:35;;97721:2;;97780:1;;97770:12;97721:2;97715:74;
Swarm Source
ipfs://5dd7ac35c5f7c6f5ec79f4ba79633e7c75138d994328bbe33fa2efc0d21be22d
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.