ETH Price: $2,812.29 (-4.96%)
 

Overview

ETH Balance

Scroll LogoScroll LogoScroll Logo0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Market Sell ETH103193092024-10-19 13:12:42463 days ago1729343562IN
0x3828a06c...214C3071B
0.00001 ETH0.000015470.04184324
Limit Sell ETH99621022024-10-07 23:21:16474 days ago1728343276IN
0x3828a06c...214C3071B
0.0001 ETH0.000018550.05956398
Limit Buy99620002024-10-07 23:16:10474 days ago1728342970IN
0x3828a06c...214C3071B
0 ETH0.000044320.15277313
Limit Buy99620002024-10-07 23:16:10474 days ago1728342970IN
0x3828a06c...214C3071B
0 ETH0.000040540.15277313
Market Buy99344972024-10-07 0:31:58475 days ago1728261118IN
0x3828a06c...214C3071B
0 ETH0.000023070.05063094
Limit Sell ETH98926242024-10-05 13:41:35477 days ago1728135695IN
0x3828a06c...214C3071B
0.001 ETH0.00001310.04050023
Market Sell ETH98299452024-10-03 9:50:27479 days ago1727949027IN
0x3828a06c...214C3071B
0.003 ETH0.000014790.05379968
Market Sell ETH96439392024-09-27 0:14:42485 days ago1727396082IN
0x3828a06c...214C3071B
0.001 ETH0.000041160.13952024
Market Buy ETH95816272024-09-24 20:35:02488 days ago1727210102IN
0x3828a06c...214C3071B
0.0001 ETH0.00004080.12419619
Limit Sell ETH95815482024-09-24 20:31:05488 days ago1727209865IN
0x3828a06c...214C3071B
0.00002 ETH0.000037460.11650684
Market Buy93052172024-09-15 7:23:06497 days ago1726384986IN
0x3828a06c...214C3071B
0 ETH0.000021430.07
Market Sell ETH88715262024-08-31 13:25:29512 days ago1725110729IN
0x3828a06c...214C3071B
0.00001 ETH0.000010040.03907861
Market Sell ETH88715242024-08-31 13:25:25512 days ago1725110725IN
0x3828a06c...214C3071B
0.00001 ETH0.000012150.04008605
Set Spread88573722024-08-31 1:46:55512 days ago1725068815IN
0x3828a06c...214C3071B
0 ETH0.000001710.03812948
Set Spread88497022024-08-30 19:25:11513 days ago1725045911IN
0x3828a06c...214C3071B
0 ETH0.000001840.03839286
Add Pair88497012024-08-30 19:25:08513 days ago1725045908IN
0x3828a06c...214C3071B
0 ETH0.000012410.03839286
Add Pair88497012024-08-30 19:25:08513 days ago1725045908IN
0x3828a06c...214C3071B
0 ETH0.000012150.03839286
Add Pair88497002024-08-30 19:25:05513 days ago1725045905IN
0x3828a06c...214C3071B
0 ETH0.000012530.03839286
Add Pair88497002024-08-30 19:25:05513 days ago1725045905IN
0x3828a06c...214C3071B
0 ETH0.000012520.03839286
Add Pair88496992024-08-30 19:25:02513 days ago1725045902IN
0x3828a06c...214C3071B
0 ETH0.00001270.03839286
Set Spread88496982024-08-30 19:24:59513 days ago1725045899IN
0x3828a06c...214C3071B
0 ETH0.000001850.03864535
Add Pair88496982024-08-30 19:24:59513 days ago1725045899IN
0x3828a06c...214C3071B
0 ETH0.000013130.03964953
Add Pair88496972024-08-30 19:24:56513 days ago1725045896IN
0x3828a06c...214C3071B
0 ETH0.000012430.03864535
Add Pair88496972024-08-30 19:24:56513 days ago1725045896IN
0x3828a06c...214C3071B
0 ETH0.00001240.03864535
Add Pair88496962024-08-30 19:24:53513 days ago1725045893IN
0x3828a06c...214C3071B
0 ETH0.000012720.03864535
View all transactions

Latest 9 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
103193092024-10-19 13:12:42463 days ago1729343562
0x3828a06c...214C3071B
0.00001 ETH
99621022024-10-07 23:21:16474 days ago1728343276
0x3828a06c...214C3071B
0.0001 ETH
98926242024-10-05 13:41:35477 days ago1728135695
0x3828a06c...214C3071B
0.001 ETH
98299452024-10-03 9:50:27479 days ago1727949027
0x3828a06c...214C3071B
0.003 ETH
96439392024-09-27 0:14:42485 days ago1727396082
0x3828a06c...214C3071B
0.001 ETH
95816272024-09-24 20:35:02488 days ago1727210102
0x3828a06c...214C3071B
0.0001 ETH
95815482024-09-24 20:31:05488 days ago1727209865
0x3828a06c...214C3071B
0.00002 ETH
88715262024-08-31 13:25:29512 days ago1725110729
0x3828a06c...214C3071B
0.00001 ETH
88715242024-08-31 13:25:25512 days ago1725110725
0x3828a06c...214C3071B
0.00001 ETH
Cross-Chain Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xd7ABA1cb...EDEFf1E47
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
MatchingEngine

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion, BSL 1.1 license

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 13 : MatchingEngine.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.24;
import {IOrderbookFactory} from "./interfaces/IOrderbookFactory.sol";
import {IOrderbook, ExchangeOrderbook} from "./interfaces/IOrderbook.sol";
import {TransferHelper} from "./libraries/TransferHelper.sol";
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IWETH} from "./interfaces/IWETH.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";

interface IRevenue {
    function reportMatch(
        address orderbook,
        address give,
        bool isBid,
        address sender,
        address owner,
        uint256 amount
    ) external;

    function isReportable() external view returns (bool isReportable);

    function feeOf(
        address account,
        bool isMaker
    ) external view returns (uint32 feeNum);

    function isSubscribed(
        address account
    ) external view returns (bool isSubscribed);
}

interface IDecimals {
    function decimals() external view returns (uint8 decimals);
}

// Onchain Matching engine for the orders
contract MatchingEngine is Initializable, ReentrancyGuard, AccessControl {
    // Market maker role
    bytes32 private constant MARKET_MAKER_ROLE = keccak256("MARKET_MAKER_ROLE");
    // fee recipient for point storage
    address private feeTo;
    // fee denominator representing 0.001%, 1/1000000 = 0.001%
    uint32 public constant feeDenom = 1000000;
    // Factories
    address public orderbookFactory;
    // WETH
    address public WETH;
    // default buy spread
    uint32 defaultBuy;
    // default sell spread
    uint32 defaultSell;

    struct OrderData {
        /// Amount after removing fee
        uint256 withoutFee;
        /// Orderbook contract address
        address orderbook;
        /// Head price on bid orderbook, the highest bid price
        uint256 bidHead;
        /// Head price on ask orderbook, the lowest ask price
        uint256 askHead;
        /// Market price on pair
        uint256 lmp;
        /// Spread(volatility) limit on limit/market | buy/sell for market suspensions(e.g. circuit breaker, tick)
        uint32 spreadLimit;
        /// Make order id
        uint32 makeId;
        /// Whether an order deposit has been cleared
        bool clear;
    }

    struct DefaultSpread {
        /// Buy spread limit
        uint32 buy;
        /// Sell spread limit
        uint32 sell;
    }

    // Spread limit setting
    mapping(address => DefaultSpread) public spreadLimits;

    event OrderDeposit(address sender, address asset, uint256 fee);

    event OrderCanceled(
        address orderbook,
        uint256 id,
        bool isBid,
        address indexed owner,
        uint256 amount
    );

    event NewMarketPrice(address orderbook, uint256 price);

    /**
     * @dev This event is emitted when an order is successfully matched with a counterparty.
     * @param orderbook The address of the order book contract to get base and quote asset contract address.
     * @param id The unique identifier of the canceled order in bid/ask order database.
     * @param isBid A boolean indicating whether the matched order is a bid (true) or ask (false).
     * @param sender The address initiating the match.
     * @param owner The address of the order owner whose order is matched with the sender.
     * @param price The price at which the order is matched.
     * @param amount The matched amount of the asset being traded in the match. if isBid==false, it is base asset, if isBid==true, it is quote asset.
     * @param clear whether or not the order is cleared
     */
    event OrderMatched(
        address orderbook,
        uint256 id,
        bool isBid,
        address sender,
        address owner,
        uint256 price,
        uint256 amount,
        bool clear
    );

    event OrderPlaced(
        address orderbook,
        uint256 id,
        address owner,
        bool isBid,
        uint256 price,
        uint256 withoutFee,
        uint256 placed
    );

    event PairAdded(
        address orderbook,
        address base,
        address quote,
        uint8 bDecimal,
        uint8 qDecimal
    );

    error TooManyMatches(uint256 n);
    error InvalidFeeRate(uint256 feeNum, uint256 feeDenom);
    error NotContract(address newImpl);
    error InvalidRole(bytes32 role, address sender);
    error OrderSizeTooSmall(uint256 amount, uint256 minRequired);
    error NoOrderMade(address base, address quote);
    error InvalidPair(address base, address quote, address pair);
    error NoLastMatchedPrice(address base, address quote);
    error BidPriceTooLow(uint256 limitPrice, uint256 lmp, uint256 minBidPrice);
    error AskPriceTooHigh(uint256 limitPrice, uint256 lmp, uint256 maxAskPrice);
    error PairDoesNotExist(address base, address quote, address pair);
    error AmountIsZero();
    error PriceIsZero();

    receive() external payable {
        assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
    }

    constructor() {
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _grantRole(MARKET_MAKER_ROLE, msg.sender);
    }

    /**
     * @dev Initialize the matching engine with orderbook factory and listing requirements.
     * It can be called only once.
     * @param orderbookFactory_ address of orderbook factory
     * @param feeTo_ address to receive fee
     * @param WETH_ address of wrapped ether contract
     *
     * Requirements:
     * - `msg.sender` must have the default admin role.
     */
    function initialize(
        address orderbookFactory_,
        address feeTo_,
        address WETH_
    ) external initializer {
        orderbookFactory = orderbookFactory_;
        feeTo = feeTo_;
        WETH = WETH_;
        defaultBuy = 200;
        defaultSell = 200;
    }

    // admin functions
    function setFeeTo(address feeTo_) external returns (bool success) {
        if (!hasRole(DEFAULT_ADMIN_ROLE, _msgSender())) {
            revert InvalidRole(DEFAULT_ADMIN_ROLE, _msgSender());
        }
        feeTo = feeTo_;
        return true;
    }

    function setDefaultSpread(
        uint32 buy,
        uint32 sell
    ) external returns (bool success) {
        if (!hasRole(MARKET_MAKER_ROLE, _msgSender())) {
            revert InvalidRole(MARKET_MAKER_ROLE, _msgSender());
        }
        defaultBuy = buy;
        defaultSell = sell;
        return true;
    }

    function setSpread(
        address base,
        address quote,
        uint32 buy,
        uint32 sell
    ) external returns (bool success) {
        if (!hasRole(MARKET_MAKER_ROLE, _msgSender())) {
            revert InvalidRole(MARKET_MAKER_ROLE, _msgSender());
        }
        _setSpread(base, quote, buy, sell);
        return true;
    }

    // user functions

    /**
     * @dev Executes a market buy order, with spread limit of 1% for price actions.
     * buys the base asset using the quote asset at the best available price in the orderbook up to `n` orders,
     * and make an order at the market price.
     * @param base The address of the base asset for the trading pair
     * @param quote The address of the quote asset for the trading pair
     * @param quoteAmount The amount of quote asset to be used for the market buy order
     * @param isMaker Boolean indicating if a order should be made at the market price in orderbook
     * @param n The maximum number of orders to match in the orderbook
     * @param recipient The address of the order owner
     * @return makePrice price where the order is placed
     * @return placed placed amount
     * @return id placed order id
     */
    function marketBuy(
        address base,
        address quote,
        uint256 quoteAmount,
        bool isMaker,
        uint32 n,
        address recipient
    )
        public
        nonReentrant
        returns (uint256 makePrice, uint256 placed, uint32 id)
    {
        OrderData memory orderData;

        // reuse quoteAmount variable as minRequired from _deposit to avoid stack too deep error
        (orderData.withoutFee, orderData.orderbook) = _deposit(
            base,
            quote,
            0,
            quoteAmount,
            true,
            isMaker
        );

        // get spread limits
        orderData.spreadLimit = _getSpread(orderData.orderbook, true);

        orderData.lmp = mktPrice(base, quote);

        // reuse quoteAmount for storing amount after taking fees
        quoteAmount = orderData.withoutFee;

        // reuse withoutFee variable for storing remaining amount due to stack too deep error
        (
            orderData.withoutFee,
            orderData.bidHead,
            orderData.askHead
        ) = _limitOrder(
            orderData.orderbook,
            orderData.withoutFee,
            quote,
            recipient,
            true,
            (orderData.lmp * (10000 + orderData.spreadLimit)) / 10000,
            n
        );

        // reuse orderData.bidHead argument for storing make price
        orderData.bidHead = _detMarketBuyMakePrice(
            orderData.orderbook,
            orderData.bidHead,
            orderData.askHead,
            orderData.spreadLimit
        );

        // add make order on market price, reuse orderData.ls for storing placed Order id
        orderData.makeId = _detMake(
            base,
            quote,
            orderData.orderbook,
            orderData.withoutFee,
            orderData.bidHead,
            true,
            isMaker,
            recipient
        );

        // check if order id is made
        if (orderData.makeId > 0) {
            //if made, set last market price to orderData.bidHead only if orderData.bidHead is greater than lmp
            if (orderData.bidHead > orderData.lmp) {
                IOrderbook(orderData.orderbook).setLmp(orderData.bidHead);
                emit NewMarketPrice(orderData.orderbook, orderData.bidHead);
            }
            emit OrderPlaced(
                orderData.orderbook,
                orderData.makeId,
                recipient,
                true,
                orderData.bidHead,
                quoteAmount,
                orderData.withoutFee
            );
        }

        return (orderData.bidHead, orderData.withoutFee, orderData.makeId);
    }

    function _detMarketBuyMakePrice(
        address orderbook,
        uint256 bidHead,
        uint256 askHead,
        uint32 spread
    ) internal view returns (uint256 price) {
        uint256 up;
        uint256 lmp = IOrderbook(orderbook).lmp();
        if (askHead == 0 && bidHead == 0) {
            // lmp must exist unless there has been no order in orderbook
            if (lmp != 0) {
                up = (lmp * (10000 + spread)) / 10000;
                return up;
            }
        } else if (askHead == 0 && bidHead != 0) {
            if (lmp != 0) {
                uint256 temp = (bidHead >= lmp ? bidHead : lmp);
                up = (temp * (10000 + spread)) / 10000;
                return up;
            }
            up = (bidHead * (10000 + spread)) / 10000;
            return up;
        } else if (askHead != 0 && bidHead == 0) {
            if (lmp != 0) {
                up = (lmp * (10000 + spread)) / 10000;
                return askHead >= up ? up : askHead;
            }
            return askHead;
        } else {
            if (lmp != 0) {
                uint256 temp = (bidHead >= lmp ? bidHead : lmp);
                up = (temp * (10000 + spread)) / 10000;
                return askHead >= up ? up : askHead;
            }
            return askHead;
        }
    }

    /**
     * @dev Executes a market sell order, with spread limit of 5% for price actions.
     * sells the base asset for the quote asset at the best available price in the orderbook up to `n` orders,
     * and make an order at the market price.
     * @param base The address of the base asset for the trading pair
     * @param quote The address of the quote asset for the trading pair
     * @param baseAmount The amount of base asset to be sold in the market sell order
     * @param isMaker Boolean indicating if an order should be made at the market price in orderbook
     * @param n The maximum number of orders to match in the orderbook
     * @return makePrice price where the order is placed
     * @return placed placed amount
     * @return id placed order id
     */
    function marketSell(
        address base,
        address quote,
        uint256 baseAmount,
        bool isMaker,
        uint32 n,
        address recipient
    )
        public
        nonReentrant
        returns (uint256 makePrice, uint256 placed, uint32 id)
    {
        OrderData memory orderData;
        (orderData.withoutFee, orderData.orderbook) = _deposit(
            base,
            quote,
            0,
            baseAmount,
            false,
            isMaker
        );

        // get spread limits
        orderData.spreadLimit = _getSpread(orderData.orderbook, false);

        orderData.lmp = mktPrice(base, quote);

        // reuse baseAmount for storing without fee
        baseAmount = orderData.withoutFee;

        // reuse withoutFee variable for storing remaining amount after matching due to stack too deep error
        (
            orderData.withoutFee,
            orderData.bidHead,
            orderData.askHead
        ) = _limitOrder(
            orderData.orderbook,
            orderData.withoutFee,
            base,
            recipient,
            false,
            (orderData.lmp * (10000 - orderData.spreadLimit)) / 10000,
            n
        );

        // reuse orderData.askHead argument for storing make price
        orderData.askHead = _detMarketSellMakePrice(
            orderData.orderbook,
            orderData.bidHead,
            orderData.askHead,
            orderData.spreadLimit
        );

        orderData.makeId = _detMake(
            base,
            quote,
            orderData.orderbook,
            orderData.withoutFee,
            orderData.askHead,
            false,
            isMaker,
            recipient
        );

        // check if order id is made
        if (orderData.makeId > 0) {
            //if made, set last market price to orderData.askHead only if askHead is smaller than lmp
            if (orderData.askHead < orderData.lmp) {
                IOrderbook(orderData.orderbook).setLmp(orderData.askHead);
                emit NewMarketPrice(orderData.orderbook, orderData.askHead);
            }
            emit OrderPlaced(
                orderData.orderbook,
                orderData.makeId,
                recipient,
                false,
                orderData.askHead,
                baseAmount,
                orderData.withoutFee
            );
        }

        return (orderData.askHead, orderData.withoutFee, orderData.makeId);
    }

    function _detMarketSellMakePrice(
        address orderbook,
        uint256 bidHead,
        uint256 askHead,
        uint32 spread
    ) internal view returns (uint256 price) {
        uint256 down;
        uint256 lmp = IOrderbook(orderbook).lmp();
        if (askHead == 0 && bidHead == 0) {
            // lmp must exist unless there has been no order in orderbook
            if (lmp != 0) {
                down = (lmp * (10000 - spread)) / 10000;
                return down == 0 ? 1 : down;
            }
        } else if (askHead == 0 && bidHead != 0) {
            if (lmp != 0) {
                down = (lmp * (10000 - spread)) / 10000;
                down = down <= bidHead ? bidHead : down;
                return down == 0 ? 1 : down;
            }
            return bidHead;
        } else if (askHead != 0 && bidHead == 0) {
            if (lmp != 0) {
                uint256 temp = lmp <= askHead ? lmp : askHead;
                down = (temp * (10000 - spread)) / 10000;
                return down == 0 ? 1 : down;
            }
            down = (askHead * (10000 - spread)) / 10000;
            return down == 0 ? 1 : down;
        } else {
            if (lmp != 0) {
                uint256 temp = lmp <= askHead ? lmp : askHead;
                down = (temp * (10000 - spread)) / 10000;
                down = down <= bidHead ? bidHead : down;
                return down == 0 ? 1 : down;
            }
            return bidHead;
        }
    }

    /**
     * @dev Executes a market buy order, with spread limit of 5% for price actions.
     * buys the base asset using the quote asset at the best available price in the orderbook up to `n` orders,
     * and make an order at the market price with quote asset as native Ethereum(or other network currencies).
     * @param base The address of the base asset for the trading pair
     * @param isMaker Boolean indicating if a order should be made at the market price in orderbook
     * @param n The maximum number of orders to match in the orderbook
     * @param recipient The address of the recipient to receive traded asset and claim ownership of made order
     * @return makePrice price where the order is placed
     * @return placed placed amount
     * @return id placed order id
     */
    function marketBuyETH(
        address base,
        bool isMaker,
        uint32 n,
        address recipient
    ) external payable returns (uint256 makePrice, uint256 placed, uint32 id) {
        IWETH(WETH).deposit{value: msg.value}();
        return marketBuy(base, WETH, msg.value, isMaker, n, recipient);
    }

    /**
     * @dev Executes a market sell order,
     * sells the base asset for the quote asset at the best available price in the orderbook up to `n` orders,
     * and make an order at the market price with base asset as native Ethereum(or other network currencies).
     * @param quote The address of the quote asset for the trading pair
     * @param isMaker Boolean indicating if an order should be made at the market price in orderbook
     * @param n The maximum number of orders to match in the orderbook
     * @param recipient The address of the recipient to receive traded asset and claim ownership of made order
     * @return makePrice price where the order is placed
     * @return placed placed amount
     * @return id placed order id
     */
    function marketSellETH(
        address quote,
        bool isMaker,
        uint32 n,
        address recipient
    ) external payable returns (uint256 makePrice, uint256 placed, uint32 id) {
        IWETH(WETH).deposit{value: msg.value}();
        return marketSell(WETH, quote, msg.value, isMaker, n, recipient);
    }

    /**
     * @dev Executes a limit buy order, with spread limit of 5% for price actions.
     * places a limit order in the orderbook for buying the base asset using the quote asset at a specified price,
     * and make an order at the limit price.
     * @param base The address of the base asset for the trading pair
     * @param quote The address of the quote asset for the trading pair
     * @param price The price, base/quote regardless of decimals of the assets in the pair represented with 8 decimals (if 1000, base is 1000x quote)
     * @param quoteAmount The amount of quote asset to be used for the limit buy order
     * @param isMaker Boolean indicating if an order should be made at the limit price
     * @param n The maximum number of orders to match in the orderbook
     * @param recipient The address of the recipient to receive traded asset and claim ownership of made order
     * @return makePrice price where the order is placed
     * @return placed placed amount
     * @return id placed order id
     */
    function limitBuy(
        address base,
        address quote,
        uint256 price,
        uint256 quoteAmount,
        bool isMaker,
        uint32 n,
        address recipient
    )
        public
        nonReentrant
        returns (uint256 makePrice, uint256 placed, uint32 id)
    {
        OrderData memory orderData;
        (orderData.withoutFee, orderData.orderbook) = _deposit(
            base,
            quote,
            price,
            quoteAmount,
            true,
            isMaker
        );

        // get spread limits
        orderData.spreadLimit = _getSpread(orderData.orderbook, true);

        // reuse quoteAmount for storing amount without fee
        quoteAmount = orderData.withoutFee;

        // reuse withoutFee variable for storing remaining amount after matching due to stack too deep error
        (
            orderData.withoutFee,
            orderData.bidHead,
            orderData.askHead
        ) = _limitOrder(
            orderData.orderbook,
            orderData.withoutFee,
            quote,
            recipient,
            true,
            price,
            n
        );

        // reuse price variable for storing make price
        (price, orderData.lmp) = _detLimitBuyMakePrice(
            orderData.orderbook,
            price,
            orderData.bidHead,
            orderData.askHead,
            orderData.spreadLimit
        );

        orderData.makeId = _detMake(
            base,
            quote,
            orderData.orderbook,
            orderData.withoutFee,
            price,
            true,
            isMaker,
            recipient
        );

        // check if order id is made
        if (orderData.makeId > 0) {
            // if made, set last market price to price only if price is higher than lmp
            if (price > orderData.lmp) {
                IOrderbook(orderData.orderbook).setLmp(price);

                emit NewMarketPrice(orderData.orderbook, price);
            }
            emit OrderPlaced(
                orderData.orderbook,
                orderData.makeId,
                recipient,
                true,
                price,
                quoteAmount,
                orderData.withoutFee
            );
        }

        return (price, orderData.withoutFee, orderData.makeId);
    }

    function _detLimitBuyMakePrice(
        address orderbook,
        uint256 lp,
        uint256 bidHead,
        uint256 askHead,
        uint32 spread
    ) internal view returns (uint256 price, uint256 lmp) {
        uint256 up;
        lmp = IOrderbook(orderbook).lmp();
        if (askHead == 0 && bidHead == 0) {
            if (lmp != 0) {
                up = (lmp * (10000 + spread)) / 10000;
                return (lp >= up ? up : lp, lmp);
            }
            return (lp, lmp);
        } else if (askHead == 0 && bidHead != 0) {
            if (lmp != 0) {
                up = (lmp * (10000 + spread)) / 10000;
                return (lp >= up ? up : lp, lmp);
            }
            up = (bidHead * (10000 + spread)) / 10000;
            return (lp >= up ? up : lp, lmp);
        } else if (askHead != 0 && bidHead == 0) {
            if (lmp != 0) {
                up = (lmp * (10000 + spread)) / 10000;
                up = lp >= up ? up : lp;
                return (up >= askHead ? askHead : up, lmp);
            }
            up = (askHead * (10000 + spread)) / 10000;
            up = lp >= up ? up : lp;
            return (up >= askHead ? askHead : up, lmp);
        } else {
            // First, set upper limit on make price for market suspenstion
            up = lp <= lmp ? lp : lmp;
            // upper limit on make price must not go above ask price
            return (up >= askHead ? askHead : up, lmp);
        }
    }

    /**
     * @dev Executes a limit sell order, with spread limit of 5% for price actions.
     * places a limit order in the orderbook for selling the base asset for the quote asset at a specified price,
     * and makes an order at the limit price.
     * @param base The address of the base asset for the trading pair
     * @param quote The address of the quote asset for the trading pair
     * @param price The price, base/quote regardless of decimals of the assets in the pair represented with 8 decimals (if 1000, base is 1000x quote)
     * @param baseAmount The amount of base asset to be used for the limit sell order
     * @param isMaker Boolean indicating if an order should be made at the limit price
     * @param n The maximum number of orders to match in the orderbook
     * @return makePrice price where the order is placed
     * @return placed placed amount
     * @return id placed order id
     */
    function limitSell(
        address base,
        address quote,
        uint256 price,
        uint256 baseAmount,
        bool isMaker,
        uint32 n,
        address recipient
    )
        public
        nonReentrant
        returns (uint256 makePrice, uint256 placed, uint32 id)
    {
        OrderData memory orderData;
        (orderData.withoutFee, orderData.orderbook) = _deposit(
            base,
            quote,
            price,
            baseAmount,
            false,
            isMaker
        );

        // get spread limit
        orderData.spreadLimit = _getSpread(orderData.orderbook, false);

        // reuse baseAmount for storing amount without fee
        baseAmount = orderData.withoutFee;

        // reuse withoutFee variable for storing remaining amount after matching due to stack too deep error
        (
            orderData.withoutFee,
            orderData.bidHead,
            orderData.askHead
        ) = _limitOrder(
            orderData.orderbook,
            orderData.withoutFee,
            base,
            recipient,
            false,
            price,
            n
        );

        // reuse price variable for make price
        (price, orderData.lmp) = _detLimitSellMakePrice(
            orderData.orderbook,
            price,
            orderData.bidHead,
            orderData.askHead,
            orderData.spreadLimit
        );

        orderData.makeId = _detMake(
            base,
            quote,
            orderData.orderbook,
            orderData.withoutFee,
            price,
            false,
            isMaker,
            recipient
        );

        if (orderData.makeId > 0) {
            // if made, set last market price to price only if price is lower than lmp
            if (price < orderData.lmp) {
                IOrderbook(orderData.orderbook).setLmp(price);

                emit NewMarketPrice(orderData.orderbook, price);
            }
            emit OrderPlaced(
                orderData.orderbook,
                orderData.makeId,
                recipient,
                false,
                price,
                baseAmount,
                orderData.withoutFee
            );
        }

        return (price, orderData.withoutFee, orderData.makeId);
    }

    function _detLimitSellMakePrice(
        address orderbook,
        uint256 lp,
        uint256 bidHead,
        uint256 askHead,
        uint32 spread
    ) internal view returns (uint256 price, uint256 lmp) {
        uint256 down;
        lmp = IOrderbook(orderbook).lmp();
        if (askHead == 0 && bidHead == 0) {
            if (lmp != 0) {
                down = (lmp * (10000 - spread)) / 10000;
                return (lp <= down ? down : lp, lmp);
            }
            return (lp, lmp);
        } else if (askHead == 0 && bidHead != 0) {
            if (lmp != 0) {
                down = (lmp * (10000 - spread)) / 10000;
                down = lp <= down ? down : lp;
                return (down <= bidHead ? bidHead : down, lmp);
            }
            down = (bidHead * (10000 - spread)) / 10000;
            down = lp <= down ? down : lp;
            return (down <= bidHead ? bidHead : down, lmp);
        } else if (askHead != 0 && bidHead == 0) {
            if (lmp != 0) {
                down = (lmp * (10000 - spread)) / 10000;
               return (lp <= down ? down : lp, lmp);
            }
            down = (askHead * (10000 - spread)) / 10000;
            return (lp <= down ? down : lp, lmp);
        } else {
            // First, set lower limit on down price for market suspenstion
            down = lp >= lmp ? lp : lmp;
            // lower limit price on sell cannot be lower than bid head price
            return (down <= bidHead ? bidHead : down, lmp);
        }
    }

    /**
     * @dev Executes a limit buy order, with spread limit of 5% for price actions.
     * places a limit order in the orderbook for buying the base asset using the quote asset at a specified price,
     * and make an order at the limit price with quote asset as native Ethereum(or network currencies).
     * @param base The address of the base asset for the trading pair
     * @param isMaker Boolean indicating if a order should be made at the market price in orderbook
     * @param n The maximum number of orders to match in the orderbook
     * @param recipient The address of the recipient to receive traded asset and claim ownership of made order
     * @return makePrice price where the order is placed
     * @return placed placed amount
     * @return id placed order id
     */
    function limitBuyETH(
        address base,
        uint256 price,
        bool isMaker,
        uint32 n,
        address recipient
    ) external payable returns (uint256 makePrice, uint256 placed, uint32 id) {
        IWETH(WETH).deposit{value: msg.value}();
        return limitBuy(base, WETH, price, msg.value, isMaker, n, recipient);
    }

    /**
     * @dev Executes a limit sell order, with spread limit of 5% for price actions.
     * places a limit order in the orderbook for selling the base asset for the quote asset at a specified price,
     * and makes an order at the limit price with base asset as native Ethereum(or network currencies).
     * @param quote The address of the quote asset for the trading pair
     * @param isMaker Boolean indicating if an order should be made at the market price in orderbook
     * @param n The maximum number of orders to match in the orderbook
     * @param recipient The address of the recipient to receive traded asset and claim ownership of made order
     * @return makePrice price where the order is placed
     * @return placed placed amount
     * @return id placed order id
     */
    function limitSellETH(
        address quote,
        uint256 price,
        bool isMaker,
        uint32 n,
        address recipient
    ) external payable returns (uint256 makePrice, uint256 placed, uint32 id) {
        IWETH(WETH).deposit{value: msg.value}();
        return limitSell(WETH, quote, price, msg.value, isMaker, n, recipient);
    }

    /**
     * @dev Creates an orderbook for a new trading pair and returns its address
     * @param base The address of the base asset for the trading pair
     * @param quote The address of the quote asset for the trading pair
     * @param initMarketPrice The initial market price for the trading pair
     * @return book The address of the newly created orderbook
     */
    function addPair(
        address base,
        address quote,
        uint256 initMarketPrice
    ) external returns (address book) {
        // create orderbook for the pair
        address orderbook = IOrderbookFactory(orderbookFactory).createBook(
            base,
            quote
        );
        IOrderbook(orderbook).setLmp(initMarketPrice);
        uint8 bDecimal = IDecimals(base).decimals();
        uint8 qDecimal = IDecimals(quote).decimals();
        // set limit spread to 2% and market spread to 5% for default pair
        _setSpread(base, quote, defaultBuy, defaultSell);
        emit PairAdded(orderbook, base, quote, bDecimal, qDecimal);
        emit NewMarketPrice(orderbook, initMarketPrice);
        return orderbook;
    }

    function _addPair(
        address base,
        address quote
    ) internal returns (address book) {
        // create orderbook for the pair
        address orderBook = IOrderbookFactory(orderbookFactory).createBook(
            base,
            quote
        );
        uint8 bDecimal = IDecimals(base).decimals();
        uint8 qDecimal = IDecimals(quote).decimals();
        // set limit spread to 2% and market spread to 5% for default pair
        _setSpread(base, quote, defaultBuy, defaultSell);
        emit PairAdded(orderBook, base, quote, bDecimal, qDecimal);
        return orderBook;
    }

    /**
     * @dev Cancels an order in an orderbook by the given order ID and order type.
     * @param base The address of the base asset for the trading pair
     * @param quote The address of the quote asset for the trading pair
     * @param isBid Boolean indicating if the order to cancel is an ask order
     * @param orderId The ID of the order to cancel
     * @return refunded Refunded amount from order
     */
    function cancelOrder(
        address base,
        address quote,
        bool isBid,
        uint32 orderId
    ) public nonReentrant returns (uint256) {
        address orderbook = IOrderbookFactory(orderbookFactory).getPair(
            base,
            quote
        );

        if (orderbook == address(0)) {
            revert InvalidPair(base, quote, orderbook);
        }

        try
            IOrderbook(orderbook).cancelOrder(isBid, orderId, msg.sender)
        returns (uint256 refunded) {
            emit OrderCanceled(orderbook, orderId, isBid, msg.sender, refunded);
            return refunded;
        } catch {
            return 0;
        }
    }

    function cancelOrders(
        address[] memory base,
        address[] memory quote,
        bool[] memory isBid,
        uint32[] memory orderIds
    ) external returns (uint256[] memory refunded) {
        refunded = new uint256[](orderIds.length);
        for (uint32 i = 0; i < orderIds.length; i++) {
            refunded[i] = cancelOrder(base[i], quote[i], isBid[i], orderIds[i]);
        }
        return refunded;
    }

    /**
     * @dev Returns the address of the orderbook with the given ID.
     * @param id The ID of the orderbook to retrieve.
     * @return The address of the orderbook.
     */
    function getOrderbookById(uint256 id) external view returns (address) {
        return IOrderbookFactory(orderbookFactory).getBook(id);
    }

    /**
     * @dev Returns the base and quote asset addresses for the given orderbook.
     * @param orderbook The address of the orderbook to retrieve the base and quote asset addresses for.
     * @return base The address of the base asset.
     * @return quote The address of the quote asset.
     */
    function getBaseQuote(
        address orderbook
    ) external view returns (address base, address quote) {
        return IOrderbookFactory(orderbookFactory).getBaseQuote(orderbook);
    }

    /**
     * @dev returns addresses of pairs in OrderbookFactory registry
     * @return pairs list of pairs from start to end
     */
    function getPairs(
        uint256 start,
        uint256 end
    ) external view returns (IOrderbookFactory.Pair[] memory pairs) {
        return IOrderbookFactory(orderbookFactory).getPairs(start, end);
    }

    /**
     * @dev returns addresses of pairs in OrderbookFactory registry
     * @return pairs list of pairs from start to end
     */
    function getPairsWithIds(
        uint256[] memory ids
    ) external view returns (IOrderbookFactory.Pair[] memory pairs) {
        return IOrderbookFactory(orderbookFactory).getPairsWithIds(ids);
    }

    /**
     * @dev returns addresses of pairs in OrderbookFactory registry
     * @return names list of pair names from start to end
     */
    function getPairNames(
        uint256 start,
        uint256 end
    ) external view returns (string[] memory names) {
        return IOrderbookFactory(orderbookFactory).getPairNames(start, end);
    }

    /**
     * @dev returns addresses of pairs in OrderbookFactory registry
     * @return names list of pair names from start to end
     */
    function getPairNamesWithIds(
        uint256[] memory ids
    ) external view returns (string[] memory names) {
        return IOrderbookFactory(orderbookFactory).getPairNamesWithIds(ids);
    }

    /**
     * @dev returns addresses of pairs in OrderbookFactory registry
     * @return mktPrices list of mktPrices from start to end
     */
    function getMktPrices(
        uint256 start,
        uint256 end
    ) external view returns (uint256[] memory mktPrices) {
        IOrderbookFactory.Pair[] memory pairs = IOrderbookFactory(
            orderbookFactory
        ).getPairs(start, end);
        mktPrices = new uint256[](pairs.length);
        for (uint256 i = 0; i < pairs.length; i++) {
            try this.mktPrice(pairs[i].base, pairs[i].quote) returns (
                uint256 price
            ) {
                uint256 p = price;
                mktPrices[i] = p;
            } catch {
                uint256 p = 0;
                mktPrices[i] = p;
            }
        }
        return mktPrices;
    }

    /**
     * @dev returns addresses of pairs in OrderbookFactory registry
     * @return mktPrices list of mktPrices from start to end
     */
    function getMktPricesWithIds(
        uint256[] memory ids
    ) external view returns (uint256[] memory mktPrices) {
        IOrderbookFactory.Pair[] memory pairs = IOrderbookFactory(
            orderbookFactory
        ).getPairsWithIds(ids);
        mktPrices = new uint256[](pairs.length);
        for (uint256 i = 0; i < pairs.length; i++) {
            try this.mktPrice(pairs[i].base, pairs[i].quote) returns (
                uint256 price
            ) {
                uint256 p = price;
                mktPrices[i] = p;
            } catch {
                uint256 p = 0;
                mktPrices[i] = p;
            }
        }
        return mktPrices;
    }

    /**
     * @dev Returns prices in the ask/bid orderbook for the given trading pair.
     * @param base The address of the base asset for the trading pair.
     * @param quote The address of the quote asset for the trading pair.
     * @param isBid Boolean indicating if the orderbook to retrieve prices from is an ask orderbook.
     * @param n The number of prices to retrieve.
     */
    function getPrices(
        address base,
        address quote,
        bool isBid,
        uint32 n
    ) external view returns (uint256[] memory) {
        address orderbook = getPair(base, quote);
        return IOrderbook(orderbook).getPrices(isBid, n);
    }

    function getPricesPaginated(
        address base,
        address quote,
        bool isBid,
        uint32 start,
        uint32 end
    ) external view returns (uint256[] memory) {
        address orderbook = getPair(base, quote);
        return IOrderbook(orderbook).getPricesPaginated(isBid, start, end);
    }

    /**
     * @dev Returns orders in the ask/bid orderbook for the given trading pair in a price.
     * @param base The address of the base asset for the trading pair.
     * @param quote The address of the quote asset for the trading pair.
     * @param isBid Boolean indicating if the orderbook to retrieve orders from is an ask orderbook.
     * @param price The price to retrieve orders from.
     * @param n The number of orders to retrieve.
     */
    function getOrders(
        address base,
        address quote,
        bool isBid,
        uint256 price,
        uint32 n
    ) external view returns (ExchangeOrderbook.Order[] memory) {
        address orderbook = getPair(base, quote);
        return IOrderbook(orderbook).getOrders(isBid, price, n);
    }

    function getOrdersPaginated(
        address base,
        address quote,
        bool isBid,
        uint256 price,
        uint32 start,
        uint32 end
    ) external view returns (ExchangeOrderbook.Order[] memory) {
        address orderbook = getPair(base, quote);
        return
            IOrderbook(orderbook).getOrdersPaginated(isBid, price, start, end);
    }

    /**
     * @dev Returns an order in the ask/bid orderbook for the given trading pair with order id.
     * @param base The address of the base asset for the trading pair.
     * @param quote The address of the quote asset for the trading pair.
     * @param isBid Boolean indicating if the orderbook to retrieve orders from is an ask orderbook.
     * @param orderId The order id to retrieve.
     */
    function getOrder(
        address base,
        address quote,
        bool isBid,
        uint32 orderId
    ) public view returns (ExchangeOrderbook.Order memory) {
        address orderbook = getPair(base, quote);
        return IOrderbook(orderbook).getOrder(isBid, orderId);
    }

    /**
     * @dev Returns order ids in the ask/bid orderbook for the given trading pair in a price.
     * @param base The address of the base asset for the trading pair.
     * @param quote The address of the quote asset for the trading pair.
     * @param isBid Boolean indicating if the orderbook to retrieve orders from is an ask orderbook.
     * @param price The price to retrieve orders from.
     * @param n The number of order ids to retrieve.
     */
    function getOrderIds(
        address base,
        address quote,
        bool isBid,
        uint256 price,
        uint32 n
    ) external view returns (uint32[] memory) {
        address orderbook = getPair(base, quote);
        return IOrderbook(orderbook).getOrderIds(isBid, price, n);
    }

    /**
     * @dev Returns the address of the orderbook for the given base and quote asset addresses.
     * @param base The address of the base asset for the trading pair.
     * @param quote The address of the quote asset for the trading pair.
     * @return book The address of the orderbook.
     */
    function getPair(
        address base,
        address quote
    ) public view returns (address book) {
        return IOrderbookFactory(orderbookFactory).getPair(base, quote);
    }

    function heads(
        address base,
        address quote
    ) external view returns (uint256 bidHead, uint256 askHead) {
        address orderbook = getPair(base, quote);
        return IOrderbook(orderbook).heads();
    }

    function mktPrice(
        address base,
        address quote
    ) public view returns (uint256) {
        address orderbook = getPair(base, quote);
        return IOrderbook(orderbook).mktPrice();
    }

    /**
     * @dev return converted amount from base to quote or vice versa
     * @param base address of base asset
     * @param quote address of quote asset
     * @param amount amount of base or quote asset
     * @param isBid if true, amount is quote asset, otherwise base asset
     * @return converted converted amount from base to quote or vice versa.
     * if true, amount is quote asset, otherwise base asset
     * if orderbook does not exist, return 0
     */
    function convert(
        address base,
        address quote,
        uint256 amount,
        bool isBid
    ) public view returns (uint256 converted) {
        address orderbook = getPair(base, quote);
        if (base == quote) {
            return amount;
        } else if (orderbook == address(0)) {
            return 0;
        } else {
            return IOrderbook(orderbook).assetValue(amount, isBid);
        }
    }

    function _setSpread(
        address base,
        address quote,
        uint32 buy,
        uint32 sell
    ) internal returns (bool success) {
        address book = getPair(base, quote);
        spreadLimits[book] = DefaultSpread(buy, sell);
        return true;
    }

    function _getSpread(
        address book,
        bool isBuy
    ) internal view returns (uint32 spreadLimit) {
        DefaultSpread memory spread;
        spread = spreadLimits[book];
        if (isBuy) {
            return spread.buy;
        } else {
            return spread.sell;
        }
    }

    /**
     * @dev Internal function which makes an order on the orderbook.
     * @param orderbook The address of the orderbook contract for the trading pair
     * @param withoutFee The remaining amount of the asset after the market order has been executed
     * @param price The price, base/quote regardless of decimals of the assets in the pair represented with 8 decimals (if 1000, base is 1000x quote)
     * @param isBid Boolean indicating if the order is a buy (false) or a sell (true)
     * @param recipient The address of the recipient to receive traded asset and claim ownership of made order
     */
    function _makeOrder(
        address orderbook,
        uint256 withoutFee,
        uint256 price,
        bool isBid,
        address recipient
    ) internal returns (uint32 id) {
        // create order
        if (isBid) {
            id = IOrderbook(orderbook).placeBid(recipient, price, withoutFee);
        } else {
            id = IOrderbook(orderbook).placeAsk(recipient, price, withoutFee);
        }
        return id;
    }

    /**
     * @dev Match bid if `isBid` is true, match ask if `isBid` is false.
     */
    function _matchAt(
        address orderbook,
        address give,
        address recipient,
        bool isBid,
        uint256 amount,
        uint256 price,
        uint32 i,
        uint32 n
    ) internal returns (uint256 remaining, uint32 k) {
        if (n > 20) {
            revert TooManyMatches(n);
        }
        remaining = amount;
        while (
            remaining > 0 &&
            !IOrderbook(orderbook).isEmpty(!isBid, price) &&
            i < n
        ) {
            // fpop OrderLinkedList by price, if ask you get bid order, if bid you get ask order. Get quote asset on bid order on buy, base asset on ask order on sell
            (uint32 orderId, uint256 required, bool clear) = IOrderbook(
                orderbook
            ).fpop(!isBid, price, remaining);
            // order exists, and amount is not 0
            if (remaining <= required) {
                // execute order
                TransferHelper.safeTransfer(give, orderbook, remaining);
                address owner = IOrderbook(orderbook).execute(
                    orderId,
                    !isBid,
                    recipient,
                    remaining,
                    clear
                );
                // report points on match
                _report(orderbook, give, isBid, remaining, owner);
                // emit event order matched
                emit OrderMatched(
                    orderbook,
                    orderId,
                    isBid,
                    recipient,
                    owner,
                    price,
                    remaining,
                    clear
                );
                // end loop as remaining is 0
                return (0, n);
            }
            // order is null
            else if (required == 0) {
                ++i;
                continue;
            }
            // remaining >= depositAmount
            else {
                remaining -= required;
                TransferHelper.safeTransfer(give, orderbook, required);
                address owner = IOrderbook(orderbook).execute(
                    orderId,
                    !isBid,
                    recipient,
                    required,
                    clear
                );
                // report points on match
                _report(orderbook, give, isBid, required, owner);
                // emit event order matched
                emit OrderMatched(
                    orderbook,
                    orderId,
                    isBid,
                    recipient,
                    owner,
                    price,
                    required,
                    clear
                );
                ++i;
            }
        }
        k = i;
        return (remaining, k);
    }

    /**
     * @dev Executes limit order by matching orders in the orderbook based on the provided limit price.
     * @param orderbook The address of the orderbook to execute the limit order on.
     * @param amount The amount of asset to trade.
     * @param give The address of the asset to be traded.
     * @param recipient The address to receive asset after matching a trade
     * @param isBid True if the order is an ask (sell) order, false if it is a bid (buy) order.
     * @param limitPrice The maximum price at which the order can be executed.
     * @param n The maximum number of matches to execute.
     * @return remaining The remaining amount of asset that was not traded.
     */
    function _limitOrder(
        address orderbook,
        uint256 amount,
        address give,
        address recipient,
        bool isBid,
        uint256 limitPrice,
        uint32 n
    ) internal returns (uint256 remaining, uint256 bidHead, uint256 askHead) {
        remaining = amount;
        uint256 lmp = IOrderbook(orderbook).lmp();
        bidHead = IOrderbook(orderbook).clearEmptyHead(true);
        askHead = IOrderbook(orderbook).clearEmptyHead(false);
        uint32 i = 0;
        // In LimitBuy
        if (isBid) {
            if (lmp != 0) {
                if (askHead != 0 && limitPrice < askHead) {
                    return (remaining, bidHead, askHead);
                } else if (askHead == 0) {
                    return (remaining, bidHead, askHead);
                }
            }
            // check if there is any matching ask order until matching ask order price is lower than the limit bid Price
            while (
                remaining > 0 && askHead != 0 && askHead <= limitPrice && i < n
            ) {
                lmp = askHead;
                (remaining, i) = _matchAt(
                    orderbook,
                    give,
                    recipient,
                    isBid,
                    remaining,
                    askHead,
                    i,
                    n
                );
                // i == 0 when orders are all empty and only head price is left
                askHead = i == 0
                    ? 0
                    : IOrderbook(orderbook).clearEmptyHead(false);
            }
            // update heads
            bidHead = IOrderbook(orderbook).clearEmptyHead(true);
        }
        // In LimitSell
        else {
            // check limit ask price is within 20% spread of last matched price
            if (lmp != 0) {
                if (bidHead != 0 && limitPrice > bidHead) {
                    return (remaining, bidHead, askHead);
                } else if (bidHead == 0) {
                    return (remaining, bidHead, askHead);
                }
            }
            while (
                remaining > 0 && bidHead != 0 && bidHead >= limitPrice && i < n
            ) {
                lmp = bidHead;
                (remaining, i) = _matchAt(
                    orderbook,
                    give,
                    recipient,
                    isBid,
                    remaining,
                    bidHead,
                    i,
                    n
                );
                // i == 0 when orders are all empty and only head price is left
                bidHead = i == 0
                    ? 0
                    : IOrderbook(orderbook).clearEmptyHead(true);
            }
            // update heads
            askHead = IOrderbook(orderbook).clearEmptyHead(false);
        }
        // set new market price as the orders are matched
        if (lmp != 0) {
            IOrderbook(orderbook).setLmp(lmp);
            emit NewMarketPrice(orderbook, lmp);
        }

        return (remaining, bidHead, askHead); // return bidHead, and askHead
    }

    /**
     * @dev Determines if an order can be made at the market price,
     * and if so, makes the an order on the orderbook.
     * If an order cannot be made, transfers the remaining asset to either the orderbook or the user.
     * @param base The address of the base asset for the trading pair
     * @param quote The address of the quote asset for the trading pair
     * @param orderbook The address of the orderbook contract for the trading pair
     * @param remaining The remaining amount of the asset after the market order has been taken
     * @param price The price used to determine if an order can be made
     * @param isBid Boolean indicating if the order was a buy (true) or a sell (false)
     * @param isMaker Boolean indicating if an order is for storing in orderbook
     * @param recipient The address to receive asset after matching a trade and making an order
     * @return id placed order id
     */
    function _detMake(
        address base,
        address quote,
        address orderbook,
        uint256 remaining,
        uint256 price,
        bool isBid,
        bool isMaker,
        address recipient
    ) internal returns (uint32 id) {
        if (remaining > 0) {
            address stopTo = isMaker ? orderbook : recipient;
            TransferHelper.safeTransfer(
                isBid ? quote : base,
                stopTo,
                remaining
            );
            if (isMaker) {
                id = _makeOrder(orderbook, remaining, price, isBid, recipient);
                return id;
            }
        }
    }

    function _report(
        address orderbook,
        address give,
        bool isBid,
        uint256 matched,
        address owner
    ) internal {
        if (
            _isContract(feeTo) && IRevenue(feeTo).isReportable() && matched > 0
        ) {
            // report matched amount to accountant with give token on matching order
            IRevenue(feeTo).reportMatch(
                orderbook,
                give,
                isBid,
                msg.sender,
                owner,
                matched
            );
        }
    }

    /**
     * @dev Deposit amount of asset to the contract with the given asset information and subtracts the fee.
     * @param base The address of the base asset.
     * @param quote The address of the quote asset.
     * @param amount The amount of asset to deposit.
     * @param isBid Whether it is an ask order or not.
     * If ask, the quote asset is transferred to the contract.
     * @return withoutFee The amount of asset without the fee.
     * @return pair The address of the orderbook for the given asset pair.
     */
    function _deposit(
        address base,
        address quote,
        uint256 price,
        uint256 amount,
        bool isBid,
        bool isMaker
    ) internal returns (uint256 withoutFee, address pair) {
        // check if amount is zero
        if (amount == 0) {
            revert AmountIsZero();
        }
        // get orderbook address from the base and quote asset
        pair = getPair(base, quote);
        if (pair == address(0)) {
            revert InvalidPair(base, quote, pair);
        }

        // check if amount is valid in case of both market and limit
        uint256 converted = _convert(pair, price, amount, !isBid);
        uint256 minRequired = _convert(pair, price, 1, !isBid);

        if (converted <= minRequired) {
            revert OrderSizeTooSmall(converted, minRequired);
        }
        // check sender's fee
        uint256 fee = _fee(amount, msg.sender, isMaker);
        withoutFee = amount - fee;
        if (isBid) {
            // transfer input asset give user to this contract
            if (quote != WETH) {
                TransferHelper.safeTransferFrom(
                    quote,
                    msg.sender,
                    address(this),
                    amount
                );
            }
            TransferHelper.safeTransfer(quote, feeTo, fee);
        } else {
            // transfer input asset give user to this contract
            if (base != WETH) {
                TransferHelper.safeTransferFrom(
                    base,
                    msg.sender,
                    address(this),
                    amount
                );
            }
            TransferHelper.safeTransfer(base, feeTo, fee);
        }
        emit OrderDeposit(msg.sender, isBid ? quote : base, fee);

        return (withoutFee, pair);
    }

    function _fee(
        uint256 amount,
        address account,
        bool isMaker
    ) internal view returns (uint256 fee) {
        if (_isContract(feeTo) && IRevenue(feeTo).isSubscribed(account)) {
            uint32 feeNum = IRevenue(feeTo).feeOf(account, isMaker);
            return (amount * feeNum) / feeDenom;
        }
        return amount / 100;
    }

    function _isContract(address addr) internal view returns (bool isContract) {
        uint size;
        assembly {
            size := extcodesize(addr)
        }
        return size > 0;
    }

    /**
     * @dev return converted amount from base to quote or vice versa
     * @param orderbook address of orderbook
     * @param price price of base/quote regardless of decimals of the assets in the pair represented with 8 decimals (if 1000, base is 1000x quote) proposed by a trader
     * @param amount amount of base or quote asset
     * @param isBid if true, amount is quote asset, otherwise base asset
     * @return converted converted amount from base to quote or vice versa.
     * if true, amount is quote asset, otherwise base asset
     * if orderbook does not exist, return 0
     */
    function _convert(
        address orderbook,
        uint256 price,
        uint256 amount,
        bool isBid
    ) internal view returns (uint256 converted) {
        if (orderbook == address(0)) {
            return 0;
        } else {
            return
                price == 0
                    ? IOrderbook(orderbook).assetValue(amount, isBid)
                    : IOrderbook(orderbook).convert(price, amount, isBid);
        }
    }
}

// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.24;

interface IOrderbookFactory {
    struct Pair {
        address base;
        address quote;
    }

    function createBook(address bid_, address ask_) external returns (address orderbook);

    function getBook(uint256 bookId_) external view returns (address orderbook);

    function getPair(address base, address quote) external view returns (address);

    function getBaseQuote(address orderbook) external view returns (address base, address quote);

    function allPairsLength() external view returns (uint256);

    /// Address of a manager
    function engine() external view returns (address);

    function getPairs(uint256 start, uint256 end) external view returns (Pair[] memory);

    function getPairsWithIds(uint256[] memory ids) external view returns (Pair[] memory);

    function getPairNames(uint256 start, uint256 end) external view returns (string[] memory names);

    function getPairNamesWithIds(uint256[] memory ids) external view returns (string[] memory names);
}

// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.24;

import "../libraries/ExchangeOrderbook.sol";

interface IOrderbook {
    function initialize(uint256 id, address base_, address quote_, address engine_) external;

    function fpop(bool isBid, uint256 price, uint256 remaining) external returns (uint32 orderId, uint256 required, bool clear);

    function setLmp(uint256 lmp) external;

    function mktPrice() external view returns (uint256);

    function assetValue(uint256 amount, bool isBid) external view returns (uint256 converted);

    function isEmpty(bool isBid, uint256 price) external view returns (bool);

    function getRequired(bool isBid, uint256 price, uint32 orderId) external view returns (uint256 required);

    function clearEmptyHead(bool isBid) external returns (uint256 head);

    function convert(uint256 price, uint256 amount, bool isBid) external view returns (uint256 converted);

    function placeAsk(address owner, uint256 price, uint256 amount) external returns (uint32 orderId);

    function placeBid(address owner, uint256 price, uint256 amount) external returns (uint32 orderId);

    function cancelOrder(bool isBid, uint32 orderId, address owner)
        external
        returns (uint256 remaining);

    function execute(uint32 orderId, bool isBid, address sender, uint256 amount, bool clear)
        external
        returns (address owner);

    function heads() external view returns (uint256 bidHead, uint256 askHead);

    function askHead() external view returns (uint256);

    function bidHead() external view returns (uint256);

    function orderHead(bool isBid, uint256 price) external view returns (uint32);

    function lmp() external view returns (uint256);

    function getPrices(bool isBid, uint32 n) external view returns (uint256[] memory);

    function getPricesPaginated(bool isBid, uint32 start, uint32 end) external view returns (uint256[] memory);

    function getOrders(bool isBid, uint256 price, uint32 n) external view returns (ExchangeOrderbook.Order[] memory);

    function getOrdersPaginated(bool isBid, uint256 price, uint32 start, uint32 end) external view returns (ExchangeOrderbook.Order[] memory);

    function getOrder(bool isBid, uint32 orderId) external view returns (ExchangeOrderbook.Order memory);

    function getOrderIds(bool isBid, uint256 price, uint32 n) external view returns (uint32[] memory);

    function getBaseQuote() external view returns(address base, address quote);

    function sfpop(
        bool isBid,
        uint256 price,
        uint32 orderId,
        bool isHead
    ) external view returns(uint32 id, uint256 required, bool clear);

    function nextPrice(
        bool isBid,
        uint256 price
    ) external view returns (uint256 next); 

    function nextOrder(
        bool isBid,
        uint256 price,
        uint32 orderId
    ) external view returns (uint32 next);
}

// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.24;

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    function safeApprove(address token, address to, uint256 value) internal {
        // bytes4(keccak256(bytes("approve(address,uint256)")));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "AF");
    }

    function safeTransfer(address token, address to, uint256 value) internal {
        // bytes4(keccak256(bytes("transfer(address,uint256)")));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "TF");
    }

    function safeTransferFrom(address token, address from, address to, uint256 value) internal {
        // bytes4(keccak256(bytes("transferFrom(address,address,uint256)")));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "TFF");
    }

    function safeTransferETH(address to, uint256 value) internal {
        (bool success,) = to.call{value: value}(new bytes(0));
        require(success, "ETF");
    }

    function decimals(address token) internal view returns (uint8) {
        // bytes4(keccak256(bytes("decimals()")));
        (bool success, bytes memory data) = token.staticcall(abi.encodeWithSelector(0x313ce567));
        require(success, "DF");
        return abi.decode(data, (uint8));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.24;

interface IWETH {
    function deposit() external payable;

    function transfer(address to, uint256 value) external returns (bool);

    function withdraw(uint256) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        return _roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        if (!hasRole(role, account)) {
            _roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}

// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.24;

library ExchangeOrderbook {
    // Order struct
    struct Order {
        address owner;
        uint256 price;
        uint256 depositAmount;
    }

    // Order Linked List
    struct OrderStorage {
        /// Hashmap-style linked list of prices to route orders
        // key: price, value: order indices linked hashmap
        mapping(uint256 => mapping(uint32 => uint32)) list;
        mapping(uint32 => Order) orders;
        // Head of the linked list(i.e. lowest ask price / highest bid price)
        mapping(uint256 => uint32) head;
        // count of the orders, used for array allocation
        uint32 count;
        address engine;
    }

    error OrderIdIsZero(uint32 id);
    error PriceIsZero(uint256 price);

    // for orders, lower depositAmount are next, higher depositAmount comes first
    function _insertId(
        OrderStorage storage self,
        uint256 price,
        uint32 id,
        uint256 amount
    ) internal {
        uint32 last = 0;
        uint32 head = self.head[price];
        mapping(uint32 => uint32) storage list = self.list[price];
        mapping(uint32 => Order) storage orders = self.orders;
        // insert order to the linked list
        // if the list is empty
        if (head == 0 || amount > self.orders[head].depositAmount) {
            self.head[price] = id;
            list[id] = head;
            return;
        }
        // Traverse through list until we find the right spot where id's deposit amount is higher than next
        while (head != 0) {
            // what if order deposit amount is bigger than the next order's deposit amount?
            uint32 next = list[head];
            if (amount < orders[next].depositAmount) {
                // Keep traversing
                head = list[head];
                last = next;
            } else if (amount > orders[next].depositAmount) {
                // This is either order is cancelled or order is at the end of the list
                if (orders[next].depositAmount == 0) {
                    // Insert order at the end of the list
                    list[head] = id;
                    list[id] = 0;
                    return;
                }
                // Insert order in the middle of the list
                list[head] = id;
                list[id] = next;
                return;
            }
            // what if there is same order with same deposit amount?
            else if (amount == orders[next].depositAmount) {
                list[id] = list[next];
                list[next] = id;
                return;
            }
        }
    }

    // pop front
    function _fpop(
        OrderStorage storage self,
        uint256 price
    ) internal returns (uint256) {
        uint32 first = self.head[price];
        if (first == 0) {
            return 0;
        }
        uint32 next = self.list[price][first];
        self.head[price] = next;
        delete self.list[price][first];
        return first;
    }

    function _createOrder(
        OrderStorage storage self,
        address owner,
        uint256 price,
        uint256 depositAmount
    ) internal returns (uint32 id) {
        if(price == 0) {
            revert PriceIsZero(price);
        }
        Order memory order = Order({
            owner: owner,
            price: price,
            depositAmount: depositAmount
        });
        // In order to prevent order overflow, order id must start from 1
        self.count = self.count == 0 || self.count == type(uint32).max
            ? 1
            : self.count + 1;
        self.orders[self.count] = order;
        return self.count;
    }

    function _decreaseOrder(
        OrderStorage storage self,
        uint32 id,
        uint256 amount,
        uint256 dust,
        bool clear
    ) internal returns (uint256 sendFund, uint256 deletePrice) {
        uint256 decreased = self.orders[id].depositAmount < amount
            ? 0
            : self.orders[id].depositAmount - amount;
        // remove dust
        if (decreased <= dust || clear) {
            decreased = self.orders[id].depositAmount;
            deletePrice = _deleteOrder(self, id);
            return (decreased, deletePrice);
        } else {
            self.orders[id].depositAmount = decreased;
            return (amount, deletePrice);
        }
    }

    function _deleteOrder(
        OrderStorage storage self,
        uint32 id
    ) internal returns (uint256 deletePrice) {
        uint256 price = self.orders[id].price;
        uint32 last = 0;
        uint32 head = self.head[price];
        uint32 next;
        uint16 i;
        mapping(uint32 => uint32) storage list = self.list[price];
        // delete id in the order linked list
        if (head == id) {
            self.head[price] = list[head];
            delete list[id];
        } else {
            // search for the order id in the linked list
            while (head != 0) {
                next = list[head];
                if (next == id) {
                    list[head] = list[next];
                    delete list[id];
                    break;
                }
                last = head;
                head = next;
                ++i;
            }
        }
        // delete order
        delete self.orders[id];
        return self.head[price] == 0 ? price : 0;
    }

    // show n order ids at the price in the orderbook
    function _getOrderIds(
        OrderStorage storage self,
        uint256 price,
        uint32 n
    ) internal view returns (uint32[] memory) {
        uint32 head = self.head[price];
        uint32[] memory orders = new uint32[](n);
        uint32 i = 0;
        while (head != 0 && i < n) {
            orders[i] = head;
            head = self.list[price][head];
            i++;
        }
        return orders;
    }

    function _getOrders(
        OrderStorage storage self,
        uint256 price,
        uint32 n
    ) internal view returns (Order[] memory) {
        uint32 head = self.head[price];
        Order[] memory orders = new Order[](n);
        uint32 i = 0;
        while (head != 0 && i < n) {
            orders[i] = self.orders[head];
            head = self.list[price][head];
            i++;
        }
        return orders;
    }

    function _getOrdersPaginated(
        OrderStorage storage self,
        uint256 price,
        uint32 start,
        uint32 end
    ) internal view returns (Order[] memory) {
        uint32 head = self.head[price];
        Order[] memory orders = new Order[](end - start);
        uint32 i = 0;
        while (head != 0 && i < start) {
            head = self.list[price][head];
            i++;
        }
        if (head == 0) {
            return orders;
        }
        while (head != 0 && i < end) {
            orders[i] = self.orders[head];
            head = self.list[price][head];
            i++;
        }
        return orders;
    }

    function _head(
        OrderStorage storage self,
        uint256 price
    ) internal view returns (uint32) {
        return self.head[price];
    }

    function _isEmpty(
        OrderStorage storage self,
        uint256 price
    ) internal view returns (bool) {
        return self.head[price] == 0;
    }

    function _next(
        OrderStorage storage self,
        uint256 price,
        uint32 curr
    ) internal view returns (uint32) {
        return self.list[price][curr];
    }

    function _getOrder(
        OrderStorage storage self,
        uint32 id
    ) internal view returns (Order memory) {
        return self.orders[id];
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "remappings": [
    "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
    "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"AmountIsZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"limitPrice","type":"uint256"},{"internalType":"uint256","name":"lmp","type":"uint256"},{"internalType":"uint256","name":"maxAskPrice","type":"uint256"}],"name":"AskPriceTooHigh","type":"error"},{"inputs":[{"internalType":"uint256","name":"limitPrice","type":"uint256"},{"internalType":"uint256","name":"lmp","type":"uint256"},{"internalType":"uint256","name":"minBidPrice","type":"uint256"}],"name":"BidPriceTooLow","type":"error"},{"inputs":[{"internalType":"uint256","name":"feeNum","type":"uint256"},{"internalType":"uint256","name":"feeDenom","type":"uint256"}],"name":"InvalidFeeRate","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"address","name":"pair","type":"address"}],"name":"InvalidPair","type":"error"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"}],"name":"InvalidRole","type":"error"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"NoLastMatchedPrice","type":"error"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"NoOrderMade","type":"error"},{"inputs":[{"internalType":"address","name":"newImpl","type":"address"}],"name":"NotContract","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minRequired","type":"uint256"}],"name":"OrderSizeTooSmall","type":"error"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"address","name":"pair","type":"address"}],"name":"PairDoesNotExist","type":"error"},{"inputs":[],"name":"PriceIsZero","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"TooManyMatches","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"orderbook","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"NewMarketPrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"orderbook","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isBid","type":"bool"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"OrderCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"OrderDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"orderbook","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isBid","type":"bool"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"clear","type":"bool"}],"name":"OrderMatched","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"orderbook","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bool","name":"isBid","type":"bool"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withoutFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"placed","type":"uint256"}],"name":"OrderPlaced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"orderbook","type":"address"},{"indexed":false,"internalType":"address","name":"base","type":"address"},{"indexed":false,"internalType":"address","name":"quote","type":"address"},{"indexed":false,"internalType":"uint8","name":"bDecimal","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"qDecimal","type":"uint8"}],"name":"PairAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint256","name":"initMarketPrice","type":"uint256"}],"name":"addPair","outputs":[{"internalType":"address","name":"book","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"bool","name":"isBid","type":"bool"},{"internalType":"uint32","name":"orderId","type":"uint32"}],"name":"cancelOrder","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"base","type":"address[]"},{"internalType":"address[]","name":"quote","type":"address[]"},{"internalType":"bool[]","name":"isBid","type":"bool[]"},{"internalType":"uint32[]","name":"orderIds","type":"uint32[]"}],"name":"cancelOrders","outputs":[{"internalType":"uint256[]","name":"refunded","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isBid","type":"bool"}],"name":"convert","outputs":[{"internalType":"uint256","name":"converted","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeDenom","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"orderbook","type":"address"}],"name":"getBaseQuote","outputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"getMktPrices","outputs":[{"internalType":"uint256[]","name":"mktPrices","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"getMktPricesWithIds","outputs":[{"internalType":"uint256[]","name":"mktPrices","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"bool","name":"isBid","type":"bool"},{"internalType":"uint32","name":"orderId","type":"uint32"}],"name":"getOrder","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"depositAmount","type":"uint256"}],"internalType":"struct ExchangeOrderbook.Order","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"bool","name":"isBid","type":"bool"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint32","name":"n","type":"uint32"}],"name":"getOrderIds","outputs":[{"internalType":"uint32[]","name":"","type":"uint32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getOrderbookById","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"bool","name":"isBid","type":"bool"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint32","name":"n","type":"uint32"}],"name":"getOrders","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"depositAmount","type":"uint256"}],"internalType":"struct ExchangeOrderbook.Order[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"bool","name":"isBid","type":"bool"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"}],"name":"getOrdersPaginated","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"depositAmount","type":"uint256"}],"internalType":"struct ExchangeOrderbook.Order[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"book","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"getPairNames","outputs":[{"internalType":"string[]","name":"names","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"getPairNamesWithIds","outputs":[{"internalType":"string[]","name":"names","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"getPairs","outputs":[{"components":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"internalType":"struct IOrderbookFactory.Pair[]","name":"pairs","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"getPairsWithIds","outputs":[{"components":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"internalType":"struct IOrderbookFactory.Pair[]","name":"pairs","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"bool","name":"isBid","type":"bool"},{"internalType":"uint32","name":"n","type":"uint32"}],"name":"getPrices","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"bool","name":"isBid","type":"bool"},{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"}],"name":"getPricesPaginated","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"heads","outputs":[{"internalType":"uint256","name":"bidHead","type":"uint256"},{"internalType":"uint256","name":"askHead","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"orderbookFactory_","type":"address"},{"internalType":"address","name":"feeTo_","type":"address"},{"internalType":"address","name":"WETH_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"quoteAmount","type":"uint256"},{"internalType":"bool","name":"isMaker","type":"bool"},{"internalType":"uint32","name":"n","type":"uint32"},{"internalType":"address","name":"recipient","type":"address"}],"name":"limitBuy","outputs":[{"internalType":"uint256","name":"makePrice","type":"uint256"},{"internalType":"uint256","name":"placed","type":"uint256"},{"internalType":"uint32","name":"id","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"isMaker","type":"bool"},{"internalType":"uint32","name":"n","type":"uint32"},{"internalType":"address","name":"recipient","type":"address"}],"name":"limitBuyETH","outputs":[{"internalType":"uint256","name":"makePrice","type":"uint256"},{"internalType":"uint256","name":"placed","type":"uint256"},{"internalType":"uint32","name":"id","type":"uint32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"baseAmount","type":"uint256"},{"internalType":"bool","name":"isMaker","type":"bool"},{"internalType":"uint32","name":"n","type":"uint32"},{"internalType":"address","name":"recipient","type":"address"}],"name":"limitSell","outputs":[{"internalType":"uint256","name":"makePrice","type":"uint256"},{"internalType":"uint256","name":"placed","type":"uint256"},{"internalType":"uint32","name":"id","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"isMaker","type":"bool"},{"internalType":"uint32","name":"n","type":"uint32"},{"internalType":"address","name":"recipient","type":"address"}],"name":"limitSellETH","outputs":[{"internalType":"uint256","name":"makePrice","type":"uint256"},{"internalType":"uint256","name":"placed","type":"uint256"},{"internalType":"uint32","name":"id","type":"uint32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint256","name":"quoteAmount","type":"uint256"},{"internalType":"bool","name":"isMaker","type":"bool"},{"internalType":"uint32","name":"n","type":"uint32"},{"internalType":"address","name":"recipient","type":"address"}],"name":"marketBuy","outputs":[{"internalType":"uint256","name":"makePrice","type":"uint256"},{"internalType":"uint256","name":"placed","type":"uint256"},{"internalType":"uint32","name":"id","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"bool","name":"isMaker","type":"bool"},{"internalType":"uint32","name":"n","type":"uint32"},{"internalType":"address","name":"recipient","type":"address"}],"name":"marketBuyETH","outputs":[{"internalType":"uint256","name":"makePrice","type":"uint256"},{"internalType":"uint256","name":"placed","type":"uint256"},{"internalType":"uint32","name":"id","type":"uint32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint256","name":"baseAmount","type":"uint256"},{"internalType":"bool","name":"isMaker","type":"bool"},{"internalType":"uint32","name":"n","type":"uint32"},{"internalType":"address","name":"recipient","type":"address"}],"name":"marketSell","outputs":[{"internalType":"uint256","name":"makePrice","type":"uint256"},{"internalType":"uint256","name":"placed","type":"uint256"},{"internalType":"uint32","name":"id","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"quote","type":"address"},{"internalType":"bool","name":"isMaker","type":"bool"},{"internalType":"uint32","name":"n","type":"uint32"},{"internalType":"address","name":"recipient","type":"address"}],"name":"marketSellETH","outputs":[{"internalType":"uint256","name":"makePrice","type":"uint256"},{"internalType":"uint256","name":"placed","type":"uint256"},{"internalType":"uint32","name":"id","type":"uint32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"mktPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"orderbookFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"buy","type":"uint32"},{"internalType":"uint32","name":"sell","type":"uint32"}],"name":"setDefaultSpread","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeTo_","type":"address"}],"name":"setFeeTo","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint32","name":"buy","type":"uint32"},{"internalType":"uint32","name":"sell","type":"uint32"}],"name":"setSpread","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"spreadLimits","outputs":[{"internalType":"uint32","name":"buy","type":"uint32"},{"internalType":"uint32","name":"sell","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

0x60806040523480156200001157600080fd5b506001600090815562000025903362000059565b50620000527f75e5bf8b7de9fd9f24c97951733c6410a040b7a07b543096cb36c6dda365aa8b3362000059565b50620000f0565b60008281526001602090815260408083206001600160a01b038516845290915281205460ff16620000e65760008381526001602081815260408084206001600160a01b0387168086529252808420805460ff19169093179092559051339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a4506001620000ea565b5060005b92915050565b61551e80620001006000396000f3fe60806040526004361061026b5760003560e01c80637640379e11610144578063b5acfa62116100b6578063d547741f1161007a578063d547741f14610864578063dc85cde714610884578063e6a4390514610897578063e794b1c1146108b7578063f2364e91146108ca578063f46901ed146108ea57600080fd5b8063b5acfa62146107b1578063b92bf451146107d1578063b98ad392146107e4578063c0c53b8b14610804578063c1a3ddb81461082457600080fd5b80638a645e45116101085780638a645e45146106ef5780638f6440511461070f57806391d148541461073c57806399c6d42a1461075c578063a217fddf1461077c578063ad5c46481461079157600080fd5b80637640379e146106425780637e069db01461066257806383e185d2146106825780638572b584146106a257806389556190146106cf57600080fd5b80633213f797116101dd57806341fbece9116101a157806341fbece91461053b57806351d1f2f61461055b57806357cc4c0d1461056e5780636036edf2146105ca5780636752cfaa146105ea5780636e300b401461062257600080fd5b80633213f7971461046d578063349d1b5f1461049a57806336568abe146104db5780633d177c79146104fb5780633de07eea1461051b57600080fd5b8063248a9ca31161022f578063248a9ca31461036c578063288be22b146103ab5780632f2ff15d146103cb5780632f9c754d146103eb57806330372dc414610418578063303f13851461044d57600080fd5b806301ffc9a714610291578063062496fe146102c6578063187f8b05146102f357806319a86577146103205780631a83eba01461034c57600080fd5b3661028c576004546001600160a01b0316331461028a5761028a614335565b005b600080fd5b34801561029d57600080fd5b506102b16102ac36600461434b565b61090a565b60405190151581526020015b60405180910390f35b3480156102d257600080fd5b506102e66102e13660046143aa565b610941565b6040516102bd9190614412565b3480156102ff57600080fd5b5061031361030e36600461447d565b6109e0565b6040516102bd91906144d9565b34801561032c57600080fd5b50610337620f424081565b60405163ffffffff90911681526020016102bd565b34801561035857600080fd5b506102b1610367366004614503565b610a9e565b34801561037857600080fd5b5061039d61038736600461453c565b6000908152600160208190526040909120015490565b6040519081526020016102bd565b3480156103b757600080fd5b506102b16103c6366004614555565b610b41565b3480156103d757600080fd5b5061028a6103e6366004614596565b610b8c565b3480156103f757600080fd5b5061040b6104063660046145bb565b610bb8565b6040516102bd91906145dd565b34801561042457600080fd5b50610438610433366004614615565b610da1565b604080519283526020830191909152016102bd565b34801561045957600080fd5b5061040b6104683660046147b4565b610e1f565b34801561047957600080fd5b5061048d6104883660046145bb565b610f3e565b6040516102bd91906148e0565b3480156104a657600080fd5b506104ba6104b536600461495a565b610fbe565b60408051938452602084019290925263ffffffff16908201526060016102bd565b3480156104e757600080fd5b5061028a6104f6366004614596565b61118b565b34801561050757600080fd5b5061039d610516366004614615565b6111c3565b34801561052757600080fd5b5061040b6105363660046149de565b611234565b34801561054757600080fd5b506102e6610556366004614a6e565b611419565b6104ba610569366004614ae7565b6114bf565b34801561057a57600080fd5b506105ad610589366004614b38565b60056020526000908152604090205463ffffffff8082169164010000000090041682565b6040805163ffffffff9384168152929091166020830152016102bd565b3480156105d657600080fd5b5061040b6105e536600461447d565b611559565b3480156105f657600080fd5b5061060a61060536600461453c565b6115e4565b6040516001600160a01b0390911681526020016102bd565b34801561062e57600080fd5b5061048d61063d3660046149de565b611652565b34801561064e57600080fd5b5061039d61065d366004614b55565b6116c8565b34801561066e57600080fd5b506104ba61067d366004614b9d565b61178a565b34801561068e57600080fd5b5061040b61069d366004614c08565b6119bc565b3480156106ae57600080fd5b506106c26106bd3660046143aa565b611a4f565b6040516102bd9190614c6b565b3480156106db57600080fd5b506104ba6106ea36600461495a565b611ae1565b3480156106fb57600080fd5b5060035461060a906001600160a01b031681565b34801561071b57600080fd5b5061072f61072a3660046149de565b611c7e565b6040516102bd9190614ca9565b34801561074857600080fd5b506102b1610757366004614596565b611cf4565b34801561076857600080fd5b5061039d61077736600461447d565b611d1f565b34801561078857600080fd5b5061039d600081565b34801561079d57600080fd5b5060045461060a906001600160a01b031681565b3480156107bd57600080fd5b5061060a6107cc366004614d05565b611ed4565b6104ba6107df366004614ae7565b612139565b3480156107f057600080fd5b506104ba6107ff366004614b9d565b6121c3565b34801561081057600080fd5b5061028a61081f366004614d46565b6123bd565b34801561083057600080fd5b5061084461083f366004614b38565b612522565b604080516001600160a01b039384168152929091166020830152016102bd565b34801561087057600080fd5b5061028a61087f366004614596565b61259c565b6104ba610892366004614d91565b6125c2565b3480156108a357600080fd5b5061060a6108b2366004614615565b61265e565b6104ba6108c5366004614d91565b6126d5565b3480156108d657600080fd5b5061072f6108e53660046145bb565b612760565b3480156108f657600080fd5b506102b1610905366004614b38565b6127d9565b60006001600160e01b03198216637965db0b60e01b148061093b57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6060600061094f878761265e565b60405163f3eb41a960e01b815286151560048201526024810186905263ffffffff851660448201529091506001600160a01b0382169063f3eb41a990606401600060405180830381865afa1580156109ab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109d39190810190614e51565b9150505b95945050505050565b610a0d604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b6000610a19868661265e565b604051635d9e5cd360e11b8152851515600482015263ffffffff851660248201529091506001600160a01b0382169063bb3cb9a690604401606060405180830381865afa158015610a6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a929190614ef1565b9150505b949350505050565b6000610ab86000805160206154c983398151915233611cf4565b610afd576000805160206154c9833981519152335b604051638bc10a7160e01b815260048101929092526001600160a01b031660248201526044015b60405180910390fd5b506004805467ffffffffffffffff60a01b1916600160a01b63ffffffff9485160263ffffffff60c01b191617600160c01b9290931691909102919091179055600190565b6000610b5b6000805160206154c983398151915233611cf4565b610b74576000805160206154c983398151915233610acd565b610b8085858585612817565b50600195945050505050565b60008281526001602081905260409091200154610ba88161288d565b610bb2838361289a565b50505050565b60035460405163f2364e9160e01b815260048101849052602481018390526060916000916001600160a01b039091169063f2364e9190604401600060405180830381865afa158015610c0e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c369190810190614f0d565b905080516001600160401b03811115610c5157610c51614643565b604051908082528060200260200182016040528015610c7a578160200160208202803683370190505b50915060005b8151811015610d9957306001600160a01b0316633d177c79838381518110610caa57610caa614fca565b602002602001015160000151848481518110610cc857610cc8614fca565b6020026020010151602001516040518363ffffffff1660e01b8152600401610d069291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa925050508015610d3f575060408051601f3d908101601f19168201909252610d3c91810190614fe0565b60015b610d6a57600080848381518110610d5857610d58614fca565b60200260200101818152505050610d91565b600081905080858481518110610d8257610d82614fca565b60200260200101818152505050505b600101610c80565b505092915050565b6000806000610db0858561265e565b9050806001600160a01b031663b8b238316040518163ffffffff1660e01b81526004016040805180830381865afa158015610def573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e139190614ff9565b92509250509250929050565b606081516001600160401b03811115610e3a57610e3a614643565b604051908082528060200260200182016040528015610e63578160200160208202803683370190505b50905060005b82518163ffffffff161015610f3557610f00868263ffffffff1681518110610e9357610e93614fca565b6020026020010151868363ffffffff1681518110610eb357610eb3614fca565b6020026020010151868463ffffffff1681518110610ed357610ed3614fca565b6020026020010151868563ffffffff1681518110610ef357610ef3614fca565b6020026020010151611d1f565b828263ffffffff1681518110610f1857610f18614fca565b602090810291909101015280610f2d81615033565b915050610e69565b50949350505050565b600354604051633213f79760e01b815260048101849052602481018390526060916001600160a01b031690633213f79790604401600060405180830381865afa158015610f8f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fb79190810190615056565b9392505050565b6000806000610fcb612913565b610fd36142d9565b610fe28b8b8b8b60008c61293d565b6001600160a01b031660208301819052908252611000906000612afb565b63ffffffff1660a08201528051602082015190985061102590898d8860008e8c612b69565b6060840181905260408401829052918352602083015160a084015161104f9391928d92909161304e565b608083015260208201518251919a50611070918d918d918d60008d8c613209565b63ffffffff1660c082018190521561116457806080015189101561112557602081015160405163d0c48a8360e01b8152600481018b90526001600160a01b039091169063d0c48a8390602401600060405180830381600087803b1580156110d657600080fd5b505af11580156110ea573d6000803e3d6000fd5b505050602080830151604080516001600160a01b0390921682529181018c905260008051602061548983398151915292500160405180910390a15b6000805160206154a983398151915281602001518260c001518760008d8d876000015160405161115b979695949392919061515a565b60405180910390a15b805160c090910151899450909250905061117e6001600055565b9750975097945050505050565b6001600160a01b03811633146111b45760405163334bd91960e11b815260040160405180910390fd5b6111be8282613261565b505050565b6000806111d0848461265e565b9050806001600160a01b03166337632e3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611210573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a969190614fe0565b600354604051638f64405160e01b81526060916000916001600160a01b0390911690638f6440519061126a9086906004016145dd565b600060405180830381865afa158015611287573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112af9190810190614f0d565b905080516001600160401b038111156112ca576112ca614643565b6040519080825280602002602001820160405280156112f3578160200160208202803683370190505b50915060005b815181101561141257306001600160a01b0316633d177c7983838151811061132357611323614fca565b60200260200101516000015184848151811061134157611341614fca565b6020026020010151602001516040518363ffffffff1660e01b815260040161137f9291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa9250505080156113b8575060408051601f3d908101601f191682019092526113b591810190614fe0565b60015b6113e3576000808483815181106113d1576113d1614fca565b6020026020010181815250505061140a565b6000819050808584815181106113fb576113fb614fca565b60200260200101818152505050505b6001016112f9565b5050919050565b60606000611427888861265e565b6040516354c12a7160e01b815287151560048201526024810187905263ffffffff8087166044830152851660648201529091506001600160a01b038216906354c12a7190608401600060405180830381865afa15801561148b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114b39190810190614e51565b98975050505050505050565b6000806000600460009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561151457600080fd5b505af1158015611528573d6000803e3d6000fd5b505060045461154993506001600160a01b03169150899050348989896121c3565b9250925092509450945094915050565b60606000611567868661265e565b604051633eb9f3f760e21b8152851515600482015263ffffffff851660248201529091506001600160a01b0382169063fae7cfdc90604401600060405180830381865afa1580156115bc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a9291908101906151a1565b60035460405163e0ff5b8b60e01b8152600481018390526000916001600160a01b03169063e0ff5b8b90602401602060405180830381865afa15801561162e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093b9190615226565b6003546040516301b8c02d60e61b81526060916001600160a01b031690636e300b40906116839085906004016145dd565b600060405180830381865afa1580156116a0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261093b9190810190615056565b6000806116d5868661265e565b9050846001600160a01b0316866001600160a01b0316036116f95783915050610a96565b6001600160a01b038116611711576000915050610a96565b604051630b11a8c960e31b81526004810185905283151560248201526001600160a01b0382169063588d464890604401602060405180830381865afa15801561175e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117829190614fe0565b915050610a96565b6000806000611797612913565b61179f6142d9565b6117af8a8a60008b60018c61293d565b6001600160a01b0316602083018190529082526117cd906001612afb565b63ffffffff1660a08201526117e28a8a6111c3565b60808201528051602082015160a0830151919950611836918a908c908990600190612710906118119082615243565b63ffffffff1688608001516118269190615260565b6118309190615277565b8c612b69565b6060840181905260408401829052918352602083015160a084015161185e93919291906132ce565b604082018190526020820151825161187f928d928d92909160018d8c613209565b63ffffffff1660c08201819052156119905780608001518160400151111561194d5780602001516001600160a01b031663d0c48a8382604001516040518263ffffffff1660e01b81526004016118d791815260200190565b600060405180830381600087803b1580156118f157600080fd5b505af1158015611905573d6000803e3d6000fd5b50505050600080516020615489833981519152816020015182604001516040516119449291906001600160a01b03929092168252602082015260400190565b60405180910390a15b6000805160206154a983398151915281602001518260c0015187600185604001518d8760000151604051611987979695949392919061515a565b60405180910390a15b806040015181600001518260c00151935093509350506119b06001600055565b96509650969350505050565b606060006119ca878761265e565b604051637a33b06160e11b8152861515600482015263ffffffff8087166024830152851660448201529091506001600160a01b0382169063f46760c290606401600060405180830381865afa158015611a27573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109d391908101906151a1565b60606000611a5d878761265e565b604051633f20424160e21b815286151560048201526024810186905263ffffffff851660448201529091506001600160a01b0382169063fc81090490606401600060405180830381865afa158015611ab9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109d39190810190615299565b6000806000611aee612913565b611af66142d9565b611b058b8b8b8b60018c61293d565b6001600160a01b031660208301819052908252611b23906001612afb565b63ffffffff1660a082015280516020820151909850611b4890898c8860018e8c612b69565b6060840181905260408401829052918352602083015160a0840151611b729391928d9290916134ca565b608083015260208201518251919a50611b93918d918d918d60018d8c613209565b63ffffffff1660c0820181905215611164578060800151891115611c4857602081015160405163d0c48a8360e01b8152600481018b90526001600160a01b039091169063d0c48a8390602401600060405180830381600087803b158015611bf957600080fd5b505af1158015611c0d573d6000803e3d6000fd5b505050602080830151604080516001600160a01b0390921682529181018c905260008051602061548983398151915292500160405180910390a15b6000805160206154a983398151915281602001518260c001518760018d8d876000015160405161115b979695949392919061515a565b600354604051638f64405160e01b81526060916001600160a01b031690638f64405190611caf9085906004016145dd565b600060405180830381865afa158015611ccc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261093b9190810190614f0d565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6000611d29612913565b60035460405163e6a4390560e01b81526001600160a01b0387811660048301528681166024830152600092169063e6a4390590604401602060405180830381865afa158015611d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da09190615226565b90506001600160a01b038116611de45760405163bfe877e160e01b81526001600160a01b038088166004830152808716602483015282166044820152606401610af4565b60405163764abdc160e11b8152841515600482015263ffffffff841660248201523360448201526001600160a01b0382169063ec957b82906064016020604051808303816000875af1925050508015611e5a575060408051601f3d908101601f19168201909252611e5791810190614fe0565b60015b611e68576000915050611eca565b604080516001600160a01b038416815263ffffffff861660208201528615158183015260608101839052905133917f6455b26713a0e0ba431d88c86da77ddfca232ffe0a76eeb89cc7ff18d338e009919081900360800190a29150611eca9050565b610a966001600055565b60035460405163228b199d60e11b81526001600160a01b03858116600483015284811660248301526000928392911690634516333a906044016020604051808303816000875af1158015611f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f509190615226565b60405163d0c48a8360e01b8152600481018590529091506001600160a01b0382169063d0c48a8390602401600060405180830381600087803b158015611f9557600080fd5b505af1158015611fa9573d6000803e3d6000fd5b505050506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120119190615327565b90506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612053573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120779190615327565b6004549091506120a1908890889063ffffffff600160a01b8204811691600160c01b900416612817565b50604080516001600160a01b038581168252898116602083015288168183015260ff84811660608301528316608082015290517f7bcab975bb0905a5c55a953d0c96d393a2f651e71517523687754cd56403fbc79181900360a00190a1604080516001600160a01b038516815260208101879052600080516020615489833981519152910160405180910390a1509095945050505050565b6000806000600460009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561218e57600080fd5b505af11580156121a2573d6000803e3d6000fd5b505060045461154993508a92506001600160a01b031690503489898961178a565b60008060006121d0612913565b6121d86142d9565b6121e88a8a60008b60008c61293d565b6001600160a01b031660208301819052908252612206906000612afb565b63ffffffff1660a082015261221b8a8a6111c3565b60808201528051602082015160a083015191995061224a918a908d90899060009061271090611811908261534a565b6060840181905260408401829052918352602083015160a08401516122729391929190613668565b6060820181905260208201518251612293928d928d92909160008d8c613209565b63ffffffff1660c082018190521561239d5780608001518160600151101561235a576020810151606082015160405163d0c48a8360e01b81526001600160a01b039092169163d0c48a83916122ee9160040190815260200190565b600060405180830381600087803b15801561230857600080fd5b505af115801561231c573d6000803e3d6000fd5b5050506020808301516060840151604080516001600160a01b0390931683529282015260008051602061548983398151915292500160405180910390a15b6000805160206154a983398151915281602001518260c0015187600085606001518d8760000151604051612394979695949392919061515a565b60405180910390a15b806060015181600001518260c00151935093509350506119b06001600055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03166000811580156124025750825b90506000826001600160401b0316600114801561241e5750303b155b90508115801561242c575080155b1561244a5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561247457845460ff60401b1916600160401b1785555b600380546001600160a01b03199081166001600160a01b038b81169190911790925560028054909116898316179055600480549188166001600160c01b031990921691909117601960a31b1763ffffffff60c01b1916601960c31b179055831561251857845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6003546040516318347bb760e31b81526001600160a01b038381166004830152600092839291169063c1a3ddb8906024016040805180830381865afa15801561256f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125939190615367565b91509150915091565b600082815260016020819052604090912001546125b88161288d565b610bb28383613261565b6000806000600460009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561261757600080fd5b505af115801561262b573d6000803e3d6000fd5b505060045461264d93508b92506001600160a01b0316905089348a8a8a611ae1565b925092509250955095509592505050565b60035460405163e6a4390560e01b81526001600160a01b0384811660048301528381166024830152600092169063e6a4390590604401602060405180830381865afa1580156126b1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb79190615226565b6000806000600460009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561272a57600080fd5b505af115801561273e573d6000803e3d6000fd5b505060045461264d93506001600160a01b031691508a905089348a8a8a610fbe565b60035460405163f2364e9160e01b815260048101849052602481018390526060916001600160a01b03169063f2364e9190604401600060405180830381865afa1580156127b1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fb79190810190614f0d565b60006127e58133611cf4565b6127f157600033610acd565b50600280546001600160a01b0319166001600160a01b0392909216919091179055600190565b600080612824868661265e565b60408051808201825263ffffffff808816825286811660208084019182526001600160a01b03909516600090815260059095529290932090518154925184166401000000000267ffffffffffffffff199093169316929092171790555060019050949350505050565b612897813361387a565b50565b60006128a68383611cf4565b61290b5760008381526001602081815260408084206001600160a01b0387168086529252808420805460ff19169093179092559051339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a450600161093b565b50600061093b565b60026000540361293657604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b60008084600003612961576040516310eb483f60e21b815260040160405180910390fd5b61296b888861265e565b90506001600160a01b0381166129af5760405163bfe877e160e01b81526001600160a01b03808a166004830152808916602483015282166044820152606401610af4565b60006129be82888888156138b7565b905060006129d08389600189156138b7565b90508082116129fc5760405163200772a360e11b81526004810183905260248101829052604401610af4565b6000612a098833886139ca565b9050612a158189615396565b94508615612a5b576004546001600160a01b038b8116911614612a3e57612a3e8a33308b613b00565b600254612a56908b906001600160a01b031683613c0a565b612a94565b6004546001600160a01b038c8116911614612a7c57612a7c8b33308b613b00565b600254612a94908c906001600160a01b031683613c0a565b7f6fc423e360a132634001b3add06785f7feff6a435202af430ff9547492b3a97a3388612ac1578c612ac3565b8b5b604080516001600160a01b039384168152929091166020830152810183905260600160405180910390a1505050965096945050505050565b604080518082018252600080825260209182018190526001600160a01b03851681526005825282812083518085019094525463ffffffff80821685526401000000009091041691830191909152908215612b575751905061093b565b60200151905061093b565b5092915050565b600080600088925060008a6001600160a01b031663dec5e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd59190614fe0565b604051630ccc4b0d60e31b8152600160048201529091506001600160a01b038c16906366625868906024016020604051808303816000875af1158015612c1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c439190614fe0565b604051630ccc4b0d60e31b8152600060048201529093506001600160a01b038c16906366625868906024016020604051808303816000875af1158015612c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cb19190614fe0565b915060008715612e31578115612cea578215801590612ccf57508287105b15612cdb57505061117e565b82600003612cea57505061117e565b600085118015612cf957508215155b8015612d055750868311155b8015612d1c57508563ffffffff168163ffffffff16105b15612dbf57829150612d348c8b8b8b8988878d613d0a565b909550905063ffffffff811615612db557604051630ccc4b0d60e31b8152600060048201526001600160a01b038d16906366625868906024016020604051808303816000875af1158015612d8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db09190614fe0565b612db8565b60005b9250612cea565b604051630ccc4b0d60e31b8152600160048201526001600160a01b038d16906366625868906024016020604051808303816000875af1158015612e06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e2a9190614fe0565b9350612fa3565b8115612e60578315801590612e4557508387115b15612e5157505061117e565b83600003612e6057505061117e565b600085118015612e6f57508315155b8015612e7b5750868410155b8015612e9257508563ffffffff168163ffffffff16105b15612f3557839150612eaa8c8b8b8b8989878d613d0a565b909550905063ffffffff811615612f2b57604051630ccc4b0d60e31b8152600160048201526001600160a01b038d16906366625868906024016020604051808303816000875af1158015612f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f269190614fe0565b612f2e565b60005b9350612e60565b604051630ccc4b0d60e31b8152600060048201526001600160a01b038d16906366625868906024016020604051808303816000875af1158015612f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa09190614fe0565b92505b811561303f5760405163d0c48a8360e01b8152600481018390526001600160a01b038d169063d0c48a8390602401600060405180830381600087803b158015612feb57600080fd5b505af1158015612fff573d6000803e3d6000fd5b505050506000805160206154898339815191528c836040516130369291906001600160a01b03929092168252602082015260400190565b60405180910390a15b50509750975097945050505050565b6000806000876001600160a01b031663dec5e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613091573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b59190614fe0565b9150841580156130c3575085155b1561311857811561310f576127106130db858261534a565b6130eb9063ffffffff1684615260565b6130f59190615277565b9050808711156131055786613107565b805b9250506131ff565b869250506131ff565b8415801561312557508515155b1561319f5781156131825761271061313d858261534a565b61314d9063ffffffff1684615260565b6131579190615277565b9050808711156131675786613169565b805b9050858111156131795780613107565b859250506131ff565b61271061318f858261534a565b61314d9063ffffffff1688615260565b84158015906131ac575085155b156131e15781156131c4576127106130db858261534a565b6127106131d1858261534a565b6130eb9063ffffffff1687615260565b818710156131ef5781613169565b5085858111156131795780613107565b9550959350505050565b600085156114b35760008361321e5782613220565b875b905061323985613230578a613232565b895b8289613c0a565b83156132545761324c88888888876140a3565b9150506114b3565b5098975050505050505050565b600061326d8383611cf4565b1561290b5760008381526001602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161093b565b6000806000866001600160a01b031663dec5e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613311573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133359190614fe0565b905084158015613343575085155b1561338457801561337f5761271061335b8582615243565b61336b9063ffffffff1683615260565b6133759190615277565b9250610a96915050565b6134c0565b8415801561339157508515155b156133ff5780156133e2576000818710156133ac57816133ae565b865b90506127106133bd8682615243565b6133cd9063ffffffff1683615260565b6133d79190615277565b9350610a9692505050565b6127106133ef8582615243565b61336b9063ffffffff1688615260565b841580159061340c575085155b15613463578015613459576127106134248582615243565b6134349063ffffffff1683615260565b61343e9190615277565b91508185101561344e5784613450565b815b92505050610a96565b8492505050610a96565b801561345957600081871015613479578161347b565b865b905061271061348a8682615243565b61349a9063ffffffff1683615260565b6134a49190615277565b9250828610156134b457856134b6565b825b9350505050610a96565b5050949350505050565b6000806000876001600160a01b031663dec5e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561350d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135319190614fe0565b91508415801561353f575085155b1561358157811561310f576127106135578582615243565b6135679063ffffffff1684615260565b6135719190615277565b9050808710156131055786613107565b8415801561358e57508515155b156135c35781156135a6576127106135578582615243565b6127106135b38582615243565b6135679063ffffffff1688615260565b84158015906135d0575085155b1561364a57811561362d576127106135e88582615243565b6135f89063ffffffff1684615260565b6136029190615277565b9050808710156136125786613614565b805b9050848110156136245780613107565b849250506131ff565b61271061363a8582615243565b6135f89063ffffffff1687615260565b818711156136585781613614565b5085848110156136245780613107565b6000806000866001600160a01b031663dec5e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156136ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136cf9190614fe0565b9050841580156136dd575085155b1561372857801561337f576127106136f5858261534a565b6137059063ffffffff1683615260565b61370f9190615277565b9150811561371d5781613450565b600192505050610a96565b8415801561373557508515155b156137905780156137865761271061374d858261534a565b61375d9063ffffffff1683615260565b6137679190615277565b915085821115613777578161370f565b859150811561371d5781613450565b8592505050610a96565b841580159061379d575085155b1561381a5780156137fd576000858211156137b857856137ba565b815b90506127106137c9868261534a565b6137d99063ffffffff1683615260565b6137e39190615277565b925082156137f157826134b6565b60019350505050610a96565b61271061380a858261534a565b6137059063ffffffff1687615260565b8015613786576000858211156138305785613832565b815b9050612710613841868261534a565b6138519063ffffffff1683615260565b61385b9190615277565b92508683111561386b57826137e3565b86925082156137f157826134b6565b6138848282611cf4565b6138b35760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610af4565b5050565b60006001600160a01b0385166138cf57506000610a96565b831561395257604051639c0e0bf160e01b8152600481018590526024810184905282151560448201526001600160a01b03861690639c0e0bf190606401602060405180830381865afa158015613929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061394d9190614fe0565b6139c3565b604051630b11a8c960e31b81526004810184905282151560248201526001600160a01b0386169063588d464890604401602060405180830381865afa15801561399f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139c39190614fe0565b9050610a96565b6002546000906001600160a01b03163b15158015613a515750600254604051632e4aba1f60e21b81526001600160a01b0385811660048301529091169063b92ae87c90602401602060405180830381865afa158015613a2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a5191906153a9565b15613af55760025460405163403647cb60e01b81526001600160a01b0385811660048301528415156024830152600092169063403647cb90604401602060405180830381865afa158015613aa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613acd91906153c6565b9050620f4240613ae363ffffffff831687615260565b613aed9190615277565b915050610fb7565b610a96606485615277565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691613b6491906153e3565b6000604051808303816000865af19150503d8060008114613ba1576040519150601f19603f3d011682016040523d82523d6000602084013e613ba6565b606091505b5091509150818015613bd0575080511580613bd0575080806020019051810190613bd091906153a9565b613c025760405162461bcd60e51b81526020600482015260036024820152622a232360e91b6044820152606401610af4565b505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691613c6691906153e3565b6000604051808303816000865af19150503d8060008114613ca3576040519150601f19603f3d011682016040523d82523d6000602084013e613ca8565b606091505b5091509150818015613cd2575080511580613cd2575080806020019051810190613cd291906153a9565b613d035760405162461bcd60e51b81526020600482015260026024820152612a2360f11b6044820152606401610af4565b5050505050565b60008060148363ffffffff161115613d3d5760405163e35f129760e01b815263ffffffff84166004820152602401610af4565b8591505b600082118015613dbe575060405163f6b1d5b960e01b815287156004820152602481018690526001600160a01b038b169063f6b1d5b990604401602060405180830381865afa158015613d98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dbc91906153a9565b155b8015613dd557508263ffffffff168463ffffffff16105b15614093576040516269486760e81b8152871560048201526024810186905260448101839052600090819081906001600160a01b038e16906369486700906064016060604051808303816000875af1158015613e35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e5991906153ff565b925092509250818511613f6757613e718c8e87613c0a565b60405163633ab49b60e01b815263ffffffff841660048201528a1560248201526001600160a01b038c81166044830152606482018790528215156084830152600091908f169063633ab49b9060a4016020604051808303816000875af1158015613edf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f039190615226565b9050613f128e8e8d89856141b0565b7f300f06e7b7030626edac9403f475fd6becc56ed53ac3ecb1d79243bfd207119b8e858d8f858e8c89604051613f4f989796959493929190615437565b60405180910390a16000879550955050505050614096565b81600003613f8257613f7887615033565b9650505050613d41565b613f8c8286615396565b9450613f998c8e84613c0a565b60405163633ab49b60e01b815263ffffffff841660048201528a1560248201526001600160a01b038c81166044830152606482018490528215156084830152600091908f169063633ab49b9060a4016020604051808303816000875af1158015614007573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061402b9190615226565b905061403a8e8e8d86856141b0565b7f300f06e7b7030626edac9403f475fd6becc56ed53ac3ecb1d79243bfd207119b8e858d8f858e8989604051614077989796959493929190615437565b60405180910390a161408888615033565b975050505050613d41565b50825b9850989650505050505050565b6000821561412c57604051630238bd6560e11b81526001600160a01b03838116600483015260248201869052604482018790528716906304717aca906064016020604051808303816000875af1158015614101573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061412591906153c6565b90506109d7565b604051632f496e7160e21b81526001600160a01b038381166004830152602482018690526044820187905287169063bd25b9c4906064016020604051808303816000875af1158015614182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141a691906153c6565b9695505050505050565b6002546001600160a01b03163b1515801561423d5750600260009054906101000a90046001600160a01b03166001600160a01b0316635472e1236040518163ffffffff1660e01b8152600401602060405180830381865afa158015614219573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061423d91906153a9565b80156142495750600082115b15613d035760025460405163ece9126360e01b81526001600160a01b03878116600483015286811660248301528515156044830152336064830152838116608483015260a482018590529091169063ece912639060c401600060405180830381600087803b1580156142ba57600080fd5b505af11580156142ce573d6000803e3d6000fd5b505050505050505050565b6040518061010001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600063ffffffff168152602001600063ffffffff1681526020016000151581525090565b634e487b7160e01b600052600160045260246000fd5b60006020828403121561435d57600080fd5b81356001600160e01b031981168114610fb757600080fd5b6001600160a01b038116811461289757600080fd5b801515811461289757600080fd5b63ffffffff8116811461289757600080fd5b600080600080600060a086880312156143c257600080fd5b85356143cd81614375565b945060208601356143dd81614375565b935060408601356143ed8161438a565b925060608601359150608086013561440481614398565b809150509295509295909350565b6020808252825182820181905260009190848201906040850190845b818110156144715761445e83855180516001600160a01b0316825260208082015190830152604090810151910152565b928401926060929092019160010161442e565b50909695505050505050565b6000806000806080858703121561449357600080fd5b843561449e81614375565b935060208501356144ae81614375565b925060408501356144be8161438a565b915060608501356144ce81614398565b939692955090935050565b81516001600160a01b0316815260208083015190820152604080830151908201526060810161093b565b6000806040838503121561451657600080fd5b823561452181614398565b9150602083013561453181614398565b809150509250929050565b60006020828403121561454e57600080fd5b5035919050565b6000806000806080858703121561456b57600080fd5b843561457681614375565b9350602085013561458681614375565b925060408501356144be81614398565b600080604083850312156145a957600080fd5b82359150602083013561453181614375565b600080604083850312156145ce57600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b81811015614471578351835292840192918401916001016145f9565b6000806040838503121561462857600080fd5b823561463381614375565b9150602083013561453181614375565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171561467b5761467b614643565b60405290565b604051601f8201601f191681016001600160401b03811182821017156146a9576146a9614643565b604052919050565b60006001600160401b038211156146ca576146ca614643565b5060051b60200190565b600082601f8301126146e557600080fd5b813560206146fa6146f5836146b1565b614681565b8083825260208201915060208460051b87010193508684111561471c57600080fd5b602086015b8481101561474157803561473481614375565b8352918301918301614721565b509695505050505050565b600082601f83011261475d57600080fd5b8135602061476d6146f5836146b1565b8083825260208201915060208460051b87010193508684111561478f57600080fd5b602086015b848110156147415780356147a781614398565b8352918301918301614794565b600080600080608085870312156147ca57600080fd5b84356001600160401b03808211156147e157600080fd5b6147ed888389016146d4565b955060209150818701358181111561480457600080fd5b61481089828a016146d4565b95505060408701358181111561482557600080fd5b8701601f8101891361483657600080fd5b80356148446146f5826146b1565b81815260059190911b8201840190848101908b83111561486357600080fd5b928501925b8284101561488a57833561487b8161438a565b82529285019290850190614868565b965050505060608701359150808211156148a357600080fd5b506148b08782880161474c565b91505092959194509250565b60005b838110156148d75781810151838201526020016148bf565b50506000910152565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561494d57878503603f190184528151805180875261492e818989018a85016148bc565b601f01601f191695909501860194509285019290850190600101614907565b5092979650505050505050565b600080600080600080600060e0888a03121561497557600080fd5b873561498081614375565b9650602088013561499081614375565b9550604088013594506060880135935060808801356149ae8161438a565b925060a08801356149be81614398565b915060c08801356149ce81614375565b8091505092959891949750929550565b600060208083850312156149f157600080fd5b82356001600160401b03811115614a0757600080fd5b8301601f81018513614a1857600080fd5b8035614a266146f5826146b1565b81815260059190911b82018301908381019087831115614a4557600080fd5b928401925b82841015614a6357833582529284019290840190614a4a565b979650505050505050565b60008060008060008060c08789031215614a8757600080fd5b8635614a9281614375565b95506020870135614aa281614375565b94506040870135614ab28161438a565b9350606087013592506080870135614ac981614398565b915060a0870135614ad981614398565b809150509295509295509295565b60008060008060808587031215614afd57600080fd5b8435614b0881614375565b93506020850135614b188161438a565b92506040850135614b2881614398565b915060608501356144ce81614375565b600060208284031215614b4a57600080fd5b8135610fb781614375565b60008060008060808587031215614b6b57600080fd5b8435614b7681614375565b93506020850135614b8681614375565b92506040850135915060608501356144ce8161438a565b60008060008060008060c08789031215614bb657600080fd5b8635614bc181614375565b95506020870135614bd181614375565b9450604087013593506060870135614be88161438a565b92506080870135614bf881614398565b915060a0870135614ad981614375565b600080600080600060a08688031215614c2057600080fd5b8535614c2b81614375565b94506020860135614c3b81614375565b93506040860135614c4b8161438a565b92506060860135614c5b81614398565b9150608086013561440481614398565b6020808252825182820181905260009190848201906040850190845b8181101561447157835163ffffffff1683529284019291840191600101614c87565b602080825282518282018190526000919060409081850190868401855b82811015614cf857815180516001600160a01b0390811686529087015116868501529284019290850190600101614cc6565b5091979650505050505050565b600080600060608486031215614d1a57600080fd5b8335614d2581614375565b92506020840135614d3581614375565b929592945050506040919091013590565b600080600060608486031215614d5b57600080fd5b8335614d6681614375565b92506020840135614d7681614375565b91506040840135614d8681614375565b809150509250925092565b600080600080600060a08688031215614da957600080fd5b8535614db481614375565b9450602086013593506040860135614dcb8161438a565b92506060860135614ddb81614398565b9150608086013561440481614375565b600060608284031215614dfd57600080fd5b604051606081018181106001600160401b0382111715614e1f57614e1f614643565b80604052508091508251614e3281614375565b8082525060208301516020820152604083015160408201525092915050565b60006020808385031215614e6457600080fd5b82516001600160401b03811115614e7a57600080fd5b8301601f81018513614e8b57600080fd5b8051614e996146f5826146b1565b808282526020820191506060602060608502860101935088841115614ebd57600080fd5b6020850194505b83851015614ee557614ed68986614deb565b83529384019391850191614ec4565b50979650505050505050565b600060608284031215614f0357600080fd5b610fb78383614deb565b60006020808385031215614f2057600080fd5b82516001600160401b03811115614f3657600080fd5b8301601f81018513614f4757600080fd5b8051614f556146f5826146b1565b81815260069190911b82018301908381019087831115614f7457600080fd5b928401925b82841015614a635760408489031215614f925760008081fd5b614f9a614659565b8451614fa581614375565b815284860151614fb481614375565b8187015282526040939093019290840190614f79565b634e487b7160e01b600052603260045260246000fd5b600060208284031215614ff257600080fd5b5051919050565b6000806040838503121561500c57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b600063ffffffff80831681810361504c5761504c61501d565b6001019392505050565b6000602080838503121561506957600080fd5b82516001600160401b038082111561508057600080fd5b8185019150601f86601f84011261509657600080fd5b82516150a46146f5826146b1565b81815260059190911b840185019085810190898311156150c357600080fd5b8686015b8381101561514c578051868111156150df5760008081fd5b8701603f81018c136150f15760008081fd5b8881015160408882111561510757615107614643565b615118828901601f19168c01614681565b8281528e8284860101111561512d5760008081fd5b61513c838d83018487016148bc565b86525050509187019187016150c7565b509998505050505050505050565b6001600160a01b03978816815263ffffffff9690961660208701529390951660408501529015156060840152608083015260a082019290925260c081019190915260e00190565b600060208083850312156151b457600080fd5b82516001600160401b038111156151ca57600080fd5b8301601f810185136151db57600080fd5b80516151e96146f5826146b1565b81815260059190911b8201830190838101908783111561520857600080fd5b928401925b82841015614a635783518252928401929084019061520d565b60006020828403121561523857600080fd5b8151610fb781614375565b63ffffffff818116838216019080821115612b6257612b6261501d565b808202811582820484141761093b5761093b61501d565b60008261529457634e487b7160e01b600052601260045260246000fd5b500490565b600060208083850312156152ac57600080fd5b82516001600160401b038111156152c257600080fd5b8301601f810185136152d357600080fd5b80516152e16146f5826146b1565b81815260059190911b8201830190838101908783111561530057600080fd5b928401925b82841015614a6357835161531881614398565b82529284019290840190615305565b60006020828403121561533957600080fd5b815160ff81168114610fb757600080fd5b63ffffffff828116828216039080821115612b6257612b6261501d565b6000806040838503121561537a57600080fd5b825161538581614375565b602084015190925061453181614375565b8181038181111561093b5761093b61501d565b6000602082840312156153bb57600080fd5b8151610fb78161438a565b6000602082840312156153d857600080fd5b8151610fb781614398565b600082516153f58184602087016148bc565b9190910192915050565b60008060006060848603121561541457600080fd5b835161541f81614398565b602085015160408601519194509250614d868161438a565b6001600160a01b03988916815263ffffffff979097166020880152941515604087015292861660608601529416608084015260a083019390935260c082019290925290151560e0820152610100019056fe97ad0c394f25bbd1393e568879c09de001fb1d6fd24cff6ae6c10e0f98873fe50783a9538328f521bae51128cb03e09233a2a8ec644b0e4f2e9f6246d7014fc575e5bf8b7de9fd9f24c97951733c6410a040b7a07b543096cb36c6dda365aa8ba26469706673582212202962d1607e69abef126eac6c084f939ef7fa86178f1b62ae67536f60758ae2d764736f6c63430008180033

Deployed Bytecode

0x60806040526004361061026b5760003560e01c80637640379e11610144578063b5acfa62116100b6578063d547741f1161007a578063d547741f14610864578063dc85cde714610884578063e6a4390514610897578063e794b1c1146108b7578063f2364e91146108ca578063f46901ed146108ea57600080fd5b8063b5acfa62146107b1578063b92bf451146107d1578063b98ad392146107e4578063c0c53b8b14610804578063c1a3ddb81461082457600080fd5b80638a645e45116101085780638a645e45146106ef5780638f6440511461070f57806391d148541461073c57806399c6d42a1461075c578063a217fddf1461077c578063ad5c46481461079157600080fd5b80637640379e146106425780637e069db01461066257806383e185d2146106825780638572b584146106a257806389556190146106cf57600080fd5b80633213f797116101dd57806341fbece9116101a157806341fbece91461053b57806351d1f2f61461055b57806357cc4c0d1461056e5780636036edf2146105ca5780636752cfaa146105ea5780636e300b401461062257600080fd5b80633213f7971461046d578063349d1b5f1461049a57806336568abe146104db5780633d177c79146104fb5780633de07eea1461051b57600080fd5b8063248a9ca31161022f578063248a9ca31461036c578063288be22b146103ab5780632f2ff15d146103cb5780632f9c754d146103eb57806330372dc414610418578063303f13851461044d57600080fd5b806301ffc9a714610291578063062496fe146102c6578063187f8b05146102f357806319a86577146103205780631a83eba01461034c57600080fd5b3661028c576004546001600160a01b0316331461028a5761028a614335565b005b600080fd5b34801561029d57600080fd5b506102b16102ac36600461434b565b61090a565b60405190151581526020015b60405180910390f35b3480156102d257600080fd5b506102e66102e13660046143aa565b610941565b6040516102bd9190614412565b3480156102ff57600080fd5b5061031361030e36600461447d565b6109e0565b6040516102bd91906144d9565b34801561032c57600080fd5b50610337620f424081565b60405163ffffffff90911681526020016102bd565b34801561035857600080fd5b506102b1610367366004614503565b610a9e565b34801561037857600080fd5b5061039d61038736600461453c565b6000908152600160208190526040909120015490565b6040519081526020016102bd565b3480156103b757600080fd5b506102b16103c6366004614555565b610b41565b3480156103d757600080fd5b5061028a6103e6366004614596565b610b8c565b3480156103f757600080fd5b5061040b6104063660046145bb565b610bb8565b6040516102bd91906145dd565b34801561042457600080fd5b50610438610433366004614615565b610da1565b604080519283526020830191909152016102bd565b34801561045957600080fd5b5061040b6104683660046147b4565b610e1f565b34801561047957600080fd5b5061048d6104883660046145bb565b610f3e565b6040516102bd91906148e0565b3480156104a657600080fd5b506104ba6104b536600461495a565b610fbe565b60408051938452602084019290925263ffffffff16908201526060016102bd565b3480156104e757600080fd5b5061028a6104f6366004614596565b61118b565b34801561050757600080fd5b5061039d610516366004614615565b6111c3565b34801561052757600080fd5b5061040b6105363660046149de565b611234565b34801561054757600080fd5b506102e6610556366004614a6e565b611419565b6104ba610569366004614ae7565b6114bf565b34801561057a57600080fd5b506105ad610589366004614b38565b60056020526000908152604090205463ffffffff8082169164010000000090041682565b6040805163ffffffff9384168152929091166020830152016102bd565b3480156105d657600080fd5b5061040b6105e536600461447d565b611559565b3480156105f657600080fd5b5061060a61060536600461453c565b6115e4565b6040516001600160a01b0390911681526020016102bd565b34801561062e57600080fd5b5061048d61063d3660046149de565b611652565b34801561064e57600080fd5b5061039d61065d366004614b55565b6116c8565b34801561066e57600080fd5b506104ba61067d366004614b9d565b61178a565b34801561068e57600080fd5b5061040b61069d366004614c08565b6119bc565b3480156106ae57600080fd5b506106c26106bd3660046143aa565b611a4f565b6040516102bd9190614c6b565b3480156106db57600080fd5b506104ba6106ea36600461495a565b611ae1565b3480156106fb57600080fd5b5060035461060a906001600160a01b031681565b34801561071b57600080fd5b5061072f61072a3660046149de565b611c7e565b6040516102bd9190614ca9565b34801561074857600080fd5b506102b1610757366004614596565b611cf4565b34801561076857600080fd5b5061039d61077736600461447d565b611d1f565b34801561078857600080fd5b5061039d600081565b34801561079d57600080fd5b5060045461060a906001600160a01b031681565b3480156107bd57600080fd5b5061060a6107cc366004614d05565b611ed4565b6104ba6107df366004614ae7565b612139565b3480156107f057600080fd5b506104ba6107ff366004614b9d565b6121c3565b34801561081057600080fd5b5061028a61081f366004614d46565b6123bd565b34801561083057600080fd5b5061084461083f366004614b38565b612522565b604080516001600160a01b039384168152929091166020830152016102bd565b34801561087057600080fd5b5061028a61087f366004614596565b61259c565b6104ba610892366004614d91565b6125c2565b3480156108a357600080fd5b5061060a6108b2366004614615565b61265e565b6104ba6108c5366004614d91565b6126d5565b3480156108d657600080fd5b5061072f6108e53660046145bb565b612760565b3480156108f657600080fd5b506102b1610905366004614b38565b6127d9565b60006001600160e01b03198216637965db0b60e01b148061093b57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6060600061094f878761265e565b60405163f3eb41a960e01b815286151560048201526024810186905263ffffffff851660448201529091506001600160a01b0382169063f3eb41a990606401600060405180830381865afa1580156109ab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109d39190810190614e51565b9150505b95945050505050565b610a0d604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b6000610a19868661265e565b604051635d9e5cd360e11b8152851515600482015263ffffffff851660248201529091506001600160a01b0382169063bb3cb9a690604401606060405180830381865afa158015610a6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a929190614ef1565b9150505b949350505050565b6000610ab86000805160206154c983398151915233611cf4565b610afd576000805160206154c9833981519152335b604051638bc10a7160e01b815260048101929092526001600160a01b031660248201526044015b60405180910390fd5b506004805467ffffffffffffffff60a01b1916600160a01b63ffffffff9485160263ffffffff60c01b191617600160c01b9290931691909102919091179055600190565b6000610b5b6000805160206154c983398151915233611cf4565b610b74576000805160206154c983398151915233610acd565b610b8085858585612817565b50600195945050505050565b60008281526001602081905260409091200154610ba88161288d565b610bb2838361289a565b50505050565b60035460405163f2364e9160e01b815260048101849052602481018390526060916000916001600160a01b039091169063f2364e9190604401600060405180830381865afa158015610c0e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c369190810190614f0d565b905080516001600160401b03811115610c5157610c51614643565b604051908082528060200260200182016040528015610c7a578160200160208202803683370190505b50915060005b8151811015610d9957306001600160a01b0316633d177c79838381518110610caa57610caa614fca565b602002602001015160000151848481518110610cc857610cc8614fca565b6020026020010151602001516040518363ffffffff1660e01b8152600401610d069291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa925050508015610d3f575060408051601f3d908101601f19168201909252610d3c91810190614fe0565b60015b610d6a57600080848381518110610d5857610d58614fca565b60200260200101818152505050610d91565b600081905080858481518110610d8257610d82614fca565b60200260200101818152505050505b600101610c80565b505092915050565b6000806000610db0858561265e565b9050806001600160a01b031663b8b238316040518163ffffffff1660e01b81526004016040805180830381865afa158015610def573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e139190614ff9565b92509250509250929050565b606081516001600160401b03811115610e3a57610e3a614643565b604051908082528060200260200182016040528015610e63578160200160208202803683370190505b50905060005b82518163ffffffff161015610f3557610f00868263ffffffff1681518110610e9357610e93614fca565b6020026020010151868363ffffffff1681518110610eb357610eb3614fca565b6020026020010151868463ffffffff1681518110610ed357610ed3614fca565b6020026020010151868563ffffffff1681518110610ef357610ef3614fca565b6020026020010151611d1f565b828263ffffffff1681518110610f1857610f18614fca565b602090810291909101015280610f2d81615033565b915050610e69565b50949350505050565b600354604051633213f79760e01b815260048101849052602481018390526060916001600160a01b031690633213f79790604401600060405180830381865afa158015610f8f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fb79190810190615056565b9392505050565b6000806000610fcb612913565b610fd36142d9565b610fe28b8b8b8b60008c61293d565b6001600160a01b031660208301819052908252611000906000612afb565b63ffffffff1660a08201528051602082015190985061102590898d8860008e8c612b69565b6060840181905260408401829052918352602083015160a084015161104f9391928d92909161304e565b608083015260208201518251919a50611070918d918d918d60008d8c613209565b63ffffffff1660c082018190521561116457806080015189101561112557602081015160405163d0c48a8360e01b8152600481018b90526001600160a01b039091169063d0c48a8390602401600060405180830381600087803b1580156110d657600080fd5b505af11580156110ea573d6000803e3d6000fd5b505050602080830151604080516001600160a01b0390921682529181018c905260008051602061548983398151915292500160405180910390a15b6000805160206154a983398151915281602001518260c001518760008d8d876000015160405161115b979695949392919061515a565b60405180910390a15b805160c090910151899450909250905061117e6001600055565b9750975097945050505050565b6001600160a01b03811633146111b45760405163334bd91960e11b815260040160405180910390fd5b6111be8282613261565b505050565b6000806111d0848461265e565b9050806001600160a01b03166337632e3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611210573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a969190614fe0565b600354604051638f64405160e01b81526060916000916001600160a01b0390911690638f6440519061126a9086906004016145dd565b600060405180830381865afa158015611287573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112af9190810190614f0d565b905080516001600160401b038111156112ca576112ca614643565b6040519080825280602002602001820160405280156112f3578160200160208202803683370190505b50915060005b815181101561141257306001600160a01b0316633d177c7983838151811061132357611323614fca565b60200260200101516000015184848151811061134157611341614fca565b6020026020010151602001516040518363ffffffff1660e01b815260040161137f9291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa9250505080156113b8575060408051601f3d908101601f191682019092526113b591810190614fe0565b60015b6113e3576000808483815181106113d1576113d1614fca565b6020026020010181815250505061140a565b6000819050808584815181106113fb576113fb614fca565b60200260200101818152505050505b6001016112f9565b5050919050565b60606000611427888861265e565b6040516354c12a7160e01b815287151560048201526024810187905263ffffffff8087166044830152851660648201529091506001600160a01b038216906354c12a7190608401600060405180830381865afa15801561148b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114b39190810190614e51565b98975050505050505050565b6000806000600460009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561151457600080fd5b505af1158015611528573d6000803e3d6000fd5b505060045461154993506001600160a01b03169150899050348989896121c3565b9250925092509450945094915050565b60606000611567868661265e565b604051633eb9f3f760e21b8152851515600482015263ffffffff851660248201529091506001600160a01b0382169063fae7cfdc90604401600060405180830381865afa1580156115bc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a9291908101906151a1565b60035460405163e0ff5b8b60e01b8152600481018390526000916001600160a01b03169063e0ff5b8b90602401602060405180830381865afa15801561162e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093b9190615226565b6003546040516301b8c02d60e61b81526060916001600160a01b031690636e300b40906116839085906004016145dd565b600060405180830381865afa1580156116a0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261093b9190810190615056565b6000806116d5868661265e565b9050846001600160a01b0316866001600160a01b0316036116f95783915050610a96565b6001600160a01b038116611711576000915050610a96565b604051630b11a8c960e31b81526004810185905283151560248201526001600160a01b0382169063588d464890604401602060405180830381865afa15801561175e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117829190614fe0565b915050610a96565b6000806000611797612913565b61179f6142d9565b6117af8a8a60008b60018c61293d565b6001600160a01b0316602083018190529082526117cd906001612afb565b63ffffffff1660a08201526117e28a8a6111c3565b60808201528051602082015160a0830151919950611836918a908c908990600190612710906118119082615243565b63ffffffff1688608001516118269190615260565b6118309190615277565b8c612b69565b6060840181905260408401829052918352602083015160a084015161185e93919291906132ce565b604082018190526020820151825161187f928d928d92909160018d8c613209565b63ffffffff1660c08201819052156119905780608001518160400151111561194d5780602001516001600160a01b031663d0c48a8382604001516040518263ffffffff1660e01b81526004016118d791815260200190565b600060405180830381600087803b1580156118f157600080fd5b505af1158015611905573d6000803e3d6000fd5b50505050600080516020615489833981519152816020015182604001516040516119449291906001600160a01b03929092168252602082015260400190565b60405180910390a15b6000805160206154a983398151915281602001518260c0015187600185604001518d8760000151604051611987979695949392919061515a565b60405180910390a15b806040015181600001518260c00151935093509350506119b06001600055565b96509650969350505050565b606060006119ca878761265e565b604051637a33b06160e11b8152861515600482015263ffffffff8087166024830152851660448201529091506001600160a01b0382169063f46760c290606401600060405180830381865afa158015611a27573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109d391908101906151a1565b60606000611a5d878761265e565b604051633f20424160e21b815286151560048201526024810186905263ffffffff851660448201529091506001600160a01b0382169063fc81090490606401600060405180830381865afa158015611ab9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109d39190810190615299565b6000806000611aee612913565b611af66142d9565b611b058b8b8b8b60018c61293d565b6001600160a01b031660208301819052908252611b23906001612afb565b63ffffffff1660a082015280516020820151909850611b4890898c8860018e8c612b69565b6060840181905260408401829052918352602083015160a0840151611b729391928d9290916134ca565b608083015260208201518251919a50611b93918d918d918d60018d8c613209565b63ffffffff1660c0820181905215611164578060800151891115611c4857602081015160405163d0c48a8360e01b8152600481018b90526001600160a01b039091169063d0c48a8390602401600060405180830381600087803b158015611bf957600080fd5b505af1158015611c0d573d6000803e3d6000fd5b505050602080830151604080516001600160a01b0390921682529181018c905260008051602061548983398151915292500160405180910390a15b6000805160206154a983398151915281602001518260c001518760018d8d876000015160405161115b979695949392919061515a565b600354604051638f64405160e01b81526060916001600160a01b031690638f64405190611caf9085906004016145dd565b600060405180830381865afa158015611ccc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261093b9190810190614f0d565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6000611d29612913565b60035460405163e6a4390560e01b81526001600160a01b0387811660048301528681166024830152600092169063e6a4390590604401602060405180830381865afa158015611d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da09190615226565b90506001600160a01b038116611de45760405163bfe877e160e01b81526001600160a01b038088166004830152808716602483015282166044820152606401610af4565b60405163764abdc160e11b8152841515600482015263ffffffff841660248201523360448201526001600160a01b0382169063ec957b82906064016020604051808303816000875af1925050508015611e5a575060408051601f3d908101601f19168201909252611e5791810190614fe0565b60015b611e68576000915050611eca565b604080516001600160a01b038416815263ffffffff861660208201528615158183015260608101839052905133917f6455b26713a0e0ba431d88c86da77ddfca232ffe0a76eeb89cc7ff18d338e009919081900360800190a29150611eca9050565b610a966001600055565b60035460405163228b199d60e11b81526001600160a01b03858116600483015284811660248301526000928392911690634516333a906044016020604051808303816000875af1158015611f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f509190615226565b60405163d0c48a8360e01b8152600481018590529091506001600160a01b0382169063d0c48a8390602401600060405180830381600087803b158015611f9557600080fd5b505af1158015611fa9573d6000803e3d6000fd5b505050506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120119190615327565b90506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612053573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120779190615327565b6004549091506120a1908890889063ffffffff600160a01b8204811691600160c01b900416612817565b50604080516001600160a01b038581168252898116602083015288168183015260ff84811660608301528316608082015290517f7bcab975bb0905a5c55a953d0c96d393a2f651e71517523687754cd56403fbc79181900360a00190a1604080516001600160a01b038516815260208101879052600080516020615489833981519152910160405180910390a1509095945050505050565b6000806000600460009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561218e57600080fd5b505af11580156121a2573d6000803e3d6000fd5b505060045461154993508a92506001600160a01b031690503489898961178a565b60008060006121d0612913565b6121d86142d9565b6121e88a8a60008b60008c61293d565b6001600160a01b031660208301819052908252612206906000612afb565b63ffffffff1660a082015261221b8a8a6111c3565b60808201528051602082015160a083015191995061224a918a908d90899060009061271090611811908261534a565b6060840181905260408401829052918352602083015160a08401516122729391929190613668565b6060820181905260208201518251612293928d928d92909160008d8c613209565b63ffffffff1660c082018190521561239d5780608001518160600151101561235a576020810151606082015160405163d0c48a8360e01b81526001600160a01b039092169163d0c48a83916122ee9160040190815260200190565b600060405180830381600087803b15801561230857600080fd5b505af115801561231c573d6000803e3d6000fd5b5050506020808301516060840151604080516001600160a01b0390931683529282015260008051602061548983398151915292500160405180910390a15b6000805160206154a983398151915281602001518260c0015187600085606001518d8760000151604051612394979695949392919061515a565b60405180910390a15b806060015181600001518260c00151935093509350506119b06001600055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03166000811580156124025750825b90506000826001600160401b0316600114801561241e5750303b155b90508115801561242c575080155b1561244a5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561247457845460ff60401b1916600160401b1785555b600380546001600160a01b03199081166001600160a01b038b81169190911790925560028054909116898316179055600480549188166001600160c01b031990921691909117601960a31b1763ffffffff60c01b1916601960c31b179055831561251857845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6003546040516318347bb760e31b81526001600160a01b038381166004830152600092839291169063c1a3ddb8906024016040805180830381865afa15801561256f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125939190615367565b91509150915091565b600082815260016020819052604090912001546125b88161288d565b610bb28383613261565b6000806000600460009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561261757600080fd5b505af115801561262b573d6000803e3d6000fd5b505060045461264d93508b92506001600160a01b0316905089348a8a8a611ae1565b925092509250955095509592505050565b60035460405163e6a4390560e01b81526001600160a01b0384811660048301528381166024830152600092169063e6a4390590604401602060405180830381865afa1580156126b1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb79190615226565b6000806000600460009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561272a57600080fd5b505af115801561273e573d6000803e3d6000fd5b505060045461264d93506001600160a01b031691508a905089348a8a8a610fbe565b60035460405163f2364e9160e01b815260048101849052602481018390526060916001600160a01b03169063f2364e9190604401600060405180830381865afa1580156127b1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fb79190810190614f0d565b60006127e58133611cf4565b6127f157600033610acd565b50600280546001600160a01b0319166001600160a01b0392909216919091179055600190565b600080612824868661265e565b60408051808201825263ffffffff808816825286811660208084019182526001600160a01b03909516600090815260059095529290932090518154925184166401000000000267ffffffffffffffff199093169316929092171790555060019050949350505050565b612897813361387a565b50565b60006128a68383611cf4565b61290b5760008381526001602081815260408084206001600160a01b0387168086529252808420805460ff19169093179092559051339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a450600161093b565b50600061093b565b60026000540361293657604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b60008084600003612961576040516310eb483f60e21b815260040160405180910390fd5b61296b888861265e565b90506001600160a01b0381166129af5760405163bfe877e160e01b81526001600160a01b03808a166004830152808916602483015282166044820152606401610af4565b60006129be82888888156138b7565b905060006129d08389600189156138b7565b90508082116129fc5760405163200772a360e11b81526004810183905260248101829052604401610af4565b6000612a098833886139ca565b9050612a158189615396565b94508615612a5b576004546001600160a01b038b8116911614612a3e57612a3e8a33308b613b00565b600254612a56908b906001600160a01b031683613c0a565b612a94565b6004546001600160a01b038c8116911614612a7c57612a7c8b33308b613b00565b600254612a94908c906001600160a01b031683613c0a565b7f6fc423e360a132634001b3add06785f7feff6a435202af430ff9547492b3a97a3388612ac1578c612ac3565b8b5b604080516001600160a01b039384168152929091166020830152810183905260600160405180910390a1505050965096945050505050565b604080518082018252600080825260209182018190526001600160a01b03851681526005825282812083518085019094525463ffffffff80821685526401000000009091041691830191909152908215612b575751905061093b565b60200151905061093b565b5092915050565b600080600088925060008a6001600160a01b031663dec5e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd59190614fe0565b604051630ccc4b0d60e31b8152600160048201529091506001600160a01b038c16906366625868906024016020604051808303816000875af1158015612c1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c439190614fe0565b604051630ccc4b0d60e31b8152600060048201529093506001600160a01b038c16906366625868906024016020604051808303816000875af1158015612c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cb19190614fe0565b915060008715612e31578115612cea578215801590612ccf57508287105b15612cdb57505061117e565b82600003612cea57505061117e565b600085118015612cf957508215155b8015612d055750868311155b8015612d1c57508563ffffffff168163ffffffff16105b15612dbf57829150612d348c8b8b8b8988878d613d0a565b909550905063ffffffff811615612db557604051630ccc4b0d60e31b8152600060048201526001600160a01b038d16906366625868906024016020604051808303816000875af1158015612d8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db09190614fe0565b612db8565b60005b9250612cea565b604051630ccc4b0d60e31b8152600160048201526001600160a01b038d16906366625868906024016020604051808303816000875af1158015612e06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e2a9190614fe0565b9350612fa3565b8115612e60578315801590612e4557508387115b15612e5157505061117e565b83600003612e6057505061117e565b600085118015612e6f57508315155b8015612e7b5750868410155b8015612e9257508563ffffffff168163ffffffff16105b15612f3557839150612eaa8c8b8b8b8989878d613d0a565b909550905063ffffffff811615612f2b57604051630ccc4b0d60e31b8152600160048201526001600160a01b038d16906366625868906024016020604051808303816000875af1158015612f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f269190614fe0565b612f2e565b60005b9350612e60565b604051630ccc4b0d60e31b8152600060048201526001600160a01b038d16906366625868906024016020604051808303816000875af1158015612f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa09190614fe0565b92505b811561303f5760405163d0c48a8360e01b8152600481018390526001600160a01b038d169063d0c48a8390602401600060405180830381600087803b158015612feb57600080fd5b505af1158015612fff573d6000803e3d6000fd5b505050506000805160206154898339815191528c836040516130369291906001600160a01b03929092168252602082015260400190565b60405180910390a15b50509750975097945050505050565b6000806000876001600160a01b031663dec5e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613091573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b59190614fe0565b9150841580156130c3575085155b1561311857811561310f576127106130db858261534a565b6130eb9063ffffffff1684615260565b6130f59190615277565b9050808711156131055786613107565b805b9250506131ff565b869250506131ff565b8415801561312557508515155b1561319f5781156131825761271061313d858261534a565b61314d9063ffffffff1684615260565b6131579190615277565b9050808711156131675786613169565b805b9050858111156131795780613107565b859250506131ff565b61271061318f858261534a565b61314d9063ffffffff1688615260565b84158015906131ac575085155b156131e15781156131c4576127106130db858261534a565b6127106131d1858261534a565b6130eb9063ffffffff1687615260565b818710156131ef5781613169565b5085858111156131795780613107565b9550959350505050565b600085156114b35760008361321e5782613220565b875b905061323985613230578a613232565b895b8289613c0a565b83156132545761324c88888888876140a3565b9150506114b3565b5098975050505050505050565b600061326d8383611cf4565b1561290b5760008381526001602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161093b565b6000806000866001600160a01b031663dec5e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613311573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133359190614fe0565b905084158015613343575085155b1561338457801561337f5761271061335b8582615243565b61336b9063ffffffff1683615260565b6133759190615277565b9250610a96915050565b6134c0565b8415801561339157508515155b156133ff5780156133e2576000818710156133ac57816133ae565b865b90506127106133bd8682615243565b6133cd9063ffffffff1683615260565b6133d79190615277565b9350610a9692505050565b6127106133ef8582615243565b61336b9063ffffffff1688615260565b841580159061340c575085155b15613463578015613459576127106134248582615243565b6134349063ffffffff1683615260565b61343e9190615277565b91508185101561344e5784613450565b815b92505050610a96565b8492505050610a96565b801561345957600081871015613479578161347b565b865b905061271061348a8682615243565b61349a9063ffffffff1683615260565b6134a49190615277565b9250828610156134b457856134b6565b825b9350505050610a96565b5050949350505050565b6000806000876001600160a01b031663dec5e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561350d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135319190614fe0565b91508415801561353f575085155b1561358157811561310f576127106135578582615243565b6135679063ffffffff1684615260565b6135719190615277565b9050808710156131055786613107565b8415801561358e57508515155b156135c35781156135a6576127106135578582615243565b6127106135b38582615243565b6135679063ffffffff1688615260565b84158015906135d0575085155b1561364a57811561362d576127106135e88582615243565b6135f89063ffffffff1684615260565b6136029190615277565b9050808710156136125786613614565b805b9050848110156136245780613107565b849250506131ff565b61271061363a8582615243565b6135f89063ffffffff1687615260565b818711156136585781613614565b5085848110156136245780613107565b6000806000866001600160a01b031663dec5e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156136ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136cf9190614fe0565b9050841580156136dd575085155b1561372857801561337f576127106136f5858261534a565b6137059063ffffffff1683615260565b61370f9190615277565b9150811561371d5781613450565b600192505050610a96565b8415801561373557508515155b156137905780156137865761271061374d858261534a565b61375d9063ffffffff1683615260565b6137679190615277565b915085821115613777578161370f565b859150811561371d5781613450565b8592505050610a96565b841580159061379d575085155b1561381a5780156137fd576000858211156137b857856137ba565b815b90506127106137c9868261534a565b6137d99063ffffffff1683615260565b6137e39190615277565b925082156137f157826134b6565b60019350505050610a96565b61271061380a858261534a565b6137059063ffffffff1687615260565b8015613786576000858211156138305785613832565b815b9050612710613841868261534a565b6138519063ffffffff1683615260565b61385b9190615277565b92508683111561386b57826137e3565b86925082156137f157826134b6565b6138848282611cf4565b6138b35760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610af4565b5050565b60006001600160a01b0385166138cf57506000610a96565b831561395257604051639c0e0bf160e01b8152600481018590526024810184905282151560448201526001600160a01b03861690639c0e0bf190606401602060405180830381865afa158015613929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061394d9190614fe0565b6139c3565b604051630b11a8c960e31b81526004810184905282151560248201526001600160a01b0386169063588d464890604401602060405180830381865afa15801561399f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139c39190614fe0565b9050610a96565b6002546000906001600160a01b03163b15158015613a515750600254604051632e4aba1f60e21b81526001600160a01b0385811660048301529091169063b92ae87c90602401602060405180830381865afa158015613a2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a5191906153a9565b15613af55760025460405163403647cb60e01b81526001600160a01b0385811660048301528415156024830152600092169063403647cb90604401602060405180830381865afa158015613aa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613acd91906153c6565b9050620f4240613ae363ffffffff831687615260565b613aed9190615277565b915050610fb7565b610a96606485615277565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691613b6491906153e3565b6000604051808303816000865af19150503d8060008114613ba1576040519150601f19603f3d011682016040523d82523d6000602084013e613ba6565b606091505b5091509150818015613bd0575080511580613bd0575080806020019051810190613bd091906153a9565b613c025760405162461bcd60e51b81526020600482015260036024820152622a232360e91b6044820152606401610af4565b505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691613c6691906153e3565b6000604051808303816000865af19150503d8060008114613ca3576040519150601f19603f3d011682016040523d82523d6000602084013e613ca8565b606091505b5091509150818015613cd2575080511580613cd2575080806020019051810190613cd291906153a9565b613d035760405162461bcd60e51b81526020600482015260026024820152612a2360f11b6044820152606401610af4565b5050505050565b60008060148363ffffffff161115613d3d5760405163e35f129760e01b815263ffffffff84166004820152602401610af4565b8591505b600082118015613dbe575060405163f6b1d5b960e01b815287156004820152602481018690526001600160a01b038b169063f6b1d5b990604401602060405180830381865afa158015613d98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dbc91906153a9565b155b8015613dd557508263ffffffff168463ffffffff16105b15614093576040516269486760e81b8152871560048201526024810186905260448101839052600090819081906001600160a01b038e16906369486700906064016060604051808303816000875af1158015613e35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e5991906153ff565b925092509250818511613f6757613e718c8e87613c0a565b60405163633ab49b60e01b815263ffffffff841660048201528a1560248201526001600160a01b038c81166044830152606482018790528215156084830152600091908f169063633ab49b9060a4016020604051808303816000875af1158015613edf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f039190615226565b9050613f128e8e8d89856141b0565b7f300f06e7b7030626edac9403f475fd6becc56ed53ac3ecb1d79243bfd207119b8e858d8f858e8c89604051613f4f989796959493929190615437565b60405180910390a16000879550955050505050614096565b81600003613f8257613f7887615033565b9650505050613d41565b613f8c8286615396565b9450613f998c8e84613c0a565b60405163633ab49b60e01b815263ffffffff841660048201528a1560248201526001600160a01b038c81166044830152606482018490528215156084830152600091908f169063633ab49b9060a4016020604051808303816000875af1158015614007573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061402b9190615226565b905061403a8e8e8d86856141b0565b7f300f06e7b7030626edac9403f475fd6becc56ed53ac3ecb1d79243bfd207119b8e858d8f858e8989604051614077989796959493929190615437565b60405180910390a161408888615033565b975050505050613d41565b50825b9850989650505050505050565b6000821561412c57604051630238bd6560e11b81526001600160a01b03838116600483015260248201869052604482018790528716906304717aca906064016020604051808303816000875af1158015614101573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061412591906153c6565b90506109d7565b604051632f496e7160e21b81526001600160a01b038381166004830152602482018690526044820187905287169063bd25b9c4906064016020604051808303816000875af1158015614182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141a691906153c6565b9695505050505050565b6002546001600160a01b03163b1515801561423d5750600260009054906101000a90046001600160a01b03166001600160a01b0316635472e1236040518163ffffffff1660e01b8152600401602060405180830381865afa158015614219573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061423d91906153a9565b80156142495750600082115b15613d035760025460405163ece9126360e01b81526001600160a01b03878116600483015286811660248301528515156044830152336064830152838116608483015260a482018590529091169063ece912639060c401600060405180830381600087803b1580156142ba57600080fd5b505af11580156142ce573d6000803e3d6000fd5b505050505050505050565b6040518061010001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600063ffffffff168152602001600063ffffffff1681526020016000151581525090565b634e487b7160e01b600052600160045260246000fd5b60006020828403121561435d57600080fd5b81356001600160e01b031981168114610fb757600080fd5b6001600160a01b038116811461289757600080fd5b801515811461289757600080fd5b63ffffffff8116811461289757600080fd5b600080600080600060a086880312156143c257600080fd5b85356143cd81614375565b945060208601356143dd81614375565b935060408601356143ed8161438a565b925060608601359150608086013561440481614398565b809150509295509295909350565b6020808252825182820181905260009190848201906040850190845b818110156144715761445e83855180516001600160a01b0316825260208082015190830152604090810151910152565b928401926060929092019160010161442e565b50909695505050505050565b6000806000806080858703121561449357600080fd5b843561449e81614375565b935060208501356144ae81614375565b925060408501356144be8161438a565b915060608501356144ce81614398565b939692955090935050565b81516001600160a01b0316815260208083015190820152604080830151908201526060810161093b565b6000806040838503121561451657600080fd5b823561452181614398565b9150602083013561453181614398565b809150509250929050565b60006020828403121561454e57600080fd5b5035919050565b6000806000806080858703121561456b57600080fd5b843561457681614375565b9350602085013561458681614375565b925060408501356144be81614398565b600080604083850312156145a957600080fd5b82359150602083013561453181614375565b600080604083850312156145ce57600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b81811015614471578351835292840192918401916001016145f9565b6000806040838503121561462857600080fd5b823561463381614375565b9150602083013561453181614375565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171561467b5761467b614643565b60405290565b604051601f8201601f191681016001600160401b03811182821017156146a9576146a9614643565b604052919050565b60006001600160401b038211156146ca576146ca614643565b5060051b60200190565b600082601f8301126146e557600080fd5b813560206146fa6146f5836146b1565b614681565b8083825260208201915060208460051b87010193508684111561471c57600080fd5b602086015b8481101561474157803561473481614375565b8352918301918301614721565b509695505050505050565b600082601f83011261475d57600080fd5b8135602061476d6146f5836146b1565b8083825260208201915060208460051b87010193508684111561478f57600080fd5b602086015b848110156147415780356147a781614398565b8352918301918301614794565b600080600080608085870312156147ca57600080fd5b84356001600160401b03808211156147e157600080fd5b6147ed888389016146d4565b955060209150818701358181111561480457600080fd5b61481089828a016146d4565b95505060408701358181111561482557600080fd5b8701601f8101891361483657600080fd5b80356148446146f5826146b1565b81815260059190911b8201840190848101908b83111561486357600080fd5b928501925b8284101561488a57833561487b8161438a565b82529285019290850190614868565b965050505060608701359150808211156148a357600080fd5b506148b08782880161474c565b91505092959194509250565b60005b838110156148d75781810151838201526020016148bf565b50506000910152565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561494d57878503603f190184528151805180875261492e818989018a85016148bc565b601f01601f191695909501860194509285019290850190600101614907565b5092979650505050505050565b600080600080600080600060e0888a03121561497557600080fd5b873561498081614375565b9650602088013561499081614375565b9550604088013594506060880135935060808801356149ae8161438a565b925060a08801356149be81614398565b915060c08801356149ce81614375565b8091505092959891949750929550565b600060208083850312156149f157600080fd5b82356001600160401b03811115614a0757600080fd5b8301601f81018513614a1857600080fd5b8035614a266146f5826146b1565b81815260059190911b82018301908381019087831115614a4557600080fd5b928401925b82841015614a6357833582529284019290840190614a4a565b979650505050505050565b60008060008060008060c08789031215614a8757600080fd5b8635614a9281614375565b95506020870135614aa281614375565b94506040870135614ab28161438a565b9350606087013592506080870135614ac981614398565b915060a0870135614ad981614398565b809150509295509295509295565b60008060008060808587031215614afd57600080fd5b8435614b0881614375565b93506020850135614b188161438a565b92506040850135614b2881614398565b915060608501356144ce81614375565b600060208284031215614b4a57600080fd5b8135610fb781614375565b60008060008060808587031215614b6b57600080fd5b8435614b7681614375565b93506020850135614b8681614375565b92506040850135915060608501356144ce8161438a565b60008060008060008060c08789031215614bb657600080fd5b8635614bc181614375565b95506020870135614bd181614375565b9450604087013593506060870135614be88161438a565b92506080870135614bf881614398565b915060a0870135614ad981614375565b600080600080600060a08688031215614c2057600080fd5b8535614c2b81614375565b94506020860135614c3b81614375565b93506040860135614c4b8161438a565b92506060860135614c5b81614398565b9150608086013561440481614398565b6020808252825182820181905260009190848201906040850190845b8181101561447157835163ffffffff1683529284019291840191600101614c87565b602080825282518282018190526000919060409081850190868401855b82811015614cf857815180516001600160a01b0390811686529087015116868501529284019290850190600101614cc6565b5091979650505050505050565b600080600060608486031215614d1a57600080fd5b8335614d2581614375565b92506020840135614d3581614375565b929592945050506040919091013590565b600080600060608486031215614d5b57600080fd5b8335614d6681614375565b92506020840135614d7681614375565b91506040840135614d8681614375565b809150509250925092565b600080600080600060a08688031215614da957600080fd5b8535614db481614375565b9450602086013593506040860135614dcb8161438a565b92506060860135614ddb81614398565b9150608086013561440481614375565b600060608284031215614dfd57600080fd5b604051606081018181106001600160401b0382111715614e1f57614e1f614643565b80604052508091508251614e3281614375565b8082525060208301516020820152604083015160408201525092915050565b60006020808385031215614e6457600080fd5b82516001600160401b03811115614e7a57600080fd5b8301601f81018513614e8b57600080fd5b8051614e996146f5826146b1565b808282526020820191506060602060608502860101935088841115614ebd57600080fd5b6020850194505b83851015614ee557614ed68986614deb565b83529384019391850191614ec4565b50979650505050505050565b600060608284031215614f0357600080fd5b610fb78383614deb565b60006020808385031215614f2057600080fd5b82516001600160401b03811115614f3657600080fd5b8301601f81018513614f4757600080fd5b8051614f556146f5826146b1565b81815260069190911b82018301908381019087831115614f7457600080fd5b928401925b82841015614a635760408489031215614f925760008081fd5b614f9a614659565b8451614fa581614375565b815284860151614fb481614375565b8187015282526040939093019290840190614f79565b634e487b7160e01b600052603260045260246000fd5b600060208284031215614ff257600080fd5b5051919050565b6000806040838503121561500c57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b600063ffffffff80831681810361504c5761504c61501d565b6001019392505050565b6000602080838503121561506957600080fd5b82516001600160401b038082111561508057600080fd5b8185019150601f86601f84011261509657600080fd5b82516150a46146f5826146b1565b81815260059190911b840185019085810190898311156150c357600080fd5b8686015b8381101561514c578051868111156150df5760008081fd5b8701603f81018c136150f15760008081fd5b8881015160408882111561510757615107614643565b615118828901601f19168c01614681565b8281528e8284860101111561512d5760008081fd5b61513c838d83018487016148bc565b86525050509187019187016150c7565b509998505050505050505050565b6001600160a01b03978816815263ffffffff9690961660208701529390951660408501529015156060840152608083015260a082019290925260c081019190915260e00190565b600060208083850312156151b457600080fd5b82516001600160401b038111156151ca57600080fd5b8301601f810185136151db57600080fd5b80516151e96146f5826146b1565b81815260059190911b8201830190838101908783111561520857600080fd5b928401925b82841015614a635783518252928401929084019061520d565b60006020828403121561523857600080fd5b8151610fb781614375565b63ffffffff818116838216019080821115612b6257612b6261501d565b808202811582820484141761093b5761093b61501d565b60008261529457634e487b7160e01b600052601260045260246000fd5b500490565b600060208083850312156152ac57600080fd5b82516001600160401b038111156152c257600080fd5b8301601f810185136152d357600080fd5b80516152e16146f5826146b1565b81815260059190911b8201830190838101908783111561530057600080fd5b928401925b82841015614a6357835161531881614398565b82529284019290840190615305565b60006020828403121561533957600080fd5b815160ff81168114610fb757600080fd5b63ffffffff828116828216039080821115612b6257612b6261501d565b6000806040838503121561537a57600080fd5b825161538581614375565b602084015190925061453181614375565b8181038181111561093b5761093b61501d565b6000602082840312156153bb57600080fd5b8151610fb78161438a565b6000602082840312156153d857600080fd5b8151610fb781614398565b600082516153f58184602087016148bc565b9190910192915050565b60008060006060848603121561541457600080fd5b835161541f81614398565b602085015160408601519194509250614d868161438a565b6001600160a01b03988916815263ffffffff979097166020880152941515604087015292861660608601529416608084015260a083019390935260c082019290925290151560e0820152610100019056fe97ad0c394f25bbd1393e568879c09de001fb1d6fd24cff6ae6c10e0f98873fe50783a9538328f521bae51128cb03e09233a2a8ec644b0e4f2e9f6246d7014fc575e5bf8b7de9fd9f24c97951733c6410a040b7a07b543096cb36c6dda365aa8ba26469706673582212202962d1607e69abef126eac6c084f939ef7fa86178f1b62ae67536f60758ae2d764736f6c63430008180033

Deployed Bytecode Sourcemap

1187:56458:7:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5051:4;;-1:-1:-1;;;;;5051:4:7;5037:10;:18;5030:26;;;;:::i;:::-;1187:56458;;;;;2565:202:0;;;;;;;;;;-1:-1:-1;2565:202:0;;;;;:::i;:::-;;:::i;:::-;;;602:14:13;;595:22;577:41;;565:2;550:18;2565:202:0;;;;;;;;39157:310:7;;;;;;;;;;-1:-1:-1;39157:310:7;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;40257:286::-;;;;;;;;;;-1:-1:-1;40257:286:7;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;1501:41::-;;;;;;;;;;;;1535:7;1501:41;;;;;3773:10:13;3761:23;;;3743:42;;3731:2;3716:18;1501:41:7;3599:192:13;6208:319:7;;;;;;;;;;-1:-1:-1;6208:319:7;;;;;:::i;:::-;;:::i;3810:120:0:-;;;;;;;;;;-1:-1:-1;3810:120:0;;;;;:::i;:::-;3875:7;3901:12;;;:6;:12;;;;;;;;:22;;;3810:120;;;;4516:25:13;;;4504:2;4489:18;3810:120:0;4370:177:13;6533:347:7;;;;;;;;;;-1:-1:-1;6533:347:7;;;;;:::i;:::-;;:::i;4226:136:0:-;;;;;;;;;;-1:-1:-1;4226:136:0;;;;;:::i;:::-;;:::i;36202:683:7:-;;;;;;;;;;-1:-1:-1;36202:683:7;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;41809:226::-;;;;;;;;;;-1:-1:-1;41809:226:7;;;;;:::i;:::-;;:::i;:::-;;;;7001:25:13;;;7057:2;7042:18;;7035:34;;;;6974:18;41809:226:7;6827:248:13;33400:428:7;;;;;;;;;;-1:-1:-1;33400:428:7;;;;;:::i;:::-;;:::i;35506:202::-;;;;;;;;;;-1:-1:-1;35506:202:7;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;24444:2278::-;;;;;;;;;;-1:-1:-1;24444:2278:7;;;;;:::i;:::-;;:::i;:::-;;;;13521:25:13;;;13577:2;13562:18;;13555:34;;;;13637:10;13625:23;13605:18;;;13598:51;13509:2;13494:18;24444:2278:7;13321:334:13;5328:245:0;;;;;;;;;;-1:-1:-1;5328:245:0;;;;;:::i;:::-;;:::i;42041:205:7:-;;;;;;;;;;-1:-1:-1;42041:205:7;;;;;:::i;:::-;;:::i;37036:676::-;;;;;;;;;;-1:-1:-1;37036:676:7;;;;;:::i;:::-;;:::i;39473:373::-;;;;;;;;;;-1:-1:-1;39473:373:7;;;;;:::i;:::-;;:::i;18363:321::-;;;;;;:::i;:::-;;:::i;2559:53::-;;;;;;;;;;-1:-1:-1;2559:53:7;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;16715:10:13;16752:15;;;16734:34;;16804:15;;;;16799:2;16784:18;;16777:43;16678:18;2559:53:7;16535:291:13;38109:264:7;;;;;;;;;;-1:-1:-1;38109:264:7;;;;;:::i;:::-;;:::i;34017:141::-;;;;;;;;;;-1:-1:-1;34017:141:7;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;17180:32:13;;;17162:51;;17150:2;17135:18;34017:141:7;17016:203:13;35856:195:7;;;;;;;;;;-1:-1:-1;35856:195:7;;;;;:::i;:::-;;:::i;42726:428::-;;;;;;;;;;-1:-1:-1;42726:428:7;;;;;:::i;:::-;;:::i;7750:2661::-;;;;;;;;;;-1:-1:-1;7750:2661:7;;;;;:::i;:::-;;:::i;38379:315::-;;;;;;;;;;-1:-1:-1;38379:315:7;;;;;:::i;:::-;;:::i;41012:297::-;;;;;;;;;;-1:-1:-1;41012:297:7;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;19724:2324::-;;;;;;;;;;-1:-1:-1;19724:2324:7;;;;;:::i;:::-;;:::i;1565:31::-;;;;;;;;;;-1:-1:-1;1565:31:7;;;;-1:-1:-1;;;;;1565:31:7;;;35155:203;;;;;;;;;;-1:-1:-1;35155:203:7;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;2854:136:0:-;;;;;;;;;;-1:-1:-1;2854:136:0;;;;;:::i;:::-;;:::i;32723:671:7:-;;;;;;;;;;-1:-1:-1;32723:671:7;;;;;:::i;:::-;;:::i;2187:49:0:-;;;;;;;;;;-1:-1:-1;2187:49:0;2232:4;2187:49;;1614:19:7;;;;;;;;;;-1:-1:-1;1614:19:7;;;;-1:-1:-1;;;;;1614:19:7;;;30933:750;;;;;;;;;;-1:-1:-1;30933:750:7;;;;;:::i;:::-;;:::i;17279:317::-;;;;;;:::i;:::-;;:::i;12523:2466::-;;;;;;;;;;-1:-1:-1;12523:2466:7;;;;;:::i;:::-;;:::i;5640:281::-;;;;;;;;;;-1:-1:-1;5640:281:7;;;;;:::i;:::-;;:::i;34469:190::-;;;;;;;;;;-1:-1:-1;34469:190:7;;;;;:::i;:::-;;:::i;:::-;;;;-1:-1:-1;;;;;22232:15:13;;;22214:34;;22284:15;;;;22279:2;22264:18;;22257:43;22149:18;34469:190:7;22002:304:13;4642:138:0;;;;;;;;;;-1:-1:-1;4642:138:0;;;;;:::i;:::-;;:::i;29050:345:7:-;;;;;;:::i;:::-;;:::i;41620:183::-;;;;;;;;;;-1:-1:-1;41620:183:7;;;;;:::i;:::-;;:::i;30201:349::-;;;;;;:::i;:::-;;:::i;34802:210::-;;;;;;;;;;-1:-1:-1;34802:210:7;;;;;:::i;:::-;;:::i;5950:252::-;;;;;;;;;;-1:-1:-1;5950:252:7;;;;;:::i;:::-;;:::i;2565:202:0:-;2650:4;-1:-1:-1;;;;;;2673:47:0;;-1:-1:-1;;;2673:47:0;;:87;;-1:-1:-1;;;;;;;;;;861:40:5;;;2724:36:0;2666:94;2565:202;-1:-1:-1;;2565:202:0:o;39157:310:7:-;39311:32;39355:17;39375:20;39383:4;39389:5;39375:7;:20::i;:::-;39412:48;;-1:-1:-1;;;39412:48:7;;23267:14:13;;23260:22;39412:48:7;;;23242:41:13;23299:18;;;23292:34;;;23374:10;23362:23;;23342:18;;;23335:51;39355:40:7;;-1:-1:-1;;;;;;39412:31:7;;;;;23215:18:13;;39412:48:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;39412:48:7;;;;;;;;;;;;:::i;:::-;39405:55;;;39157:310;;;;;;;;:::o;40257:286::-;40391:30;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40391:30:7;40433:17;40453:20;40461:4;40467:5;40453:7;:20::i;:::-;40490:46;;-1:-1:-1;;;40490:46:7;;25165:14:13;;25158:22;40490:46:7;;;25140:41:13;25229:10;25217:23;;25197:18;;;25190:51;40433:40:7;;-1:-1:-1;;;;;;40490:30:7;;;;;25113:18:13;;40490:46:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;40483:53;;;40257:286;;;;;;;:::o;6208:319::-;6299:12;6328:40;-1:-1:-1;;;;;;;;;;;735:10:3;2854:136:0;:::i;6328:40:7:-;6323:123;;-1:-1:-1;;;;;;;;;;;735:10:3;6422:12:7;6391:44;;-1:-1:-1;;;6391:44:7;;;;;25676:25:13;;;;-1:-1:-1;;;;;25737:32:13;25717:18;;;25710:60;25649:18;;6391:44:7;;;;;;;;6323:123;-1:-1:-1;6455:10:7;:16;;-1:-1:-1;;;;6481:18:7;-1:-1:-1;;;6455:16:7;;;;;-1:-1:-1;;;;6481:18:7;;-1:-1:-1;;;6481:18:7;;;;;;;;;;;;;;-1:-1:-1;;6208:319:7:o;6533:347::-;6662:12;6691:40;-1:-1:-1;;;;;;;;;;;735:10:3;2854:136:0;:::i;6691:40:7:-;6686:123;;-1:-1:-1;;;;;;;;;;;735:10:3;6785:12:7;656:96:3;6686:123:7;6818:34;6829:4;6835:5;6842:3;6847:4;6818:10;:34::i;:::-;-1:-1:-1;6869:4:7;;6533:347;-1:-1:-1;;;;;6533:347:7:o;4226:136:0:-;3875:7;3901:12;;;:6;:12;;;;;;;;:22;;2464:16;2475:4;2464:10;:16::i;:::-;4330:25:::1;4341:4;4347:7;4330:10;:25::i;:::-;;4226:136:::0;;;:::o;36202:683:7:-;36406:16;;36375:78;;-1:-1:-1;;;36375:78:7;;;;;7001:25:13;;;7042:18;;;7035:34;;;36297:26:7;;36335:37;;-1:-1:-1;;;;;36406:16:7;;;;36375:66;;6974:18:13;;36375:78:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;36375:78:7;;;;;;;;;;;;:::i;:::-;36335:118;;36489:5;:12;-1:-1:-1;;;;;36475:27:7;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;36475:27:7;;36463:39;;36517:9;36512:341;36536:5;:12;36532:1;:16;36512:341;;;36573:4;-1:-1:-1;;;;;36573:13:7;;36587:5;36593:1;36587:8;;;;;;;;:::i;:::-;;;;;;;:13;;;36602:5;36608:1;36602:8;;;;;;;;:::i;:::-;;;;;;;:14;;;36573:44;;;;;;;;;;;;;;;-1:-1:-1;;;;;22232:15:13;;;22214:34;;22284:15;;22279:2;22264:18;;22257:43;22164:2;22149:18;;22002:304;36573:44:7;;;;;;;;;;;;;;;;;;;-1:-1:-1;36573:44:7;;;;;;;;-1:-1:-1;;36573:44:7;;;;;;;;;;;;:::i;:::-;;;36569:274;;36781:9;36827:1;36812:9;36822:1;36812:12;;;;;;;;:::i;:::-;;;;;;:16;;;;;36763:80;36569:274;;;36690:9;36702:5;36690:17;;36740:1;36725:9;36735:1;36725:12;;;;;;;;:::i;:::-;;;;;;:16;;;;;36672:84;36618:138;36569:274;36550:3;;36512:341;;;;36862:16;36202:683;;;;:::o;41809:226::-;41898:15;41915;41942:17;41962:20;41970:4;41976:5;41962:7;:20::i;:::-;41942:40;;42010:9;-1:-1:-1;;;;;41999:27:7;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;41992:36;;;;;41809:226;;;;;:::o;33400:428::-;33572:25;33634:8;:15;-1:-1:-1;;;;;33620:30:7;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;33620:30:7;;33609:41;;33665:8;33660:137;33683:8;:15;33679:1;:19;;;33660:137;;;33733:53;33745:4;33750:1;33745:7;;;;;;;;;;:::i;:::-;;;;;;;33754:5;33760:1;33754:8;;;;;;;;;;:::i;:::-;;;;;;;33764:5;33770:1;33764:8;;;;;;;;;;:::i;:::-;;;;;;;33774;33783:1;33774:11;;;;;;;;;;:::i;:::-;;;;;;;33733;:53::i;:::-;33719:8;33728:1;33719:11;;;;;;;;;;:::i;:::-;;;;;;;;;;:67;33700:3;;;;:::i;:::-;;;;33660:137;;;;33400:428;;;;;;:::o;35506:202::-;35659:16;;35641:60;;-1:-1:-1;;;35641:60:7;;;;;7001:25:13;;;7042:18;;;7035:34;;;35601:21:7;;-1:-1:-1;;;;;35659:16:7;;35641:48;;6974:18:13;;35641:60:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;35641:60:7;;;;;;;;;;;;:::i;:::-;35634:67;35506:202;-1:-1:-1;;;35506:202:7:o;24444:2278::-;24685:17;24704:14;24720:9;2356:21:4;:19;:21::i;:::-;24745:26:7::1;;:::i;:::-;24827:138;24849:4;24867:5;24886;24905:10;24929:5;24948:7;24827:8;:138::i;:::-;-1:-1:-1::0;;;;;24781:184:7::1;24804:19;::::0;::::1;24781:184:::0;;;;;;25028:38:::1;::::0;24782:20:::1;25028:10;:38::i;:::-;25004:62;;:21;::::0;::::1;:62:::0;25149:20;;25423:19:::1;::::0;::::1;::::0;25149:20;;-1:-1:-1;25398:182:7::1;::::0;25149:20;25490:4;25508:9;25149:20:::1;25550:5:::0;25569:1;25398:11:::1;:182::i;:::-;25368:17;::::0;::::1;25289:291:::0;;;25337:17:::1;::::0;::::1;25289:291:::0;;;;;;-1:-1:-1;25699:19:7;::::1;::::0;25813:21:::1;::::0;::::1;::::0;25663:181:::1;::::0;25699:19;;25732:5;;25289:291;;25663:22:::1;:181::i;:::-;25646:13;::::0;::::1;25638:206:::0;25933:19:::1;::::0;::::1;::::0;25966:20;;25638:206;;-1:-1:-1;25874:204:7::1;::::0;25896:4;;25914:5;;25638:206;25966:20:::1;26038:7:::0;26059:9;25874:8:::1;:204::i;:::-;25855:223;;:16;::::0;::::1;:223:::0;;;26093:20;26089:562:::1;;26228:9;:13;;;26220:5;:21;26216:171;;;26272:19;::::0;::::1;::::0;26261:45:::1;::::0;-1:-1:-1;;;26261:45:7;;::::1;::::0;::::1;4516:25:13::0;;;-1:-1:-1;;;;;26261:38:7;;::::1;::::0;::::1;::::0;4489:18:13;;26261:45:7::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;;26345:19:7::1;::::0;;::::1;::::0;26330:42:::1;::::0;;-1:-1:-1;;;;;29944:32:13;;;29926:51;;29993:18;;;29986:34;;;-1:-1:-1;;;;;;;;;;;26330:42:7;-1:-1:-1;29899:18:13;26330:42:7::1;;;;;;;26216:171;-1:-1:-1::0;;;;;;;;;;;26434:9:7::1;:19;;;26471:9;:16;;;26505:9;26532:5;26555;26578:10;26606:9;:20;;;26405:235;;;;;;;;;;;;:::i;:::-;;;;;;;;26089:562;26676:20:::0;;26698:16:::1;::::0;;::::1;::::0;26669:5;;-1:-1:-1;26676:20:7;;-1:-1:-1;26698:16:7;-1:-1:-1;2398:20:4;1713:1;2924:7;:21;2744:208;2398:20;24444:2278:7;;;;;;;;;;;:::o;5328:245:0:-;-1:-1:-1;;;;;5421:34:0;;735:10:3;5421:34:0;5417:102;;5478:30;;-1:-1:-1;;;5478:30:0;;;;;;;;;;;5417:102;5529:37;5541:4;5547:18;5529:11;:37::i;:::-;;5328:245;;:::o;42041:205:7:-;42131:7;42150:17;42170:20;42178:4;42184:5;42170:7;:20::i;:::-;42150:40;;42218:9;-1:-1:-1;;;;;42207:30:7;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;37036:676::-;37233:16;;37202:78;;-1:-1:-1;;;37202:78:7;;37124:26;;37162:37;;-1:-1:-1;;;;;37233:16:7;;;;37202:73;;:78;;37276:3;;37202:78;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;37202:78:7;;;;;;;;;;;;:::i;:::-;37162:118;;37316:5;:12;-1:-1:-1;;;;;37302:27:7;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;37302:27:7;;37290:39;;37344:9;37339:341;37363:5;:12;37359:1;:16;37339:341;;;37400:4;-1:-1:-1;;;;;37400:13:7;;37414:5;37420:1;37414:8;;;;;;;;:::i;:::-;;;;;;;:13;;;37429:5;37435:1;37429:8;;;;;;;;:::i;:::-;;;;;;;:14;;;37400:44;;;;;;;;;;;;;;;-1:-1:-1;;;;;22232:15:13;;;22214:34;;22284:15;;22279:2;22264:18;;22257:43;22164:2;22149:18;;22002:304;37400:44:7;;;;;;;;;;;;;;;;;;;-1:-1:-1;37400:44:7;;;;;;;;-1:-1:-1;;37400:44:7;;;;;;;;;;;;:::i;:::-;;;37396:274;;37608:9;37654:1;37639:9;37649:1;37639:12;;;;;;;;:::i;:::-;;;;;;:16;;;;;37590:80;37396:274;;;37517:9;37529:5;37517:17;;37567:1;37552:9;37562:1;37552:12;;;;;;;;:::i;:::-;;;;;;:16;;;;;37499:84;37445:138;37396:274;37377:3;;37339:341;;;;37689:16;37036:676;;;:::o;39473:373::-;39660:32;39704:17;39724:20;39732:4;39738:5;39724:7;:20::i;:::-;39773:66;;-1:-1:-1;;;39773:66:7;;30971:14:13;;30964:22;39773:66:7;;;30946:41:13;31003:18;;;30996:34;;;31049:10;31095:15;;;31075:18;;;31068:43;31147:15;;31127:18;;;31120:43;39704:40:7;;-1:-1:-1;;;;;;39773:40:7;;;;;30918:19:13;;39773:66:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;39773:66:7;;;;;;;;;;;;:::i;:::-;39754:85;39473:373;-1:-1:-1;;;;;;;;39473:373:7:o;18363:321::-;18508:17;18527:14;18543:9;18570:4;;;;;;;;;-1:-1:-1;;;;;18570:4:7;-1:-1:-1;;;;;18564:19:7;;18591:9;18564:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;18631:4:7;;18620:57;;-1:-1:-1;;;;;;18631:4:7;;-1:-1:-1;18637:5:7;;-1:-1:-1;18644:9:7;18655:7;18664:1;18667:9;18620:10;:57::i;:::-;18613:64;;;;;;18363:321;;;;;;;;:::o;38109:264::-;38240:16;38268:17;38288:20;38296:4;38302:5;38288:7;:20::i;:::-;38325:41;;-1:-1:-1;;;38325:41:7;;25165:14:13;;25158:22;38325:41:7;;;25140::13;25229:10;25217:23;;25197:18;;;25190:51;38268:40:7;;-1:-1:-1;;;;;;38325:31:7;;;;;25113:18:13;;38325:41:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;38325:41:7;;;;;;;;;;;;:::i;34017:141::-;34122:16;;34104:47;;-1:-1:-1;;;34104:47:7;;;;;4516:25:13;;;34078:7:7;;-1:-1:-1;;;;;34122:16:7;;34104:43;;4489:18:13;;34104:47:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;35856:195::-;36002:16;;35984:60;;-1:-1:-1;;;35984:60:7;;35944:21;;-1:-1:-1;;;;;36002:16:7;;35984:55;;:60;;36040:3;;35984:60;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;35984:60:7;;;;;;;;;;;;:::i;42726:428::-;42859:17;42888;42908:20;42916:4;42922:5;42908:7;:20::i;:::-;42888:40;;42950:5;-1:-1:-1;;;;;42942:13:7;:4;-1:-1:-1;;;;;42942:13:7;;42938:210;;42978:6;42971:13;;;;;42938:210;-1:-1:-1;;;;;43005:23:7;;43001:147;;43051:1;43044:8;;;;;43001:147;43090:47;;-1:-1:-1;;;43090:47:7;;;;;32484:25:13;;;32552:14;;32545:22;32525:18;;;32518:50;-1:-1:-1;;;;;43090:32:7;;;;;32457:18:13;;43090:47:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43083:54;;;;;7750:2661;7969:17;7988:14;8004:9;2356:21:4;:19;:21::i;:::-;8029:26:7::1;;:::i;:::-;8209:134;8231:4;8249:5;8268:1;8283:11;8308:4;8326:7;8209:8;:134::i;:::-;-1:-1:-1::0;;;;;8163:180:7::1;8186:19;::::0;::::1;8163:180:::0;;;;;;8407:37:::1;::::0;8439:4:::1;8407:10;:37::i;:::-;8383:61;;:21;::::0;::::1;:61:::0;8471:21:::1;8480:4:::0;8486:5;8471:8:::1;:21::i;:::-;8455:13;::::0;::::1;:37:::0;8583:20;;8842:19:::1;::::0;::::1;::::0;8995:21:::1;::::0;::::1;::::0;8583:20;;-1:-1:-1;8817:234:7::1;::::0;8583:20;;8909:5;;8928:9;;8951:4:::1;::::0;9021:5:::1;::::0;8987:29:::1;::::0;9021:5;8987:29:::1;:::i;:::-;8970:47;;:9;:13;;;:47;;;;:::i;:::-;8969:57;;;;:::i;:::-;9040:1;8817:11;:234::i;:::-;8787:17;::::0;::::1;8708:343:::0;;;8756:17:::1;::::0;::::1;8708:343:::0;;;;;;-1:-1:-1;9185:19:7;::::1;::::0;9280:21:::1;::::0;::::1;::::0;9149:162:::1;::::0;9185:19;;8708:343;;9149:22:::1;:162::i;:::-;9129:17;::::0;::::1;:182:::0;;;9490:19:::1;::::0;::::1;::::0;9523:20;;9431:215:::1;::::0;9453:4;;9471:5;;9490:19;;9588:4:::1;9606:7:::0;9627:9;9431:8:::1;:215::i;:::-;9412:234;;:16;::::0;::::1;:234:::0;;;9698:20;9694:634:::1;;9870:9;:13;;;9850:9;:17;;;:33;9846:206;;;9914:9;:19;;;-1:-1:-1::0;;;;;9903:38:7::1;;9942:9;:17;;;9903:57;;;;;;;;;;;;;4516:25:13::0;;4504:2;4489:18;;4370:177;9903:57:7::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;-1:-1:-1::0;;;;;;;;;;;9998:9:7::1;:19;;;10019:9;:17;;;9983:54;;;;;;-1:-1:-1::0;;;;;29944:32:13;;;;29926:51;;30008:2;29993:18;;29986:34;29914:2;29899:18;;29752:274;9983:54:7::1;;;;;;;;9846:206;-1:-1:-1::0;;;;;;;;;;;10099:9:7::1;:19;;;10136:9;:16;;;10170:9;10197:4;10219:9;:17;;;10254:11;10283:9;:20;;;10070:247;;;;;;;;;;;;:::i;:::-;;;;;;;;9694:634;10346:9;:17;;;10365:9;:20;;;10387:9;:16;;;10338:66;;;;;;;2398:20:4::0;1713:1;2924:7;:21;2744:208;2398:20;7750:2661:7;;;;;;;;;;:::o;38379:315::-;38543:16;38571:17;38591:20;38599:4;38605:5;38591:7;:20::i;:::-;38628:59;;-1:-1:-1;;;38628:59:7;;33368:14:13;;33361:22;38628:59:7;;;33343:41:13;33403:10;33449:15;;;33429:18;;;33422:43;33501:15;;33481:18;;;33474:43;38571:40:7;;-1:-1:-1;;;;;;38628:40:7;;;;;33316:18:13;;38628:59:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;38628:59:7;;;;;;;;;;;;:::i;41012:297::-;41168:15;41195:17;41215:20;41223:4;41229:5;41215:7;:20::i;:::-;41252:50;;-1:-1:-1;;;41252:50:7;;23267:14:13;;23260:22;41252:50:7;;;23242:41:13;23299:18;;;23292:34;;;23374:10;23362:23;;23342:18;;;23335:51;41195:40:7;;-1:-1:-1;;;;;;41252:33:7;;;;;23215:18:13;;41252:50:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;41252:50:7;;;;;;;;;;;;:::i;19724:2324::-;19965:17;19984:14;20000:9;2356:21:4;:19;:21::i;:::-;20025:26:7::1;;:::i;:::-;20107:138;20129:4;20147:5;20166;20185:11;20210:4;20228:7;20107:8;:138::i;:::-;-1:-1:-1::0;;;;;20061:184:7::1;20084:19;::::0;::::1;20061:184:::0;;;;;;20309:37:::1;::::0;20341:4:::1;20309:10;:37::i;:::-;20285:61;;:21;::::0;::::1;:61:::0;20431:20;;20705:19:::1;::::0;::::1;::::0;20431:20;;-1:-1:-1;20680:182:7::1;::::0;20431:20;20772:5;20791:9;20814:4:::1;20832:5:::0;20851:1;20680:11:::1;:182::i;:::-;20650:17;::::0;::::1;20571:291:::0;;;20619:17:::1;::::0;::::1;20571:291:::0;;;;;;-1:-1:-1;20988:19:7;::::1;::::0;21102:21:::1;::::0;::::1;::::0;20953:180:::1;::::0;20988:19;;21021:5;;20571:291;;20953:21:::1;:180::i;:::-;20936:13;::::0;::::1;20928:205:::0;21222:19:::1;::::0;::::1;::::0;21255:20;;20928:205;;-1:-1:-1;21163:203:7::1;::::0;21185:4;;21203:5;;20928:205;21308:4:::1;21326:7:::0;21347:9;21163:8:::1;:203::i;:::-;21144:222;;:16;::::0;::::1;:222:::0;;;21418:20;21414:563:::1;;21554:9;:13;;;21546:5;:21;21542:171;;;21598:19;::::0;::::1;::::0;21587:45:::1;::::0;-1:-1:-1;;;21587:45:7;;::::1;::::0;::::1;4516:25:13::0;;;-1:-1:-1;;;;;21587:38:7;;::::1;::::0;::::1;::::0;4489:18:13;;21587:45:7::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;;21671:19:7::1;::::0;;::::1;::::0;21656:42:::1;::::0;;-1:-1:-1;;;;;29944:32:13;;;29926:51;;29993:18;;;29986:34;;;-1:-1:-1;;;;;;;;;;;21656:42:7;-1:-1:-1;29899:18:13;21656:42:7::1;;;;;;;21542:171;-1:-1:-1::0;;;;;;;;;;;21760:9:7::1;:19;;;21797:9;:16;;;21831:9;21858:4;21880:5;21903:11;21932:9;:20;;;21731:235;;;;;;;;;;;;:::i;35155:203::-:0;35313:16;;35295:56;;-1:-1:-1;;;35295:56:7;;35239:37;;-1:-1:-1;;;;;35313:16:7;;35295:51;;:56;;35347:3;;35295:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;35295:56:7;;;;;;;;;;;;:::i;2854:136:0:-;2931:4;2954:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;2954:29:0;;;;;;;;;;;;;;;2854:136::o;32723:671:7:-;32868:7;2356:21:4;:19;:21::i;:::-;32925:16:7::1;::::0;32907:90:::1;::::0;-1:-1:-1;;;32907:90:7;;-1:-1:-1;;;;;22232:15:13;;;32907:90:7::1;::::0;::::1;22214:34:13::0;22284:15;;;22264:18;;;22257:43;32887:17:7::1;::::0;32925:16:::1;::::0;32907:43:::1;::::0;22149:18:13;;32907:90:7::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;32887:110:::0;-1:-1:-1;;;;;;33012:23:7;::::1;33008:96;;33058:35;::::0;-1:-1:-1;;;33058:35:7;;-1:-1:-1;;;;;34745:15:13;;;33058:35:7::1;::::0;::::1;34727:34:13::0;34797:15;;;34777:18;;;34770:43;34849:15;;34829:18;;;34822:43;34662:18;;33058:35:7::1;34487:384:13::0;33008:96:7::1;33130:61;::::0;-1:-1:-1;;;33130:61:7;;35095:14:13;;35088:22;33130:61:7::1;::::0;::::1;35070:41:13::0;35159:10;35147:23;;35127:18;;;35120:51;33180:10:7::1;35187:18:13::0;;;35180:60;-1:-1:-1;;;;;33130:33:7;::::1;::::0;::::1;::::0;35043:18:13;;33130:61:7::1;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;33130:61:7::1;::::0;;::::1;;::::0;;::::1;-1:-1:-1::0;;33130:61:7::1;::::0;::::1;::::0;;;::::1;::::0;;::::1;::::0;::::1;:::i;:::-;;;33114:274;;33376:1;33369:8;;;;;33114:274;33246:62;::::0;;-1:-1:-1;;;;;35493:32:13;;35475:51;;35574:10;35562:23;;35557:2;35542:18;;35535:51;35629:14;;35622:22;35602:18;;;35595:50;35676:2;35661:18;;35654:34;;;33246:62:7;;33287:10:::1;::::0;33246:62:::1;::::0;;;;;35462:3:13;33246:62:7;;::::1;33329:8:::0;-1:-1:-1;33322:15:7::1;::::0;-1:-1:-1;33322:15:7::1;2387:1:4;2398:20:::0;1713:1;2924:7;:21;2744:208;30933:750:7;31155:16;;31137:93;;-1:-1:-1;;;31137:93:7;;-1:-1:-1;;;;;22232:15:13;;;31137:93:7;;;22214:34:13;22284:15;;;22264:18;;;22257:43;31052:12:7;;;;31155:16;;;31137:46;;22149:18:13;;31137:93:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;31240:45;;-1:-1:-1;;;31240:45:7;;;;;4516:25:13;;;31117:113:7;;-1:-1:-1;;;;;;31240:28:7;;;;;4489:18:13;;31240:45:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31295:14;31322:4;-1:-1:-1;;;;;31312:24:7;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;31295:43;;31348:14;31375:5;-1:-1:-1;;;;;31365:25:7;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;31501:10;;31348:44;;-1:-1:-1;31477:48:7;;31488:4;;31494:5;;31501:10;-1:-1:-1;;;31501:10:7;;;;;-1:-1:-1;;;31513:11:7;;;31477:10;:48::i;:::-;-1:-1:-1;31540:53:7;;;-1:-1:-1;;;;;36284:15:13;;;36266:34;;36336:15;;;36331:2;36316:18;;36309:43;36388:15;;36368:18;;;36361:43;36452:4;36440:17;;;36435:2;36420:18;;36413:45;36495:17;;36489:3;36474:19;;36467:46;31540:53:7;;;;;;;36215:3:13;31540:53:7;;;31608:42;;;-1:-1:-1;;;;;29944:32:13;;29926:51;;30008:2;29993:18;;29986:34;;;-1:-1:-1;;;;;;;;;;;31608:42:7;29899:18:13;31608:42:7;;;;;;;-1:-1:-1;31667:9:7;;30933:750;-1:-1:-1;;;;;30933:750:7:o;17279:317::-;17422:17;17441:14;17457:9;17484:4;;;;;;;;;-1:-1:-1;;;;;17484:4:7;-1:-1:-1;;;;;17478:19:7;;17505:9;17478:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;17550:4:7;;17534:55;;-1:-1:-1;17544:4:7;;-1:-1:-1;;;;;;17550:4:7;;-1:-1:-1;17556:9:7;17567:7;17576:1;17579:9;17534;:55::i;12523:2466::-;12742:17;12761:14;12777:9;2356:21:4;:19;:21::i;:::-;12802:26:7::1;;:::i;:::-;12884:134;12906:4;12924:5;12943:1;12958:10;12982:5;13001:7;12884:8;:134::i;:::-;-1:-1:-1::0;;;;;12838:180:7::1;12861:19;::::0;::::1;12838:180:::0;;;;;;13082:38:::1;::::0;12839:20:::1;13082:10;:38::i;:::-;13058:62;;:21;::::0;::::1;:62:::0;13147:21:::1;13156:4:::0;13162:5;13147:8:::1;:21::i;:::-;13131:13;::::0;::::1;:37:::0;13244:20;;13518:19:::1;::::0;::::1;::::0;13671:21:::1;::::0;::::1;::::0;13244:20;;-1:-1:-1;13493:234:7::1;::::0;13244:20;;13585:4;;13603:9;;13244:20:::1;::::0;13697:5:::1;::::0;13663:29:::1;::::0;13697:5;13663:29:::1;:::i;13493:234::-;13463:17;::::0;::::1;13384:343:::0;;;13432:17:::1;::::0;::::1;13384:343:::0;;;;;;-1:-1:-1;13862:19:7;::::1;::::0;13957:21:::1;::::0;::::1;::::0;13825:163:::1;::::0;13862:19;;13384:343;;13825:23:::1;:163::i;:::-;13805:17;::::0;::::1;:183:::0;;;14077:19:::1;::::0;::::1;::::0;14110:20;;14018:216:::1;::::0;14040:4;;14058:5;;14077:19;;14110:20:::1;14194:7:::0;14215:9;14018:8:::1;:216::i;:::-;13999:235;;:16;::::0;::::1;:235:::0;;;14286:20;14282:624:::1;;14448:9;:13;;;14428:9;:17;;;:33;14424:206;;;14492:19;::::0;::::1;::::0;14520:17:::1;::::0;::::1;::::0;14481:57:::1;::::0;-1:-1:-1;;;14481:57:7;;-1:-1:-1;;;;;14481:38:7;;::::1;::::0;::::1;::::0;:57:::1;::::0;::::1;;4516:25:13::0;;;4504:2;4489:18;;4370:177;14481:57:7::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;;14576:19:7::1;::::0;;::::1;::::0;14597:17:::1;::::0;::::1;::::0;14561:54:::1;::::0;;-1:-1:-1;;;;;29944:32:13;;;29926:51;;29993:18;;;29986:34;-1:-1:-1;;;;;;;;;;;14561:54:7;-1:-1:-1;29899:18:13;14561:54:7::1;;;;;;;14424:206;-1:-1:-1::0;;;;;;;;;;;14677:9:7::1;:19;;;14714:9;:16;;;14748:9;14775:5;14798:9;:17;;;14833:10;14861:9;:20;;;14648:247;;;;;;;;;;;;:::i;:::-;;;;;;;;14282:624;14924:9;:17;;;14943:9;:20;;;14965:9;:16;;;14916:66;;;;;;;2398:20:4::0;1713:1;2924:7;:21;2744:208;5640:281:7;8870:21:2;4302:15;;-1:-1:-1;;;4302:15:2;;;;4301:16;;-1:-1:-1;;;;;4348:14:2;4158:30;4726:16;;:34;;;;;4746:14;4726:34;4706:54;;4770:17;4790:11;-1:-1:-1;;;;;4790:16:2;4805:1;4790:16;:50;;;;-1:-1:-1;4818:4:2;4810:25;:30;4790:50;4770:70;;4856:12;4855:13;:30;;;;;4873:12;4872:13;4855:30;4851:91;;;4908:23;;-1:-1:-1;;;4908:23:2;;;;;;;;;;;4851:91;4951:18;;-1:-1:-1;;4951:18:2;4968:1;4951:18;;;4979:67;;;;5013:22;;-1:-1:-1;;;;5013:22:2;-1:-1:-1;;;5013:22:2;;;4979:67;5779:16:7::1;:36:::0;;-1:-1:-1;;;;;;5779:36:7;;::::1;-1:-1:-1::0;;;;;5779:36:7;;::::1;::::0;;;::::1;::::0;;;5825:5:::1;:14:::0;;;;::::1;::::0;;::::1;;::::0;;5849:4:::1;:12:::0;;;;::::1;-1:-1:-1::0;;;;;;5871:16:7;;;;;;;-1:-1:-1;;;5871:16:7::1;-1:-1:-1::0;;;;5897:17:7::1;-1:-1:-1::0;;;5897:17:7::1;::::0;;5066:101:2;;;;5100:23;;-1:-1:-1;;;;5100:23:2;;;5142:14;;-1:-1:-1;36857:50:13;;5142:14:2;;36845:2:13;36830:18;5142:14:2;;;;;;;5066:101;4092:1081;;;;;5640:281:7;;;:::o;34469:190::-;34611:16;;34593:59;;-1:-1:-1;;;34593:59:7;;-1:-1:-1;;;;;17180:32:13;;;34593:59:7;;;17162:51:13;34547:12:7;;;;34611:16;;;34593:48;;17135:18:13;;34593:59:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;34586:66;;;;34469:190;;;:::o;4642:138:0:-;3875:7;3901:12;;;:6;:12;;;;;;;;:22;;2464:16;2475:4;2464:10;:16::i;:::-;4747:26:::1;4759:4;4765:7;4747:11;:26::i;29050:345:7:-:0;29215:17;29234:14;29250:9;29277:4;;;;;;;;;-1:-1:-1;;;;;29277:4:7;-1:-1:-1;;;;;29271:19:7;;29298:9;29271:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;29342:4:7;;29327:61;;-1:-1:-1;29336:4:7;;-1:-1:-1;;;;;;29342:4:7;;-1:-1:-1;29348:5:7;29355:9;29366:7;29375:1;29378:9;29327:8;:61::i;:::-;29320:68;;;;;;29050:345;;;;;;;;;:::o;41620:183::-;41758:16;;41740:56;;-1:-1:-1;;;41740:56:7;;-1:-1:-1;;;;;22232:15:13;;;41740:56:7;;;22214:34:13;22284:15;;;22264:18;;;22257:43;41709:12:7;;41758:16;;41740:43;;22149:18:13;;41740:56:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;30201:349::-;30368:17;30387:14;30403:9;30430:4;;;;;;;;;-1:-1:-1;;;;;30430:4:7;-1:-1:-1;;;;;30424:19:7;;30451:9;30424:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;30490:4:7;;30480:63;;-1:-1:-1;;;;;;30490:4:7;;-1:-1:-1;30496:5:7;;-1:-1:-1;30503:5:7;30510:9;30521:7;30530:1;30533:9;30480;:63::i;34802:210::-;34967:16;;34949:56;;-1:-1:-1;;;34949:56:7;;;;;7001:25:13;;;7042:18;;;7035:34;;;34893:37:7;;-1:-1:-1;;;;;34967:16:7;;34949:44;;6974:18:13;;34949:56:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;34949:56:7;;;;;;;;;;;;:::i;5950:252::-;6002:12;6031:41;6002:12;735:10:3;2854:136:0;:::i;6031:41:7:-;6026:125;;2232:4:0;735:10:3;6127:12:7;656:96:3;6026:125:7;-1:-1:-1;6160:5:7;:14;;-1:-1:-1;;;;;;6160:14:7;-1:-1:-1;;;;;6160:14:7;;;;;;;;;;-1:-1:-1;;5950:252:7:o;43160:272::-;43290:12;43314;43329:20;43337:4;43343:5;43329:7;:20::i;:::-;43380:24;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;43359:18:7;;;-1:-1:-1;43359:18:7;;;:12;:18;;;;;;;:45;;;;;;;;;;-1:-1:-1;;43359:45:7;;;;;;;;;;;;-1:-1:-1;43359:45:7;;-1:-1:-1;43160:272:7;;;;;;:::o;3199:103:0:-;3265:30;3276:4;735:10:3;3265::0;:30::i;:::-;3199:103;:::o;6179:316::-;6256:4;6277:22;6285:4;6291:7;6277;:22::i;:::-;6272:217;;6315:12;;;;6347:4;6315:12;;;;;;;;-1:-1:-1;;;;;6315:29:0;;;;;;;;;;:36;;-1:-1:-1;;6315:36:0;;;;;;;6370:40;;735:10:3;;6315:12:0;;6370:40;;6315:12;6370:40;-1:-1:-1;6431:4:0;6424:11;;6272:217;-1:-1:-1;6473:5:0;6466:12;;2431:307:4;1755:1;2558:7;;:18;2554:86;;2599:30;;-1:-1:-1;;;2599:30:4;;;;;;;;;;;2554:86;1755:1;2714:7;:17;2431:307::o;54196:1820:7:-;54372:18;54392:12;54455:6;54465:1;54455:11;54451:63;;54489:14;;-1:-1:-1;;;54489:14:7;;;;;;;;;;;54451:63;54593:20;54601:4;54607:5;54593:7;:20::i;:::-;54586:27;-1:-1:-1;;;;;;54627:18:7;;54623:86;;54668:30;;-1:-1:-1;;;54668:30:7;;-1:-1:-1;;;;;34745:15:13;;;54668:30:7;;;34727:34:13;34797:15;;;34777:18;;;34770:43;34849:15;;34829:18;;;34822:43;34662:18;;54668:30:7;34487:384:13;54623:86:7;54788:17;54808:37;54817:4;54823:5;54830:6;54839:5;54838:6;54808:8;:37::i;:::-;54788:57;;54855:19;54877:32;54886:4;54892:5;54899:1;54903:5;54902:6;54877:8;:32::i;:::-;54855:54;;54937:11;54924:9;:24;54920:103;;54971:41;;-1:-1:-1;;;54971:41:7;;;;;7001:25:13;;;7042:18;;;7035:34;;;6974:18;;54971:41:7;6827:248:13;54920:103:7;55062:11;55076:33;55081:6;55089:10;55101:7;55076:4;:33::i;:::-;55062:47;-1:-1:-1;55132:12:7;55062:47;55132:6;:12;:::i;:::-;55119:25;;55158:5;55154:754;;;55255:4;;-1:-1:-1;;;;;55246:13:7;;;55255:4;;55246:13;55242:223;;55279:171;55332:5;55359:10;55399:4;55426:6;55279:31;:171::i;:::-;55513:5;;55478:46;;55506:5;;-1:-1:-1;;;;;55513:5:7;55520:3;55478:27;:46::i;:::-;55154:754;;;55630:4;;-1:-1:-1;;;;;55622:12:7;;;55630:4;;55622:12;55618:221;;55654:170;55707:4;55733:10;55773:4;55800:6;55654:31;:170::i;:::-;55886:5;;55852:45;;55880:4;;-1:-1:-1;;;;;55886:5:7;55893:3;55852:27;:45::i;:::-;55922:51;55935:10;55947:5;:20;;55963:4;55947:20;;;55955:5;55947:20;55922:51;;;-1:-1:-1;;;;;37699:15:13;;;37681:34;;37751:15;;;;37746:2;37731:18;;37724:43;37783:18;;37776:34;;;37631:2;37616:18;55922:51:7;;;;;;;55984:25;;;54196:1820;;;;;;;;;:::o;43438:303::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;43605:18:7;;;;:12;:18;;;;;43596:27;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;43633:102:7;;;;43665:10;;-1:-1:-1;43658:17:7;;43633:102;43713:11;;;;-1:-1:-1;43706:18:7;;43633:102;43549:192;43438:303;;;;:::o;48401:3107::-;48612:17;48631:15;48648;48687:6;48675:18;;48703:11;48728:9;-1:-1:-1;;;;;48717:25:7;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;48764:42;;-1:-1:-1;;;48764:42:7;;48801:4;48764:42;;;577:41:13;48703::7;;-1:-1:-1;;;;;;48764:36:7;;;;;550:18:13;;48764:42:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;48826:43;;-1:-1:-1;;;48826:43:7;;48863:5;48826:43;;;577:41:13;48754:52:7;;-1:-1:-1;;;;;;48826:36:7;;;;;550:18:13;;48826:43:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;48816:53;;48879:8;48928:5;48924:2312;;;48953:8;;48949:266;;48985:12;;;;;:36;;;49014:7;49001:10;:20;48985:36;48981:220;;;49045:36;;;;48981:220;49110:7;49121:1;49110:12;49106:95;;49146:36;;;;49106:95;49385:1;49373:9;:13;:29;;;;-1:-1:-1;49390:12:7;;;49373:29;:54;;;;;49417:10;49406:7;:21;;49373:54;:63;;;;;49435:1;49431:5;;:1;:5;;;49373:63;49349:634;;;49475:7;49469:13;;49517:247;49547:9;49578:4;49604:9;49635:5;49662:9;49693:7;49722:1;49745;49517:8;:247::i;:::-;49500:264;;-1:-1:-1;49500:264:7;-1:-1:-1;49872:6:7;;;;:96;;49925:43;;-1:-1:-1;;;49925:43:7;;49962:5;49925:43;;;577:41:13;-1:-1:-1;;;;;49925:36:7;;;;;550:18:13;;49925:43:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;49872:96;;;49901:1;49872:96;49862:106;;49349:634;;;50034:42;;-1:-1:-1;;;50034:42:7;;50071:4;50034:42;;;577:41:13;-1:-1:-1;;;;;50034:36:7;;;;;550:18:13;;50034:42:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;50024:52;;48924:2312;;;50223:8;;50219:266;;50255:12;;;;;:36;;;50284:7;50271:10;:20;50255:36;50251:220;;;50315:36;;;;50251:220;50380:7;50391:1;50380:12;50376:95;;50416:36;;;;50376:95;50534:1;50522:9;:13;:29;;;;-1:-1:-1;50539:12:7;;;50522:29;:54;;;;;50566:10;50555:7;:21;;50522:54;:63;;;;;50584:1;50580:5;;:1;:5;;;50522:63;50498:633;;;50624:7;50618:13;;50666:247;50696:9;50727:4;50753:9;50784:5;50811:9;50842:7;50871:1;50894;50666:8;:247::i;:::-;50649:264;;-1:-1:-1;50649:264:7;-1:-1:-1;51021:6:7;;;;:95;;51074:42;;-1:-1:-1;;;51074:42:7;;51111:4;51074:42;;;577:41:13;-1:-1:-1;;;;;51074:36:7;;;;;550:18:13;;51074:42:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;51021:95;;;51050:1;51021:95;51011:105;;50498:633;;;51182:43;;-1:-1:-1;;;51182:43:7;;51219:5;51182:43;;;577:41:13;-1:-1:-1;;;;;51182:36:7;;;;;550:18:13;;51182:43:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;51172:53;;48924:2312;51307:8;;51303:121;;51331:33;;-1:-1:-1;;;51331:33:7;;;;;4516:25:13;;;-1:-1:-1;;;;;51331:28:7;;;;;4489:18:13;;51331:33:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;51398:9:7;51409:3;51383:30;;;;;;-1:-1:-1;;;;;29944:32:13;;;;29926:51;;30008:2;29993:18;;29986:34;29914:2;29899:18;;29752:274;51383:30:7;;;;;;;;51303:121;51434:36;;48401:3107;;;;;;;;;;;:::o;26728:1519::-;26909:13;26924:11;26947:12;26986:9;-1:-1:-1;;;;;26975:25:7;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;26969:33;-1:-1:-1;27016:12:7;;:28;;;;-1:-1:-1;27032:12:7;;27016:28;27012:1229;;;27064:8;;27060:140;;27126:5;27107:14;27115:6;27126:5;27107:14;:::i;:::-;27100:22;;;;:3;:22;:::i;:::-;27099:32;;;;:::i;:::-;27092:39;;27163:4;27157:2;:10;;:22;;27177:2;27157:22;;;27170:4;27157:22;27149:36;;;;;27060:140;27221:2;27213:16;;;;;27012:1229;27250:12;;:28;;;;-1:-1:-1;27266:12:7;;;27250:28;27246:995;;;27298:8;;27294:197;;27360:5;27341:14;27349:6;27360:5;27341:14;:::i;:::-;27334:22;;;;:3;:22;:::i;:::-;27333:32;;;;:::i;:::-;27326:39;;27396:4;27390:2;:10;;:22;;27410:2;27390:22;;;27403:4;27390:22;27383:29;;27446:7;27438:4;:15;;:32;;27466:4;27438:32;;;27456:7;27430:46;;;;;27294:197;27542:5;27523:14;27531:6;27542:5;27523:14;:::i;:::-;27512:26;;;;:7;:26;:::i;27246:995::-;27671:12;;;;;:28;;-1:-1:-1;27687:12:7;;27671:28;27667:574;;;27719:8;;27715:139;;27781:5;27762:14;27770:6;27781:5;27762:14;:::i;27715:139::-;27905:5;27886:14;27894:6;27905:5;27886:14;:::i;:::-;27875:26;;;;:7;:26;:::i;27667:574::-;28079:3;28073:2;:9;;:20;;28090:3;28073:20;;;-1:-1:-1;28085:2:7;28192:15;;;;:32;;28220:4;28192:32;;26728:1519;;;;;;;;;:::o;52446:644::-;52679:9;52704:13;;52700:384;;52733:14;52750:7;:31;;52772:9;52750:31;;;52760:9;52750:31;52733:48;;52795:130;52840:5;:20;;52856:4;52840:20;;;52848:5;52840:20;52878:6;52902:9;52795:27;:130::i;:::-;52943:7;52939:135;;;52975:57;52986:9;52997;53008:5;53015;53022:9;52975:10;:57::i;:::-;52970:62;;53050:9;;;52939:135;52719:365;52446:644;;;;;;;;;;:::o;6730:317:0:-;6808:4;6828:22;6836:4;6842:7;6828;:22::i;:::-;6824:217;;;6898:5;6866:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;6866:29:0;;;;;;;;;;:37;;-1:-1:-1;;6866:37:0;;;6922:40;735:10:3;;6866:12:0;;6922:40;;6898:5;6922:40;-1:-1:-1;6983:4:0;6976:11;;10417:1315:7;10578:13;10603:10;10623:11;10648:9;-1:-1:-1;;;;;10637:25:7;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10623:41;-1:-1:-1;10678:12:7;;:28;;;;-1:-1:-1;10694:12:7;;10678:28;10674:1052;;;10800:8;;10796:111;;10860:5;10841:14;10849:6;10860:5;10841:14;:::i;:::-;10834:22;;;;:3;:22;:::i;:::-;10833:32;;;;:::i;:::-;10828:37;-1:-1:-1;10883:9:7;;-1:-1:-1;;10883:9:7;10796:111;10674:1052;;;10927:12;;:28;;;;-1:-1:-1;10943:12:7;;;10927:28;10923:803;;;10975:8;;10971:177;;11003:12;11030:3;11019:7;:14;;:30;;11046:3;11019:30;;;11036:7;11019:30;11003:47;-1:-1:-1;11101:5:7;11082:14;11090:6;11101:5;11082:14;:::i;:::-;11074:23;;;;:4;:23;:::i;:::-;11073:33;;;;:::i;:::-;11068:38;-1:-1:-1;11124:9:7;;-1:-1:-1;;;11124:9:7;10971:177;11197:5;11178:14;11186:6;11197:5;11178:14;:::i;:::-;11167:26;;;;:7;:26;:::i;10923:803::-;11246:12;;;;;:28;;-1:-1:-1;11262:12:7;;11246:28;11242:484;;;11294:8;;11290:137;;11354:5;11335:14;11343:6;11354:5;11335:14;:::i;:::-;11328:22;;;;:3;:22;:::i;:::-;11327:32;;;;:::i;:::-;11322:37;;11395:2;11384:7;:13;;:28;;11405:7;11384:28;;;11400:2;11384:28;11377:35;;;;;;11290:137;11447:7;11440:14;;;;;;11242:484;11489:8;;11485:203;;11517:12;11544:3;11533:7;:14;;:30;;11560:3;11533:30;;;11550:7;11533:30;11517:47;-1:-1:-1;11615:5:7;11596:14;11604:6;11615:5;11596:14;:::i;:::-;11588:23;;;;:4;:23;:::i;:::-;11587:33;;;;:::i;:::-;11582:38;;11656:2;11645:7;:13;;:28;;11666:7;11645:28;;;11661:2;11645:28;11638:35;;;;;;;11242:484;10593:1139;;10417:1315;;;;;;:::o;22054:1461::-;22234:13;22249:11;22272:10;22309:9;-1:-1:-1;;;;;22298:25:7;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;22292:33;-1:-1:-1;22339:12:7;;:28;;;;-1:-1:-1;22355:12:7;;22339:28;22335:1174;;;22387:8;;22383:134;;22447:5;22428:14;22436:6;22447:5;22428:14;:::i;:::-;22421:22;;;;:3;:22;:::i;:::-;22420:32;;;;:::i;:::-;22415:37;;22484:2;22478;:8;;:18;;22494:2;22478:18;;22335:1174;22567:12;;:28;;;;-1:-1:-1;22583:12:7;;;22567:28;22563:946;;;22615:8;;22611:134;;22675:5;22656:14;22664:6;22675:5;22656:14;:::i;22611:134::-;22794:5;22775:14;22783:6;22794:5;22775:14;:::i;:::-;22764:26;;;;:7;:26;:::i;22563:946::-;22866:12;;;;;:28;;-1:-1:-1;22882:12:7;;22866:28;22862:647;;;22914:8;;22910:185;;22974:5;22955:14;22963:6;22974:5;22955:14;:::i;:::-;22948:22;;;;:3;:22;:::i;:::-;22947:32;;;;:::i;:::-;22942:37;;23008:2;23002;:8;;:18;;23018:2;23002:18;;;23013:2;23002:18;22997:23;;23052:7;23046:2;:13;;:28;;23072:2;23046:28;;;23062:7;23038:42;;;;;22910:185;23144:5;23125:14;23133:6;23144:5;23125:14;:::i;:::-;23114:26;;;;:7;:26;:::i;22862:647::-;23359:3;23353:2;:9;;:20;;23370:3;23353:20;;;-1:-1:-1;23365:2:7;23464:13;;;;:28;;23490:2;23464:28;;14995:1476;15157:13;15182:12;15204:11;15229:9;-1:-1:-1;;;;;15218:25:7;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15204:41;-1:-1:-1;15259:12:7;;:28;;;;-1:-1:-1;15275:12:7;;15259:28;15255:1210;;;15381:8;;15377:131;;15443:5;15424:14;15432:6;15443:5;15424:14;:::i;:::-;15417:22;;;;:3;:22;:::i;:::-;15416:32;;;;:::i;:::-;15409:39;-1:-1:-1;15473:9:7;;:20;;15489:4;15473:20;;;15485:1;15466:27;;;;;;15255:1210;15528:12;;:28;;;;-1:-1:-1;15544:12:7;;;15528:28;15524:941;;;15576:8;;15572:188;;15638:5;15619:14;15627:6;15638:5;15619:14;:::i;:::-;15612:22;;;;:3;:22;:::i;:::-;15611:32;;;;:::i;:::-;15604:39;;15676:7;15668:4;:15;;:32;;15696:4;15668:32;;;15686:7;15661:39;-1:-1:-1;15725:9:7;;:20;;15741:4;15725:20;;15572:188;15780:7;15773:14;;;;;;15524:941;15808:12;;;;;:28;;-1:-1:-1;15824:12:7;;15808:28;15804:661;;;15856:8;;15852:195;;15884:12;15906:7;15899:3;:14;;:30;;15922:7;15899:30;;;15916:3;15899:30;15884:45;-1:-1:-1;15982:5:7;15963:14;15971:6;15982:5;15963:14;:::i;:::-;15955:23;;;;:4;:23;:::i;:::-;15954:33;;;;:::i;:::-;15947:40;-1:-1:-1;16012:9:7;;:20;;16028:4;16012:20;;;16024:1;16005:27;;;;;;;15852:195;16098:5;16079:14;16087:6;16098:5;16079:14;:::i;:::-;16068:26;;;;:7;:26;:::i;15804:661::-;16179:8;;16175:252;;16207:12;16229:7;16222:3;:14;;:30;;16245:7;16222:30;;;16239:3;16222:30;16207:45;-1:-1:-1;16305:5:7;16286:14;16294:6;16305:5;16286:14;:::i;:::-;16278:23;;;;:4;:23;:::i;:::-;16277:33;;;;:::i;:::-;16270:40;;16343:7;16335:4;:15;;:32;;16363:4;16335:32;;;16353:7;16328:39;-1:-1:-1;16392:9:7;;:20;;16408:4;16392:20;;3432:197:0;3520:22;3528:4;3534:7;3520;:22::i;:::-;3515:108;;3565:47;;-1:-1:-1;;;3565:47:0;;-1:-1:-1;;;;;29944:32:13;;3565:47:0;;;29926:51:13;29993:18;;;29986:34;;;29899:18;;3565:47:0;29752:274:13;3515:108:0;3432:197;;:::o;57197:446:7:-;57338:17;-1:-1:-1;;;;;57371:23:7;;57367:270;;-1:-1:-1;57417:1:7;57410:8;;57367:270;57472:10;;:154;;57575:51;;-1:-1:-1;;;57575:51:7;;;;;38296:25:13;;;38337:18;;;38330:34;;;38407:14;;38400:22;38380:18;;;38373:50;-1:-1:-1;;;;;57575:29:7;;;;;38269:18:13;;57575:51:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;57472:154;;;57505:47;;-1:-1:-1;;;57505:47:7;;;;;32484:25:13;;;32552:14;;32545:22;32525:18;;;32518:50;-1:-1:-1;;;;;57505:32:7;;;;;32457:18:13;;57505:47:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;57449:177;;;;56022:366;56175:5;;56136:11;;-1:-1:-1;;;;;56175:5:7;56529:17;56572:8;;56163:59;;;;-1:-1:-1;56194:5:7;;56185:37;;-1:-1:-1;;;56185:37:7;;-1:-1:-1;;;;;17180:32:13;;;56185:37:7;;;17162:51:13;56194:5:7;;;;56185:28;;17135:18:13;;56185:37:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;56159:194;;;56263:5;;56254:39;;-1:-1:-1;;;56254:39:7;;-1:-1:-1;;;;;38870:32:13;;;56254:39:7;;;38852:51:13;38946:14;;38939:22;38919:18;;;38912:50;56238:13:7;;56263:5;;56254:21;;38825:18:13;;56254:39:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;56238:55;-1:-1:-1;1535:7:7;56315:15;56314:28;56315:15;;:6;:15;:::i;:::-;56314:28;;;;:::i;:::-;56307:35;;;;;56159:194;56369:12;56378:3;56369:6;:12;:::i;876:368:12:-;1102:51;;;-1:-1:-1;;;;;37699:15:13;;;1102:51:12;;;37681:34:13;37751:15;;;37731:18;;;37724:43;37783:18;;;;37776:34;;;1102:51:12;;;;;;;;;;37616:18:13;;;;1102:51:12;;;;;;;-1:-1:-1;;;;;1102:51:12;-1:-1:-1;;;1102:51:12;;;1091:63;;-1:-1:-1;;;;1091:10:12;;;;:63;;1102:51;1091:63;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1055:99;;;;1172:7;:57;;;;-1:-1:-1;1184:11:12;;:16;;:44;;;1215:4;1204:24;;;;;;;;;;;;:::i;:::-;1164:73;;;;-1:-1:-1;;;1164:73:12;;39721:2:13;1164:73:12;;;39703:21:13;39760:1;39740:18;;;39733:29;-1:-1:-1;;;39778:18:13;;;39771:33;39821:18;;1164:73:12;39519:326:13;1164:73:12;967:277;;876:368;;;;:::o;539:331::-;735:45;;;-1:-1:-1;;;;;29944:32:13;;;735:45:12;;;29926:51:13;29993:18;;;;29986:34;;;735:45:12;;;;;;;;;;29899:18:13;;;;735:45:12;;;;;;;-1:-1:-1;;;;;735:45:12;-1:-1:-1;;;735:45:12;;;724:57;;-1:-1:-1;;;;724:10:12;;;;:57;;735:45;724:57;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;688:93;;;;799:7;:57;;;;-1:-1:-1;811:11:12;;:16;;:44;;;842:4;831:24;;;;;;;;;;;;:::i;:::-;791:72;;;;-1:-1:-1;;;791:72:12;;40052:2:13;791:72:12;;;40034:21:13;40091:1;40071:18;;;40064:29;-1:-1:-1;;;40109:18:13;;;40102:32;40151:18;;791:72:12;39850:325:13;791:72:12;612:258;;539:331;;;:::o;44893:2804:7:-;45114:17;45133:8;45161:2;45157:1;:6;;;45153:61;;;45186:17;;-1:-1:-1;;;45186:17:7;;3773:10:13;3761:23;;45186:17:7;;;3743:42:13;3716:18;;45186:17:7;3599:192:13;45153:61:7;45235:6;45223:18;;45251:2394;45283:1;45271:9;:13;:74;;;;-1:-1:-1;45301:44:7;;-1:-1:-1;;;45301:44:7;;45331:6;;45301:44;;;40546:41:13;40603:18;;;40596:34;;;-1:-1:-1;;;;;45301:29:7;;;;;40519:18:13;;45301:44:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;45300:45;45271:74;:95;;;;;45365:1;45361:5;;:1;:5;;;45271:95;45251:2394;;;45607:82;;-1:-1:-1;;;45607:82:7;;45664:6;;45607:82;;;40837:41:13;40894:18;;;40887:34;;;40937:18;;;40930:34;;;45559:14:7;;;;;;-1:-1:-1;;;;;45607:56:7;;;;;40810:18:13;;45607:82:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;45558:131;;;;;;45769:8;45756:9;:21;45752:1883;;45830:55;45858:4;45864:9;45875;45830:27;:55::i;:::-;45919:193;;-1:-1:-1;;;45919:193:7;;;41681:23:13;;45919:193:7;;;41663:42:13;45999:6:7;;41721:18:13;;;41714:50;-1:-1:-1;;;;;41800:32:13;;;41780:18;;;41773:60;41849:18;;;41842:34;;;41920:14;;41913:22;41892:19;;;41885:51;45903:13:7;;45919:29;;;;;;41635:19:13;;45919:193:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;45903:209;;46172:49;46180:9;46191:4;46197:5;46204:9;46215:5;46172:7;:49::i;:::-;46288:260;46322:9;46353:7;46382:5;46409:9;46440:5;46467;46494:9;46525:5;46288:260;;;;;;;;;;;;;:::i;:::-;;;;;;;;46620:1;46623;46612:13;;;;;;;;;;45752:1883;46691:8;46703:1;46691:13;46687:948;;46724:3;;;:::i;:::-;;;46745:8;;;;;46687:948;46846:21;46859:8;46846:21;;:::i;:::-;;;46885:54;46913:4;46919:9;46930:8;46885:27;:54::i;:::-;46973:192;;-1:-1:-1;;;46973:192:7;;;41681:23:13;;46973:192:7;;;41663:42:13;47053:6:7;;41721:18:13;;;41714:50;-1:-1:-1;;;;;41800:32:13;;;41780:18;;;41773:60;41849:18;;;41842:34;;;41920:14;;41913:22;41892:19;;;41885:51;46957:13:7;;46973:29;;;;;;41635:19:13;;46973:192:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;46957:208;;47225:48;47233:9;47244:4;47250:5;47257:8;47267:5;47225:7;:48::i;:::-;47340:259;47374:9;47405:7;47434:5;47461:9;47492:5;47519;47546:8;47576:5;47340:259;;;;;;;;;;;;;:::i;:::-;;;;;;;;47617:3;;;:::i;:::-;;;46828:807;45377:2268;;;45251:2394;;;-1:-1:-1;47658:1:7;44893:2804;;;;;;;;;;;;:::o;44362:436::-;44531:9;44580:5;44576:197;;;44606:60;;-1:-1:-1;;;44606:60:7;;-1:-1:-1;;;;;42952:32:13;;;44606:60:7;;;42934:51:13;43001:18;;;42994:34;;;43044:18;;;43037:34;;;44606:30:7;;;;;42907:18:13;;44606:60:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;44601:65;;44576:197;;;44702:60;;-1:-1:-1;;;44702:60:7;;-1:-1:-1;;;;;42952:32:13;;;44702:60:7;;;42934:51:13;43001:18;;;42994:34;;;43044:18;;;43037:34;;;44702:30:7;;;;;42907:18:13;;44702:60:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;44697:65;44362:436;-1:-1:-1;;;;;;44362:436:7:o;53096:559::-;53284:5;;-1:-1:-1;;;;;53284:5:7;56529:17;56572:8;;53272:52;;;;;53303:5;;;;;;;;;-1:-1:-1;;;;;53303:5:7;-1:-1:-1;;;;;53294:28:7;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;53272:67;;;;;53338:1;53328:7;:11;53272:67;53255:394;;;53458:5;;53449:189;;-1:-1:-1;;;53449:189:7;;-1:-1:-1;;;;;43419:15:13;;;53449:189:7;;;43401:34:13;43471:15;;;43451:18;;;43444:43;43530:14;;43523:22;43503:18;;;43496:50;53566:10:7;43562:18:13;;;43555:43;43635:15;;;43614:19;;;43607:44;43667:19;;;43660:35;;;53458:5:7;;;;53449:27;;43335:19:13;;53449:189:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53096:559;;;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:127:13:-;75:10;70:3;66:20;63:1;56:31;106:4;103:1;96:15;130:4;127:1;120:15;146:286;204:6;257:2;245:9;236:7;232:23;228:32;225:52;;;273:1;270;263:12;225:52;299:23;;-1:-1:-1;;;;;;351:32:13;;341:43;;331:71;;398:1;395;388:12;629:131;-1:-1:-1;;;;;704:31:13;;694:42;;684:70;;750:1;747;740:12;765:118;851:5;844:13;837:21;830:5;827:32;817:60;;873:1;870;863:12;888:121;973:10;966:5;962:22;955:5;952:33;942:61;;999:1;996;989:12;1014:732;1105:6;1113;1121;1129;1137;1190:3;1178:9;1169:7;1165:23;1161:33;1158:53;;;1207:1;1204;1197:12;1158:53;1246:9;1233:23;1265:31;1290:5;1265:31;:::i;:::-;1315:5;-1:-1:-1;1372:2:13;1357:18;;1344:32;1385:33;1344:32;1385:33;:::i;:::-;1437:7;-1:-1:-1;1496:2:13;1481:18;;1468:32;1509:30;1468:32;1509:30;:::i;:::-;1558:7;-1:-1:-1;1612:2:13;1597:18;;1584:32;;-1:-1:-1;1668:3:13;1653:19;;1640:33;1682:32;1640:33;1682:32;:::i;:::-;1733:7;1723:17;;;1014:732;;;;;;;;:::o;1984:697::-;2201:2;2253:21;;;2323:13;;2226:18;;;2345:22;;;2172:4;;2201:2;2424:15;;;;2398:2;2383:18;;;2172:4;2467:188;2481:6;2478:1;2475:13;2467:188;;;2530:43;2569:3;2560:6;2554:13;1826:12;;-1:-1:-1;;;;;1822:38:13;1810:51;;1910:4;1899:16;;;1893:23;1877:14;;;1870:47;1966:4;1955:16;;;1949:23;1933:14;;1926:47;1751:228;2530:43;2630:15;;;;2602:4;2593:14;;;;;2503:1;2496:9;2467:188;;;-1:-1:-1;2672:3:13;;1984:697;-1:-1:-1;;;;;;1984:697:13:o;2686:663::-;2768:6;2776;2784;2792;2845:3;2833:9;2824:7;2820:23;2816:33;2813:53;;;2862:1;2859;2852:12;2813:53;2901:9;2888:23;2920:31;2945:5;2920:31;:::i;:::-;2970:5;-1:-1:-1;3027:2:13;3012:18;;2999:32;3040:33;2999:32;3040:33;:::i;:::-;3092:7;-1:-1:-1;3151:2:13;3136:18;;3123:32;3164:30;3123:32;3164:30;:::i;:::-;3213:7;-1:-1:-1;3272:2:13;3257:18;;3244:32;3285;3244;3285;:::i;:::-;2686:663;;;;-1:-1:-1;2686:663:13;;-1:-1:-1;;2686:663:13:o;3354:240::-;1826:12;;-1:-1:-1;;;;;1822:38:13;1810:51;;1910:4;1899:16;;;1893:23;1877:14;;;1870:47;1966:4;1955:16;;;1949:23;1933:14;;;1926:47;3534:2;3519:18;;3546:42;1751:228;3796:384;3862:6;3870;3923:2;3911:9;3902:7;3898:23;3894:32;3891:52;;;3939:1;3936;3929:12;3891:52;3978:9;3965:23;3997:30;4021:5;3997:30;:::i;:::-;4046:5;-1:-1:-1;4103:2:13;4088:18;;4075:32;4116;4075;4116;:::i;:::-;4167:7;4157:17;;;3796:384;;;;;:::o;4185:180::-;4244:6;4297:2;4285:9;4276:7;4272:23;4268:32;4265:52;;;4313:1;4310;4303:12;4265:52;-1:-1:-1;4336:23:13;;4185:180;-1:-1:-1;4185:180:13:o;4552:667::-;4636:6;4644;4652;4660;4713:3;4701:9;4692:7;4688:23;4684:33;4681:53;;;4730:1;4727;4720:12;4681:53;4769:9;4756:23;4788:31;4813:5;4788:31;:::i;:::-;4838:5;-1:-1:-1;4895:2:13;4880:18;;4867:32;4908:33;4867:32;4908:33;:::i;:::-;4960:7;-1:-1:-1;5019:2:13;5004:18;;4991:32;5032;4991;5032;:::i;5224:315::-;5292:6;5300;5353:2;5341:9;5332:7;5328:23;5324:32;5321:52;;;5369:1;5366;5359:12;5321:52;5405:9;5392:23;5382:33;;5465:2;5454:9;5450:18;5437:32;5478:31;5503:5;5478:31;:::i;5544:248::-;5612:6;5620;5673:2;5661:9;5652:7;5648:23;5644:32;5641:52;;;5689:1;5686;5679:12;5641:52;-1:-1:-1;;5712:23:13;;;5782:2;5767:18;;;5754:32;;-1:-1:-1;5544:248:13:o;5797:632::-;5968:2;6020:21;;;6090:13;;5993:18;;;6112:22;;;5939:4;;5968:2;6191:15;;;;6165:2;6150:18;;;5939:4;6234:169;6248:6;6245:1;6242:13;6234:169;;;6309:13;;6297:26;;6378:15;;;;6343:12;;;;6270:1;6263:9;6234:169;;6434:388;6502:6;6510;6563:2;6551:9;6542:7;6538:23;6534:32;6531:52;;;6579:1;6576;6569:12;6531:52;6618:9;6605:23;6637:31;6662:5;6637:31;:::i;:::-;6687:5;-1:-1:-1;6744:2:13;6729:18;;6716:32;6757:33;6716:32;6757:33;:::i;7080:127::-;7141:10;7136:3;7132:20;7129:1;7122:31;7172:4;7169:1;7162:15;7196:4;7193:1;7186:15;7212:257;7284:4;7278:11;;;7316:17;;-1:-1:-1;;;;;7348:34:13;;7384:22;;;7345:62;7342:88;;;7410:18;;:::i;:::-;7446:4;7439:24;7212:257;:::o;7474:275::-;7545:2;7539:9;7610:2;7591:13;;-1:-1:-1;;7587:27:13;7575:40;;-1:-1:-1;;;;;7630:34:13;;7666:22;;;7627:62;7624:88;;;7692:18;;:::i;:::-;7728:2;7721:22;7474:275;;-1:-1:-1;7474:275:13:o;7754:183::-;7814:4;-1:-1:-1;;;;;7839:6:13;7836:30;7833:56;;;7869:18;;:::i;:::-;-1:-1:-1;7914:1:13;7910:14;7926:4;7906:25;;7754:183::o;7942:743::-;7996:5;8049:3;8042:4;8034:6;8030:17;8026:27;8016:55;;8067:1;8064;8057:12;8016:55;8103:6;8090:20;8129:4;8153:60;8169:43;8209:2;8169:43;:::i;:::-;8153:60;:::i;:::-;8235:3;8259:2;8254:3;8247:15;8287:4;8282:3;8278:14;8271:21;;8344:4;8338:2;8335:1;8331:10;8323:6;8319:23;8315:34;8301:48;;8372:3;8364:6;8361:15;8358:35;;;8389:1;8386;8379:12;8358:35;8425:4;8417:6;8413:17;8439:217;8455:6;8450:3;8447:15;8439:217;;;8535:3;8522:17;8552:31;8577:5;8552:31;:::i;:::-;8596:18;;8634:12;;;;8472;;8439:217;;;-1:-1:-1;8674:5:13;7942:743;-1:-1:-1;;;;;;7942:743:13:o;8690:741::-;8743:5;8796:3;8789:4;8781:6;8777:17;8773:27;8763:55;;8814:1;8811;8804:12;8763:55;8850:6;8837:20;8876:4;8900:60;8916:43;8956:2;8916:43;:::i;8900:60::-;8982:3;9006:2;9001:3;8994:15;9034:4;9029:3;9025:14;9018:21;;9091:4;9085:2;9082:1;9078:10;9070:6;9066:23;9062:34;9048:48;;9119:3;9111:6;9108:15;9105:35;;;9136:1;9133;9126:12;9105:35;9172:4;9164:6;9160:17;9186:216;9202:6;9197:3;9194:15;9186:216;;;9282:3;9269:17;9299:30;9323:5;9299:30;:::i;:::-;9342:18;;9380:12;;;;9219;;9186:216;;9436:1658;9618:6;9626;9634;9642;9695:3;9683:9;9674:7;9670:23;9666:33;9663:53;;;9712:1;9709;9702:12;9663:53;9752:9;9739:23;-1:-1:-1;;;;;9822:2:13;9814:6;9811:14;9808:34;;;9838:1;9835;9828:12;9808:34;9861:61;9914:7;9905:6;9894:9;9890:22;9861:61;:::i;:::-;9851:71;;9941:2;9931:12;;9996:2;9985:9;9981:18;9968:32;10025:2;10015:8;10012:16;10009:36;;;10041:1;10038;10031:12;10009:36;10064:63;10119:7;10108:8;10097:9;10093:24;10064:63;:::i;:::-;10054:73;;;10180:2;10169:9;10165:18;10152:32;10209:2;10199:8;10196:16;10193:36;;;10225:1;10222;10215:12;10193:36;10248:24;;10303:4;10295:13;;10291:27;-1:-1:-1;10281:55:13;;10332:1;10329;10322:12;10281:55;10368:2;10355:16;10391:60;10407:43;10447:2;10407:43;:::i;10391:60::-;10485:15;;;10567:1;10563:10;;;;10555:19;;10551:28;;;10516:12;;;;10591:19;;;10588:39;;;10623:1;10620;10613:12;10588:39;10647:11;;;;10667:214;10683:6;10678:3;10675:15;10667:214;;;10763:3;10750:17;10780:28;10802:5;10780:28;:::i;:::-;10821:18;;10700:12;;;;10859;;;;10667:214;;;10900:5;-1:-1:-1;;;;10958:2:13;10943:18;;10930:32;;-1:-1:-1;10974:16:13;;;10971:36;;;11003:1;11000;10993:12;10971:36;;11026:62;11080:7;11069:8;11058:9;11054:24;11026:62;:::i;:::-;11016:72;;;9436:1658;;;;;;;:::o;11099:250::-;11184:1;11194:113;11208:6;11205:1;11202:13;11194:113;;;11284:11;;;11278:18;11265:11;;;11258:39;11230:2;11223:10;11194:113;;;-1:-1:-1;;11341:1:13;11323:16;;11316:27;11099:250::o;11354:1014::-;11516:4;11545:2;11585;11574:9;11570:18;11615:2;11604:9;11597:21;11638:6;11673;11667:13;11704:6;11696;11689:22;11742:2;11731:9;11727:18;11720:25;;11804:2;11794:6;11791:1;11787:14;11776:9;11772:30;11768:39;11754:53;;11842:2;11834:6;11830:15;11863:1;11873:466;11887:6;11884:1;11881:13;11873:466;;;11952:22;;;-1:-1:-1;;11948:36:13;11936:49;;12008:13;;12050:9;;12072:24;;;12109:74;12050:9;12157:15;;;12144:11;;;12109:74;:::i;:::-;12249:2;12226:17;-1:-1:-1;;12222:31:13;12210:44;;;;12206:53;;;-1:-1:-1;12317:12:13;;;;12282:15;;;;11909:1;11902:9;11873:466;;;-1:-1:-1;12356:6:13;;11354:1014;-1:-1:-1;;;;;;;11354:1014:13:o;12373:943::-;12482:6;12490;12498;12506;12514;12522;12530;12583:3;12571:9;12562:7;12558:23;12554:33;12551:53;;;12600:1;12597;12590:12;12551:53;12639:9;12626:23;12658:31;12683:5;12658:31;:::i;:::-;12708:5;-1:-1:-1;12765:2:13;12750:18;;12737:32;12778:33;12737:32;12778:33;:::i;:::-;12830:7;-1:-1:-1;12884:2:13;12869:18;;12856:32;;-1:-1:-1;12935:2:13;12920:18;;12907:32;;-1:-1:-1;12991:3:13;12976:19;;12963:33;13005:30;12963:33;13005:30;:::i;:::-;13054:7;-1:-1:-1;13113:3:13;13098:19;;13085:33;13127:32;13085:33;13127:32;:::i;:::-;13178:7;-1:-1:-1;13237:3:13;13222:19;;13209:33;13251;13209;13251;:::i;:::-;13303:7;13293:17;;;12373:943;;;;;;;;;;:::o;13842:891::-;13926:6;13957:2;14000;13988:9;13979:7;13975:23;13971:32;13968:52;;;14016:1;14013;14006:12;13968:52;14056:9;14043:23;-1:-1:-1;;;;;14081:6:13;14078:30;14075:50;;;14121:1;14118;14111:12;14075:50;14144:22;;14197:4;14189:13;;14185:27;-1:-1:-1;14175:55:13;;14226:1;14223;14216:12;14175:55;14262:2;14249:16;14285:60;14301:43;14341:2;14301:43;:::i;14285:60::-;14379:15;;;14461:1;14457:10;;;;14449:19;;14445:28;;;14410:12;;;;14485:19;;;14482:39;;;14517:1;14514;14507:12;14482:39;14541:11;;;;14561:142;14577:6;14572:3;14569:15;14561:142;;;14643:17;;14631:30;;14594:12;;;;14681;;;;14561:142;;;14722:5;13842:891;-1:-1:-1;;;;;;;13842:891:13:o;14738:872::-;14837:6;14845;14853;14861;14869;14877;14930:3;14918:9;14909:7;14905:23;14901:33;14898:53;;;14947:1;14944;14937:12;14898:53;14986:9;14973:23;15005:31;15030:5;15005:31;:::i;:::-;15055:5;-1:-1:-1;15112:2:13;15097:18;;15084:32;15125:33;15084:32;15125:33;:::i;:::-;15177:7;-1:-1:-1;15236:2:13;15221:18;;15208:32;15249:30;15208:32;15249:30;:::i;:::-;15298:7;-1:-1:-1;15352:2:13;15337:18;;15324:32;;-1:-1:-1;15408:3:13;15393:19;;15380:33;15422:32;15380:33;15422:32;:::i;:::-;15473:7;-1:-1:-1;15532:3:13;15517:19;;15504:33;15546:32;15504:33;15546:32;:::i;:::-;15597:7;15587:17;;;14738:872;;;;;;;;:::o;15615:663::-;15697:6;15705;15713;15721;15774:3;15762:9;15753:7;15749:23;15745:33;15742:53;;;15791:1;15788;15781:12;15742:53;15830:9;15817:23;15849:31;15874:5;15849:31;:::i;:::-;15899:5;-1:-1:-1;15956:2:13;15941:18;;15928:32;15969:30;15928:32;15969:30;:::i;:::-;16018:7;-1:-1:-1;16077:2:13;16062:18;;16049:32;16090;16049;16090;:::i;:::-;16141:7;-1:-1:-1;16200:2:13;16185:18;;16172:32;16213:33;16172:32;16213:33;:::i;16283:247::-;16342:6;16395:2;16383:9;16374:7;16370:23;16366:32;16363:52;;;16411:1;16408;16401:12;16363:52;16450:9;16437:23;16469:31;16494:5;16469:31;:::i;17224:592::-;17307:6;17315;17323;17331;17384:3;17372:9;17363:7;17359:23;17355:33;17352:53;;;17401:1;17398;17391:12;17352:53;17440:9;17427:23;17459:31;17484:5;17459:31;:::i;:::-;17509:5;-1:-1:-1;17566:2:13;17551:18;;17538:32;17579:33;17538:32;17579:33;:::i;:::-;17631:7;-1:-1:-1;17685:2:13;17670:18;;17657:32;;-1:-1:-1;17741:2:13;17726:18;;17713:32;17754:30;17713:32;17754:30;:::i;17821:874::-;17921:6;17929;17937;17945;17953;17961;18014:3;18002:9;17993:7;17989:23;17985:33;17982:53;;;18031:1;18028;18021:12;17982:53;18070:9;18057:23;18089:31;18114:5;18089:31;:::i;:::-;18139:5;-1:-1:-1;18196:2:13;18181:18;;18168:32;18209:33;18168:32;18209:33;:::i;:::-;18261:7;-1:-1:-1;18315:2:13;18300:18;;18287:32;;-1:-1:-1;18371:2:13;18356:18;;18343:32;18384:30;18343:32;18384:30;:::i;:::-;18433:7;-1:-1:-1;18492:3:13;18477:19;;18464:33;18506:32;18464:33;18506:32;:::i;:::-;18557:7;-1:-1:-1;18616:3:13;18601:19;;18588:33;18630;18588;18630;:::i;18700:803::-;18790:6;18798;18806;18814;18822;18875:3;18863:9;18854:7;18850:23;18846:33;18843:53;;;18892:1;18889;18882:12;18843:53;18931:9;18918:23;18950:31;18975:5;18950:31;:::i;:::-;19000:5;-1:-1:-1;19057:2:13;19042:18;;19029:32;19070:33;19029:32;19070:33;:::i;:::-;19122:7;-1:-1:-1;19181:2:13;19166:18;;19153:32;19194:30;19153:32;19194:30;:::i;:::-;19243:7;-1:-1:-1;19302:2:13;19287:18;;19274:32;19315;19274;19315;:::i;:::-;19366:7;-1:-1:-1;19425:3:13;19410:19;;19397:33;19439:32;19397:33;19439:32;:::i;19508:647::-;19677:2;19729:21;;;19799:13;;19702:18;;;19821:22;;;19648:4;;19677:2;19900:15;;;;19874:2;19859:18;;;19648:4;19943:186;19957:6;19954:1;19951:13;19943:186;;;20022:13;;20037:10;20018:30;20006:43;;20104:15;;;;20069:12;;;;19979:1;19972:9;19943:186;;20160:842;20375:2;20427:21;;;20497:13;;20400:18;;;20519:22;;;20346:4;;20375:2;20560;;20578:18;;;;20619:15;;;20346:4;20662:314;20676:6;20673:1;20670:13;20662:314;;;20735:13;;20819:9;;-1:-1:-1;;;;;20815:18:13;;;20803:31;;20878:11;;;20872:18;20868:27;20854:12;;;20847:49;20916:12;;;;20951:15;;;;20788:1;20691:9;20662:314;;;-1:-1:-1;20993:3:13;;20160:842;-1:-1:-1;;;;;;;20160:842:13:o;21007:456::-;21084:6;21092;21100;21153:2;21141:9;21132:7;21128:23;21124:32;21121:52;;;21169:1;21166;21159:12;21121:52;21208:9;21195:23;21227:31;21252:5;21227:31;:::i;:::-;21277:5;-1:-1:-1;21334:2:13;21319:18;;21306:32;21347:33;21306:32;21347:33;:::i;:::-;21007:456;;21399:7;;-1:-1:-1;;;21453:2:13;21438:18;;;;21425:32;;21007:456::o;21468:529::-;21545:6;21553;21561;21614:2;21602:9;21593:7;21589:23;21585:32;21582:52;;;21630:1;21627;21620:12;21582:52;21669:9;21656:23;21688:31;21713:5;21688:31;:::i;:::-;21738:5;-1:-1:-1;21795:2:13;21780:18;;21767:32;21808:33;21767:32;21808:33;:::i;:::-;21860:7;-1:-1:-1;21919:2:13;21904:18;;21891:32;21932:33;21891:32;21932:33;:::i;:::-;21984:7;21974:17;;;21468:529;;;;;:::o;22311:732::-;22402:6;22410;22418;22426;22434;22487:3;22475:9;22466:7;22462:23;22458:33;22455:53;;;22504:1;22501;22494:12;22455:53;22543:9;22530:23;22562:31;22587:5;22562:31;:::i;:::-;22612:5;-1:-1:-1;22664:2:13;22649:18;;22636:32;;-1:-1:-1;22720:2:13;22705:18;;22692:32;22733:30;22692:32;22733:30;:::i;:::-;22782:7;-1:-1:-1;22841:2:13;22826:18;;22813:32;22854;22813;22854;:::i;:::-;22905:7;-1:-1:-1;22964:3:13;22949:19;;22936:33;22978;22936;22978;:::i;23397:599::-;23460:5;23508:4;23496:9;23491:3;23487:19;23483:30;23480:50;;;23526:1;23523;23516:12;23480:50;23559:2;23553:9;23601:4;23593:6;23589:17;23672:6;23660:10;23657:22;-1:-1:-1;;;;;23624:10:13;23621:34;23618:62;23615:88;;;23683:18;;:::i;:::-;23723:10;23719:2;23712:22;;23752:6;23743:15;;23788:9;23782:16;23807:33;23832:7;23807:33;:::i;:::-;23864:7;23856:6;23849:23;;23926:2;23915:9;23911:18;23905:25;23900:2;23892:6;23888:15;23881:50;23985:2;23974:9;23970:18;23964:25;23959:2;23951:6;23947:15;23940:50;;23397:599;;;;:::o;24001:968::-;24119:6;24150:2;24193;24181:9;24172:7;24168:23;24164:32;24161:52;;;24209:1;24206;24199:12;24161:52;24242:9;24236:16;-1:-1:-1;;;;;24267:6:13;24264:30;24261:50;;;24307:1;24304;24297:12;24261:50;24330:22;;24383:4;24375:13;;24371:27;-1:-1:-1;24361:55:13;;24412:1;24409;24402:12;24361:55;24441:2;24435:9;24464:60;24480:43;24520:2;24480:43;:::i;24464:60::-;24546:3;24570:2;24565:3;24558:15;24598:2;24593:3;24589:12;24582:19;;24620:4;24675:2;24667:4;24663:2;24659:13;24655:2;24651:22;24647:31;24633:45;;24701:7;24693:6;24690:19;24687:39;;;24722:1;24719;24712:12;24687:39;24754:2;24750;24746:11;24735:22;;24766:173;24782:6;24777:3;24774:15;24766:173;;;24848:48;24888:7;24883:3;24848:48;:::i;:::-;24836:61;;24799:12;;;;24917;;;;24766:173;;;-1:-1:-1;24958:5:13;24001:968;-1:-1:-1;;;;;;;24001:968:13:o;25252:245::-;25345:6;25398:2;25386:9;25377:7;25373:23;25369:32;25366:52;;;25414:1;25411;25404:12;25366:52;25437:54;25483:7;25472:9;25437:54;:::i;25781:1335::-;25898:6;25929:2;25972;25960:9;25951:7;25947:23;25943:32;25940:52;;;25988:1;25985;25978:12;25940:52;26021:9;26015:16;-1:-1:-1;;;;;26046:6:13;26043:30;26040:50;;;26086:1;26083;26076:12;26040:50;26109:22;;26162:4;26154:13;;26150:27;-1:-1:-1;26140:55:13;;26191:1;26188;26181:12;26140:55;26220:2;26214:9;26243:60;26259:43;26299:2;26259:43;:::i;26243:60::-;26337:15;;;26419:1;26415:10;;;;26407:19;;26403:28;;;26368:12;;;;26443:19;;;26440:39;;;26475:1;26472;26465:12;26440:39;26499:11;;;;26519:567;26535:6;26530:3;26527:15;26519:567;;;26617:4;26611:3;26602:7;26598:17;26594:28;26591:118;;;26663:1;26692:2;26688;26681:14;26591:118;26735:22;;:::i;:::-;26791:3;26785:10;26808:33;26833:7;26808:33;:::i;:::-;26854:22;;26910:12;;;26904:19;26936:33;26904:19;26936:33;:::i;:::-;26989:14;;;26982:31;27026:18;;26561:4;26552:14;;;;;27064:12;;;;26519:567;;27121:127;27182:10;27177:3;27173:20;27170:1;27163:31;27213:4;27210:1;27203:15;27237:4;27234:1;27227:15;27253:184;27323:6;27376:2;27364:9;27355:7;27351:23;27347:32;27344:52;;;27392:1;27389;27382:12;27344:52;-1:-1:-1;27415:16:13;;27253:184;-1:-1:-1;27253:184:13:o;27442:245::-;27521:6;27529;27582:2;27570:9;27561:7;27557:23;27553:32;27550:52;;;27598:1;27595;27588:12;27550:52;-1:-1:-1;;27621:16:13;;27677:2;27662:18;;;27656:25;27621:16;;27656:25;;-1:-1:-1;27442:245:13:o;27692:127::-;27753:10;27748:3;27744:20;27741:1;27734:31;27784:4;27781:1;27774:15;27808:4;27805:1;27798:15;27824:201;27862:3;27890:10;27935:2;27928:5;27924:14;27962:2;27953:7;27950:15;27947:41;;27968:18;;:::i;:::-;28017:1;28004:15;;27824:201;-1:-1:-1;;;27824:201:13:o;28030:1717::-;28135:6;28166:2;28209;28197:9;28188:7;28184:23;28180:32;28177:52;;;28225:1;28222;28215:12;28177:52;28258:9;28252:16;-1:-1:-1;;;;;28328:2:13;28320:6;28317:14;28314:34;;;28344:1;28341;28334:12;28314:34;28382:6;28371:9;28367:22;28357:32;;28408:4;28450:7;28443:4;28439:2;28435:13;28431:27;28421:55;;28472:1;28469;28462:12;28421:55;28501:2;28495:9;28524:60;28540:43;28580:2;28540:43;:::i;28524:60::-;28618:15;;;28700:1;28696:10;;;;28688:19;;28684:28;;;28649:12;;;;28724:19;;;28721:39;;;28756:1;28753;28746:12;28721:39;28788:2;28784;28780:11;28800:917;28816:6;28811:3;28808:15;28800:917;;;28895:3;28889:10;28931:2;28918:11;28915:19;28912:109;;;28975:1;29004:2;29000;28993:14;28912:109;29044:20;;29099:2;29091:11;;29087:25;-1:-1:-1;29077:123:13;;29154:1;29183:2;29179;29172:14;29077:123;29237:2;29233;29229:11;29223:18;29265:2;29290;29286;29283:10;29280:36;;;29296:18;;:::i;:::-;29342:51;29366:11;;;-1:-1:-1;;29362:25:13;29358:34;;29342:51;:::i;:::-;29420:2;29413:5;29406:17;29465:7;29459:3;29454:2;29450;29446:11;29442:21;29439:34;29436:127;;;29515:1;29545:3;29540;29533:16;29436:127;29576:68;29641:2;29636;29629:5;29625:14;29619:3;29615:2;29611:12;29576:68;:::i;:::-;29657:18;;-1:-1:-1;;;29695:12:13;;;;28833;;28800:917;;;-1:-1:-1;29736:5:13;28030:1717;-1:-1:-1;;;;;;;;;28030:1717:13:o;30031:689::-;-1:-1:-1;;;;;30395:15:13;;;30377:34;;30459:10;30447:23;;;;30442:2;30427:18;;30420:51;30507:15;;;;30502:2;30487:18;;30480:43;30566:14;;30559:22;30554:2;30539:18;;30532:50;30613:3;30598:19;;30591:35;30357:3;30642:19;;30635:35;;;;30701:3;30686:19;;30679:35;;;;30326:3;30311:19;;30031:689::o;31174:881::-;31269:6;31300:2;31343;31331:9;31322:7;31318:23;31314:32;31311:52;;;31359:1;31356;31349:12;31311:52;31392:9;31386:16;-1:-1:-1;;;;;31417:6:13;31414:30;31411:50;;;31457:1;31454;31447:12;31411:50;31480:22;;31533:4;31525:13;;31521:27;-1:-1:-1;31511:55:13;;31562:1;31559;31552:12;31511:55;31591:2;31585:9;31614:60;31630:43;31670:2;31630:43;:::i;31614:60::-;31708:15;;;31790:1;31786:10;;;;31778:19;;31774:28;;;31739:12;;;;31814:19;;;31811:39;;;31846:1;31843;31836:12;31811:39;31870:11;;;;31890:135;31906:6;31901:3;31898:15;31890:135;;;31972:10;;31960:23;;31923:12;;;;32003;;;;31890:135;;32060:251;32130:6;32183:2;32171:9;32162:7;32158:23;32154:32;32151:52;;;32199:1;32196;32189:12;32151:52;32231:9;32225:16;32250:31;32275:5;32250:31;:::i;32579:172::-;32646:10;32676;;;32688;;;32672:27;;32711:11;;;32708:37;;;32725:18;;:::i;32756:168::-;32829:9;;;32860;;32877:15;;;32871:22;;32857:37;32847:71;;32898:18;;:::i;32929:217::-;32969:1;32995;32985:132;;33039:10;33034:3;33030:20;33027:1;33020:31;33074:4;33071:1;33064:15;33102:4;33099:1;33092:15;32985:132;-1:-1:-1;33131:9:13;;32929:217::o;33528:954::-;33622:6;33653:2;33696;33684:9;33675:7;33671:23;33667:32;33664:52;;;33712:1;33709;33702:12;33664:52;33745:9;33739:16;-1:-1:-1;;;;;33770:6:13;33767:30;33764:50;;;33810:1;33807;33800:12;33764:50;33833:22;;33886:4;33878:13;;33874:27;-1:-1:-1;33864:55:13;;33915:1;33912;33905:12;33864:55;33944:2;33938:9;33967:60;33983:43;34023:2;33983:43;:::i;33967:60::-;34061:15;;;34143:1;34139:10;;;;34131:19;;34127:28;;;34092:12;;;;34167:19;;;34164:39;;;34199:1;34196;34189:12;34164:39;34223:11;;;;34243:209;34259:6;34254:3;34251:15;34243:209;;;34332:3;34326:10;34349:30;34373:5;34349:30;:::i;:::-;34392:18;;34276:12;;;;34430;;;;34243:209;;35699:273;35767:6;35820:2;35808:9;35799:7;35795:23;35791:32;35788:52;;;35836:1;35833;35826:12;35788:52;35868:9;35862:16;35918:4;35911:5;35907:16;35900:5;35897:27;35887:55;;35938:1;35935;35928:12;36524:175;36592:10;36635;;;36623;;;36619:27;;36658:12;;;36655:38;;;36673:18;;:::i;36918:385::-;36997:6;37005;37058:2;37046:9;37037:7;37033:23;37029:32;37026:52;;;37074:1;37071;37064:12;37026:52;37106:9;37100:16;37125:31;37150:5;37125:31;:::i;:::-;37225:2;37210:18;;37204:25;37175:5;;-1:-1:-1;37238:33:13;37204:25;37238:33;:::i;37308:128::-;37375:9;;;37396:11;;;37393:37;;;37410:18;;:::i;38434:245::-;38501:6;38554:2;38542:9;38533:7;38529:23;38525:32;38522:52;;;38570:1;38567;38560:12;38522:52;38602:9;38596:16;38621:28;38643:5;38621:28;:::i;38973:249::-;39042:6;39095:2;39083:9;39074:7;39070:23;39066:32;39063:52;;;39111:1;39108;39101:12;39063:52;39143:9;39137:16;39162:30;39186:5;39162:30;:::i;39227:287::-;39356:3;39394:6;39388:13;39410:66;39469:6;39464:3;39457:4;39449:6;39445:17;39410:66;:::i;:::-;39492:16;;;;;39227:287;-1:-1:-1;;39227:287:13:o;40975:438::-;41059:6;41067;41075;41128:2;41116:9;41107:7;41103:23;41099:32;41096:52;;;41144:1;41141;41134:12;41096:52;41176:9;41170:16;41195:30;41219:5;41195:30;:::i;:::-;41289:2;41274:18;;41268:25;41338:2;41323:18;;41317:25;41244:5;;-1:-1:-1;41268:25:13;-1:-1:-1;41351:30:13;41317:25;41351:30;:::i;41947:780::-;-1:-1:-1;;;;;42333:15:13;;;42315:34;;42397:10;42385:23;;;;42380:2;42365:18;;42358:51;42452:14;;42445:22;42440:2;42425:18;;42418:50;42504:15;;;42499:2;42484:18;;42477:43;42557:15;;42551:3;42536:19;;42529:44;42295:3;42589:19;;42582:35;;;;42648:3;42633:19;;42626:35;;;;42705:14;;42698:22;42692:3;42677:19;;42670:51;42264:3;42249:19;;41947:780::o

Swarm Source

ipfs://2962d1607e69abef126eac6c084f939ef7fa86178f1b62ae67536f60758ae2d7

Block Transaction Gas Used Reward
view all blocks sequenced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.