Contract 0xd610457e0904301192cb660616d97e07a853e453

Contract Overview

Balance:
0 BNB
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x622b84d797c22e0012e4443361961828b94ba8f6c3580d248806844fbbc0de5c0x6080604083980502021-04-29 8:19:01147 days 23 hrs ago0x20000b9b01e93a39db9d286e9264eff7f2af16e9 IN  Contract Creation0 BNB0.05033244
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x2e241822f9c2319d9c16f41bbe9995cefc6384da058492e8e149f9054c26b38888320882021-05-14 10:36:05132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x2e241822f9c2319d9c16f41bbe9995cefc6384da058492e8e149f9054c26b38888320882021-05-14 10:36:05132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x2e241822f9c2319d9c16f41bbe9995cefc6384da058492e8e149f9054c26b38888320882021-05-14 10:36:05132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x2e241822f9c2319d9c16f41bbe9995cefc6384da058492e8e149f9054c26b38888320882021-05-14 10:36:05132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x2e241822f9c2319d9c16f41bbe9995cefc6384da058492e8e149f9054c26b38888320882021-05-14 10:36:05132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x91ae51e37f9ffddbefb47ddc904de917c5d6e1945dd9613fde0908e18896069e88319952021-05-14 10:31:26132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x91ae51e37f9ffddbefb47ddc904de917c5d6e1945dd9613fde0908e18896069e88319952021-05-14 10:31:26132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x91ae51e37f9ffddbefb47ddc904de917c5d6e1945dd9613fde0908e18896069e88319952021-05-14 10:31:26132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x91ae51e37f9ffddbefb47ddc904de917c5d6e1945dd9613fde0908e18896069e88319952021-05-14 10:31:26132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x91ae51e37f9ffddbefb47ddc904de917c5d6e1945dd9613fde0908e18896069e88319952021-05-14 10:31:26132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x6625d14dcdaae17da87e119307e5bd5b10b27f46eb3a79a7a20deee50385cbe588319542021-05-14 10:29:23132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x6625d14dcdaae17da87e119307e5bd5b10b27f46eb3a79a7a20deee50385cbe588319542021-05-14 10:29:23132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x6625d14dcdaae17da87e119307e5bd5b10b27f46eb3a79a7a20deee50385cbe588319542021-05-14 10:29:23132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x6625d14dcdaae17da87e119307e5bd5b10b27f46eb3a79a7a20deee50385cbe588319542021-05-14 10:29:23132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x6625d14dcdaae17da87e119307e5bd5b10b27f46eb3a79a7a20deee50385cbe588319542021-05-14 10:29:23132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0xb132b2004fedcc2ce441af99c74e4b1b898533ecaf574667e91328369f3158c888319102021-05-14 10:27:11132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0xb132b2004fedcc2ce441af99c74e4b1b898533ecaf574667e91328369f3158c888319102021-05-14 10:27:11132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0xb132b2004fedcc2ce441af99c74e4b1b898533ecaf574667e91328369f3158c888319102021-05-14 10:27:11132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0xb132b2004fedcc2ce441af99c74e4b1b898533ecaf574667e91328369f3158c888319102021-05-14 10:27:11132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0xb132b2004fedcc2ce441af99c74e4b1b898533ecaf574667e91328369f3158c888319102021-05-14 10:27:11132 days 20 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x91cd24b88a449cabbdc74fb154b70b64f31d10157780c55cfed8f6ba867d131988316482021-05-14 10:14:05132 days 21 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x91cd24b88a449cabbdc74fb154b70b64f31d10157780c55cfed8f6ba867d131988316482021-05-14 10:14:05132 days 21 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x91cd24b88a449cabbdc74fb154b70b64f31d10157780c55cfed8f6ba867d131988316482021-05-14 10:14:05132 days 21 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x91cd24b88a449cabbdc74fb154b70b64f31d10157780c55cfed8f6ba867d131988316482021-05-14 10:14:05132 days 21 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
0x91cd24b88a449cabbdc74fb154b70b64f31d10157780c55cfed8f6ba867d131988316482021-05-14 10:14:05132 days 21 hrs ago 0x6de5f13e81e78996195d9547317b4d265ec0bbd0 0xd610457e0904301192cb660616d97e07a853e4530 BNB
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SakePerp

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at BscScan.com on 2021-04-29
*/

// File: @openzeppelin\contracts-upgradeable\math\SafeMathUpgradeable.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMathUpgradeable {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

// File: contracts\utils\DecimalMath.sol

pragma solidity ^0.6.12;


/// @dev Implements simple fixed point math add, sub, mul and div operations.
/// @author Alberto Cuesta Cañada
library DecimalMath {
    using SafeMathUpgradeable for uint256;

    /// @dev Returns 1 in the fixed point representation, with `decimals` decimals.
    function unit(uint8 decimals) internal pure returns (uint256) {
        return 10**uint256(decimals);
    }

    /// @dev Adds x and y, assuming they are both fixed point with 18 decimals.
    function addd(uint256 x, uint256 y) internal pure returns (uint256) {
        return x.add(y);
    }

    /// @dev Subtracts y from x, assuming they are both fixed point with 18 decimals.
    function subd(uint256 x, uint256 y) internal pure returns (uint256) {
        return x.sub(y);
    }

    /// @dev Multiplies x and y, assuming they are both fixed point with 18 digits.
    function muld(uint256 x, uint256 y) internal pure returns (uint256) {
        return muld(x, y, 18);
    }

    /// @dev Multiplies x and y, assuming they are both fixed point with `decimals` digits.
    function muld(
        uint256 x,
        uint256 y,
        uint8 decimals
    ) internal pure returns (uint256) {
        return x.mul(y).div(unit(decimals));
    }

    /// @dev Divides x between y, assuming they are both fixed point with 18 digits.
    function divd(uint256 x, uint256 y) internal pure returns (uint256) {
        return divd(x, y, 18);
    }

    /// @dev Divides x between y, assuming they are both fixed point with `decimals` digits.
    function divd(
        uint256 x,
        uint256 y,
        uint8 decimals
    ) internal pure returns (uint256) {
        return x.mul(unit(decimals)).div(y);
    }
}

// File: contracts\utils\Decimal.sol

pragma solidity ^0.6.12;



library Decimal {
    using DecimalMath for uint256;
    using SafeMathUpgradeable for uint256;

    struct decimal {
        uint256 d;
    }

    function zero() internal pure returns (decimal memory) {
        return decimal(0);
    }

    function one() internal pure returns (decimal memory) {
        return decimal(DecimalMath.unit(18));
    }

    function toUint(decimal memory x) internal pure returns (uint256) {
        return x.d;
    }

    function modD(decimal memory x, decimal memory y) internal pure returns (decimal memory) {
        return decimal(x.d.mul(DecimalMath.unit(18)) % y.d);
    }

    function cmp(decimal memory x, decimal memory y) internal pure returns (int8) {
        if (x.d > y.d) {
            return 1;
        } else if (x.d < y.d) {
            return -1;
        }
        return 0;
    }

    /// @dev add two decimals
    function addD(decimal memory x, decimal memory y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.add(y.d);
        return t;
    }

    /// @dev subtract two decimals
    function subD(decimal memory x, decimal memory y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.sub(y.d);
        return t;
    }

    /// @dev multiple two decimals
    function mulD(decimal memory x, decimal memory y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.muld(y.d);
        return t;
    }

    /// @dev multiple a decimal by a uint256
    function mulScalar(decimal memory x, uint256 y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.mul(y);
        return t;
    }

    /// @dev divide two decimals
    function divD(decimal memory x, decimal memory y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.divd(y.d);
        return t;
    }

    /// @dev divide a decimal by a uint256
    function divScalar(decimal memory x, uint256 y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.div(y);
        return t;
    }
}

// File: @openzeppelin\contracts-upgradeable\math\SignedSafeMathUpgradeable.sol


pragma solidity >=0.6.0 <0.8.0;

/**
 * @title SignedSafeMath
 * @dev Signed math operations with safety checks that revert on error.
 */
library SignedSafeMathUpgradeable {
    int256 constant private _INT256_MIN = -2**255;

    /**
     * @dev Returns the multiplication of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(int256 a, int256 b) internal pure returns (int256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow");

        int256 c = a * b;
        require(c / a == b, "SignedSafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two signed integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(int256 a, int256 b) internal pure returns (int256) {
        require(b != 0, "SignedSafeMath: division by zero");
        require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow");

        int256 c = a / b;

        return c;
    }

    /**
     * @dev Returns the subtraction of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");

        return c;
    }

    /**
     * @dev Returns the addition of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");

        return c;
    }
}

// File: contracts\utils\SignedDecimalMath.sol

pragma solidity ^0.6.12;


/// @dev Implements simple signed fixed point math add, sub, mul and div operations.
library SignedDecimalMath {
    using SignedSafeMathUpgradeable for int256;

    /// @dev Returns 1 in the fixed point representation, with `decimals` decimals.
    function unit(uint8 decimals) internal pure returns (int256) {
        return int256(10**uint256(decimals));
    }

    /// @dev Adds x and y, assuming they are both fixed point with 18 decimals.
    function addd(int256 x, int256 y) internal pure returns (int256) {
        return x.add(y);
    }

    /// @dev Subtracts y from x, assuming they are both fixed point with 18 decimals.
    function subd(int256 x, int256 y) internal pure returns (int256) {
        return x.sub(y);
    }

    /// @dev Multiplies x and y, assuming they are both fixed point with 18 digits.
    function muld(int256 x, int256 y) internal pure returns (int256) {
        return muld(x, y, 18);
    }

    /// @dev Multiplies x and y, assuming they are both fixed point with `decimals` digits.
    function muld(
        int256 x,
        int256 y,
        uint8 decimals
    ) internal pure returns (int256) {
        return x.mul(y).div(unit(decimals));
    }

    /// @dev Divides x between y, assuming they are both fixed point with 18 digits.
    function divd(int256 x, int256 y) internal pure returns (int256) {
        return divd(x, y, 18);
    }

    /// @dev Divides x between y, assuming they are both fixed point with `decimals` digits.
    function divd(
        int256 x,
        int256 y,
        uint8 decimals
    ) internal pure returns (int256) {
        return x.mul(unit(decimals)).div(y);
    }
}

// File: contracts\utils\SignedDecimal.sol


pragma solidity ^0.6.12;




library SignedDecimal {
    using SignedDecimalMath for int256;
    using SignedSafeMathUpgradeable for int256;

    struct signedDecimal {
        int256 d;
    }

    function zero() internal pure returns (signedDecimal memory) {
        return signedDecimal(0);
    }

    function toInt(signedDecimal memory x) internal pure returns (int256) {
        return x.d;
    }

    function isNegative(signedDecimal memory x) internal pure returns (bool) {
        if (x.d < 0) {
            return true;
        }
        return false;
    }

    function abs(signedDecimal memory x) internal pure returns (Decimal.decimal memory) {
        Decimal.decimal memory t;
        if (x.d < 0) {
            t.d = uint256(0 - x.d);
        } else {
            t.d = uint256(x.d);
        }
        return t;
    }

    /// @dev add two decimals
    function addD(signedDecimal memory x, signedDecimal memory y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.add(y.d);
        return t;
    }

    /// @dev subtract two decimals
    function subD(signedDecimal memory x, signedDecimal memory y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.sub(y.d);
        return t;
    }

    /// @dev multiple two decimals
    function mulD(signedDecimal memory x, signedDecimal memory y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.muld(y.d);
        return t;
    }

    /// @dev multiple a signedDecimal by a int256
    function mulScalar(signedDecimal memory x, int256 y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.mul(y);
        return t;
    }

    /// @dev divide two decimals
    function divD(signedDecimal memory x, signedDecimal memory y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.divd(y.d);
        return t;
    }

    /// @dev divide a signedDecimal by a int256
    function divScalar(signedDecimal memory x, int256 y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.div(y);
        return t;
    }
}

// File: contracts\utils\MixedDecimal.sol

pragma solidity ^0.6.12;




/// @dev To handle a signedDecimal add/sub/mul/div a decimal and provide convert decimal to signedDecimal helper
library MixedDecimal {
    using SignedDecimal for SignedDecimal.signedDecimal;
    using SignedSafeMathUpgradeable for int256;

    uint256 private constant _INT256_MAX = 2**255 - 1;
    string private constant ERROR_NON_CONVERTIBLE = "MixedDecimal: uint value is bigger than _INT256_MAX";

    modifier convertible(Decimal.decimal memory x) {
        require(_INT256_MAX >= x.d, ERROR_NON_CONVERTIBLE);
        _;
    }

    function fromDecimal(Decimal.decimal memory x)
        internal
        pure
        convertible(x)
        returns (SignedDecimal.signedDecimal memory)
    {
        return SignedDecimal.signedDecimal(int256(x.d));
    }

    function toUint(SignedDecimal.signedDecimal memory x) internal pure returns (uint256) {
        return x.abs().d;
    }

    /// @dev add SignedDecimal.signedDecimal and Decimal.decimal, using SignedSafeMath directly
    function addD(SignedDecimal.signedDecimal memory x, Decimal.decimal memory y)
        internal
        pure
        convertible(y)
        returns (SignedDecimal.signedDecimal memory)
    {
        SignedDecimal.signedDecimal memory t;
        t.d = x.d.add(int256(y.d));
        return t;
    }

    /// @dev subtract SignedDecimal.signedDecimal by Decimal.decimal, using SignedSafeMath directly
    function subD(SignedDecimal.signedDecimal memory x, Decimal.decimal memory y)
        internal
        pure
        convertible(y)
        returns (SignedDecimal.signedDecimal memory)
    {
        SignedDecimal.signedDecimal memory t;
        t.d = x.d.sub(int256(y.d));
        return t;
    }

    /// @dev multiple a SignedDecimal.signedDecimal by Decimal.decimal
    function mulD(SignedDecimal.signedDecimal memory x, Decimal.decimal memory y)
        internal
        pure
        convertible(y)
        returns (SignedDecimal.signedDecimal memory)
    {
        SignedDecimal.signedDecimal memory t;
        t = x.mulD(fromDecimal(y));
        return t;
    }

    /// @dev multiple a SignedDecimal.signedDecimal by a uint256
    function mulScalar(SignedDecimal.signedDecimal memory x, uint256 y)
        internal
        pure
        returns (SignedDecimal.signedDecimal memory)
    {
        require(_INT256_MAX >= y, ERROR_NON_CONVERTIBLE);
        SignedDecimal.signedDecimal memory t;
        t = x.mulScalar(int256(y));
        return t;
    }

    /// @dev divide a SignedDecimal.signedDecimal by a Decimal.decimal
    function divD(SignedDecimal.signedDecimal memory x, Decimal.decimal memory y)
        internal
        pure
        convertible(y)
        returns (SignedDecimal.signedDecimal memory)
    {
        SignedDecimal.signedDecimal memory t;
        t = x.divD(fromDecimal(y));
        return t;
    }

    /// @dev divide a SignedDecimal.signedDecimal by a uint256
    function divScalar(SignedDecimal.signedDecimal memory x, uint256 y)
        internal
        pure
        returns (SignedDecimal.signedDecimal memory)
    {
        require(_INT256_MAX >= y, ERROR_NON_CONVERTIBLE);
        SignedDecimal.signedDecimal memory t;
        t = x.divScalar(int256(y));
        return t;
    }
}

// File: contracts\utils\BlockContext.sol


pragma solidity ^0.6.12;

// wrap block.xxx functions for testing
// only support timestamp and number so far
abstract contract BlockContext {
    //◥◤◥◤◥◤◥◤◥◤◥◤◥◤◥◤ add state variables below ◥◤◥◤◥◤◥◤◥◤◥◤◥◤◥◤//

    //◢◣◢◣◢◣◢◣◢◣◢◣◢◣◢◣ add state variables above ◢◣◢◣◢◣◢◣◢◣◢◣◢◣◢◣//
    uint256[50] private __gap;

    function _blockTimestamp() internal view virtual returns (uint256) {
        return block.timestamp;
    }

    function _blockNumber() internal view virtual returns (uint256) {
        return block.number;
    }
}

// File: @openzeppelin\contracts-upgradeable\token\ERC20\IERC20Upgradeable.sol



pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// File: contracts\types\ISakePerpVaultTypes.sol


pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

interface ISakePerpVaultTypes {
    /**
     * @notice pool types
     * @param HIGH high risk pool
     * @param LOW low risk pool
     */
    enum Risk {HIGH, LOW}
}

// File: contracts\types\IExchangeTypes.sol

pragma solidity ^0.6.12;




interface IExchangeTypes {
    /**
     * @notice asset direction, used in getInputPrice, getOutputPrice, swapInput and swapOutput
     * @param ADD_TO_AMM add asset to Amm
     * @param REMOVE_FROM_AMM remove asset from Amm
     */
    enum Dir {ADD_TO_AMM, REMOVE_FROM_AMM}

    struct LiquidityChangedSnapshot {
        SignedDecimal.signedDecimal cumulativeNotional;
        // the base/quote reserve of amm right before liquidity changed
        Decimal.decimal quoteAssetReserve;
        Decimal.decimal baseAssetReserve;
        // total position size owned by amm after last snapshot taken
        // `totalPositionSize` = currentBaseAssetReserve - lastLiquidityChangedHistoryItem.baseAssetReserve + prevTotalPositionSize
        SignedDecimal.signedDecimal totalPositionSize;
    }
}

// File: node_modules\@openzeppelin\contracts-upgradeable\proxy\Initializable.sol


// solhint-disable-next-line compiler-version
pragma solidity >=0.4.24 <0.8.0;


/**
 * @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 a proxied contract can't have 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.
 * 
 * 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 {UpgradeableProxy-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.
 */
abstract contract Initializable {

    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }

    /// @dev Returns true if and only if the function is running in the constructor
    function _isConstructor() private view returns (bool) {
        // extcodesize checks the size of the code stored in an address, and
        // address returns the current address. Since the code is still not
        // deployed when running a constructor, any checks on its code size will
        // yield zero, making it an effective way to detect if a contract is
        // under construction or not.
        address self = address(this);
        uint256 cs;
        // solhint-disable-next-line no-inline-assembly
        assembly { cs := extcodesize(self) }
        return cs == 0;
    }
}

// File: node_modules\@openzeppelin\contracts-upgradeable\GSN\ContextUpgradeable.sol


pragma solidity >=0.6.0 <0.8.0;


/*
 * @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 GSN 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 ContextUpgradeable is Initializable {
    function __Context_init() internal initializer {
        __Context_init_unchained();
    }

    function __Context_init_unchained() internal initializer {
    }
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
    uint256[50] private __gap;
}




// File: @openzeppelin\contracts-upgradeable\token\ERC20\ERC20Upgradeable.sol


pragma solidity >=0.6.0 <0.8.0;





/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable {
    using SafeMathUpgradeable for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    function __ERC20_init(string memory name_, string memory symbol_) internal initializer {
        __Context_init_unchained();
        __ERC20_init_unchained(name_, symbol_);
    }

    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal initializer {
        _name = name_;
        _symbol = symbol_;
        _decimals = 18;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
     * called.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Sets {decimals} to a value other than the default one of 18.
     *
     * WARNING: This function should only be called from the constructor. Most
     * applications that interact with token contracts will not expect
     * {decimals} to ever change, and may work incorrectly if it does.
     */
    function _setupDecimals(uint8 decimals_) internal {
        _decimals = decimals_;
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
    uint256[44] private __gap;
}

// File: @openzeppelin\contracts-upgradeable\access\OwnableUpgradeable.sol


pragma solidity >=0.6.0 <0.8.0;


/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal initializer {
        __Context_init_unchained();
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal initializer {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
    uint256[49] private __gap;
}

// File: contracts\MMLPToken.sol


pragma solidity ^0.6.12;



contract MMLPToken is ERC20Upgradeable, OwnableUpgradeable {
    constructor(string memory _name, string memory _symbol) public {
        __ERC20_init(_name, _symbol);
        __Ownable_init();
    }

    function mint(address _account, uint256 _amount) external onlyOwner {
        _mint(_account, _amount);
    }

    function burn(address _account, uint256 _amount) external onlyOwner {
        _burn(_account, _amount);
    }
}

// File: contracts\interface\IExchangeState.sol


pragma solidity ^0.6.12;







interface IExchangeState {
    function getMaxHoldingBaseAsset() external view returns (Decimal.decimal memory);

    function getOpenInterestNotionalCap() external view returns (Decimal.decimal memory);

    function initMarginRatio() external view returns (Decimal.decimal memory);

    function maintenanceMarginRatio() external view returns (Decimal.decimal memory);

    function liquidationFeeRatio() external view returns (Decimal.decimal memory);

    function maxLiquidationFee() external view returns (Decimal.decimal memory);

    function spreadRatio() external view returns (Decimal.decimal memory);

    function maxOracleSpreadRatio() external view returns (Decimal.decimal memory);

    function getInputPriceWithReserves(
        IExchangeTypes.Dir _dir,
        Decimal.decimal memory _quoteAssetAmount,
        Decimal.decimal memory _quoteAssetPoolAmount,
        Decimal.decimal memory _baseAssetPoolAmount
    ) external pure returns (Decimal.decimal memory);

    function getOutputPriceWithReserves(
        IExchangeTypes.Dir _dir,
        Decimal.decimal memory _baseAssetAmount,
        Decimal.decimal memory _quoteAssetPoolAmount,
        Decimal.decimal memory _baseAssetPoolAmount
    ) external pure returns (Decimal.decimal memory);

    function calcFee(Decimal.decimal calldata _quoteAssetAmount) external view returns (Decimal.decimal memory);

    function mint(
        ISakePerpVaultTypes.Risk _level,
        address account,
        uint256 amount
    ) external;

    function burn(
        ISakePerpVaultTypes.Risk _level,
        address account,
        uint256 amount
    ) external;

    function getLPToken(ISakePerpVaultTypes.Risk _level) external view returns (MMLPToken);
}

// File: contracts\interface\IExchange.sol


pragma solidity ^0.6.12;








interface IExchange is IExchangeTypes {
    function swapInput(
        Dir _dir,
        Decimal.decimal calldata _quoteAssetAmount,
        Decimal.decimal calldata _baseAssetAmountLimit
    ) external returns (Decimal.decimal memory);

    function swapOutput(
        Dir _dir,
        Decimal.decimal calldata _baseAssetAmount,
        Decimal.decimal calldata _quoteAssetAmountLimit,
        bool _skipFluctuationCheck
    ) external returns (Decimal.decimal memory);

    function migrateLiquidity(Decimal.decimal calldata _liquidityMultiplier, Decimal.decimal calldata _priceLimitRatio)
        external;

    function shutdown() external;

    function settleFunding() external returns (SignedDecimal.signedDecimal memory);

    function calcFee(Decimal.decimal calldata _quoteAssetAmount) external view returns (Decimal.decimal memory);

    function calcBaseAssetAfterLiquidityMigration(
        SignedDecimal.signedDecimal memory _baseAssetAmount,
        Decimal.decimal memory _fromQuoteReserve,
        Decimal.decimal memory _fromBaseReserve
    ) external view returns (SignedDecimal.signedDecimal memory);

    function getInputTwap(Dir _dir, Decimal.decimal calldata _quoteAssetAmount)
        external
        view
        returns (Decimal.decimal memory);

    function getOutputTwap(Dir _dir, Decimal.decimal calldata _baseAssetAmount)
        external
        view
        returns (Decimal.decimal memory);

    function getInputPrice(Dir _dir, Decimal.decimal calldata _quoteAssetAmount)
        external
        view
        returns (Decimal.decimal memory);

    function getOutputPrice(Dir _dir, Decimal.decimal calldata _baseAssetAmount)
        external
        view
        returns (Decimal.decimal memory);

    function getInputPriceWithReserves(
        Dir _dir,
        Decimal.decimal memory _quoteAssetAmount,
        Decimal.decimal memory _quoteAssetPoolAmount,
        Decimal.decimal memory _baseAssetPoolAmount
    ) external view returns (Decimal.decimal memory);

    function getOutputPriceWithReserves(
        Dir _dir,
        Decimal.decimal memory _baseAssetAmount,
        Decimal.decimal memory _quoteAssetPoolAmount,
        Decimal.decimal memory _baseAssetPoolAmount
    ) external view returns (Decimal.decimal memory);

    function getSpotPrice() external view returns (Decimal.decimal memory);

    function getLiquidityHistoryLength() external view returns (uint256);

    // overridden by state variable
    function quoteAsset() external view returns (IERC20Upgradeable);

    function open() external view returns (bool);

    // can not be overridden by state variable due to type `Deciaml.decimal`
    function getSettlementPrice() external view returns (Decimal.decimal memory);

    function getCumulativeNotional() external view returns (SignedDecimal.signedDecimal memory);

    function getMaxHoldingBaseAsset() external view returns (Decimal.decimal memory);

    function getOpenInterestNotionalCap() external view returns (Decimal.decimal memory);

    function getLiquidityChangedSnapshots(uint256 i) external view returns (LiquidityChangedSnapshot memory);

    function mint(
        ISakePerpVaultTypes.Risk _level,
        address account,
        uint256 amount
    ) external;

    function burn(
        ISakePerpVaultTypes.Risk _level,
        address account,
        uint256 amount
    ) external;

    function getMMUnrealizedPNL(Decimal.decimal memory _baseAssetReserve, Decimal.decimal memory _quoteAssetReserve)
        external
        view
        returns (SignedDecimal.signedDecimal memory);

    function moveAMMPriceToOracle(uint256 _oraclePrice, bytes32 _priceFeedKey) external;

    function setPriceFeed(address _priceFeed) external;

    function getReserve() external view returns (Decimal.decimal memory, Decimal.decimal memory);

    function initMarginRatio() external view returns (Decimal.decimal memory);

    function maintenanceMarginRatio() external view returns (Decimal.decimal memory);

    function liquidationFeeRatio() external view returns (Decimal.decimal memory);

    function maxLiquidationFee() external view returns (Decimal.decimal memory);

    function spreadRatio() external view returns (Decimal.decimal memory);

    function priceFeedKey() external view returns (bytes32);

    function tradeLimitRatio() external view returns (uint256);

    function priceAdjustRatio() external view returns (uint256);

    function fluctuationLimitRatio() external view returns (uint256);

    function fundingPeriod() external view returns (uint256);

    function adjustTotalPosition(
        SignedDecimal.signedDecimal memory adjustedPosition,
        SignedDecimal.signedDecimal memory oldAdjustedPosition
    ) external;

    function getTotalPositionSize() external view returns (SignedDecimal.signedDecimal memory);

    function exchangeState() external view returns (IExchangeState);

    function getUnderlyingPrice() external view returns (Decimal.decimal memory);

    function isOverSpreadLimit() external view returns (bool);
}

// File: contracts\interface\IInsuranceFund.sol


pragma solidity ^0.6.12;



interface IInsuranceFund {
    function withdraw(Decimal.decimal calldata _amount) external returns (Decimal.decimal memory badDebt);

    function setExchange(IExchange _exchange) external;

    function setBeneficiary(address _beneficiary) external;
}

// File: contracts\interface\ISystemSettings.sol


pragma solidity ^0.6.12;




interface ISystemSettings {
    function insuranceFundFeeRatio() external view returns (Decimal.decimal memory);

    function lpWithdrawFeeRatio() external view returns (Decimal.decimal memory);

    function overnightFeeRatio() external view returns (Decimal.decimal memory);

    function overnightFeeLpShareRatio() external view returns (Decimal.decimal memory);

    function fundingFeeLpShareRatio() external view returns (Decimal.decimal memory);

    function overnightFeePeriod() external view returns (uint256);

    function isExistedExchange(IExchange _exchange) external view returns (bool);

    function getAllExchanges() external view returns (IExchange[] memory);

    function getInsuranceFund(IExchange _exchange) external view returns (IInsuranceFund);

    function setNextOvernightFeeTime(IExchange _exchange) external;

    function nextOvernightFeeTime(address _exchange) external view returns (uint256);
}

// File: contracts\interface\ISakePerpVault.sol


pragma solidity ^0.6.12;






interface ISakePerpVault is ISakePerpVaultTypes {
    function withdraw(
        IExchange _exchange,
        address _receiver,
        Decimal.decimal memory _amount
    ) external;

    function realizeBadDebt(IExchange _exchange, Decimal.decimal memory _badDebt) external;

    function modifyLiquidity() external;

    function getMMLiquidity(address _exchange, Risk _risk) external view returns (SignedDecimal.signedDecimal memory);

    function getAllMMLiquidity(address _exchange)
        external
        view
        returns (SignedDecimal.signedDecimal memory, SignedDecimal.signedDecimal memory);

    function getTotalMMLiquidity(address _exchange) external view returns (SignedDecimal.signedDecimal memory);

    function getTotalMMAvailableLiquidity(address _exchange) external view returns (SignedDecimal.signedDecimal memory);

    function getTotalLpUnrealizedPNL(IExchange _exchange) external view returns (SignedDecimal.signedDecimal memory);

    function addCachedLiquidity(address _exchange, Decimal.decimal memory _DeltalpLiquidity) external;

    function requireMMNotBankrupt(address _exchange) external;

    function getMMCachedLiquidity(address _exchange, Risk _risk) external view returns (Decimal.decimal memory);

    function getTotalMMCachedLiquidity(address _exchange) external view returns (Decimal.decimal memory);

    function setHighRiskLiquidityWeight(address _exchange, uint256 _weight) external;

    function setMaxLoss(
        address _exchange,
        Risk _risk,
        uint256 _max
    ) external;
}

// File: contracts\types\ISakePerpTypes.sol


pragma solidity ^0.6.12;



interface ISakePerpTypes {
    //
    // Struct and Enum
    //
    enum Side {BUY, SELL}
    enum PnlCalcOption { SPOT_PRICE, TWAP, ORACLE }

    /// @notice This struct records personal position information
    /// @param size denominated in amm.baseAsset
    /// @param margin isolated margin
    /// @param openNotional the quoteAsset value of position when opening position. the cost of the position
    /// @param lastUpdatedCumulativePremiumFraction for calculating funding payment, record at the moment every time when trader open/reduce/close position
    /// @param lastUpdatedCumulativeOvernightFeeRate for calculating holding fee, record at the moment every time when trader open/reduce/close position
    /// @param liquidityHistoryIndex
    /// @param blockNumber the block number of the last position
    struct Position {
        SignedDecimal.signedDecimal size;
        Decimal.decimal margin;
        Decimal.decimal openNotional;
        SignedDecimal.signedDecimal lastUpdatedCumulativePremiumFraction;
        Decimal.decimal lastUpdatedCumulativeOvernightFeeRate;
        uint256 liquidityHistoryIndex;
        uint256 blockNumber;
    }
}

// File: contracts\interface\ISakePerp.sol

pragma solidity ^0.6.12;




interface ISakePerp is ISakePerpTypes {
    function getMMLiquidity(address _exchange) external view returns (SignedDecimal.signedDecimal memory);

    function getLatestCumulativePremiumFraction(IExchange _exchange)
        external
        view
        returns (SignedDecimal.signedDecimal memory);

    function getLatestCumulativeOvernightFeeRate(IExchange _exchange) external view returns (Decimal.decimal memory);

    function getPositionNotionalAndUnrealizedPnl(
        IExchange _exchange,
        address _trader,
        PnlCalcOption _pnlCalcOption
    ) external view returns (Decimal.decimal memory positionNotional, SignedDecimal.signedDecimal memory unrealizedPnl);

    function getPosition(IExchange _exchange, address _trader) external view returns (Position memory);

    function getUnadjustedPosition(IExchange _exchange, address _trader)
        external
        view
        returns (Position memory position);

    function getMarginRatio(IExchange _exchange, address _trader)
        external
        view
        returns (SignedDecimal.signedDecimal memory);
}

// File: contracts\interface\ISakePerpState.sol


pragma solidity ^0.6.12;




interface ISakePerpState {
    struct TradingState {
        uint256 lastestLongTime;
        uint256 lastestShortTime;
    }

    struct RemainMarginInfo {
        Decimal.decimal remainMargin;
        Decimal.decimal badDebt;
        SignedDecimal.signedDecimal fundingPayment;
        Decimal.decimal overnightFee;
    }

    function checkWaitingPeriod(
        address _exchange,
        address _trader,
        ISakePerpTypes.Side _side
    ) external returns (bool);

    function updateOpenInterestNotional(IExchange _exchange, SignedDecimal.signedDecimal memory _amount) external;

    function getWhiteList() external view returns (address);

    function getPositionNotionalAndUnrealizedPnl(
        IExchange _exchange,
        ISakePerpTypes.Position memory _position,
        ISakePerpTypes.PnlCalcOption _pnlCalcOption
    ) external view returns (Decimal.decimal memory positionNotional, SignedDecimal.signedDecimal memory unrealizedPnl);

    function calcPositionAfterLiquidityMigration(
        IExchange _exchange,
        ISakePerpTypes.Position memory _position,
        uint256 _latestLiquidityIndex
    ) external view returns (ISakePerpTypes.Position memory);

    function calcPositionAfterLiquidityMigrationWithoutNew(
        IExchange _exchange,
        ISakePerpTypes.Position memory _position,
        uint256 _latestLiquidityIndex
    ) external returns (SignedDecimal.signedDecimal memory);

    function calcRemainMarginWithFundingPaymentAndOvernightFee(
        IExchange _exchange,
        ISakePerpTypes.Position memory _oldPosition,
        SignedDecimal.signedDecimal memory _marginDelta
    ) external view returns (RemainMarginInfo memory remainMarginInfo);
}

// File: node_modules\@openzeppelin\contracts-upgradeable\utils\AddressUpgradeable.sol


pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// File: @openzeppelin\contracts-upgradeable\token\ERC20\SafeERC20Upgradeable.sol


pragma solidity >=0.6.0 <0.8.0;




/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20Upgradeable {
    using SafeMathUpgradeable for uint256;
    using AddressUpgradeable for address;

    function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// File: contracts\SakePerp.sol


pragma solidity 0.6.12;





// note BaseRelayRecipient must come after OwnerPausableUpgradeSafe so its msg.sender takes precedence
// (yes, the ordering is reversed comparing to Python)
contract SakePerp is ISakePerp, OwnableUpgradeable, BlockContext {
    using Decimal for Decimal.decimal;
    using SignedDecimal for SignedDecimal.signedDecimal;
    using MixedDecimal for SignedDecimal.signedDecimal;
    using SafeERC20Upgradeable for IERC20Upgradeable;
    using SafeMathUpgradeable for uint256;
    //
    // EVENTS
    //
    event MarginChanged(
        address indexed sender,
        address indexed exchange,
        int256 amount,
        int256 fundingPayment,
        uint256 overnightFee
    );
    event PositionAdjusted(
        address indexed exchange,
        address indexed trader,
        int256 newPositionSize,
        uint256 oldLiquidityIndex,
        uint256 newLiquidityIndex
    );
    event PositionSettled(address indexed exchange, address indexed trader, uint256 valueTransferred);
    event RestrictionModeEntered(address exchange, uint256 blockNumber);

    /// @notice This event is emitted when position change
    /// @param trader the address which execute this transaction
    /// @param exchange IExchange address
    /// @param margin margin
    /// @param positionNotional margin * leverage
    /// @param exchangedPositionSize position size, e.g. ETHUSDC or LINKUSDC
    /// @param fee transaction fee
    /// @param positionSizeAfter position size after this transaction, might be increased or decreased
    /// @param realizedPnl realized pnl after this position changed
    /// @param unrealizedPnlAfter unrealized pnl after this position changed
    /// @param badDebt position change amount cleared by insurance funds
    /// @param liquidationPenalty amount of remaining margin lost due to liquidation
    /// @param spotPrice quote asset reserve / base asset reserve
    /// @param fundingPayment funding payment (+: trader paid, -: trader received)
    /// @param overnightPayment overnight payment
    event PositionChanged(
        address indexed trader,
        address indexed exchange,
        uint256 margin,
        uint256 positionNotional,
        int256 exchangedPositionSize,
        uint256 fee,
        int256 positionSizeAfter,
        int256 realizedPnl,
        int256 unrealizedPnlAfter,
        uint256 badDebt,
        uint256 liquidationPenalty,
        uint256 spotPrice,
        int256 fundingPayment,
        uint256 overnightPayment
    );

    /// @notice This event is emitted when position liquidated
    /// @param trader the account address being liquidated
    /// @param exchange IExchange address
    /// @param positionNotional liquidated position value minus liquidationFee
    /// @param positionSize liquidated position size
    /// @param liquidationFee liquidation fee to the liquidator
    /// @param liquidator the address which execute this transaction
    /// @param badDebt liquidation fee amount cleared by insurance funds
    event PositionLiquidated(
        address indexed trader,
        address indexed exchange,
        uint256 positionNotional,
        uint256 positionSize,
        uint256 liquidationFee,
        address liquidator,
        uint256 badDebt
    );

    /// @notice This event is emitted when overnight fee payed
    /// @param exchange exchange address
    /// @param totalOpenNotional the total open notional
    /// @param overnightFee the total overinight fee this time
    /// @param rate current overnight feerate
    event OvernightFeePayed(address indexed exchange, uint256 totalOpenNotional, uint256 overnightFee, uint256 rate);

    /// @notice This struct is used for avoiding stack too deep error when passing too many var between functions
    struct PositionResp {
        Position position;
        // the quote asset amount trader will send if open position, will receive if close
        Decimal.decimal exchangedQuoteAssetAmount;
        // if realizedPnl + realizedFundingPayment + margin is negative, it's the abs value of it
        Decimal.decimal badDebt;
        // the base asset amount trader will receive if open position, will send if close
        SignedDecimal.signedDecimal exchangedPositionSize;
        // funding payment incurred during this position response
        SignedDecimal.signedDecimal fundingPayment;
        // overnight payment incurred during this position response
        Decimal.decimal overnightFee;
        // realizedPnl = unrealizedPnl * closedRatio
        SignedDecimal.signedDecimal realizedPnl;
        // positive = trader transfer margin to vault, negative = trader receive margin from vault
        // it's 0 when internalReducePosition, its addedMargin when internalIncreasePosition
        // it's min(0, oldPosition + realizedFundingPayment + realizedPnl) when internalClosePosition
        SignedDecimal.signedDecimal marginToVault;
        // unrealized pnl after open position
        SignedDecimal.signedDecimal unrealizedPnlAfter;
    }

    struct ExchangeMap {
        // issue #1471
        // last block when it turn restriction mode on.
        // In restriction mode, no one can do multi open/close/liquidate position in the same block.
        // If any underwater position being closed (having a bad debt and make insuranceFund loss),
        // or any liquidation happened,
        // restriction mode is ON in that block and OFF(default) in the next block.
        // This design is to prevent the attacker being benefited from the multiple action in one block
        // in extreme cases
        uint256 lastRestrictionBlock;
        SignedDecimal.signedDecimal[] cumulativePremiumFractions;
        Decimal.decimal[] cumulativeOvernightFeerates;
        mapping(address => Position) positionMap;
        Decimal.decimal totalOpenNotional;
    }

    //**********************************************************//
    //    Can not change the order of below state variables     //
    //**********************************************************//
    // key by exchange address
    mapping(address => ExchangeMap) internal exchangeMap;

    ISystemSettings public systemSettings;

    ISakePerpVault public sakePerpVault;
    ISakePerpState public sakePerpState;

    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private status;
    bool public paused;
    //**********************************************************//
    //    Can not change the order of above state variables     //
    //**********************************************************//

    //◥◤◥◤◥◤◥◤◥◤◥◤◥◤◥◤ add state variables below ◥◤◥◤◥◤◥◤◥◤◥◤◥◤◥◤//

    //◢◣◢◣◢◣◢◣◢◣◢◣◢◣◢◣ add state variables above ◢◣◢◣◢◣◢◣◢◣◢◣◢◣◢◣//
    uint256[50] private __gap;

    //
    // FUNCTIONS
    //
    // openzeppelin doesn't support struct input
    // https://github.com/OpenZeppelin/openzeppelin-sdk/issues/1523
    function initialize(
        address _systemsettings,
        address _sakePerpVault,
        address _sakePerpState
    ) public initializer {
        __Ownable_init();

        systemSettings = ISystemSettings(_systemsettings);
        sakePerpVault = ISakePerpVault(_sakePerpVault);
        sakePerpState = ISakePerpState(_sakePerpState);
        status = _NOT_ENTERED;
        paused = false;
    }

    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        status = _NOT_ENTERED;
    }

    modifier whenNotPaused() {
        require(!paused, "Pausable: paused");
        _;
    }

    //
    // External
    //
    /**
     * @dev set system settings
     */
    function setSystemSettings(ISystemSettings _systemSettings) external onlyOwner {
        systemSettings = _systemSettings;
    }

    /**
     * @notice add margin to increase margin ratio
     * @param _exchange IExchange address
     * @param _addedMargin added margin in 18 digits
     */
    function addMargin(IExchange _exchange, Decimal.decimal calldata _addedMargin)
        external
        whenNotPaused()
        nonReentrant()
    {
        // check condition
        requireExchange(_exchange, true);
        requireNonZeroInput(_addedMargin);

        // update margin part in personal position
        address trader = msg.sender;
        Position memory position = adjustPositionForLiquidityChanged(_exchange, trader);
        position.margin = position.margin.addD(_addedMargin);
        setPosition(_exchange, trader, position);

        // transfer token from trader
        IERC20Upgradeable(_exchange.quoteAsset()).safeTransferFrom(
            trader,
            address(sakePerpVault),
            _addedMargin.toUint()
        );

        emit MarginChanged(trader, address(_exchange), int256(_addedMargin.toUint()), 0, 0);
    }

    /**
     * @notice remove margin to decrease margin ratio
     * @param _exchange IExchange address
     * @param _removedMargin removed margin in 18 digits
     */
    function removeMargin(IExchange _exchange, Decimal.decimal calldata _removedMargin)
        external
        whenNotPaused()
        nonReentrant()
    {
        // check condition
        requireExchange(_exchange, true);
        requireNonZeroInput(_removedMargin);

        // update margin part in personal position
        address trader = msg.sender;
        Position memory position = adjustPositionForLiquidityChanged(_exchange, trader);

        // realize funding payment if there's no bad debt
        SignedDecimal.signedDecimal memory marginDelta = MixedDecimal.fromDecimal(_removedMargin).mulScalar(-1);
        ISakePerpState.RemainMarginInfo memory remainMarginInfo =
            sakePerpState.calcRemainMarginWithFundingPaymentAndOvernightFee(_exchange, position, marginDelta);
        require(remainMarginInfo.badDebt.toUint() == 0, "margin is not enough");

        position.margin = remainMarginInfo.remainMargin;
        position.lastUpdatedCumulativePremiumFraction = getLatestCumulativePremiumFraction(_exchange);
        position.lastUpdatedCumulativeOvernightFeeRate = getLatestCumulativeOvernightFeeRate(_exchange);
        setPosition(_exchange, trader, position);

        // check margin ratio
        requireMoreMarginRatio(getMarginRatio(_exchange, trader), _exchange.initMarginRatio(), true);

        // transfer token back to trader
        withdraw(_exchange, trader, _removedMargin);

        emit MarginChanged(
            trader,
            address(_exchange),
            marginDelta.toInt(),
            remainMarginInfo.fundingPayment.toInt(),
            remainMarginInfo.overnightFee.toUint()
        );
    }

    /**
     * @notice settle all the positions when exchange is shutdown. The settlement price is according to IExchange.settlementPrice
     * @param _exchange IExchange address
     */
    function settlePosition(IExchange _exchange) external nonReentrant() {
        // check condition
        requireExchange(_exchange, false);

        address trader = msg.sender;
        Position memory pos = getPosition(_exchange, trader);
        requirePositionSize(pos.size);

        // update position
        clearPosition(_exchange, trader);

        // calculate settledValue
        // If Settlement Price = 0, everyone takes back her collateral.
        // else Returned Fund = Position Size * (Settlement Price - Open Price) + Collateral
        Decimal.decimal memory settlementPrice = _exchange.getSettlementPrice();
        Decimal.decimal memory settledValue;
        if (settlementPrice.toUint() == 0) {
            settledValue = pos.margin;
        } else {
            // returnedFund = positionSize * (settlementPrice - openPrice) + positionMargin
            // openPrice = positionOpenNotional / positionSize.abs()
            SignedDecimal.signedDecimal memory returnedFund =
                pos
                    .size
                    .mulD(MixedDecimal.fromDecimal(settlementPrice).subD(pos.openNotional.divD(pos.size.abs())))
                    .addD(pos.margin);
            // if `returnedFund` is negative, trader can't get anything back
            if (returnedFund.toInt() > 0) {
                settledValue = returnedFund.abs();
            }
        }

        // transfer token based on settledValue. no insurance fund support
        if (settledValue.toUint() > 0) {
            withdraw(_exchange, trader, settledValue);
            //IERC20Upgradeable(_exchange.quoteAsset()).safeTransfer(trader, settledValue.toUint());
        }

        // emit event
        emit PositionSettled(address(_exchange), trader, settledValue.toUint());
    }

    // if increase position
    //   marginToVault = addMargin
    //   marginDiff = realizedFundingPayment + realizedPnl(0)
    //   pos.margin += marginToVault + marginDiff
    //   vault.margin += marginToVault + marginDiff
    //   required(enoughMarginRatio)
    // else if reduce position()
    //   marginToVault = 0
    //   marginDiff = realizedFundingPayment + realizedPnl
    //   pos.margin += marginToVault + marginDiff
    //   if pos.margin < 0, badDebt = abs(pos.margin), set pos.margin = 0
    //   vault.margin += marginToVault + marginDiff
    //   required(enoughMarginRatio)
    // else if close
    //   marginDiff = realizedFundingPayment + realizedPnl
    //   pos.margin += marginDiff
    //   if pos.margin < 0, badDebt = abs(pos.margin)
    //   marginToVault = -pos.margin
    //   set pos.margin = 0
    //   vault.margin += marginToVault + marginDiff
    // else if close and open a larger position in reverse side
    //   close()
    //   positionNotional -= exchangedQuoteAssetAmount
    //   newMargin = positionNotional / leverage
    //   internalIncreasePosition(newMargin, leverage)
    // else if liquidate
    //   close()
    //   pay liquidation fee to liquidator
    //   move the remain margin to insuranceFund

    /**
     * @notice open a position
     * @param _exchange exchange address
     * @param _side enum Side; BUY for long and SELL for short
     * @param _quoteAssetAmount quote asset amount in 18 digits. Can Not be 0
     * @param _leverage leverage  in 18 digits. Can Not be 0
     * @param _baseAssetAmountLimit minimum base asset amount expected to get to prevent from slippage.
     */
    function openPosition(
        IExchange _exchange,
        Side _side,
        Decimal.decimal calldata _quoteAssetAmount,
        Decimal.decimal calldata _leverage,
        Decimal.decimal calldata _baseAssetAmountLimit
    ) external whenNotPaused() nonReentrant() {
        requireExchange(_exchange, true);
        requireNonZeroInput(_quoteAssetAmount);
        requireNonZeroInput(_leverage);
        requireMoreMarginRatio(
            MixedDecimal.fromDecimal(Decimal.one()).divD(_leverage),
            _exchange.initMarginRatio(),
            true
        );
        requireNotRestrictionMode(_exchange);

        address trader = msg.sender;
        require(
            sakePerpState.checkWaitingPeriod(address(_exchange), trader, _side),
            "cannot open position during waiting period"
        );

        PositionResp memory positionResp;
        {
            // add scope for stack too deep error
            int256 oldPositionSize = adjustPositionForLiquidityChanged(_exchange, trader).size.toInt();
            bool isNewPosition = oldPositionSize == 0 ? true : false;
            if (!isNewPosition) {
                requireMoreMarginRatio(getMarginRatio(_exchange, trader), _exchange.maintenanceMarginRatio(), true);
            }

            // increase or decrease position depends on old position's side and size
            if (isNewPosition || (oldPositionSize > 0 ? Side.BUY : Side.SELL) == _side) {
                positionResp = internalIncreasePosition(
                    _exchange,
                    _side,
                    _quoteAssetAmount.mulD(_leverage),
                    _baseAssetAmountLimit,
                    _leverage
                );
            } else {
                positionResp = openReversePosition(
                    _exchange,
                    _side,
                    _quoteAssetAmount,
                    _leverage,
                    _baseAssetAmountLimit
                );
            }

            // update the position state
            setPosition(_exchange, trader, positionResp.position);

            // to prevent attacker to leverage the bad debt to withdraw extra token from  insurance fund
            if (positionResp.badDebt.toUint() > 0) {
                enterRestrictionMode(_exchange);
            }

            //ransfer the actual token between trader and vault
            IERC20Upgradeable quoteToken = _exchange.quoteAsset();
            if (positionResp.marginToVault.toInt() > 0) {
                quoteToken.safeTransferFrom(trader, address(sakePerpVault), positionResp.marginToVault.abs().toUint());
            } else if (positionResp.marginToVault.toInt() < 0) {
                withdraw(_exchange, trader, positionResp.marginToVault.abs());
            }

            //check MM
            sakePerpVault.requireMMNotBankrupt(address(_exchange));
        }

        // calculate fee and transfer token for fees
        //@audit - can optimize by changing amm.swapInput/swapOutput's return type to (exchangedAmount, quoteToll, quoteSpread, quoteReserve, baseReserve) (@wraecca)
        Decimal.decimal memory transferredFee = transferFee(trader, _exchange, positionResp.exchangedQuoteAssetAmount);

        // emit event
        uint256 spotPrice = _exchange.getSpotPrice().toUint();
        int256 fundingPayment = positionResp.fundingPayment.toInt(); // pre-fetch for stack too deep error
        uint256 overnightFee = positionResp.overnightFee.toUint();
        emit PositionChanged(
            trader,
            address(_exchange),
            positionResp.position.margin.toUint(),
            positionResp.exchangedQuoteAssetAmount.toUint(),
            positionResp.exchangedPositionSize.toInt(),
            transferredFee.toUint(),
            positionResp.position.size.toInt(),
            positionResp.realizedPnl.toInt(),
            positionResp.unrealizedPnlAfter.toInt(),
            positionResp.badDebt.toUint(),
            0,
            spotPrice,
            fundingPayment,
            overnightFee
        );
    }

    /**
     * @notice close all the positions
     * @param _exchange IExchange address
     */
    function closePosition(IExchange _exchange, Decimal.decimal calldata _quoteAssetAmountLimit)
        external
        whenNotPaused()
        nonReentrant()
    {
        // check conditions
        requireExchange(_exchange, true);
        requireNotRestrictionMode(_exchange);

        // update position
        address trader = msg.sender;
        Position memory position = adjustPositionForLiquidityChanged(_exchange, trader);
        Side _side = position.size.isNegative() ? Side.BUY : Side.SELL;
        require(
            sakePerpState.checkWaitingPeriod(address(_exchange), trader, _side),
            "cannot close position during waiting period"
        );

        PositionResp memory positionResp = internalClosePosition(_exchange, trader, _quoteAssetAmountLimit, true);

        {
            // add scope for stack too deep error
            // transfer the actual token from trader and vault
            if (positionResp.badDebt.toUint() > 0) {
                enterRestrictionMode(_exchange);
                realizeBadDebt(_exchange, positionResp.badDebt);
            }
            withdraw(_exchange, trader, positionResp.marginToVault.abs());
        }

        //check MM
        sakePerpVault.requireMMNotBankrupt(address(_exchange));

        // calculate fee and transfer token for fees
        Decimal.decimal memory transferredFee = transferFee(trader, _exchange, positionResp.exchangedQuoteAssetAmount);

        {
            // avoid stack too deep
            // prepare event
            uint256 spotPrice = _exchange.getSpotPrice().toUint();
            int256 fundingPayment = positionResp.fundingPayment.toInt();
            uint256 overnightFee = positionResp.overnightFee.toUint();
            emit PositionChanged(
                trader,
                address(_exchange),
                0, // margin
                positionResp.exchangedQuoteAssetAmount.toUint(),
                positionResp.exchangedPositionSize.toInt(),
                transferredFee.toUint(),
                positionResp.position.size.toInt(),
                positionResp.realizedPnl.toInt(),
                0, // unrealizedPnl
                positionResp.badDebt.toUint(),
                0,
                spotPrice,
                fundingPayment,
                overnightFee
            );
        }
    }

    /**
     * @notice liquidate trader's underwater position. Require trader's margin ratio less than maintenance margin ratio
     * @dev liquidator can NOT open any positions in the same block to prevent from price manipulation.
     * @param _exchange IExchange address
     * @param _trader trader address
     */
    function liquidate(IExchange _exchange, address _trader) external nonReentrant() {
        // check conditions
        requireExchange(_exchange, true);
        {
            SignedDecimal.signedDecimal memory marginRatio = getMarginRatio(_exchange, _trader);

            // including oracle-based margin ratio as reference price when amm is over spread limit
            if (_exchange.isOverSpreadLimit()) {
                SignedDecimal.signedDecimal memory marginRatioBasedOnOracle = getMarginRatioBasedOnOracle(_exchange, _trader);
                if (marginRatioBasedOnOracle.subD(marginRatio).toInt() > 0) {
                    marginRatio = marginRatioBasedOnOracle;
                }
            }
            requireMoreMarginRatio(marginRatio, _exchange.maintenanceMarginRatio(), false);
        }

        // update states
        adjustPositionForLiquidityChanged(_exchange, _trader);
        PositionResp memory positionResp = internalClosePosition(_exchange, _trader, Decimal.zero(), false);
        enterRestrictionMode(_exchange);

        {
            // avoid stack too deep
            // Amount pay to liquidator
            Decimal.decimal memory liquidationFee =
                positionResp.exchangedQuoteAssetAmount.mulD(_exchange.liquidationFeeRatio());
            if (liquidationFee.cmp(_exchange.maxLiquidationFee()) > 0) {
                liquidationFee = _exchange.maxLiquidationFee();
            }

            // neither trader nor liquidator should pay anything for liquidating position
            // in here, -marginToVault means remainMargin

            Decimal.decimal memory remainMargin = positionResp.marginToVault.abs();
            // add scope for stack too deep error
            // if the remainMargin is not enough for liquidationFee, count it as bad debt
            // else, then the rest will be transferred to insuranceFund
            Decimal.decimal memory liquidationBadDebt;
            Decimal.decimal memory totalBadDebt = positionResp.badDebt;
            SignedDecimal.signedDecimal memory totalMarginToVault = positionResp.marginToVault;
            if (liquidationFee.toUint() > remainMargin.toUint()) {
                liquidationBadDebt = liquidationFee.subD(remainMargin);
                totalBadDebt = totalBadDebt.addD(liquidationBadDebt);
            } else {
                totalMarginToVault = totalMarginToVault.addD(liquidationFee);
            }

            // transfer the actual token between trader and vault
            if (totalBadDebt.toUint() > 0) {
                realizeBadDebt(_exchange, totalBadDebt);
            }
            if (totalMarginToVault.toInt() < 0) {
                transferToInsuranceFund(_exchange, totalMarginToVault.abs());
            }
            withdraw(_exchange, msg.sender, liquidationFee);

            emit PositionLiquidated(
                _trader,
                address(_exchange),
                positionResp.exchangedQuoteAssetAmount.toUint(),
                positionResp.exchangedPositionSize.toUint(),
                liquidationFee.toUint(),
                msg.sender,
                liquidationBadDebt.toUint()
            );
        }

        {
            emit PositionChanged(
                _trader,
                address(_exchange),
                0,
                positionResp.exchangedQuoteAssetAmount.toUint(),
                positionResp.exchangedPositionSize.toInt(),
                0,
                0,
                positionResp.realizedPnl.toInt(),
                0,
                positionResp.badDebt.toUint(),
                positionResp.marginToVault.abs().toUint(),
                _exchange.getSpotPrice().toUint(),
                positionResp.fundingPayment.toInt(),
                positionResp.overnightFee.toUint()
            );
        }
    }

    /**
     * @notice if funding rate is positive, traders with long position pay traders with short position and vice versa.
     * @param _exchange IExchange address
     */
    function payFunding(IExchange _exchange) external {
        requireExchange(_exchange, true);

        SignedDecimal.signedDecimal memory baseAssetDelta = _exchange.getTotalPositionSize();
        SignedDecimal.signedDecimal memory premiumFraction = _exchange.settleFunding();
        exchangeMap[address(_exchange)].cumulativePremiumFractions.push(
            premiumFraction.addD(getLatestCumulativePremiumFraction(_exchange))
        );

        // funding payment = premium fraction * position
        // eg. if alice takes 10 long position, baseAssetDelta = 10
        // if premiumFraction is positive: long pay short, amm get positive funding payment
        // if premiumFraction is negative: short pay long, amm get negative funding payment
        // if position side * premiumFraction < 0, funding payment is negative which means loss
        SignedDecimal.signedDecimal memory ammFundingPaymentLoss = premiumFraction.mulD(baseAssetDelta);

        if (ammFundingPaymentLoss.toInt() < 0) {
            realizeBadDebt(_exchange, ammFundingPaymentLoss.abs());
        } else {
            handleFundingFeeAndOvernightFee(
                _exchange,
                ammFundingPaymentLoss.abs(),
                systemSettings.fundingFeeLpShareRatio()
            );
            // address insuranceFundAddress = address(systemSettings.getInsuranceFund(_exchange));
            // require(insuranceFundAddress != address(0), "Invalid InsuranceFund");
            // Decimal.decimal memory insuranceFundFee =
            //     ammFundingPaymentLoss.abs().mulD(systemSettings.fundingFeeLpShareRatio());
            // sakePerpVault.withdraw(_exchange.quoteAsset(), insuranceFundAddress, insuranceFundFee);
            // Decimal.decimal memory fundingFee = ammFundingPaymentLoss.abs().subD(insuranceFundFee);
            // sakePerpVault.addCachedLiquidity(_exchange, fundingFee);
        }
    }

    /**
     * @notice if overnight fee rate is positive, traders with long position pay traders with short position and vice versa.
     * @param _exchange IExchange address
     */
    function payOvernightFee(IExchange _exchange) external {
        requireExchange(_exchange, true);
        systemSettings.setNextOvernightFeeTime(_exchange);

        Decimal.decimal memory overnightFeeRate = systemSettings.overnightFeeRatio();
        exchangeMap[address(_exchange)].cumulativeOvernightFeerates.push(
            overnightFeeRate.addD(getLatestCumulativeOvernightFeeRate(_exchange))
        );

        Decimal.decimal memory totalOpenNotional = exchangeMap[address(_exchange)].totalOpenNotional;
        Decimal.decimal memory exchageOvernightPayment = overnightFeeRate.mulD(totalOpenNotional);

        if (exchageOvernightPayment.toUint() > 0) {
            handleFundingFeeAndOvernightFee(
                _exchange,
                exchageOvernightPayment,
                systemSettings.overnightFeeLpShareRatio()
            );
        }

        emit OvernightFeePayed(
            address(_exchange),
            totalOpenNotional.toUint(),
            exchageOvernightPayment.toUint(),
            overnightFeeRate.toUint()
        );
    }

    /**
     * @notice adjust msg.sender's position when liquidity migration happened
     * @param _exchange Exchange address
     */
    function adjustPosition(IExchange _exchange) external {
        adjustPositionForLiquidityChanged(_exchange, msg.sender);
    }

    //
    // VIEW FUNCTIONS
    //
    /**
     * @notice get margin ratio, marginRatio = (margin + funding payments + unrealized Pnl) / openNotional
     * use spot and twap price to calculate unrealized Pnl, final unrealized Pnl depends on which one is higher
     * @param _exchange IExchange address
     * @param _trader trader address
     * @return margin ratio in 18 digits
     */
    function getMarginRatio(IExchange _exchange, address _trader)
        public
        view
        override
        returns (SignedDecimal.signedDecimal memory)
    {
        Position memory position = getPosition(_exchange, _trader);
        requirePositionSize(position.size);
        requireNonZeroInput(position.openNotional);

        (Decimal.decimal memory spotPositionNotional, SignedDecimal.signedDecimal memory spotPricePnl) =
            (getPositionNotionalAndUnrealizedPnl(_exchange, _trader, PnlCalcOption.SPOT_PRICE));
        (Decimal.decimal memory twapPositionNotional, SignedDecimal.signedDecimal memory twapPricePnl) =
            (getPositionNotionalAndUnrealizedPnl(_exchange, _trader, PnlCalcOption.TWAP));
        (SignedDecimal.signedDecimal memory unrealizedPnl, Decimal.decimal memory positionNotional) =
            spotPricePnl.toInt() > twapPricePnl.toInt()
                ? (spotPricePnl, spotPositionNotional)
                : (twapPricePnl, twapPositionNotional);

        return _getMarginRatio(_exchange, position, unrealizedPnl, positionNotional);
    }

    function getMarginRatioBasedOnOracle(IExchange _exchange, address _trader)
        public
        view
        returns (SignedDecimal.signedDecimal memory)
    {
        Position memory position = getPosition(_exchange, _trader);
        requirePositionSize(position.size);
        (Decimal.decimal memory oraclePositionNotional, SignedDecimal.signedDecimal memory oraclePricePnl) =
            (getPositionNotionalAndUnrealizedPnl(_exchange, _trader, PnlCalcOption.ORACLE));
        return _getMarginRatio(_exchange, position, oraclePricePnl, oraclePositionNotional);
    }

    function _getMarginRatio(
        IExchange _exchange,
        Position memory _position,
        SignedDecimal.signedDecimal memory _unrealizedPnl,
        Decimal.decimal memory _positionNotional
    ) internal view returns (SignedDecimal.signedDecimal memory) {
        ISakePerpState.RemainMarginInfo memory remainMarginInfo =
            sakePerpState.calcRemainMarginWithFundingPaymentAndOvernightFee(_exchange, _position, _unrealizedPnl);
        return
            MixedDecimal.fromDecimal(remainMarginInfo.remainMargin).subD(remainMarginInfo.badDebt).divD(
                _positionNotional
            );
    }

    /**
     * @notice get personal position information, and adjust size if migration is necessary
     * @param _exchange IExchange address
     * @param _trader trader address
     * @return struct Position
     */
    function getPosition(IExchange _exchange, address _trader) public view override returns (Position memory) {
        Position memory pos = getUnadjustedPosition(_exchange, _trader);
        uint256 latestLiquidityIndex = _exchange.getLiquidityHistoryLength().sub(1);
        if (pos.liquidityHistoryIndex == latestLiquidityIndex) {
            return pos;
        }

        return sakePerpState.calcPositionAfterLiquidityMigration(_exchange, pos, latestLiquidityIndex);
    }

    /**
     * @notice get position notional and unrealized Pnl without fee expense and funding payment
     * @param _exchange IExchange address
     * @param _trader trader address
     * @param _pnlCalcOption enum PnlCalcOption, SPOT_PRICE for spot price and TWAP for twap price
     * @return positionNotional position notional
     * @return unrealizedPnl unrealized Pnl
     */
    function getPositionNotionalAndUnrealizedPnl(
        IExchange _exchange,
        address _trader,
        PnlCalcOption _pnlCalcOption
    )
        public
        view
        override
        returns (Decimal.decimal memory positionNotional, SignedDecimal.signedDecimal memory unrealizedPnl)
    {
        Position memory position = getPosition(_exchange, _trader);
        return sakePerpState.getPositionNotionalAndUnrealizedPnl(_exchange, position, _pnlCalcOption);
    }

    /**
     * @notice get latest cumulative premium fraction.
     * @param _exchange IExchange address
     * @return latest cumulative premium fraction in 18 digits
     */
    function getLatestCumulativePremiumFraction(IExchange _exchange)
        public
        view
        override
        returns (SignedDecimal.signedDecimal memory)
    {
        uint256 len = exchangeMap[address(_exchange)].cumulativePremiumFractions.length;
        if (len > 0) {
            return exchangeMap[address(_exchange)].cumulativePremiumFractions[len - 1];
        }
    }

    /**
     * @notice get latest cumulative overnight feerate.
     * @param _exchange IExchange address
     * @return latest cumulative overnight feerate in 18 digits
     */
    function getLatestCumulativeOvernightFeeRate(IExchange _exchange)
        public
        view
        override
        returns (Decimal.decimal memory)
    {
        uint256 len = exchangeMap[address(_exchange)].cumulativeOvernightFeerates.length;
        if (len > 0) {
            return exchangeMap[address(_exchange)].cumulativeOvernightFeerates[len - 1];
        }
    }

    /**
     * @notice get MM liquidity.
     * @param _exchange IExchange address
     * @return MM liquidity in 18 digits
     *
     */
    function getMMLiquidity(address _exchange) public view override returns (SignedDecimal.signedDecimal memory) {
        return sakePerpVault.getTotalMMLiquidity(_exchange);
    }

    //
    // INTERNAL FUNCTIONS
    //

    function enterRestrictionMode(IExchange _exchange) internal {
        uint256 blockNumber = _blockNumber();
        exchangeMap[address(_exchange)].lastRestrictionBlock = blockNumber;
        emit RestrictionModeEntered(address(_exchange), blockNumber);
    }

    function setPosition(
        IExchange _exchange,
        address _trader,
        Position memory _position
    ) internal {
        Position storage positionStorage = exchangeMap[address(_exchange)].positionMap[_trader];
        exchangeMap[address(_exchange)].totalOpenNotional = exchangeMap[address(_exchange)].totalOpenNotional.subD(
            positionStorage.openNotional
        );
        positionStorage.size = _position.size;
        positionStorage.margin = _position.margin;
        positionStorage.openNotional = _position.openNotional;
        positionStorage.lastUpdatedCumulativePremiumFraction = _position.lastUpdatedCumulativePremiumFraction;
        positionStorage.lastUpdatedCumulativeOvernightFeeRate = _position.lastUpdatedCumulativeOvernightFeeRate;
        positionStorage.blockNumber = _position.blockNumber;
        positionStorage.liquidityHistoryIndex = _position.liquidityHistoryIndex;
        exchangeMap[address(_exchange)].totalOpenNotional = exchangeMap[address(_exchange)].totalOpenNotional.addD(
            positionStorage.openNotional
        );
    }

    function clearPosition(IExchange _exchange, address _trader) internal {
        Position memory position = exchangeMap[address(_exchange)].positionMap[_trader];
        exchangeMap[address(_exchange)].totalOpenNotional = exchangeMap[address(_exchange)].totalOpenNotional.subD(
            position.openNotional
        );

        // keep the record in order to retain the last updated block number
        exchangeMap[address(_exchange)].positionMap[_trader] = Position({
            size: SignedDecimal.zero(),
            margin: Decimal.zero(),
            openNotional: Decimal.zero(),
            lastUpdatedCumulativePremiumFraction: SignedDecimal.zero(),
            lastUpdatedCumulativeOvernightFeeRate: Decimal.zero(),
            blockNumber: _blockNumber(),
            liquidityHistoryIndex: 0
        });
    }

    // only called from openPosition and closeAndOpenReversePosition. caller need to ensure there's enough marginRatio
    function internalIncreasePosition(
        IExchange _exchange,
        Side _side,
        Decimal.decimal memory _openNotional,
        Decimal.decimal memory _minPositionSize,
        Decimal.decimal memory _leverage
    ) internal returns (PositionResp memory positionResp) {
        address trader = msg.sender;
        Position memory oldPosition = getUnadjustedPosition(_exchange, trader);
        positionResp.exchangedPositionSize = swapInput(_exchange, _side, _openNotional, _minPositionSize);
        SignedDecimal.signedDecimal memory newSize = oldPosition.size.addD(positionResp.exchangedPositionSize);
        // if size is 0 (means a new position), set the latest liquidity index
        uint256 liquidityHistoryIndex = oldPosition.liquidityHistoryIndex;
        if (oldPosition.size.toInt() == 0) {
            liquidityHistoryIndex = _exchange.getLiquidityHistoryLength().sub(1);
        }

        sakePerpState.updateOpenInterestNotional(_exchange, MixedDecimal.fromDecimal(_openNotional));
        // if the trader is not in the whitelist, check max position size
        if (trader != sakePerpState.getWhiteList()) {
            Decimal.decimal memory maxHoldingBaseAsset = _exchange.getMaxHoldingBaseAsset();
            if (maxHoldingBaseAsset.toUint() > 0) {
                // total position size should be less than `positionUpperBound`
                require(newSize.abs().cmp(maxHoldingBaseAsset) <= 0, "hit position size upper bound");
            }
        }

        Position memory position;
        {
            //avoid stakc too deep
            SignedDecimal.signedDecimal memory increaseMarginRequirement =
                MixedDecimal.fromDecimal(_openNotional.divD(_leverage));

            ISakePerpState.RemainMarginInfo memory remainMarginInfo =
                sakePerpState.calcRemainMarginWithFundingPaymentAndOvernightFee(
                    _exchange,
                    oldPosition,
                    increaseMarginRequirement
                );

            positionResp.marginToVault = increaseMarginRequirement;
            positionResp.fundingPayment = remainMarginInfo.fundingPayment;
            positionResp.overnightFee = remainMarginInfo.overnightFee;

            position.margin = remainMarginInfo.remainMargin;
        }

        {
            //avoid stack too deep
            (, SignedDecimal.signedDecimal memory unrealizedPnl) =
                getPositionNotionalAndUnrealizedPnl(_exchange, trader, PnlCalcOption.SPOT_PRICE);
            positionResp.unrealizedPnlAfter = unrealizedPnl;
        }

        // update positionResp
        positionResp.exchangedQuoteAssetAmount = _openNotional;
        position.size = newSize;
        position.openNotional = oldPosition.openNotional.addD(positionResp.exchangedQuoteAssetAmount);
        position.liquidityHistoryIndex = liquidityHistoryIndex;
        position.lastUpdatedCumulativePremiumFraction = getLatestCumulativePremiumFraction(_exchange);
        position.lastUpdatedCumulativeOvernightFeeRate = getLatestCumulativeOvernightFeeRate(_exchange);
        position.blockNumber = _blockNumber();
        positionResp.position = position;
    }

    function openReversePosition(
        IExchange _exchange,
        Side _side,
        Decimal.decimal memory _quoteAssetAmount,
        Decimal.decimal memory _leverage,
        Decimal.decimal memory _baseAssetAmountLimit
    ) internal returns (PositionResp memory) {
        Decimal.decimal memory openNotional = _quoteAssetAmount.mulD(_leverage);
        (Decimal.decimal memory oldPositionNotional, SignedDecimal.signedDecimal memory unrealizedPnl) =
            getPositionNotionalAndUnrealizedPnl(_exchange, msg.sender, PnlCalcOption.SPOT_PRICE);
        PositionResp memory positionResp;

        // reduce position if old position is larger
        if (oldPositionNotional.toUint() > openNotional.toUint()) {
            sakePerpState.updateOpenInterestNotional(_exchange, MixedDecimal.fromDecimal(openNotional).mulScalar(-1));
            Position memory oldPosition = getUnadjustedPosition(_exchange, msg.sender);
            positionResp.exchangedPositionSize = swapInput(_exchange, _side, openNotional, _baseAssetAmountLimit);

            // realizedPnl = unrealizedPnl * closedRatio
            // closedRatio = positionResp.exchangedPositionSiz / oldPosition.size
            if (oldPosition.size.toInt() != 0) {
                positionResp.realizedPnl = unrealizedPnl.mulD(positionResp.exchangedPositionSize.abs()).divD(
                    oldPosition.size.abs()
                );
            }

            //
            {
                //avoid stack too deep
                ISakePerpState.RemainMarginInfo memory remainMarginInfo =
                    sakePerpState.calcRemainMarginWithFundingPaymentAndOvernightFee(
                        _exchange,
                        oldPosition,
                        positionResp.realizedPnl
                    );

                positionResp.badDebt = remainMarginInfo.badDebt;
                positionResp.fundingPayment = remainMarginInfo.fundingPayment;
                positionResp.overnightFee = remainMarginInfo.overnightFee;
                positionResp.exchangedQuoteAssetAmount = openNotional;

                //stack too deep, temp use oldPosition
                oldPosition.margin = remainMarginInfo.remainMargin;
                //position.margin = remainMargin;
            }

            // positionResp.unrealizedPnlAfter = unrealizedPnl - realizedPnl
            positionResp.unrealizedPnlAfter = unrealizedPnl.subD(positionResp.realizedPnl);

            // calculate openNotional (it's different depends on long or short side)
            // long: unrealizedPnl = positionNotional - openNotional => openNotional = positionNotional - unrealizedPnl
            // short: unrealizedPnl = openNotional - positionNotional => openNotional = positionNotional + unrealizedPnl
            // positionNotional = oldPositionNotional - exchangedQuoteAssetAmount
            SignedDecimal.signedDecimal memory remainOpenNotional =
                oldPosition.size.toInt() > 0
                    ? MixedDecimal.fromDecimal(oldPositionNotional).subD(positionResp.exchangedQuoteAssetAmount).subD(
                        positionResp.unrealizedPnlAfter
                    )
                    : positionResp.unrealizedPnlAfter.addD(oldPositionNotional).subD(
                        positionResp.exchangedQuoteAssetAmount
                    );
            require(remainOpenNotional.toInt() > 0, "value of openNotional <= 0");

            {
                Position memory position;
                position.margin = oldPosition.margin;
                position.size = oldPosition.size.addD(positionResp.exchangedPositionSize);
                position.openNotional = remainOpenNotional.abs();
                position.liquidityHistoryIndex = oldPosition.liquidityHistoryIndex;
                position.lastUpdatedCumulativePremiumFraction = getLatestCumulativePremiumFraction(_exchange);
                position.lastUpdatedCumulativeOvernightFeeRate = getLatestCumulativeOvernightFeeRate(_exchange);
                position.blockNumber = _blockNumber();
                positionResp.position = position;
            }

            return positionResp;
        }

        return closeAndOpenReversePosition(_exchange, _side, _quoteAssetAmount, _leverage, _baseAssetAmountLimit);
    }

    function closeAndOpenReversePosition(
        IExchange _exchange,
        Side _side,
        Decimal.decimal memory _quoteAssetAmount,
        Decimal.decimal memory _leverage,
        Decimal.decimal memory _baseAssetAmountLimit
    ) internal returns (PositionResp memory positionResp) {
        // new position size is larger than or equal to the old position size
        // so either close or close then open a larger position
        PositionResp memory closePositionResp = internalClosePosition(_exchange, msg.sender, Decimal.zero(), true);
        // the old position is underwater. trader should close a position first
        require(closePositionResp.badDebt.toUint() == 0, "reduce an underwater position");

        // update open notional after closing position
        Decimal.decimal memory openNotional =
            _quoteAssetAmount.mulD(_leverage).subD(closePositionResp.exchangedQuoteAssetAmount);

        // if remain exchangedQuoteAssetAmount is too small (eg. 1wei) then the required margin might be 0
        // then the clearingHouse will stop opening position
        if (openNotional.divD(_leverage).toUint() == 0) {
            positionResp = closePositionResp;
        } else {
            Decimal.decimal memory updatedBaseAssetAmountLimit;
            if (_baseAssetAmountLimit.toUint() > closePositionResp.exchangedPositionSize.toUint()) {
                updatedBaseAssetAmountLimit = _baseAssetAmountLimit.subD(closePositionResp.exchangedPositionSize.abs());
            }

            PositionResp memory increasePositionResp =
                internalIncreasePosition(_exchange, _side, openNotional, updatedBaseAssetAmountLimit, _leverage);
            positionResp = PositionResp({
                position: increasePositionResp.position,
                exchangedQuoteAssetAmount: closePositionResp.exchangedQuoteAssetAmount.addD(
                    increasePositionResp.exchangedQuoteAssetAmount
                ),
                badDebt: closePositionResp.badDebt.addD(increasePositionResp.badDebt),
                fundingPayment: closePositionResp.fundingPayment.addD(increasePositionResp.fundingPayment),
                overnightFee: closePositionResp.overnightFee.addD(increasePositionResp.overnightFee),
                exchangedPositionSize: closePositionResp.exchangedPositionSize.addD(
                    increasePositionResp.exchangedPositionSize
                ),
                realizedPnl: closePositionResp.realizedPnl.addD(increasePositionResp.realizedPnl),
                unrealizedPnlAfter: SignedDecimal.zero(),
                marginToVault: closePositionResp.marginToVault.addD(increasePositionResp.marginToVault)
            });
        }
        return positionResp;
    }

    function internalClosePosition(
        IExchange _exchange,
        address _trader,
        Decimal.decimal memory _quoteAssetAmountLimit,
        bool _skipFluctuationCheck
    ) private returns (PositionResp memory positionResp) {
        // check conditions
        Position memory oldPosition = getUnadjustedPosition(_exchange, _trader);
        SignedDecimal.signedDecimal memory oldPositionSize = oldPosition.size;
        requirePositionSize(oldPositionSize);

        (, SignedDecimal.signedDecimal memory unrealizedPnl) =
            getPositionNotionalAndUnrealizedPnl(_exchange, _trader, PnlCalcOption.SPOT_PRICE);

        ISakePerpState.RemainMarginInfo memory remainMarginInfo =
            sakePerpState.calcRemainMarginWithFundingPaymentAndOvernightFee(_exchange, oldPosition, unrealizedPnl);

        positionResp.exchangedPositionSize = oldPositionSize.mulScalar(-1);
        positionResp.realizedPnl = unrealizedPnl;
        positionResp.badDebt = remainMarginInfo.badDebt;
        positionResp.fundingPayment = remainMarginInfo.fundingPayment;
        positionResp.overnightFee = remainMarginInfo.overnightFee;
        positionResp.marginToVault = MixedDecimal.fromDecimal(remainMarginInfo.remainMargin).mulScalar(-1);
        positionResp.exchangedQuoteAssetAmount = _exchange.swapOutput(
            oldPositionSize.toInt() > 0 ? IExchangeTypes.Dir.ADD_TO_AMM : IExchangeTypes.Dir.REMOVE_FROM_AMM,
            oldPositionSize.abs(),
            _quoteAssetAmountLimit,
            _skipFluctuationCheck
        );

        // bankrupt position's bad debt will be also consider as a part of the open interest
        sakePerpState.updateOpenInterestNotional(
            _exchange,
            unrealizedPnl.addD(remainMarginInfo.badDebt).addD(oldPosition.openNotional).mulScalar(-1)
        );
        clearPosition(_exchange, _trader);
    }

    function swapInput(
        IExchange _exchange,
        Side _side,
        Decimal.decimal memory _inputAmount,
        Decimal.decimal memory _minOutputAmount
    ) internal returns (SignedDecimal.signedDecimal memory) {
        IExchangeTypes.Dir dir =
            (_side == Side.BUY) ? IExchangeTypes.Dir.ADD_TO_AMM : IExchangeTypes.Dir.REMOVE_FROM_AMM;
        SignedDecimal.signedDecimal memory outputAmount =
            MixedDecimal.fromDecimal(_exchange.swapInput(dir, _inputAmount, _minOutputAmount));
        if (IExchangeTypes.Dir.REMOVE_FROM_AMM == dir) {
            return outputAmount.mulScalar(-1);
        }
        return outputAmount;
    }

    function transferFee(
        address _from,
        IExchange _exchange,
        Decimal.decimal memory _positionNotional
    ) internal returns (Decimal.decimal memory) {
        Decimal.decimal memory fee = _exchange.calcFee(_positionNotional);
        if (fee.toUint() > 0) {
            address insuranceFundAddress = address(systemSettings.getInsuranceFund(_exchange));
            require(insuranceFundAddress != address(0), "Invalid InsuranceFund");
            Decimal.decimal memory insuranceFundFee = fee.mulD(systemSettings.insuranceFundFeeRatio());
            IERC20Upgradeable(_exchange.quoteAsset()).safeTransferFrom(
                _from,
                address(insuranceFundAddress),
                insuranceFundFee.toUint()
            );
            Decimal.decimal memory lpFee = fee.subD(insuranceFundFee);
            IERC20Upgradeable(_exchange.quoteAsset()).safeTransferFrom(_from, address(sakePerpVault), lpFee.toUint());
            sakePerpVault.addCachedLiquidity(address(_exchange), lpFee);
            return fee;
        }

        return Decimal.zero();
    }

    function withdraw(
        IExchange _exchange,
        address _receiver,
        Decimal.decimal memory _amount
    ) internal {
        return sakePerpVault.withdraw(_exchange, _receiver, _amount);
    }

    function realizeBadDebt(IExchange _exchange, Decimal.decimal memory _badDebt) internal {
        return sakePerpVault.realizeBadDebt(_exchange, _badDebt);
    }

    function transferToInsuranceFund(IExchange _exchange, Decimal.decimal memory _amount) internal {
        IInsuranceFund insuranceFund = systemSettings.getInsuranceFund(_exchange);
        sakePerpVault.withdraw(_exchange, address(insuranceFund), _amount);
    }

    function handleFundingFeeAndOvernightFee(
        IExchange _exchange,
        Decimal.decimal memory _fee,
        Decimal.decimal memory _insuranceFundRatio
    ) internal {
        address insuranceFundAddress = address(systemSettings.getInsuranceFund(_exchange));
        require(insuranceFundAddress != address(0), "Invalid InsuranceFund");
        Decimal.decimal memory insuranceFundFee = _fee.mulD(_insuranceFundRatio);
        sakePerpVault.withdraw(_exchange, insuranceFundAddress, insuranceFundFee);
        Decimal.decimal memory vaultFee = _fee.subD(insuranceFundFee);
        sakePerpVault.addCachedLiquidity(address(_exchange), vaultFee);
    }

    //
    // INTERNAL VIEW FUNCTIONS
    //

    function adjustPositionForLiquidityChanged(IExchange _exchange, address _trader)
        internal
        returns (Position memory)
    {
        Position memory unadjustedPosition = getUnadjustedPosition(_exchange, _trader);
        if (unadjustedPosition.size.toInt() == 0) {
            return unadjustedPosition;
        }
        uint256 latestLiquidityIndex = _exchange.getLiquidityHistoryLength().sub(1);
        if (unadjustedPosition.liquidityHistoryIndex == latestLiquidityIndex) {
            return unadjustedPosition;
        }

        Position memory adjustedPosition =
            sakePerpState.calcPositionAfterLiquidityMigration(_exchange, unadjustedPosition, latestLiquidityIndex);
        SignedDecimal.signedDecimal memory oldAdjustedPosition =
            sakePerpState.calcPositionAfterLiquidityMigrationWithoutNew(
                _exchange,
                unadjustedPosition,
                latestLiquidityIndex
            );
        _exchange.adjustTotalPosition(adjustedPosition.size, oldAdjustedPosition);

        setPosition(_exchange, _trader, adjustedPosition);
        emit PositionAdjusted(
            address(_exchange),
            _trader,
            adjustedPosition.size.toInt(),
            unadjustedPosition.liquidityHistoryIndex,
            adjustedPosition.liquidityHistoryIndex
        );
        return adjustedPosition;
    }

    function getUnadjustedPosition(IExchange _exchange, address _trader)
        public
        view
        override
        returns (Position memory position)
    {
        position = exchangeMap[address(_exchange)].positionMap[_trader];
    }

    //
    // REQUIRE FUNCTIONS
    //
    function requireExchange(IExchange _exchange, bool _open) private view {
        require(systemSettings.isExistedExchange(_exchange), "exchange not found");
        require(_open == _exchange.open(), _open ? "exchange was closed" : "exchange is open");
    }

    function requireNonZeroInput(Decimal.decimal memory _decimal) private pure {
        require(_decimal.toUint() != 0, "input is 0");
    }

    function requirePositionSize(SignedDecimal.signedDecimal memory _size) private pure {
        require(_size.toInt() != 0, "positionSize is 0");
    }

    function requireNotRestrictionMode(IExchange _exchange) private view {
        uint256 currentBlock = _blockNumber();
        if (currentBlock == exchangeMap[address(_exchange)].lastRestrictionBlock) {
            require(
                getUnadjustedPosition(_exchange, msg.sender).blockNumber != currentBlock,
                "only one action allowed"
            );
        }
    }

    function requireMoreMarginRatio(
        SignedDecimal.signedDecimal memory _marginRatio,
        Decimal.decimal memory _baseMarginRatio,
        bool _largerThanOrEqualTo
    ) private pure {
        int256 remainingMarginRatio = _marginRatio.subD(_baseMarginRatio).toInt();
        require(
            _largerThanOrEqualTo ? remainingMarginRatio >= 0 : remainingMarginRatio < 0,
            "Margin ratio not meet criteria"
        );
    }

    //
    // Set System Open Flag
    //
    function pause(bool _pause) public onlyOwner {
        paused = _pause;
    }
}

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"exchange","type":"address"},{"indexed":false,"internalType":"int256","name":"amount","type":"int256"},{"indexed":false,"internalType":"int256","name":"fundingPayment","type":"int256"},{"indexed":false,"internalType":"uint256","name":"overnightFee","type":"uint256"}],"name":"MarginChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"exchange","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalOpenNotional","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"overnightFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"OvernightFeePayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"exchange","type":"address"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int256","name":"newPositionSize","type":"int256"},{"indexed":false,"internalType":"uint256","name":"oldLiquidityIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidityIndex","type":"uint256"}],"name":"PositionAdjusted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"exchange","type":"address"},{"indexed":false,"internalType":"uint256","name":"margin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionNotional","type":"uint256"},{"indexed":false,"internalType":"int256","name":"exchangedPositionSize","type":"int256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"int256","name":"positionSizeAfter","type":"int256"},{"indexed":false,"internalType":"int256","name":"realizedPnl","type":"int256"},{"indexed":false,"internalType":"int256","name":"unrealizedPnlAfter","type":"int256"},{"indexed":false,"internalType":"uint256","name":"badDebt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidationPenalty","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"spotPrice","type":"uint256"},{"indexed":false,"internalType":"int256","name":"fundingPayment","type":"int256"},{"indexed":false,"internalType":"uint256","name":"overnightPayment","type":"uint256"}],"name":"PositionChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"exchange","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionNotional","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidationFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"uint256","name":"badDebt","type":"uint256"}],"name":"PositionLiquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"exchange","type":"address"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint256","name":"valueTransferred","type":"uint256"}],"name":"PositionSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"exchange","type":"address"},{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"RestrictionModeEntered","type":"event"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_addedMargin","type":"tuple"}],"name":"addMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"}],"name":"adjustPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_quoteAssetAmountLimit","type":"tuple"}],"name":"closePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"}],"name":"getLatestCumulativeOvernightFeeRate","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"}],"name":"getLatestCumulativePremiumFraction","outputs":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_exchange","type":"address"}],"name":"getMMLiquidity","outputs":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"},{"internalType":"address","name":"_trader","type":"address"}],"name":"getMarginRatio","outputs":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"},{"internalType":"address","name":"_trader","type":"address"}],"name":"getMarginRatioBasedOnOracle","outputs":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"},{"internalType":"address","name":"_trader","type":"address"}],"name":"getPosition","outputs":[{"components":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"size","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"margin","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"openNotional","type":"tuple"},{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"lastUpdatedCumulativePremiumFraction","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"lastUpdatedCumulativeOvernightFeeRate","type":"tuple"},{"internalType":"uint256","name":"liquidityHistoryIndex","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"internalType":"struct ISakePerpTypes.Position","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"},{"internalType":"address","name":"_trader","type":"address"},{"internalType":"enum ISakePerpTypes.PnlCalcOption","name":"_pnlCalcOption","type":"uint8"}],"name":"getPositionNotionalAndUnrealizedPnl","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"positionNotional","type":"tuple"},{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"unrealizedPnl","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"},{"internalType":"address","name":"_trader","type":"address"}],"name":"getUnadjustedPosition","outputs":[{"components":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"size","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"margin","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"openNotional","type":"tuple"},{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"lastUpdatedCumulativePremiumFraction","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"lastUpdatedCumulativeOvernightFeeRate","type":"tuple"},{"internalType":"uint256","name":"liquidityHistoryIndex","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"internalType":"struct ISakePerpTypes.Position","name":"position","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_systemsettings","type":"address"},{"internalType":"address","name":"_sakePerpVault","type":"address"},{"internalType":"address","name":"_sakePerpState","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"},{"internalType":"address","name":"_trader","type":"address"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"},{"internalType":"enum ISakePerpTypes.Side","name":"_side","type":"uint8"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_quoteAssetAmount","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_leverage","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_baseAssetAmountLimit","type":"tuple"}],"name":"openPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_pause","type":"bool"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"}],"name":"payFunding","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"}],"name":"payOvernightFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_removedMargin","type":"tuple"}],"name":"removeMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sakePerpState","outputs":[{"internalType":"contract ISakePerpState","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sakePerpVault","outputs":[{"internalType":"contract ISakePerpVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISystemSettings","name":"_systemSettings","type":"address"}],"name":"setSystemSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IExchange","name":"_exchange","type":"address"}],"name":"settlePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"systemSettings","outputs":[{"internalType":"contract ISystemSettings","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50615a1180620000216000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c8063893d242d116100f9578063c0c53b8b11610097578063ea0a45f911610071578063ea0a45f914610379578063f2fde38b1461038c578063f47f81d31461039f578063fc0cc0a8146103a7576101a9565b8063c0c53b8b14610340578063d14da41614610353578063e4d8074e14610366576101a9565b80639a1a142e116100d35780639a1a142e146102f4578063a8c1b0bc14610307578063ac06a96e1461031a578063b33dc1901461032d576101a9565b8063893d242d146102b85780638bedf3bb146102cb5780638da5cb5b146102ec576101a9565b8063517587c61161016657806360b42f121161014057806360b42f12146102825780636891397b1461028a578063715018a61461029d57806386b9d81f146102a5576101a9565b8063517587c6146102385780635bcfc4c41461024d5780635c975abb1461026d576101a9565b806302329a29146101ae5780630475db5a146101c35780632db33aa1146101ec57806330e2ae65146101ff57806336405257146102125780633e09fa1014610225575b600080fd5b6101c16101bc366004614d40565b6103ba565b005b6101d66101d1366004614d78565b61040b565b6040516101e391906158cb565b60405180910390f35b6101c16101fa366004614cbe565b6104ba565b6101c161020d366004614e60565b6104c8565b6101c1610220366004614cbe565b610777565b6101c1610233366004614cbe565b61095b565b610240610b7e565b6040516101e3919061506e565b61026061025b366004614cbe565b610b8d565b6040516101e391906158d9565b610275610c0a565b6040516101e39190615108565b610240610c13565b610260610298366004614cbe565b610c22565b6101c1610c77565b6101c16102b3366004614d78565b610cf6565b6101c16102c6366004614df2565b611297565b6102de6102d9366004614db0565b611833565b6040516101e39291906158e3565b6102406118e6565b610260610302366004614d78565b6118f5565b6101c1610315366004614e60565b611956565b6101c1610328366004614e60565b611c82565b6101d661033b366004614d78565b611e38565b6101c161034e366004614cf6565b611f75565b610260610361366004614cbe565b61204e565b6101c1610374366004614cbe565b6120d6565b610260610387366004614d78565b61212d565b6101c161039a366004614cbe565b6121f2565b6102406122a9565b6101c16103b5366004614cbe565b6122b8565b6103c261250b565b6033546001600160a01b039081169116146103f85760405162461bcd60e51b81526004016103ef9061561b565b60405180910390fd5b609c805460ff1916911515919091179055565b610413614b86565b506001600160a01b0391821660009081526097602090815260408083209390941682526003928301815290839020835161010081018552815460e0820190815281528451808401865260018301548152818401528451808401865260028301548152818601528451808401865293820154845260608101939093528351918201909352600483015481526080820152600582015460a082015260069091015460c082015290565b6104c4813361250f565b5050565b609c5460ff16156104eb5760405162461bcd60e51b81526004016103ef906154c6565b6002609b54141561050e5760405162461bcd60e51b81526004016103ef90615849565b6002609b5561051e826001612790565b61053561053036839003830183614f86565b612926565b3361053e614b86565b610548848361250f565b9050610552614be1565b61057560001961056f61056a36889003880188614f86565b61294e565b906129b2565b905061057f614bf4565b609a54604051638b4a5bf360e01b81526001600160a01b0390911690638b4a5bf3906105b39089908790879060040161516d565b60806040518083038186803b1580156105cb57600080fd5b505afa1580156105df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106039190614f22565b905061061281602001516129d7565b1561062f5760405162461bcd60e51b81526004016103ef90615326565b8051602084015261063f86610c22565b606084015261064d86610b8d565b608084015261065d8685856129db565b6106e261066a878661212d565b876001600160a01b031663e57d56366040518163ffffffff1660e01b815260040160206040518083038186803b1580156106a357600080fd5b505afa1580156106b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106db9190614fab565b6001612aef565b6106fb86856106f636899003890189614f86565b612b30565b856001600160a01b0316846001600160a01b03167f32ee06b7b87a4e31e03f5a752748014a342c37a10b2179a2c422d887c50889fd610739856129d7565b61074685604001516129d7565b61075386606001516129d7565b60405161076293929190615203565b60405180910390a350506001609b5550505050565b6002609b54141561079a5760405162461bcd60e51b81526004016103ef90615849565b6002609b556107aa816000612790565b336107b3614b86565b6107bd8383611e38565b90506107cc8160000151612b9b565b6107d68383612bc0565b6107de614be1565b836001600160a01b031663ec2c0e636040518163ffffffff1660e01b815260040160206040518083038186803b15801561081757600080fd5b505afa15801561082b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084f9190614fab565b9050610859614be1565b610862826129d7565b610871575060208201516108e0565b610879614be1565b6108bf84602001516108b96108b16108a26108978960000151612d85565b60408a015190612db3565b6108ab8861294e565b90612dd0565b875190612e3f565b90612e5c565b905060006108cc826129d7565b13156108de576108db81612d85565b91505b505b60006108eb826129d7565b11156108fc576108fc858583612b30565b836001600160a01b0316856001600160a01b03167fba70e8457921bdd49042182753cb6259c62f923e2b64216b68372cd85ec3af6c61093a846129d7565b60405161094791906158f3565b60405180910390a350506001609b55505050565b610966816001612790565b61096e614be1565b816001600160a01b031663ffbf688e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156109a757600080fd5b505afa1580156109bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109df9190614fab565b90506109e9614be1565b826001600160a01b031663ed83d79c6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610a2457600080fd5b505af1158015610a38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a5c9190614fab565b6001600160a01b0384166000908152609760205260409020909150600101610a8d610a8685610c22565b8390612ec1565b8154600181018355600092835260209092209051910155610aac614be1565b610ab68284612e3f565b90506000610ac3826129d7565b1215610ae057610adb84610ad683612d85565b612ede565b610b78565b610b7884610aed83612d85565b609860009054906101000a90046001600160a01b03166001600160a01b0316635da7c8ec6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b3b57600080fd5b505afa158015610b4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b739190614fab565b612f46565b50505050565b6099546001600160a01b031681565b610b95614be1565b6001600160a01b0382166000908152609760205260409020600201548015610c03576001600160a01b038316600090815260976020526040902060020180546000198301908110610be257fe5b6000918252602091829020604080519384019052015481529150610c059050565b505b919050565b609c5460ff1681565b6098546001600160a01b031681565b610c2a614be1565b6001600160a01b0382166000908152609760205260409020600101548015610c03576001600160a01b038316600090815260976020526040902060010180546000198301908110610be257fe5b610c7f61250b565b6033546001600160a01b03908116911614610cac5760405162461bcd60e51b81526004016103ef9061561b565b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380546001600160a01b0319169055565b6002609b541415610d195760405162461bcd60e51b81526004016103ef90615849565b6002609b55610d29826001612790565b610d31614be1565b610d3b838361212d565b9050826001600160a01b0316639e0103626040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7657600080fd5b505afa158015610d8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dae9190614d5c565b15610de757610dbb614be1565b610dc584846118f5565b90506000610ddb610dd683856130e7565b6129d7565b1315610de5578091505b505b610e6381846001600160a01b03166383acb48a6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e2457600080fd5b505afa158015610e38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5c9190614fab565b6000612aef565b50610e6e828261250f565b50610e77614c33565b610e8b8383610e84613104565b600061311f565b9050610e9683613390565b610e9e614be1565b610f1d846001600160a01b031663cfe711036040518163ffffffff1660e01b815260040160206040518083038186803b158015610eda57600080fd5b505afa158015610eee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f129190614fab565b6020840151906133f6565b90506000610f9c856001600160a01b031663eeb016f26040518163ffffffff1660e01b815260040160206040518083038186803b158015610f5d57600080fd5b505afa158015610f71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f959190614fab565b8390613413565b60000b131561101957836001600160a01b031663eeb016f26040518163ffffffff1660e01b815260040160206040518083038186803b158015610fde57600080fd5b505afa158015610ff2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110169190614fab565b90505b611021614be1565b61102e8360e00151612d85565b9050611038614be1565b611040614be1565b50604084015161104e614be1565b5060e085015161105d846129d7565b611066866129d7565b1115611089576110768585613444565b92506110828284613461565b9150611096565b6110938186612e5c565b90505b60006110a1836129d7565b11156110b1576110b18883612ede565b60006110bc826129d7565b12156110d4576110d4886110cf83612d85565b61347e565b6110df883387612b30565b876001600160a01b0316876001600160a01b03167f5225638a979dd133f201045ab4169ec2189874d864f2b5a10be72ac6e4b421b461112189602001516129d7565b61112e8a60600151613534565b6111378a6129d7565b336111418a6129d7565b6040516111529594939291906158fc565b60405180910390a35050505050826001600160a01b0316826001600160a01b03167f4f7b1ae1435976391e4c35674eb648f299111943bfb8a5c98bfdd1f59e2a73be60006111a385602001516129d7565b6111b086606001516129d7565b6000806111c08960c001516129d7565b60006111cf8b604001516129d7565b6111df610dd68d60e00151612d85565b6112538f6001600160a01b031663dc76fabc6040518163ffffffff1660e01b815260040160206040518083038186803b15801561121b57600080fd5b505afa15801561122f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd69190614fab565b6112608e608001516129d7565b61126d8f60a001516129d7565b6040516112859c9b9a99989796959493929190615219565b60405180910390a350506001609b5550565b609c5460ff16156112ba5760405162461bcd60e51b81526004016103ef906154c6565b6002609b5414156112dd5760405162461bcd60e51b81526004016103ef90615849565b6002609b556112ed856001612790565b6112ff61053036859003850185614f86565b61131161053036849003840184614f86565b61137061133761132636859003850185614f86565b61133161056a613546565b9061356a565b866001600160a01b031663e57d56366040518163ffffffff1660e01b815260040160206040518083038186803b1580156106a357600080fd5b611379856135d5565b609a5460405163542cdc1b60e01b815233916001600160a01b03169063542cdc1b906113ad90899085908a90600401615082565b602060405180830381600087803b1580156113c757600080fd5b505af11580156113db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ff9190614d5c565b61141b5760405162461bcd60e51b81526004016103ef906156ce565b611423614c33565b6000611438611432898561250f565b516129d7565b90506000811561144957600061144c565b60015b905080611499576114996114608a8661212d565b8a6001600160a01b03166383acb48a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156106a357600080fd5b80806114cb57508760018111156114ac57fe5b600083136114bb5760016114be565b60005b60018111156114c957fe5b145b156115265761151f89896114fc6114e7368b90038b018b614f86565b6114f6368d90038d018d614f86565b906133f6565b61150b368a90038a018a614f86565b61151a368c90038c018c614f86565b61362f565b9250611560565b61155d898961153a368b90038b018b614f86565b611549368b90038b018b614f86565b611558368b90038b018b614f86565b6139f3565b92505b61156f898585600001516129db565b600061157e84604001516129d7565b111561158d5761158d89613390565b6000896001600160a01b031663fdf262b76040518163ffffffff1660e01b815260040160206040518083038186803b1580156115c857600080fd5b505afa1580156115dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116009190614cda565b905060006116118560e001516129d7565b13156116585761165385609960009054906101000a90046001600160a01b0316611641610dd68860e00151612d85565b6001600160a01b038516929190613d13565b61167f565b60006116678560e001516129d7565b121561167f5761167f8a866106f68760e00151612d85565b60995460405163f2a5dca360e01b81526001600160a01b039091169063f2a5dca3906116af908d9060040161506e565b600060405180830381600087803b1580156116c957600080fd5b505af11580156116dd573d6000803e3d6000fd5b505050505050506116ec614be1565b6116fb83898460200151613d6b565b9050600061173b896001600160a01b031663dc76fabc6040518163ffffffff1660e01b815260040160206040518083038186803b15801561121b57600080fd5b9050600061174c84608001516129d7565b9050600061175d8560a001516129d7565b90508a6001600160a01b0316866001600160a01b03167f4f7b1ae1435976391e4c35674eb648f299111943bfb8a5c98bfdd1f59e2a73be6117a58860000151602001516129d7565b6117b289602001516129d7565b6117bf8a606001516129d7565b6117c88a6129d7565b8b51516117d4906129d7565b6117e18d60c001516129d7565b6117ef8e61010001516129d7565b6117fc8f604001516129d7565b60008e8e8e6040516118199c9b9a99989796959493929190615219565b60405180910390a350506001609b55505050505050505050565b61183b614be1565b611843614be1565b61184b614b86565b6118558686611e38565b609a54604051637a7e522360e01b81529192506001600160a01b031690637a7e52239061188a90899085908990600401615136565b604080518083038186803b1580156118a157600080fd5b505afa1580156118b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d99190614fc6565b9250925050935093915050565b6033546001600160a01b031690565b6118fd614be1565b611905614b86565b61190f8484611e38565b905061191e8160000151612b9b565b611926614be1565b61192e614be1565b61193a86866002611833565b9150915061194a86848385614075565b93505050505b92915050565b609c5460ff16156119795760405162461bcd60e51b81526004016103ef906154c6565b6002609b54141561199c5760405162461bcd60e51b81526004016103ef90615849565b6002609b556119ac826001612790565b6119b5826135d5565b336119be614b86565b6119c8848361250f565b905060006119d98260000151614130565b6119e45760016119e7565b60005b609a5460405163542cdc1b60e01b81529192506001600160a01b03169063542cdc1b90611a1c90889087908690600401615082565b602060405180830381600087803b158015611a3657600080fd5b505af1158015611a4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a6e9190614d5c565b611a8a5760405162461bcd60e51b81526004016103ef90615880565b611a92614c33565b611aad8685611aa636899003890189614f86565b600161311f565b90506000611abe82604001516129d7565b1115611adb57611acd86613390565b611adb868260400151612ede565b611aed86856106f68460e00151612d85565b60995460405163f2a5dca360e01b81526001600160a01b039091169063f2a5dca390611b1d90899060040161506e565b600060405180830381600087803b158015611b3757600080fd5b505af1158015611b4b573d6000803e3d6000fd5b50505050611b57614be1565b611b6685888460200151613d6b565b90506000611ba6886001600160a01b031663dc76fabc6040518163ffffffff1660e01b815260040160206040518083038186803b15801561121b57600080fd5b90506000611bb784608001516129d7565b90506000611bc88560a001516129d7565b9050896001600160a01b0316886001600160a01b03167f4f7b1ae1435976391e4c35674eb648f299111943bfb8a5c98bfdd1f59e2a73be6000611c0e89602001516129d7565b611c1b8a606001516129d7565b611c248a6129d7565b8b5151611c30906129d7565b611c3d8d60c001516129d7565b6000611c4c8f604001516129d7565b60008e8e8e604051611c699c9b9a99989796959493929190615219565b60405180910390a350506001609b555050505050505050565b609c5460ff1615611ca55760405162461bcd60e51b81526004016103ef906154c6565b6002609b541415611cc85760405162461bcd60e51b81526004016103ef90615849565b6002609b55611cd8826001612790565b611cea61053036839003830183614f86565b33611cf3614b86565b611cfd848361250f565b9050611d1c611d1136859003850185614f86565b602083015190613461565b6020820152611d2c8483836129db565b609954611dd29083906001600160a01b0316611d50610dd636889003880188614f86565b876001600160a01b031663fdf262b76040518163ffffffff1660e01b815260040160206040518083038186803b158015611d8957600080fd5b505afa158015611d9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc19190614cda565b6001600160a01b0316929190613d13565b6001600160a01b038085169083167f32ee06b7b87a4e31e03f5a752748014a342c37a10b2179a2c422d887c50889fd611e13610dd636889003880188614f86565b600080604051611e2593929190615203565b60405180910390a350506001609b555050565b611e40614b86565b611e48614b86565b611e52848461040b565b90506000611ed26001866001600160a01b03166342b3198b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e9457600080fd5b505afa158015611ea8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ecc9190614ff1565b9061414e565b9050808260a001511415611ee857509050611950565b609a546040516361d9282960e01b81526001600160a01b03909116906361d9282990611f1c9088908690869060040161519b565b60e06040518083038186803b158015611f3457600080fd5b505afa158015611f48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6c9190614e95565b95945050505050565b600054610100900460ff1680611f8e5750611f8e614190565b80611f9c575060005460ff16155b611fb85760405162461bcd60e51b81526004016103ef90615527565b600054610100900460ff16158015611fe3576000805460ff1961ff0019909116610100171660011790555b611feb614196565b609880546001600160a01b038087166001600160a01b03199283161790925560998054868416908316179055609a8054928516929091169190911790556001609b55609c805460ff191690558015610b78576000805461ff001916905550505050565b612056614be1565b609954604051631c2c891760e31b81526001600160a01b039091169063e16448b89061208690859060040161506e565b60206040518083038186803b15801561209e57600080fd5b505afa1580156120b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119509190614fab565b6120de61250b565b6033546001600160a01b0390811691161461210b5760405162461bcd60e51b81526004016103ef9061561b565b609880546001600160a01b0319166001600160a01b0392909216919091179055565b612135614be1565b61213d614b86565b6121478484611e38565b90506121568160000151612b9b565b6121638160400151612926565b61216b614be1565b612173614be1565b61217f86866000611833565b9150915061218b614be1565b612193614be1565b61219f88886001611833565b915091506121ab614be1565b6121b3614be1565b6121bc836129d7565b6121c5866129d7565b136121d15782846121d4565b84865b915091506121e48a888484614075565b9a9950505050505050505050565b6121fa61250b565b6033546001600160a01b039081169116146122275760405162461bcd60e51b81526004016103ef9061561b565b6001600160a01b03811661224d5760405162461bcd60e51b81526004016103ef90615354565b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380546001600160a01b0319166001600160a01b0392909216919091179055565b609a546001600160a01b031681565b6122c3816001612790565b60985460405163ed99da3160e01b81526001600160a01b039091169063ed99da31906122f390849060040161506e565b600060405180830381600087803b15801561230d57600080fd5b505af1158015612321573d6000803e3d6000fd5b5050505061232d614be1565b609860009054906101000a90046001600160a01b03166001600160a01b031663e50bda386040518163ffffffff1660e01b815260040160206040518083038186803b15801561237b57600080fd5b505afa15801561238f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b39190614fab565b6001600160a01b03831660009081526097602052604090209091506002016123e46123dd84610b8d565b8390613461565b8154600181018355600092835260209092209051910155612403614be1565b506001600160a01b03821660009081526097602090815260409182902082519182019092526004909101548152612438614be1565b61244283836133f6565b9050600061244f826129d7565b11156124a8576124a88482609860009054906101000a90046001600160a01b03166001600160a01b031663575dc7b36040518163ffffffff1660e01b815260040160206040518083038186803b158015610b3b57600080fd5b836001600160a01b03167fcf30be51a3c535c7548ddbb34d9cb7e40064a002e0cf8872dce1d34e790cdd3a6124dc846129d7565b6124e5846129d7565b6124ee876129d7565b6040516124fd93929190615203565b60405180910390a250505050565b3390565b612517614b86565b61251f614b86565b612529848461040b565b905061253881600001516129d7565b612543579050611950565b60006125836001866001600160a01b03166342b3198b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e9457600080fd5b9050808260a00151141561259957509050611950565b6125a1614b86565b609a546040516361d9282960e01b81526001600160a01b03909116906361d92829906125d59089908790879060040161519b565b60e06040518083038186803b1580156125ed57600080fd5b505afa158015612601573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126259190614e95565b905061262f614be1565b609a5460405163178e8dd960e11b81526001600160a01b0390911690632f1d1bb290612663908a908890889060040161519b565b602060405180830381600087803b15801561267d57600080fd5b505af1158015612691573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b59190614fab565b825160405163ba0c476360e01b81529192506001600160a01b0389169163ba0c4763916126e69185906004016158e3565b600060405180830381600087803b15801561270057600080fd5b505af1158015612714573d6000803e3d6000fd5b505050506127238787846129db565b856001600160a01b0316876001600160a01b03167fdbb898e847eca1f5626ba536593caa10241fb631e7c8a1cb06dfdce8d3934f4961276585600001516129d7565b8760a001518660a0015160405161277e93929190615203565b60405180910390a35095945050505050565b6098546040516357de0c5b60e01b81526001600160a01b03909116906357de0c5b906127c090859060040161506e565b60206040518083038186803b1580156127d857600080fd5b505afa1580156127ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128109190614d5c565b61282c5760405162461bcd60e51b81526004016103ef906152fa565b816001600160a01b031663fcfff16f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561286557600080fd5b505afa158015612879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061289d9190614d5c565b151581151514816128d6576040518060400160405280601081526020016f32bc31b430b733b29034b99037b832b760811b815250612903565b60405180604001604052806013815260200172195e18da185b99d9481dd85cc818db1bdcd959606a1b8152505b906129215760405162461bcd60e51b81526004016103ef919061526d565b505050565b61292f816129d7565b61294b5760405162461bcd60e51b81526004016103ef906155f7565b50565b612956614be1565b8180600001516001600160ff1b0310156040518060600160405280603381526020016159a9603391399061299d5760405162461bcd60e51b81526004016103ef919061526d565b50506040805160208101909152915182525090565b6129ba614be1565b6129c2614be1565b83516129ce9084614228565b81529392505050565b5190565b6001600160a01b03808416600081815260976020818152604080842095881684526003860182528084208151808401835260028201548152959094529181528151908101909152600490930154835291612a3491613444565b6001600160a01b03851660008181526097602081815260408084209551600496870190815588515188558883015151600189015588820151516002890181905560608a01515160038a015560808a0151519789019790975560c0890151600689015560a089015160058901558151808401835296875294909352908152815190810190915290548152612ac691613461565b6001600160a01b0390941660009081526097602052604090209351600490940193909355505050565b6000612afe610dd68585612dd0565b905081612b0e5760008112612b14565b60008112155b610b785760405162461bcd60e51b81526004016103ef9061548f565b60995460405163038ef35760e41b81526001600160a01b03909116906338ef357090612b6490869086908690600401615113565b600060405180830381600087803b158015612b7e57600080fd5b505af1158015612b92573d6000803e3d6000fd5b50505050505050565b612ba4816129d7565b61294b5760405162461bcd60e51b81526004016103ef906152cf565b612bc8614b86565b506001600160a01b038083166000818152609760208181526040808420958716845260038087018352818520825161010081018452815460e08201908152815283518086018552600183015481528186015283518086018552600283015481528185019081528451808701865293830154845260608201939093528351808601855260048084015482526080830191909152600583015460a083015260069092015460c08201529151969095529282528051918201905291909301548152612c8f91613444565b6001600160a01b038416600090815260976020526040908190209151600490920191909155805160e0810190915280612cc6613104565b8152602001612cd3613104565b8152602001612ce0613104565b8152602001612ced613104565b8152602001612cfa613104565b815260200160008152602001612d0e614293565b90526001600160a01b0393841660009081526097602090815260408083209590961682526003948501815290859020825151815590820151516001820155938101515160028501556060810151519284019290925550608081015151600483015560a0810151600583015560c00151600690910155565b612d8d614be1565b612d95614be1565b825160001315612dab5782516000038152611950565b915182525090565b612dbb614be1565b612dc3614be1565b825184516129ce91614297565b612dd8614be1565b8180600001516001600160ff1b0310156040518060600160405280603381526020016159a96033913990612e1f5760405162461bcd60e51b81526004016103ef919061526d565b50612e28614be1565b83518551612e35916142a5565b8152949350505050565b612e47614be1565b612e4f614be1565b825184516129ce916142eb565b612e64614be1565b8180600001516001600160ff1b0310156040518060600160405280603381526020016159a96033913990612eab5760405162461bcd60e51b81526004016103ef919061526d565b50612eb4614be1565b83518551612e35916142f9565b612ec9614be1565b612ed1614be1565b825184516129ce916142f9565b609954604051630a16f8cb60e31b81526001600160a01b03909116906350b7c65890612f1090859085906004016150d5565b600060405180830381600087803b158015612f2a57600080fd5b505af1158015612f3e573d6000803e3d6000fd5b505050505050565b609854604051633f694ac560e11b81526000916001600160a01b031690637ed2958a90612f7790879060040161506e565b60206040518083038186803b158015612f8f57600080fd5b505afa158015612fa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc79190614cda565b90506001600160a01b038116612fef5760405162461bcd60e51b81526004016103ef906152a0565b612ff7614be1565b61300184846133f6565b60995460405163038ef35760e41b81529192506001600160a01b0316906338ef35709061303690889086908690600401615113565b600060405180830381600087803b15801561305057600080fd5b505af1158015613064573d6000803e3d6000fd5b50505050613070614be1565b61307a8583613444565b609954604051633aed6d0b60e21b81529192506001600160a01b03169063ebb5b42c906130ad90899085906004016150d5565b600060405180830381600087803b1580156130c757600080fd5b505af11580156130db573d6000803e3d6000fd5b50505050505050505050565b6130ef614be1565b6130f7614be1565b825184516129ce916142a5565b61310c614be1565b5060408051602081019091526000815290565b613127614c33565b61312f614b86565b613139868661040b565b9050613143614be1565b50805161314f81612b9b565b613157614be1565b61316388886000611833565b91505061316e614bf4565b609a54604051638b4a5bf360e01b81526001600160a01b0390911690638b4a5bf3906131a2908c908890879060040161516d565b60806040518083038186803b1580156131ba57600080fd5b505afa1580156131ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f29190614f22565b9050613200836000196129b2565b60608087019190915260c086018390526020820151604080880191909152820151608087015281015160a08601528051613241906000199061056f9061294e565b60e08601526001600160a01b03891663dc3184a06000613260866129d7565b1361326c57600161326f565b60005b61327886612d85565b8a8a6040518563ffffffff1660e01b815260040161329994939291906151da565b602060405180830381600087803b1580156132b357600080fd5b505af11580156132c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132eb9190614fab565b602080870191909152609a546040860151918301516001600160a01b03909116916302a3789e918c9161332b916000199161056f916108b9908a90612e5c565b6040518363ffffffff1660e01b81526004016133489291906150d5565b600060405180830381600087803b15801561336257600080fd5b505af1158015613376573d6000803e3d6000fd5b505050506133848989612bc0565b50505050949350505050565b600061339a614293565b6001600160a01b03831660009081526097602052604090819020829055519091507f97f920fec5d17ec336df7ad438ca8a76dcfd206ddc1d19b263b6f3e6ba3c4f31906133ea90849084906150ef565b60405180910390a15050565b6133fe614be1565b613406614be1565b825184516129ce9161433f565b80518251600091101561342857506001611950565b81518351101561343b5750600019611950565b50600092915050565b61344c614be1565b613454614be1565b825184516129ce9161414e565b613469614be1565b613471614be1565b825184516129ce9161434d565b609854604051633f694ac560e11b81526000916001600160a01b031690637ed2958a906134af90869060040161506e565b60206040518083038186803b1580156134c757600080fd5b505afa1580156134db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ff9190614cda565b60995460405163038ef35760e41b81529192506001600160a01b0316906338ef357090612b6490869085908790600401615113565b600061353f82612d85565b5192915050565b61354e614be1565b60405180602001604052806135636012614372565b9052905090565b613572614be1565b8180600001516001600160ff1b0310156040518060600160405280603381526020016159a960339139906135b95760405162461bcd60e51b81526004016103ef919061526d565b506135c2614be1565b611f6c6135ce8561294e565b869061437b565b60006135df614293565b6001600160a01b0383166000908152609760205260409020549091508114156104c4578061360d833361040b565b60c0015114156104c45760405162461bcd60e51b81526004016103ef90615458565b613637614c33565b33613640614b86565b61364a888361040b565b905061365888888888614398565b6060840152613665614be1565b6060840151825161367591612ec1565b60a0830151835191925090613689906129d7565b6136ce576136cb60018b6001600160a01b03166342b3198b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e9457600080fd5b90505b609a546001600160a01b03166302a3789e8b6136e98b61294e565b6040518363ffffffff1660e01b81526004016137069291906150d5565b600060405180830381600087803b15801561372057600080fd5b505af1158015613734573d6000803e3d6000fd5b50505050609a60009054906101000a90046001600160a01b03166001600160a01b03166309a9d76c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561378657600080fd5b505afa15801561379a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137be9190614cda565b6001600160a01b0316846001600160a01b03161461389a576137de614be1565b8a6001600160a01b031663113773946040518163ffffffff1660e01b815260040160206040518083038186803b15801561381757600080fd5b505afa15801561382b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061384f9190614fab565b9050600061385c826129d7565b11156138985760006138778261387186612d85565b90613413565b60000b13156138985760405162461bcd60e51b81526004016103ef90615697565b505b6138a2614b86565b6138aa614be1565b6138b761056a8b8a612db3565b90506138c1614bf4565b609a60009054906101000a90046001600160a01b03166001600160a01b0316638b4a5bf38e88856040518463ffffffff1660e01b81526004016139069392919061516d565b60806040518083038186803b15801561391e57600080fd5b505afa158015613932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139569190614f22565b60e08901929092525060408101516080880152606081015160a0880152516020820152613981614be1565b61398d8c876000611833565b6101008901525050602086018981528382525160408501516139ae91613461565b604082015260a081018290526139c38b610c22565b60608201526139d18b610b8d565b60808201526139de614293565b60c08201528552509298975050505050505050565b6139fb614c33565b613a03614be1565b613a0d85856133f6565b9050613a17614be1565b613a1f614be1565b613a2b89336000611833565b91509150613a37614c33565b613a40846129d7565b613a49846129d7565b1115613d0657609a546001600160a01b03166302a3789e8b613a7060001961056f8961294e565b6040518363ffffffff1660e01b8152600401613a8d9291906150d5565b600060405180830381600087803b158015613aa757600080fd5b505af1158015613abb573d6000803e3d6000fd5b50505050613ac7614b86565b613ad18b3361040b565b9050613adf8b8b878a614398565b60608301528051613aef906129d7565b15613b2157613b1b613b048260000151612d85565b611331613b148560600151612d85565b8690614479565b60c08301525b613b29614bf4565b609a60009054906101000a90046001600160a01b03166001600160a01b0316638b4a5bf38d848660c001516040518463ffffffff1660e01b8152600401613b729392919061516d565b60806040518083038186803b158015613b8a57600080fd5b505afa158015613b9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bc29190614f22565b6020808201516040808701919091528201516080860152606082015160a08601528481018890529051908301525060c0820151613c009084906130e7565b610100830152613c0e614be1565b6000613c1d83600001516129d7565b13613c4757613c4283602001516108ab87866101000151612e5c90919063ffffffff16565b613c67565b613c67836101000151613c6185602001516108ab8961294e565b906130e7565b90506000613c74826129d7565b13613c915760405162461bcd60e51b81526004016103ef906154f0565b613c99614b86565b6020808401519082015260608401518351613cb391612ec1565b8152613cbe82612d85565b604082015260a08084015190820152613cd68d610c22565b6060820152613ce48d610b8d565b6080820152613cf1614293565b60c0820152835250909450611f6c9350505050565b6121e48a8a8a8a8a6144e4565b610b78846323b872dd60e01b858585604051602401613d34939291906150b1565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526146ce565b613d73614be1565b613d7b614be1565b604051636226795560e01b81526001600160a01b03851690636226795590613da79086906004016158d9565b60206040518083038186803b158015613dbf57600080fd5b505afa158015613dd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df79190614fab565b90506000613e04826129d7565b111561406257609854604051633f694ac560e11b81526000916001600160a01b031690637ed2958a90613e3b90889060040161506e565b60206040518083038186803b158015613e5357600080fd5b505afa158015613e67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e8b9190614cda565b90506001600160a01b038116613eb35760405162461bcd60e51b81526004016103ef906152a0565b613ebb614be1565b609854604080516356d43c4760e11b81529051613f40926001600160a01b03169163ada8788e916004808301926020929190829003018186803b158015613f0157600080fd5b505afa158015613f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f399190614fab565b84906133f6565b9050613f898783613f50846129d7565b896001600160a01b031663fdf262b76040518163ffffffff1660e01b815260040160206040518083038186803b158015611d8957600080fd5b613f91614be1565b613f9b8483613444565b609954909150613ff29089906001600160a01b0316613fb9846129d7565b8a6001600160a01b031663fdf262b76040518163ffffffff1660e01b815260040160206040518083038186803b158015611d8957600080fd5b609954604051633aed6d0b60e21b81526001600160a01b039091169063ebb5b42c90614024908a9085906004016150d5565b600060405180830381600087803b15801561403e57600080fd5b505af1158015614052573d6000803e3d6000fd5b505050508394505050505061406e565b61406a613104565b9150505b9392505050565b61407d614be1565b614085614bf4565b609a54604051638b4a5bf360e01b81526001600160a01b0390911690638b4a5bf3906140b99089908990899060040161516d565b60806040518083038186803b1580156140d157600080fd5b505afa1580156140e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141099190614f22565b90506141248361133183602001516108ab856000015161294e565b9150505b949350505050565b6000808260000151121561414657506001610c05565b506000919050565b600061406e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061475d565b303b1590565b600054610100900460ff16806141af57506141af614190565b806141bd575060005460ff16155b6141d95760405162461bcd60e51b81526004016103ef90615527565b600054610100900460ff16158015614204576000805460ff1961ff0019909116610100171660011790555b61420c614789565b61421461480a565b801561294b576000805461ff001916905550565b60008261423757506000611950565b8260001914801561424b5750600160ff1b82145b156142685760405162461bcd60e51b81526004016103ef90615650565b8282028284828161427557fe5b051461406e5760405162461bcd60e51b81526004016103ef90615650565b4390565b600061406e838360126148e4565b60008183038183128015906142ba5750838113155b806142cf57506000831280156142cf57508381135b61406e5760405162461bcd60e51b81526004016103ef90615786565b600061406e83836012614903565b600082820181831280159061430e5750838112155b80614323575060008312801561432357508381125b61406e5760405162461bcd60e51b81526004016103ef906153d1565b600061406e83836012614921565b60008282018381101561406e5760405162461bcd60e51b81526004016103ef9061539a565b60ff16600a0a90565b614383614be1565b61438b614be1565b825184516129ce91614939565b6143a0614be1565b6000808560018111156143af57fe5b146143bb5760016143be565b60005b90506143c8614be1565b604051639ffca62f60e01b815261444e906001600160a01b03891690639ffca62f906143fc9086908a908a906004016151b9565b602060405180830381600087803b15801561441657600080fd5b505af115801561442a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056a9190614fab565b905081600181111561445c57fe5b6001141561412457614470816000196129b2565b92505050614128565b614481614be1565b8180600001516001600160ff1b0310156040518060600160405280603381526020016159a960339139906144c85760405162461bcd60e51b81526004016103ef919061526d565b506144d1614be1565b611f6c6144dd8561294e565b8690612e3f565b6144ec614c33565b6144f4614c33565b6145018733611aa6613104565b905061451081604001516129d7565b1561452d5760405162461bcd60e51b81526004016103ef90615718565b614535614be1565b602082015161454e9061454888886133f6565b90613444565b905061455d610dd68287612db3565b614569578192506146c3565b614571614be1565b61457e8360600151613534565b614587866129d7565b11156145a7576145a461459d8460600151612d85565b8690613444565b90505b6145af614c33565b6145bc8a8a85858b61362f565b9050604051806101200160405280826000015181526020016145ef8360200151876020015161346190919063ffffffff16565b815260200161460f8360400151876040015161346190919063ffffffff16565b815260200161462f83606001518760600151612ec190919063ffffffff16565b815260200161464f83608001518760800151612ec190919063ffffffff16565b815260200161466f8360a001518760a0015161346190919063ffffffff16565b815260200161468f8360c001518760c00151612ec190919063ffffffff16565b81526020016146af8360e001518760e00151612ec190919063ffffffff16565b81526020016146bc613104565b9052945050505b505095945050505050565b6060614723826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166149479092919063ffffffff16565b80519091501561292157808060200190518101906147419190614d5c565b6129215760405162461bcd60e51b81526004016103ef906157ca565b600081848411156147815760405162461bcd60e51b81526004016103ef919061526d565b505050900390565b600054610100900460ff16806147a257506147a2614190565b806147b0575060005460ff16155b6147cc5760405162461bcd60e51b81526004016103ef90615527565b600054610100900460ff16158015614214576000805460ff1961ff001990911661010017166001179055801561294b576000805461ff001916905550565b600054610100900460ff16806148235750614823614190565b80614831575060005460ff16155b61484d5760405162461bcd60e51b81526004016103ef90615527565b600054610100900460ff16158015614878576000805460ff1961ff0019909116610100171660011790555b600061488261250b565b603380546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350801561294b576000805461ff001916905550565b6000614128836148fd6148f685614372565b8790614956565b90614990565b600061412861491183614372565b61491b8686614228565b906149d2565b600061412861492f83614372565b6148fd8686614956565b600061406e83836012614a36565b60606141288484600085614a4f565b60008261496557506000611950565b8282028284828161497257fe5b041461406e5760405162461bcd60e51b81526004016103ef906155b6565b600061406e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614b10565b6000816149f15760405162461bcd60e51b81526004016103ef90615814565b81600019148015614a055750600160ff1b83145b15614a225760405162461bcd60e51b81526004016103ef90615575565b6000828481614a2d57fe5b05949350505050565b60006141288361491b614a4885614372565b8790614228565b606082471015614a715760405162461bcd60e51b81526004016103ef90615412565b614a7a85614b47565b614a965760405162461bcd60e51b81526004016103ef9061574f565b60006060866001600160a01b03168587604051614ab39190615052565b60006040518083038185875af1925050503d8060008114614af0576040519150601f19603f3d011682016040523d82523d6000602084013e614af5565b606091505b5091509150614b05828286614b4d565b979650505050505050565b60008183614b315760405162461bcd60e51b81526004016103ef919061526d565b506000838581614b3d57fe5b0495945050505050565b3b151590565b60608315614b5c57508161406e565b825115614b6c5782518084602001fd5b8160405162461bcd60e51b81526004016103ef919061526d565b6040518060e00160405280614b99614be1565b8152602001614ba6614be1565b8152602001614bb3614be1565b8152602001614bc0614be1565b8152602001614bcd614be1565b815260200160008152602001600081525090565b6040518060200160405280600081525090565b6040518060800160405280614c07614be1565b8152602001614c14614be1565b8152602001614c21614be1565b8152602001614c2e614be1565b905290565b604051806101200160405280614c47614b86565b8152602001614c54614be1565b8152602001614c61614be1565b8152602001614c6e614be1565b8152602001614c7b614be1565b8152602001614c07614be1565b600060208284031215610c03578081fd5b600060208284031215614caa578081fd5b614cb46020615928565b9151825250919050565b600060208284031215614ccf578081fd5b813561406e81615985565b600060208284031215614ceb578081fd5b815161406e81615985565b600080600060608486031215614d0a578182fd5b8335614d1581615985565b92506020840135614d2581615985565b91506040840135614d3581615985565b809150509250925092565b600060208284031215614d51578081fd5b813561406e8161599a565b600060208284031215614d6d578081fd5b815161406e8161599a565b60008060408385031215614d8a578182fd5b8235614d9581615985565b91506020830135614da581615985565b809150509250929050565b600080600060608486031215614dc4578081fd5b8335614dcf81615985565b92506020840135614ddf81615985565b9150604084013560038110614d35578182fd5b600080600080600060a08688031215614e09578283fd5b8535614e1481615985565b9450602086013560028110614e27578384fd5b9350614e368760408801614c88565b9250614e458760608801614c88565b9150614e548760808801614c88565b90509295509295909350565b60008060408385031215614e72578182fd5b8235614e7d81615985565b9150614e8c8460208501614c88565b90509250929050565b600060e08284031215614ea6578081fd5b614eb060e0615928565b614eba8484614c99565b8152614ec98460208501614c99565b6020820152614edb8460408501614c99565b6040820152614eed8460608501614c99565b6060820152614eff8460808501614c99565b608082015260a083015160a082015260c083015160c08201528091505092915050565b600060808284031215614f33578081fd5b614f3d6080615928565b614f478484614c99565b8152614f568460208501614c99565b6020820152614f688460408501614c99565b6040820152614f7a8460608501614c99565b60608201529392505050565b600060208284031215614f97578081fd5b614fa16020615928565b9135825250919050565b600060208284031215614fbc578081fd5b61406e8383614c99565b60008060408385031215614fd8578182fd5b614fe28484614c99565b9150614e8c8460208501614c99565b600060208284031215615002578081fd5b5051919050565b8051518252602081015151602083015260408101515160408301526060810151516060830152608081015151608083015260a081015160a083015260c081015160c08301525050565b6000825161506481846020870161594f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03848116825283166020820152606081016150a38361597b565b826040830152949350505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0392909216825251602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b6001600160a01b0393841681529190921660208201529051604082015260600190565b6001600160a01b038416815261012081016151546020830185615009565b6003831061515e57fe5b82610100830152949350505050565b6001600160a01b0384168152610120810161518b6020830185615009565b8251610100830152949350505050565b6001600160a01b0384168152610120810161515e6020830185615009565b606081016151c68561597b565b938152915160208301525160409091015290565b608081016151e78661597b565b9481529251602084015290516040830152151560609091015290565b9283526020830191909152604082015260600190565b9b8c5260208c019a909a5260408b019890985260608a0196909652608089019490945260a088019290925260c087015260e08601526101008501526101208401526101408301526101608201526101800190565b600060208252825180602084015261528c81604085016020870161594f565b601f01601f19169190910160400192915050565b602080825260159082015274125b9d985b1a5908125b9cdd5c985b98d9519d5b99605a1b604082015260600190565b6020808252601190820152700706f736974696f6e53697a65206973203607c1b604082015260600190565b602080825260129082015271195e18da185b99d9481b9bdd08199bdd5b9960721b604082015260600190565b6020808252601490820152730dac2e4ced2dc40d2e640dcdee840cadcdeeaced60631b604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526021908201527f5369676e6564536166654d6174683a206164646974696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b60208082526017908201527f6f6e6c79206f6e6520616374696f6e20616c6c6f776564000000000000000000604082015260600190565b6020808252601e908201527f4d617267696e20726174696f206e6f74206d6565742063726974657269610000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601a908201527f76616c7565206f66206f70656e4e6f74696f6e616c203c3d2030000000000000604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60208082526021908201527f5369676e6564536166654d6174683a206469766973696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252600a90820152690696e70757420697320360b41b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526027908201527f5369676e6564536166654d6174683a206d756c7469706c69636174696f6e206f604082015266766572666c6f7760c81b606082015260800190565b6020808252601d908201527f68697420706f736974696f6e2073697a6520757070657220626f756e64000000604082015260600190565b6020808252602a908201527f63616e6e6f74206f70656e20706f736974696f6e20647572696e6720776169746040820152691a5b99c81c195c9a5bd960b21b606082015260800190565b6020808252601d908201527f72656475636520616e20756e646572776174657220706f736974696f6e000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b60208082526024908201527f5369676e6564536166654d6174683a207375627472616374696f6e206f766572604082015263666c6f7760e01b606082015260800190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252818101527f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252602b908201527f63616e6e6f7420636c6f736520706f736974696f6e20647572696e672077616960408201526a1d1a5b99c81c195c9a5bd960aa1b606082015260800190565b60e081016119508284615009565b9051815260200190565b9151825251602082015260400190565b90815260200190565b948552602085019390935260408401919091526001600160a01b03166060830152608082015260a00190565b60405181810167ffffffffffffffff8111828210171561594757600080fd5b604052919050565b60005b8381101561596a578181015183820152602001615952565b83811115610b785750506000910152565b6002811061294b57fe5b6001600160a01b038116811461294b57600080fd5b801515811461294b57600080fdfe4d69786564446563696d616c3a2075696e742076616c756520697320626967676572207468616e205f494e543235365f4d4158a2646970667358221220a94c1db5072ba19a72807887283cced43b5cd19dfc2cce2e743d3784bfe7e90964736f6c634300060c0033

Deployed ByteCode Sourcemap

68627:56504:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;125049:79;;;;;;:::i;:::-;;:::i;:::-;;123268:248;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;97962:129;;;;;;:::i;:::-;;:::i;78092:1691::-;;;;;;:::i;:::-;;:::i;79983:1826::-;;;;;;:::i;:::-;;:::i;94591:1935::-;;;;;;:::i;:::-;;:::i;74761:35::-;;;:::i;:::-;;;;;;;:::i;103221:385::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;74970:18::-;;;:::i;:::-;;;;;;;:::i;74715:37::-;;;:::i;102636:394::-;;;;;;:::i;:::-;;:::i;41818:148::-;;;:::i;90497:3905::-;;;;;;:::i;:::-;;:::i;83505:4157::-;;;;;;:::i;:::-;;:::i;101957:490::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;41176:79::-;;;:::i;99618:584::-;;;;;;:::i;:::-;;:::i;87771:2393::-;;;;;;:::i;:::-;;:::i;77029:881::-;;;;;;:::i;:::-;;:::i;101074:483::-;;;;;;:::i;:::-;;:::i;75656:414::-;;;;;;:::i;:::-;;:::i;103759:179::-;;;;;;:::i;:::-;;:::i;76724:130::-;;;;;;:::i;:::-;;:::i;98500:1110::-;;;;;;:::i;:::-;;:::i;42121:244::-;;;;;;:::i;:::-;;:::i;74803:35::-;;;:::i;96721:1094::-;;;;;;:::i;:::-;;:::i;125049:79::-;41398:12;:10;:12::i;:::-;41388:6;;-1:-1:-1;;;;;41388:6:0;;;:22;;;41380:67;;;;-1:-1:-1;;;41380:67:0;;;;;;;:::i;:::-;;;;;;;;;125105:6:::1;:15:::0;;-1:-1:-1;;125105:15:0::1;::::0;::::1;;::::0;;;::::1;::::0;;125049:79::o;123268:248::-;123403:24;;:::i;:::-;-1:-1:-1;;;;;;123456:31:0;;;;;;;:11;:31;;;;;;;;:52;;;;;;:43;;;;:52;;;;;;123445:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;123445:63:0;;;;;;;;;;;123268:248::o;97962:129::-;98027:56;98061:9;98072:10;98027:33;:56::i;:::-;;97962:129;:::o;78092:1691::-;76585:6;;;;76584:7;76576:36;;;;-1:-1:-1;;;76576:36:0;;;;;;;:::i;:::-;74931:1:::1;76193:6;;:18;;76185:62;;;;-1:-1:-1::0;;;76185:62:0::1;;;;;;;:::i;:::-;74931:1;76325:6;:17:::0;78287:32:::2;78303:9:::0;78314:4:::2;78287:15;:32::i;:::-;78330:35;;;::::0;;::::2;::::0;::::2;78350:14:::0;78330:35:::2;:::i;:::-;:19;:35::i;:::-;78447:10;78468:24;;:::i;:::-;78495:52;78529:9;78540:6;78495:33;:52::i;:::-;78468:79;;78619:46;;:::i;:::-;78668:54;-1:-1:-1::0;;78668:40:0::2;;;::::0;;::::2;::::0;::::2;78693:14:::0;78668:40:::2;:::i;:::-;:24;:40::i;:::-;:50:::0;::::2;:54::i;:::-;78619:103;;78733:55;;:::i;:::-;78804:13;::::0;:97:::2;::::0;-1:-1:-1;;;78804:97:0;;-1:-1:-1;;;;;78804:13:0;;::::2;::::0;:63:::2;::::0;:97:::2;::::0;78868:9;;78879:8;;78889:11;;78804:97:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78733:168;;78920:33;:16;:24;;;:31;:33::i;:::-;:38:::0;78912:71:::2;;;;-1:-1:-1::0;;;78912:71:0::2;;;;;;;:::i;:::-;79014:29:::0;;78996:15:::2;::::0;::::2;:47:::0;79102:45:::2;79137:9:::0;79102:34:::2;:45::i;:::-;79054;::::0;::::2;:93:::0;79207:46:::2;79243:9:::0;79207:35:::2;:46::i;:::-;79158;::::0;::::2;:95:::0;79264:40:::2;79276:9:::0;79287:6;79158:8;79264:11:::2;:40::i;:::-;79348:92;79371:33;79386:9;79397:6;79371:14;:33::i;:::-;79406:9;-1:-1:-1::0;;;;;79406:25:0::2;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79435:4;79348:22;:92::i;:::-;79495:43;79504:9:::0;79515:6;79495:43:::2;;::::0;;::::2;::::0;::::2;79523:14:::0;79495:43:::2;:::i;:::-;:8;:43::i;:::-;79613:9;-1:-1:-1::0;;;;;79556:219:0::2;79584:6;-1:-1:-1::0;;;;;79556:219:0::2;;79638:19;:11;:17;:19::i;:::-;79672:39;:16;:31;;;:37;:39::i;:::-;79726:38;:16;:29;;;:36;:38::i;:::-;79556:219;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;74887:1:0::1;76503:6;:21:::0;-1:-1:-1;;;;78092:1691:0:o;79983:1826::-;74931:1;76193:6;;:18;;76185:62;;;;-1:-1:-1;;;76185:62:0;;;;;;;:::i;:::-;74931:1;76325:6;:17;80091:33:::1;80107:9:::0;80118:5:::1;80091:15;:33::i;:::-;80154:10;80175:19;;:::i;:::-;80197:30;80209:9;80220:6;80197:11;:30::i;:::-;80175:52;;80238:29;80258:3;:8;;;80238:19;:29::i;:::-;80308:32;80322:9;80333:6;80308:13;:32::i;:::-;80555:38;;:::i;:::-;80596:9;-1:-1:-1::0;;;;;80596:28:0::1;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;80555:71;;80637:35;;:::i;:::-;80687:24;:15;:22;:24::i;:::-;80683:723;;-1:-1:-1::0;80748:10:0::1;::::0;::::1;::::0;80683:723:::1;;;80954:47;;:::i;:::-;81021:183;81193:3;:10;;;81021:144;81079:85;81126:37;81148:14;:3;:8;;;:12;:14::i;:::-;81126:16;::::0;::::1;::::0;;:21:::1;:37::i;:::-;81079:41;81104:15;81079:24;:41::i;:::-;:46:::0;::::1;:85::i;:::-;81021:30:::0;;;:57:::1;:144::i;:::-;:171:::0;::::1;:183::i;:::-;80954:250;;81324:1;81301:20;:12;:18;:20::i;:::-;:24;81297:98;;;81361:18;:12;:16;:18::i;:::-;81346:33;;81297:98;80683:723;;81522:1;81498:21;:12;:19;:21::i;:::-;:25;81494:201;;;81540:41;81549:9;81560:6;81568:12;81540:8;:41::i;:::-;81771:6;-1:-1:-1::0;;;;;81735:66:0::1;81759:9;-1:-1:-1::0;;;;;81735:66:0::1;;81779:21;:12;:19;:21::i;:::-;81735:66;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;74887:1:0;76503:6;:21;-1:-1:-1;;;79983:1826:0:o;94591:1935::-;94652:32;94668:9;94679:4;94652:15;:32::i;:::-;94697:49;;:::i;:::-;94749:9;-1:-1:-1;;;;;94749:30:0;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;94697:84;;94792:50;;:::i;:::-;94845:9;-1:-1:-1;;;;;94845:23:0;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;94881:31:0;;;;;;:11;:31;;;;;94792:78;;-1:-1:-1;94881:58:0;;94959:67;94980:45;94901:9;94980:34;:45::i;:::-;94959:15;;:20;:67::i;:::-;94881:156;;;;;;;-1:-1:-1;94881:156:0;;;;;;;;;;;;95460:56;;:::i;:::-;95519:36;:15;95540:14;95519:20;:36::i;:::-;95460:95;;95604:1;95572:29;:21;:27;:29::i;:::-;:33;95568:951;;;95622:54;95637:9;95648:27;:21;:25;:27::i;:::-;95622:14;:54::i;:::-;95568:951;;;95709:178;95759:9;95787:27;:21;:25;:27::i;:::-;95833:14;;;;;;;;;-1:-1:-1;;;;;95833:14:0;-1:-1:-1;;;;;95833:37:0;;:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;95709:31;:178::i;:::-;94591:1935;;;;:::o;74761:35::-;;;-1:-1:-1;;;;;74761:35:0;;:::o;103221:385::-;103353:22;;:::i;:::-;-1:-1:-1;;;;;103407:31:0;;103393:11;103407:31;;;:11;:31;;;;;:59;;:66;103488:7;;103484:115;;-1:-1:-1;;;;;103519:31:0;;;;;;:11;:31;;;;;:59;;:68;;-1:-1:-1;;103579:7:0;;;103519:68;;;;;;;;;;;;;;;103512:75;;;;;;;;103519:68;103512:75;;;;-1:-1:-1;103512:75:0;;-1:-1:-1;103512:75:0;103484:115;103221:385;;;;;:::o;74970:18::-;;;;;;:::o;74715:37::-;;;-1:-1:-1;;;;;74715:37:0;;:::o;102636:394::-;102767:34;;:::i;:::-;-1:-1:-1;;;;;102833:31:0;;102819:11;102833:31;;;:11;:31;;;;;:58;;:65;102913:7;;102909:114;;-1:-1:-1;;;;;102944:31:0;;;;;;:11;:31;;;;;:58;;:67;;-1:-1:-1;;103003:7:0;;;102944:67;;;;;41818:148;41398:12;:10;:12::i;:::-;41388:6;;-1:-1:-1;;;;;41388:6:0;;;:22;;;41380:67;;;;-1:-1:-1;;;41380:67:0;;;;;;;:::i;:::-;41909:6:::1;::::0;41888:40:::1;::::0;41925:1:::1;::::0;-1:-1:-1;;;;;41909:6:0::1;::::0;41888:40:::1;::::0;41925:1;;41888:40:::1;41939:6;:19:::0;;-1:-1:-1;;;;;;41939:19:0::1;::::0;;41818:148::o;90497:3905::-;74931:1;76193:6;;:18;;76185:62;;;;-1:-1:-1;;;76185:62:0;;;;;;;:::i;:::-;74931:1;76325:6;:17;90618:32:::1;90634:9:::0;90645:4:::1;90618:15;:32::i;:::-;90676:46;;:::i;:::-;90725:34;90740:9;90751:7;90725:14;:34::i;:::-;90676:83;;90881:9;-1:-1:-1::0;;;;;90881:27:0::1;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;90877:338;;;90931:59;;:::i;:::-;90993:47;91021:9;91032:7;90993:27;:47::i;:::-;90931:109:::0;-1:-1:-1;91116:1:0::1;91063:50;:42;90931:109:::0;91093:11;91063:29:::1;:42::i;:::-;:48;:50::i;:::-;:54;91059:141;;;91156:24;91142:38;;91059:141;90877:338;;91229:78;91252:11;91265:9;-1:-1:-1::0;;;;;91265:32:0::1;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;91301:5;91229:22;:78::i;:::-;76355:1;91357:53;91391:9;91402:7;91357:33;:53::i;:::-;;91421:32;;:::i;:::-;91456:64;91478:9;91489:7;91498:14;:12;:14::i;:::-;91514:5;91456:21;:64::i;:::-;91421:99;;91531:31;91552:9;91531:20;:31::i;:::-;91668:37;;:::i;:::-;91725:76;91769:9;-1:-1:-1::0;;;;;91769:29:0::1;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;91725:38;::::0;::::1;::::0;;:43:::1;:76::i;:::-;91668:133;;91872:1;91820:49;91839:9;-1:-1:-1::0;;;;;91839:27:0::1;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;91820:14:::0;;:18:::1;:49::i;:::-;:53;;;91816:140;;;91911:9;-1:-1:-1::0;;;;;91911:27:0::1;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;91894:46;;91816:140;92124:35;;:::i;:::-;92162:32;:12;:26;;;:30;:32::i;:::-;92124:70;;92424:41;;:::i;:::-;92480:35;;:::i;:::-;-1:-1:-1::0;92518:20:0::1;::::0;::::1;::::0;92553:53:::1;;:::i;:::-;-1:-1:-1::0;92609:26:0::1;::::0;::::1;::::0;92680:21:::1;:12:::0;:19:::1;:21::i;:::-;92654:23;:14;:21;:23::i;:::-;:47;92650:314;;;92743:33;:14:::0;92763:12;92743:19:::1;:33::i;:::-;92722:54:::0;-1:-1:-1;92810:37:0::1;:12:::0;92722:54;92810:17:::1;:37::i;:::-;92795:52;;92650:314;;;92909:39;:18:::0;92933:14;92909:23:::1;:39::i;:::-;92888:60;;92650:314;93075:1;93051:21;:12;:19;:21::i;:::-;:25;93047:105;;;93097:39;93112:9;93123:12;93097:14;:39::i;:::-;93199:1;93170:26;:18;:24;:26::i;:::-;:30;93166:131;;;93221:60;93245:9;93256:24;:18;:22;:24::i;:::-;93221:23;:60::i;:::-;93311:47;93320:9;93331:10;93343:14;93311:8;:47::i;:::-;93451:9;-1:-1:-1::0;;;;;93380:341:0::1;93417:7;-1:-1:-1::0;;;;;93380:341:0::1;;93480:47;:12;:38;;;:45;:47::i;:::-;93546:43;:12;:34;;;:41;:43::i;:::-;93608:23;:14;:21;:23::i;:::-;93650:10;93679:27;:18;:25;:27::i;:::-;93380:341;;;;;;;;;;:::i;:::-;;;;;;;;76355:1;;;;;93833:9;-1:-1:-1::0;;;;;93765:618:0::1;93799:7;-1:-1:-1::0;;;;;93765:618:0::1;;93862:1;93882:47;:12;:38;;;:45;:47::i;:::-;93948:42;:12;:34;;;:40;:42::i;:::-;94009:1;94029::::0;94049:32:::1;:12;:24;;;:30;:32::i;:::-;94100:1;94120:29;:12;:20;;;:27;:29::i;:::-;94168:41;:32;:12;:26;;;:30;:32::i;:41::-;94228:33;:9;-1:-1:-1::0;;;;;94228:22:0::1;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:33::-;94280:35;:12;:27;;;:33;:35::i;:::-;94334:34;:12;:25;;;:32;:34::i;:::-;93765:618;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;74887:1:0;76503:6;:21;-1:-1:-1;90497:3905:0:o;83505:4157::-;76585:6;;;;76584:7;76576:36;;;;-1:-1:-1;;;76576:36:0;;;;;;;:::i;:::-;74931:1:::1;76193:6;;:18;;76185:62;;;;-1:-1:-1::0;;;76185:62:0::1;;;;;;;:::i;:::-;74931:1;76325:6;:17:::0;83791:32:::2;83807:9:::0;83818:4:::2;83791:15;:32::i;:::-;83834:38;;;::::0;;::::2;::::0;::::2;83854:17:::0;83834:38:::2;:::i;:::-;83883:30;;;::::0;;::::2;::::0;::::2;83903:9:::0;83883:30:::2;:::i;:::-;83924:164;83961:55;;;::::0;;::::2;::::0;::::2;84006:9:::0;83961:55:::2;:::i;:::-;:39;83986:13;:11;:13::i;83961:39::-;:44:::0;::::2;:55::i;:::-;84031:9;-1:-1:-1::0;;;;;84031:25:0::2;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;83924:164;84099:36;84125:9;84099:25;:36::i;:::-;84208:13;::::0;:67:::2;::::0;-1:-1:-1;;;84208:67:0;;84165:10:::2;::::0;-1:-1:-1;;;;;84208:13:0::2;::::0;:32:::2;::::0;:67:::2;::::0;84249:9;;84165:10;;84269:5;;84208:67:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;84186:159;;;;-1:-1:-1::0;;;84186:159:0::2;;;;;;;:::i;:::-;84358:32;;:::i;:::-;84467:22;84492:65;:52;84526:9;84537:6;84492:33;:52::i;:::-;:57:::0;:63:::2;:65::i;:::-;84467:90:::0;-1:-1:-1;84572:18:0::2;84593:20:::0;;:35:::2;;84623:5;84593:35;;;84616:4;84593:35;84572:56;;84648:13;84643:154;;84682:99;84705:33;84720:9;84731:6;84705:14;:33::i;:::-;84740:9;-1:-1:-1::0;;;;;84740:32:0::2;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;84682:99;84903:13;:70;;;;84968:5;84920:53;;;;;;;;84939:1;84921:15;:19;:42;;84954:9;84921:42;;;84943:8;84921:42;84920:53;;;;;;;;;84903:70;84899:631;;;85009:235;85056:9:::0;85088:5;85116:33:::2;;;::::0;;::::2;::::0;::::2;85139:9:::0;85116:33:::2;:::i;:::-;:22;;::::0;;::::2;::::0;::::2;:17:::0;:22:::2;:::i;:::-;::::0;::::2;:33::i;:::-;85009:235;;::::0;;::::2;::::0;::::2;85172:21:::0;85009:235:::2;:::i;:::-;;;::::0;;::::2;::::0;::::2;85216:9:::0;85009:235:::2;:::i;:::-;:24;:235::i;:::-;84994:250;;84899:631;;;85300:214;85342:9:::0;85374:5;85300:214:::2;;::::0;;::::2;::::0;::::2;85402:17:::0;85300:214:::2;:::i;:::-;;;::::0;;::::2;::::0;::::2;85442:9:::0;85300:214:::2;:::i;:::-;;;::::0;;::::2;::::0;::::2;85474:21:::0;85300:214:::2;:::i;:::-;:19;:214::i;:::-;85285:229;;84899:631;85588:53;85600:9;85611:6;85619:12;:21;;;85588:11;:53::i;:::-;85800:1;85768:29;:12;:20;;;:27;:29::i;:::-;:33;85764:105;;;85822:31;85843:9;85822:20;:31::i;:::-;85950:28;85981:9;-1:-1:-1::0;;;;;85981:20:0::2;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;85950:53;;86059:1;86022:34;:12;:26;;;:32;:34::i;:::-;:38;86018:327;;;86081:102;86109:6;86125:13;;;;;;;;;-1:-1:-1::0;;;;;86125:13:0::2;86141:41;:32;:12;:26;;;:30;:32::i;:41::-;-1:-1:-1::0;;;;;86081:27:0;::::2;::::0;:102;;:27:::2;:102::i;:::-;86018:327;;;86246:1;86209:34;:12;:26;;;:32;:34::i;:::-;:38;86205:140;;;86268:61;86277:9;86288:6;86296:32;:12;:26;;;:30;:32::i;86268:61::-;86385:13;::::0;:54:::2;::::0;-1:-1:-1;;;86385:54:0;;-1:-1:-1;;;;;86385:13:0;;::::2;::::0;:34:::2;::::0;:54:::2;::::0;86428:9;;86385:54:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;76355:1;;;86684:37;;:::i;:::-;86724:70;86736:6;86744:9;86755:12;:38;;;86724:11;:70::i;:::-;86684:110;;86830:17;86850:33;:9;-1:-1:-1::0;;;;;86850:22:0::2;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;:33;86830:53;;86894:21;86918:35;:12;:27;;;:33;:35::i;:::-;86894:59;;87002:20;87025:34;:12;:25;;;:32;:34::i;:::-;87002:57;;87134:9;-1:-1:-1::0;;;;;87075:579:0::2;87105:6;-1:-1:-1::0;;;;;87075:579:0::2;;87159:37;:12;:21;;;:28;;;:35;:37::i;:::-;87211:47;:12;:38;;;:45;:47::i;:::-;87273:42;:12;:34;;;:40;:42::i;:::-;87330:23;:14;:21;:23::i;:::-;87368:21:::0;;:26;:34:::2;::::0;:32:::2;:34::i;:::-;87417:32;:12;:24;;;:30;:32::i;:::-;87464:39;:12;:31;;;:37;:39::i;:::-;87518:29;:12;:20;;;:27;:29::i;:::-;87562:1;87578:9;87602:14;87631:12;87075:579;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;74887:1:0::1;76503:6;:21:::0;-1:-1:-1;;;;;;;;;83505:4157:0:o;101957:490::-;102170:39;;:::i;:::-;102211:48;;:::i;:::-;102277:24;;:::i;:::-;102304:31;102316:9;102327:7;102304:11;:31::i;:::-;102353:13;;:86;;-1:-1:-1;;;102353:86:0;;102277:58;;-1:-1:-1;;;;;;102353:13:0;;:49;;:86;;102403:9;;102277:58;;102424:14;;102353:86;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;102346:93;;;;;101957:490;;;;;;:::o;41176:79::-;41241:6;;-1:-1:-1;;;;;41241:6:0;41176:79;:::o;99618:584::-;99741:34;;:::i;:::-;99793:24;;:::i;:::-;99820:31;99832:9;99843:7;99820:11;:31::i;:::-;99793:58;;99862:34;99882:8;:13;;;99862:19;:34::i;:::-;99908:45;;:::i;:::-;99955:49;;:::i;:::-;100022:77;100058:9;100069:7;100078:20;100022:35;:77::i;:::-;99907:193;;;;100118:76;100134:9;100145:8;100155:14;100171:22;100118:15;:76::i;:::-;100111:83;;;;;99618:584;;;;;:::o;87771:2393::-;76585:6;;;;76584:7;76576:36;;;;-1:-1:-1;;;76576:36:0;;;;;;;:::i;:::-;74931:1:::1;76193:6;;:18;;76185:62;;;;-1:-1:-1::0;;;76185:62:0::1;;;;;;;:::i;:::-;74931:1;76325:6;:17:::0;87976:32:::2;87992:9:::0;88003:4:::2;87976:15;:32::i;:::-;88019:36;88045:9;88019:25;:36::i;:::-;88113:10;88134:24;;:::i;:::-;88161:52;88195:9;88206:6;88161:33;:52::i;:::-;88134:79;;88224:10;88237:26;:8;:13;;;:24;:26::i;:::-;:49;;88277:9;88237:49;;;88266:8;88237:49;88319:13;::::0;:67:::2;::::0;-1:-1:-1;;;88319:67:0;;88224:62;;-1:-1:-1;;;;;;88319:13:0::2;::::0;:32:::2;::::0;:67:::2;::::0;88360:9;;88372:6;;88224:62;;88319:67:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;88297:160;;;;-1:-1:-1::0;;;88297:160:0::2;;;;;;;:::i;:::-;88470:32;;:::i;:::-;88505:70;88527:9:::0;88538:6;88505:70:::2;;::::0;;::::2;::::0;::::2;88546:22:::0;88505:70:::2;:::i;:::-;88570:4;88505:21;:70::i;:::-;88470:105;;88754:1;88722:29;:12;:20;;;:27;:29::i;:::-;:33;88718:171;;;88776:31;88797:9;88776:20;:31::i;:::-;88826:47;88841:9;88852:12;:20;;;88826:14;:47::i;:::-;88903:61;88912:9;88923:6;88931:32;:12;:26;;;:30;:32::i;88903:61::-;89008:13;::::0;:54:::2;::::0;-1:-1:-1;;;89008:54:0;;-1:-1:-1;;;;;89008:13:0;;::::2;::::0;:34:::2;::::0;:54:::2;::::0;89051:9;;89008:54:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;89129:37;;:::i;:::-;89169:70;89181:6;89189:9;89200:12;:38;;;89169:11;:70::i;:::-;89129:110;;89334:17;89354:33;:9;-1:-1:-1::0;;;;;89354:22:0::2;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;:33;89334:53;;89402:21;89426:35;:12;:27;;;:33;:35::i;:::-;89402:59;;89476:20;89499:34;:12;:25;;;:32;:34::i;:::-;89476:57;;89620:9;-1:-1:-1::0;;;;;89553:592:0::2;89587:6;-1:-1:-1::0;;;;;89553:592:0::2;;89649:1;89679:47;:12;:38;;;:45;:47::i;:::-;89745:42;:12;:34;;;:40;:42::i;:::-;89806:23;:14;:21;:23::i;:::-;89848:21:::0;;:26;:34:::2;::::0;:32:::2;:34::i;:::-;89901:32;:12;:24;;;:30;:32::i;:::-;89952:1;89989:29;:12;:20;;;:27;:29::i;:::-;90037:1;90057:9;90085:14;90118:12;89553:592;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;74887:1:0::1;76503:6;:21:::0;-1:-1:-1;;;;;;;;87771:2393:0:o;77029:881::-;76585:6;;;;76584:7;76576:36;;;;-1:-1:-1;;;76576:36:0;;;;;;;:::i;:::-;74931:1:::1;76193:6;;:18;;76185:62;;;;-1:-1:-1::0;;;76185:62:0::1;;;;;;;:::i;:::-;74931:1;76325:6;:17:::0;77219:32:::2;77235:9:::0;77246:4:::2;77219:15;:32::i;:::-;77262:33;;;::::0;;::::2;::::0;::::2;77282:12:::0;77262:33:::2;:::i;:::-;77377:10;77398:24;;:::i;:::-;77425:52;77459:9;77470:6;77425:33;:52::i;:::-;77398:79:::0;-1:-1:-1;77506:34:0::2;;;::::0;;::::2;::::0;::::2;77527:12:::0;77506:34:::2;:::i;:::-;:15;::::0;::::2;::::0;;:20:::2;:34::i;:::-;77488:15;::::0;::::2;:52:::0;77551:40:::2;77563:9:::0;77574:6;77488:8;77551:11:::2;:40::i;:::-;77745:13;::::0;77643:163:::2;::::0;77716:6;;-1:-1:-1;;;;;77745:13:0::2;77774:21;:19;;::::0;;::::2;::::0;::::2;:12:::0;:19:::2;:::i;:21::-;77661:9;-1:-1:-1::0;;;;;77661:20:0::2;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;77643:58:0::2;::::0;:163;;:58:::2;:163::i;:::-;-1:-1:-1::0;;;;;77824:78:0;;::::2;::::0;;::::2;;77873:21;:19;;::::0;;::::2;::::0;::::2;:12:::0;:19:::2;:::i;:21::-;77897:1;77900::::0;77824:78:::2;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;74887:1:0::1;76503:6;:21:::0;-1:-1:-1;;77029:881:0:o;101074:483::-;101163:15;;:::i;:::-;101191:19;;:::i;:::-;101213:41;101235:9;101246:7;101213:21;:41::i;:::-;101191:63;;101265:28;101296:44;101338:1;101296:9;-1:-1:-1;;;;;101296:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;:44::i;:::-;101265:75;;101384:20;101355:3;:25;;;:49;101351:92;;;-1:-1:-1;101428:3:0;-1:-1:-1;101421:10:0;;101351:92;101462:13;;:87;;-1:-1:-1;;;101462:87:0;;-1:-1:-1;;;;;101462:13:0;;;;:49;;:87;;101512:9;;101523:3;;101528:20;;101462:87;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;101455:94;101074:483;-1:-1:-1;;;;;101074:483:0:o;75656:414::-;26178:13;;;;;;;;:33;;;26195:16;:14;:16::i;:::-;26178:50;;;-1:-1:-1;26216:12:0;;;;26215:13;26178:50;26170:109;;;;-1:-1:-1;;;26170:109:0;;;;;;;:::i;:::-;26292:19;26315:13;;;;;;26314:14;26339:101;;;;26374:13;:20;;-1:-1:-1;;;;26374:20:0;;;;;26409:19;26390:4;26409:19;;;26339:101;75813:16:::1;:14;:16::i;:::-;75842:14;:49:::0;;-1:-1:-1;;;;;75842:49:0;;::::1;-1:-1:-1::0;;;;;;75842:49:0;;::::1;;::::0;;;75902:13:::1;:46:::0;;;;::::1;::::0;;::::1;;::::0;;75959:13:::1;:46:::0;;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;75842:49;76016:6:::1;:21:::0;76048:6:::1;:14:::0;;-1:-1:-1;;76048:14:0::1;::::0;;26466:68;;;;26517:5;26501:21;;-1:-1:-1;;26501:21:0;;;75656:414;;;;:::o;103759:179::-;103832:34;;:::i;:::-;103886:13;;:44;;-1:-1:-1;;;103886:44:0;;-1:-1:-1;;;;;103886:13:0;;;;:33;;:44;;103920:9;;103886:44;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;76724:130::-;41398:12;:10;:12::i;:::-;41388:6;;-1:-1:-1;;;;;41388:6:0;;;:22;;;41380:67;;;;-1:-1:-1;;;41380:67:0;;;;;;;:::i;:::-;76814:14:::1;:32:::0;;-1:-1:-1;;;;;;76814:32:0::1;-1:-1:-1::0;;;;;76814:32:0;;;::::1;::::0;;;::::1;::::0;;76724:130::o;98500:1110::-;98628:34;;:::i;:::-;98680:24;;:::i;:::-;98707:31;98719:9;98730:7;98707:11;:31::i;:::-;98680:58;;98749:34;98769:8;:13;;;98749:19;:34::i;:::-;98794:42;98814:8;:21;;;98794:19;:42::i;:::-;98850:43;;:::i;:::-;98895:47;;:::i;:::-;98960:81;98996:9;99007:7;99016:24;98960:35;:81::i;:::-;98849:193;;;;99054:43;;:::i;:::-;99099:47;;:::i;:::-;99164:75;99200:9;99211:7;99220:18;99164:35;:75::i;:::-;99053:187;;;;99252:48;;:::i;:::-;99302:39;;:::i;:::-;99381:20;:12;:18;:20::i;:::-;99358;:12;:18;:20::i;:::-;:43;:155;;99478:12;99492:20;99358:155;;;99422:12;99436:20;99358:155;99251:262;;;;99533:69;99549:9;99560:8;99570:13;99585:16;99533:15;:69::i;:::-;99526:76;98500:1110;-1:-1:-1;;;;;;;;;;98500:1110:0:o;42121:244::-;41398:12;:10;:12::i;:::-;41388:6;;-1:-1:-1;;;;;41388:6:0;;;:22;;;41380:67;;;;-1:-1:-1;;;41380:67:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;42210:22:0;::::1;42202:73;;;;-1:-1:-1::0;;;42202:73:0::1;;;;;;;:::i;:::-;42312:6;::::0;42291:38:::1;::::0;-1:-1:-1;;;;;42291:38:0;;::::1;::::0;42312:6:::1;::::0;42291:38:::1;::::0;42312:6:::1;::::0;42291:38:::1;42340:6;:17:::0;;-1:-1:-1;;;;;;42340:17:0::1;-1:-1:-1::0;;;;;42340:17:0;;;::::1;::::0;;;::::1;::::0;;42121:244::o;74803:35::-;;;-1:-1:-1;;;;;74803:35:0;;:::o;96721:1094::-;96787:32;96803:9;96814:4;96787:15;:32::i;:::-;96830:14;;:49;;-1:-1:-1;;;96830:49:0;;-1:-1:-1;;;;;96830:14:0;;;;:38;;:49;;96869:9;;96830:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;96892:39;;:::i;:::-;96934:14;;;;;;;;;-1:-1:-1;;;;;96934:14:0;-1:-1:-1;;;;;96934:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;96979:31:0;;;;;;:11;:31;;;;;96892:76;;-1:-1:-1;96979:59:0;;97058:69;97080:46;96999:9;97080:35;:46::i;:::-;97058:16;;:21;:69::i;:::-;96979:159;;;;;;;-1:-1:-1;96979:159:0;;;;;;;;;;;;97151:40;;:::i;:::-;-1:-1:-1;;;;;;97194:31:0;;;;;;:11;:31;;;;;;;;;97151:92;;;;;;;;97194:49;;;;97151:92;;;97254:46;;:::i;:::-;97303:40;:16;97325:17;97303:21;:40::i;:::-;97254:89;;97395:1;97360:32;:23;:30;:32::i;:::-;:36;97356:245;;;97413:176;97463:9;97491:23;97533:14;;;;;;;;;-1:-1:-1;;;;;97533:14:0;-1:-1:-1;;;;;97533:39:0;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;97413:176;97658:9;-1:-1:-1;;;;;97618:189:0;;97683:26;:17;:24;:26::i;:::-;97724:32;:23;:30;:32::i;:::-;97771:25;:16;:23;:25::i;:::-;97618:189;;;;;;;;:::i;:::-;;;;;;;;96721:1094;;;;:::o;28114:106::-;28202:10;28114:106;:::o;121850:1410::-;121967:15;;:::i;:::-;122000:34;;:::i;:::-;122037:41;122059:9;122070:7;122037:21;:41::i;:::-;122000:78;;122093:31;:18;:23;;;:29;:31::i;:::-;122089:94;;122153:18;-1:-1:-1;122146:25:0;;122089:94;122193:28;122224:44;122266:1;122224:9;-1:-1:-1;;;;;122224:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:44;122193:75;;122327:20;122283:18;:40;;;:64;122279:122;;;-1:-1:-1;122371:18:0;-1:-1:-1;122364:25:0;;122279:122;122413:32;;:::i;:::-;122461:13;;:102;;-1:-1:-1;;;122461:102:0;;-1:-1:-1;;;;;122461:13:0;;;;:49;;:102;;122511:9;;122522:18;;122542:20;;122461:102;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;122413:150;;122574:54;;:::i;:::-;122644:13;;:178;;-1:-1:-1;;;122644:178:0;;-1:-1:-1;;;;;122644:13:0;;;;:59;;:178;;122722:9;;122750:18;;122787:20;;122644:178;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;122863:21;;122833:73;;-1:-1:-1;;;122833:73:0;;122574:248;;-1:-1:-1;;;;;;122833:29:0;;;;;:73;;122574:248;;122833:73;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;122919:49;122931:9;122942:7;122951:16;122919:11;:49::i;:::-;123048:7;-1:-1:-1;;;;;122984:234:0;123023:9;-1:-1:-1;;;;;122984:234:0;;123070:29;:16;:21;;;:27;:29::i;:::-;123114:18;:40;;;123169:16;:38;;;122984:234;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;123236:16:0;121850:1410;-1:-1:-1;;;;;121850:1410:0:o;123566:261::-;123656:14;;:43;;-1:-1:-1;;;123656:43:0;;-1:-1:-1;;;;;123656:14:0;;;;:32;;:43;;123689:9;;123656:43;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;123648:74;;;;-1:-1:-1;;;123648:74:0;;;;;;;:::i;:::-;123750:9;-1:-1:-1;;;;;123750:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;123741:25;;:5;:25;;;123768:5;:50;;;;;;;;;;;;;;;-1:-1:-1;;;123768:50:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;123768:50:0;;;;123733:86;;;;;-1:-1:-1;;;123733:86:0;;;;;;;;:::i;:::-;;123566:261;;:::o;123835:139::-;123929:17;:8;:15;:17::i;:::-;123921:45;;;;-1:-1:-1;;;123921:45:0;;;;;;;:::i;:::-;123835:139;:::o;17102:228::-;17223:34;;:::i;:::-;17202:1;17047;:3;;;-1:-1:-1;;;;;17032:18:0;;17052:21;;;;;;;;;;;;;;;;;17024:50;;;;;-1:-1:-1;;;17024:50:0;;;;;;;;:::i;:::-;-1:-1:-1;;17282:40:0::1;::::0;;::::1;::::0;::::1;::::0;;;17317:3;;17282:40;;-1:-1:-1;17282:40:0;17102:228::o;15797:185::-;15873:20;;:::i;:::-;15906:22;;:::i;:::-;15945:3;;:10;;15953:1;15945:7;:10::i;:::-;15939:16;;;15797:185;-1:-1:-1;;;15797:185:0:o;7703:95::-;7787:3;;7703:95::o;104262:1111::-;-1:-1:-1;;;;;104437:31:0;;;104402:32;104437:31;;;:11;:31;;;;;;;;:52;;;;;:43;;;:52;;;;;104552:108;;;;;;;104621:28;;;104552:108;;;:31;;;;;;;:54;;;;;;;;:49;;;;:54;;;104437:52;104552:108;;:54;:108::i;:::-;-1:-1:-1;;;;;104500:31:0;;;;;;:11;:31;;;;;;;;:160;;:49;;;;:160;;;104694:14;;104671:37;;;104744:16;;;;104719:41;:22;;;:41;104802:22;;;;104771:53;:28;;;:53;;;104890:46;;;;104835:101;:52;;;:101;105003:47;;;;104947:103;:53;;;:103;;;;105091:21;;;;105061:27;;;:51;105163:31;;;;105123:37;;;:71;105257:108;;;;;;;;;;:31;;;;;;;:54;;;;;;;;;;;;:108;;:54;:108::i;:::-;-1:-1:-1;;;;;105205:31:0;;;;;;;:11;:31;;;;;:160;;:49;;;;:160;;;;-1:-1:-1;;;104262:1111:0:o;124542:454::-;124749:27;124779:43;:35;:12;124797:16;124779:17;:35::i;:43::-;124749:73;;124855:20;:75;;124929:1;124906:20;:24;124855:75;;;124902:1;124878:20;:25;;124855:75;124833:155;;;;-1:-1:-1;;;124833:155:0;;;;;;;:::i;120460:212::-;120611:13;;:53;;-1:-1:-1;;;120611:53:0;;-1:-1:-1;;;;;120611:13:0;;;;:22;;:53;;120634:9;;120645;;120656:7;;120611:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;120460:212;;;:::o;123982:151::-;124085:13;:5;:11;:13::i;:::-;124077:48;;;;-1:-1:-1;;;124077:48:0;;;;;;;:::i;105381:841::-;105462:24;;:::i;:::-;-1:-1:-1;;;;;;105489:31:0;;;;;;;:11;:31;;;;;;;;:52;;;;;:43;;;;:52;;;;;105462:79;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;105462:79:0;;;;;;;;;;105673:21;;105604:31;;;;;;;:54;;;;;;;:49;;;;:54;;;:101;;:54;:101::i;:::-;-1:-1:-1;;;;;105552:31:0;;;;;;:11;:31;;;;;;;:153;;:49;;;;:153;;;;105850:364;;;;;;;;;105880:20;:18;:20::i;:::-;105850:364;;;;105923:14;:12;:14::i;:::-;105850:364;;;;105966:14;:12;:14::i;:::-;105850:364;;;;106033:20;:18;:20::i;:::-;105850:364;;;;106107:14;:12;:14::i;:::-;105850:364;;;;106201:1;105850:364;;;;106149:14;:12;:14::i;:::-;105850:364;;-1:-1:-1;;;;;105795:31:0;;;;;;;:11;:31;;;;;;;;:52;;;;;;:43;;;;:52;;;;;;:419;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;105795:419:0;;;;;;;;;;;;;;;;;;;;;;;;;105381:841::o;14753:269::-;14813:22;;:::i;:::-;14848:24;;:::i;:::-;14887:3;;14893:1;-1:-1:-1;14883:113:0;;;14929:3;;;14925:7;14911:22;;14883:113;;;14980:3;;14966:18;;-1:-1:-1;14966:18:0;14753:269::o;9103:173::-;9176:14;;:::i;:::-;9203:16;;:::i;:::-;9245:3;;9236;;:13;;:8;:13::i;17977:304::-;18129:34;;:::i;:::-;18108:1;17047;:3;;;-1:-1:-1;;;;;17032:18:0;;17052:21;;;;;;;;;;;;;;;;;17024:50;;;;;-1:-1:-1;;;17024:50:0;;;;;;;;:::i;:::-;;18181:36:::1;;:::i;:::-;18249:3:::0;;18234;;:20:::1;::::0;:7:::1;:20::i;:::-;18228:26:::0;;;17977:304;-1:-1:-1;;;;17977:304:0:o;15541:197::-;15626:20;;:::i;:::-;15659:22;;:::i;:::-;15707:3;;15698;;:13;;:8;:13::i;17564:304::-;17716:34;;:::i;:::-;17695:1;17047;:3;;;-1:-1:-1;;;;;17032:18:0;;17052:21;;;;;;;;;;;;;;;;;17024:50;;;;;-1:-1:-1;;;17024:50:0;;;;;;;;:::i;:::-;;17768:36:::1;;:::i;:::-;17836:3:::0;;17821;;:20:::1;::::0;:7:::1;:20::i;15061:196::-:0;15146:20;;:::i;:::-;15179:22;;:::i;:::-;15226:3;;15218;;:12;;:7;:12::i;120680:162::-;120785:13;;:49;;-1:-1:-1;;;120785:49:0;;-1:-1:-1;;;;;120785:13:0;;;;:28;;:49;;120814:9;;120825:8;;120785:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;120680:162;;:::o;121122:670::-;121350:14;;:42;;-1:-1:-1;;;121350:42:0;;121311:28;;-1:-1:-1;;;;;121350:14:0;;:31;;:42;;121382:9;;121350:42;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;121311:82;-1:-1:-1;;;;;;121412:34:0;;121404:68;;;;-1:-1:-1;;;121404:68:0;;;;;;;:::i;:::-;121483:39;;:::i;:::-;121525:30;:4;121535:19;121525:9;:30::i;:::-;121566:13;;:73;;-1:-1:-1;;;121566:73:0;;121483:72;;-1:-1:-1;;;;;;121566:13:0;;:22;;:73;;121589:9;;121600:20;;121483:72;;121566:73;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;121650:31;;:::i;:::-;121684:27;:4;121694:16;121684:9;:27::i;:::-;121722:13;;:62;;-1:-1:-1;;;121722:62:0;;121650:61;;-1:-1:-1;;;;;;121722:13:0;;:32;;:62;;121763:9;;121650:61;;121722:62;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;121122:670;;;;;;:::o;15301:196::-;15386:20;;:::i;:::-;15419:22;;:::i;:::-;15466:3;;15458;;:12;;:7;:12::i;7487:91::-;7526:14;;:::i;:::-;-1:-1:-1;7560:10:0;;;;;;;;;-1:-1:-1;7560:10:0;;7487:91;:::o;116742:1902::-;116946:32;;:::i;:::-;117020:27;;:::i;:::-;117050:41;117072:9;117083:7;117050:21;:41::i;:::-;117020:71;;117102:50;;:::i;:::-;-1:-1:-1;117155:16:0;;117182:36;117155:16;117182:19;:36::i;:::-;117234:48;;:::i;:::-;117299:81;117335:9;117346:7;117355:24;117299:35;:81::i;:::-;117231:149;;;117393:55;;:::i;:::-;117464:13;;:102;;-1:-1:-1;;;117464:102:0;;-1:-1:-1;;;;;117464:13:0;;;;:63;;:102;;117528:9;;117539:11;;117552:13;;117464:102;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;117393:173;-1:-1:-1;117616:29:0;:15;-1:-1:-1;;117616:25:0;:29::i;:::-;117579:34;;;;:66;;;;117656:24;;;:40;;;117730:24;;;;117707:20;;;;:47;;;;117795:31;;;-1:-1:-1;117765:27:0;;:61;117865:29;;;117837:25;;;:57;117959:29;;117934:69;;-1:-1:-1;;118000:2:0;117934:55;;:24;:55::i;:69::-;117905:26;;;:98;-1:-1:-1;;;;;118055:20:0;;;118116:1;118090:23;:15;:21;:23::i;:::-;:27;:96;;118152:34;118090:96;;;118120:29;118090:96;118201:21;:15;:19;:21::i;:::-;118237:22;118274:21;118055:251;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;118014:38;;;;:292;;;;118413:13;;118542:24;;;;118511;;;;-1:-1:-1;;;;;118413:13:0;;;;:40;;118468:9;;118492:89;;-1:-1:-1;;118578:2:0;118492:75;;:44;;:13;;:18;:44::i;:89::-;118413:179;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;118603:33;118617:9;118628:7;118603:13;:33::i;:::-;116742:1902;;;;;;;;;;:::o;103991:263::-;104062:19;104084:14;:12;:14::i;:::-;-1:-1:-1;;;;;104109:31:0;;;;;;:11;:31;;;;;;;:66;;;104191:55;104062:36;;-1:-1:-1;104191:55:0;;;;104129:9;;104062:36;;104191:55;:::i;:::-;;;;;;;;103991:263;;:::o;8666:173::-;8739:14;;:::i;:::-;8766:16;;:::i;:::-;8808:3;;8799;;:13;;:8;:13::i;7973:222::-;8072:3;;8066;;8045:4;;-1:-1:-1;8062:107:0;;;-1:-1:-1;8099:1:0;8092:8;;8062:107;8128:3;;8122;;:9;8118:51;;;-1:-1:-1;;;8148:9:0;;8118:51;-1:-1:-1;8186:1:0;7973:222;;;;:::o;8450:172::-;8523:14;;:::i;:::-;8550:16;;:::i;:::-;8591:3;;8583;;:12;;:7;:12::i;8234:172::-;8307:14;;:::i;:::-;8334:16;;:::i;:::-;8375:3;;8367;;:12;;:7;:12::i;120850:264::-;120987:14;;:42;;-1:-1:-1;;;120987:42:0;;120956:28;;-1:-1:-1;;;;;120987:14:0;;:31;;:42;;121019:9;;120987:42;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;121040:13;;:66;;-1:-1:-1;;;121040:66:0;;120956:73;;-1:-1:-1;;;;;;121040:13:0;;:22;;:66;;121063:9;;120956:73;;121098:7;;121040:66;;;:::i;17338:121::-;17415:7;17442;:1;:5;:7::i;:::-;:9;;17338:121;-1:-1:-1;;17338:121:0:o;7586:109::-;7624:14;;:::i;:::-;7658:29;;;;;;;;7666:20;7683:2;7666:16;:20::i;:::-;7658:29;;7651:36;-1:-1:-1;7586:109:0;:::o;19148:304::-;19300:34;;:::i;:::-;19279:1;17047;:3;;;-1:-1:-1;;;;;17032:18:0;;17052:21;;;;;;;;;;;;;;;;;17024:50;;;;;-1:-1:-1;;;17024:50:0;;;;;;;;:::i;:::-;;19352:36:::1;;:::i;:::-;19403:22;19410:14;19422:1;19410:11;:14::i;:::-;19403:1:::0;;:6:::1;:22::i;124141:393::-:0;124221:20;124244:14;:12;:14::i;:::-;-1:-1:-1;;;;;124289:31:0;;;;;;:11;:31;;;;;:52;124221:37;;-1:-1:-1;124273:68:0;;124269:258;;;124444:12;124384:44;124406:9;124417:10;124384:21;:44::i;:::-;:56;;;:72;;124358:157;;;;-1:-1:-1;;;124358:157:0;;;;;;;:::i;106350:3229::-;106600:32;;:::i;:::-;106662:10;106683:27;;:::i;:::-;106713:40;106735:9;106746:6;106713:21;:40::i;:::-;106683:70;;106801:60;106811:9;106822:5;106829:13;106844:16;106801:9;:60::i;:::-;106764:34;;;:97;106872:42;;:::i;:::-;106939:34;;;;106917:16;;:57;;:21;:57::i;:::-;107097:33;;;;107145:16;;106872:102;;-1:-1:-1;107097:33:0;107145:24;;:22;:24::i;:::-;107141:130;;107215:44;107257:1;107215:9;-1:-1:-1;;;;;107215:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:44;107191:68;;107141:130;107283:13;;-1:-1:-1;;;;;107283:13:0;:40;107324:9;107335:39;107360:13;107335:24;:39::i;:::-;107283:92;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;107475:13;;;;;;;;;-1:-1:-1;;;;;107475:13:0;-1:-1:-1;;;;;107475:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;107465:38:0;:6;-1:-1:-1;;;;;107465:38:0;;107461:403;;107520:42;;:::i;:::-;107565:9;-1:-1:-1;;;;;107565:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;107520:79;;107649:1;107618:28;:19;:26;:28::i;:::-;:32;107614:239;;;107802:1;107760:38;107778:19;107760:13;:7;:11;:13::i;:::-;:17;;:38::i;:::-;:43;;;;107752:85;;;;-1:-1:-1;;;107752:85:0;;;;;;;:::i;:::-;107461:403;;107876:24;;:::i;:::-;107962:60;;:::i;:::-;108042:55;108067:29;:13;108086:9;108067:18;:29::i;108042:55::-;107962:135;;108114:55;;:::i;:::-;108189:13;;;;;;;;;-1:-1:-1;;;;;108189:13:0;-1:-1:-1;;;;;108189:63:0;;108275:9;108307:11;108341:25;108189:196;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;108402:26;;;:54;;;;-1:-1:-1;108501:31:0;;;;108471:27;;;:61;-1:-1:-1;108575:29:0;;;108547:25;;;:57;108639:29;108621:15;;;:47;108746:48;;:::i;:::-;108815:80;108851:9;108862:6;108870:24;108815:35;:80::i;:::-;108910:31;;;:47;-1:-1:-1;;109013:38:0;;;:54;;;109078:23;;;109166:38;109136:24;;;;:69;;:29;:69::i;:::-;109112:21;;;:93;109216:30;;;:54;;;109329:45;109364:9;109329:34;:45::i;:::-;109281;;;:93;109434:46;109470:9;109434:35;:46::i;:::-;109385;;;:95;109514:14;:12;:14::i;:::-;109491:20;;;:37;109539:32;;-1:-1:-1;109539:12:0;;106350:3229;-1:-1:-1;;;;;;;;106350:3229:0:o;109587:4350::-;109841:19;;:::i;:::-;109873:35;;:::i;:::-;109911:33;:17;109934:9;109911:22;:33::i;:::-;109873:71;;109956:42;;:::i;:::-;110000:48;;:::i;:::-;110065:84;110101:9;110112:10;110124:24;110065:35;:84::i;:::-;109955:194;;;;110160:32;;:::i;:::-;110294:21;:12;:19;:21::i;:::-;110263:28;:19;:26;:28::i;:::-;:52;110259:3553;;;110332:13;;-1:-1:-1;;;;;110332:13:0;:40;110373:9;110384:52;-1:-1:-1;;110384:38:0;110409:12;110384:24;:38::i;:52::-;110332:105;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;110452:27;;:::i;:::-;110482:44;110504:9;110515:10;110482:21;:44::i;:::-;110452:74;;110578:64;110588:9;110599:5;110606:12;110620:21;110578:9;:64::i;:::-;110541:34;;;:101;110804:16;;:24;;:22;:24::i;:::-;:29;110800:226;;110881:129;110969:22;:11;:16;;;:20;:22::i;:::-;110881:60;110900:40;:12;:34;;;:38;:40::i;:::-;110881:13;;:18;:60::i;:129::-;110854:24;;;:156;110800:226;111117:55;;:::i;:::-;111196:13;;;;;;;;;-1:-1:-1;;;;;111196:13:0;-1:-1:-1;;;;;111196:63:0;;111286:9;111322:11;111360:12;:24;;;111196:211;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;111451:24;;;;;111428:20;;;;:47;;;;111524:31;;;111494:27;;;:61;111602:29;;;;111574:25;;;:57;111650:38;;;:53;;;111801:29;;111780:18;;;:50;-1:-1:-1;112044:24:0;;;;112025:44;;:13;;:18;:44::i;:::-;111991:31;;;:78;112498:53;;:::i;:::-;112598:1;112571:24;:11;:16;;;:22;:24::i;:::-;:28;:402;;112823:150;112912:12;:38;;;112823:57;112860:19;112823:12;:31;;;:36;;:57;;;;:::i;:150::-;112571:402;;;112623:176;112745:12;:31;;;112623:90;112674:12;:38;;;112623:45;112648:19;112623:24;:45::i;:90::-;:95;;:176::i;:::-;112498:475;;113025:1;112996:26;:18;:24;:26::i;:::-;:30;112988:69;;;;-1:-1:-1;;;112988:69:0;;;;;;;:::i;:::-;113093:24;;:::i;:::-;113154:18;;;;;113136:15;;;:36;113229:34;;;;113207:16;;:57;;:21;:57::i;:::-;113191:73;;113307:24;:18;:22;:24::i;:::-;113283:21;;;:48;113383:33;;;;;113350:30;;;:66;113483:45;113518:9;113483:34;:45::i;:::-;113435;;;:93;113596:46;113632:9;113596:35;:46::i;:::-;113547;;;:95;113684:14;:12;:14::i;:::-;113661:20;;;:37;113717:32;;-1:-1:-1;113717:12:0;;-1:-1:-1;113781:19:0;;-1:-1:-1;;;;113781:19:0;110259:3553;113831:98;113859:9;113870:5;113877:17;113896:9;113907:21;113831:27;:98::i;65452:216::-;65564:96;65584:5;65614:27;;;65643:4;65649:2;65653:5;65591:68;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;65591:68:0;;;;;;;;;;;;;;-1:-1:-1;;;;;65591:68:0;-1:-1:-1;;;;;;65591:68:0;;;;;;;;;;65564:19;:96::i;119335:1117::-;119486:22;;:::i;:::-;119521:26;;:::i;:::-;119550:36;;-1:-1:-1;;;119550:36:0;;-1:-1:-1;;;;;119550:17:0;;;;;:36;;119568:17;;119550:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;119521:65;;119616:1;119601:12;:3;:10;:12::i;:::-;:16;119597:814;;;119673:14;;:42;;-1:-1:-1;;;119673:42:0;;119634:28;;-1:-1:-1;;;;;119673:14:0;;:31;;:42;;119705:9;;119673:42;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;119634:82;-1:-1:-1;;;;;;119739:34:0;;119731:68;;;;-1:-1:-1;;;119731:68:0;;;;;;;:::i;:::-;119814:39;;:::i;:::-;119865:14;;:38;;;-1:-1:-1;;;119865:38:0;;;;119856:48;;-1:-1:-1;;;;;119865:14:0;;:36;;:38;;;;;;;;;;;;;;:14;:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;119856:3;;:8;:48::i;:::-;119814:90;;119919:189;119996:5;120028:20;120068:25;:16;:23;:25::i;:::-;119937:9;-1:-1:-1;;;;;119937:20:0;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;119919:189;120123:28;;:::i;:::-;120154:26;:3;120163:16;120154:8;:26::i;:::-;120269:13;;120123:57;;-1:-1:-1;120195:105:0;;120254:5;;-1:-1:-1;;;;;120269:13:0;120285:14;120123:57;120285:12;:14::i;:::-;120213:9;-1:-1:-1;;;;;120213:20:0;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;120195:105;120315:13;;:59;;-1:-1:-1;;;120315:59:0;;-1:-1:-1;;;;;120315:13:0;;;;:32;;:59;;120356:9;;120368:5;;120315:59;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;120396:3;120389:10;;;;;;;;119597:814;120430:14;:12;:14::i;:::-;120423:21;;;119335:1117;;;;;;:::o;100210:632::-;100442:34;;:::i;:::-;100489:55;;:::i;:::-;100560:13;;:101;;-1:-1:-1;;;100560:101:0;;-1:-1:-1;;;;;100560:13:0;;;;:63;;:101;;100624:9;;100635;;100646:14;;100560:101;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;100489:172;;100692:142;100802:17;100692:86;100753:16;:24;;;100692:55;100717:16;:29;;;100692:24;:55::i;:142::-;100672:162;;;100210:632;;;;;;;:::o;14580:165::-;14647:4;14674:1;14668;:3;;;:7;14664:51;;;-1:-1:-1;14699:4:0;14692:11;;14664:51;-1:-1:-1;14732:5:0;14580:165;;;:::o;1462:136::-;1520:7;1547:43;1551:1;1554;1547:43;;;;;;;;;;;;;;;;;:3;:43::i;26634:604::-;27076:4;27187:17;27223:7;26634:604;:::o;40762:129::-;26178:13;;;;;;;;:33;;;26195:16;:14;:16::i;:::-;26178:50;;;-1:-1:-1;26216:12:0;;;;26215:13;26178:50;26170:109;;;;-1:-1:-1;;;26170:109:0;;;;;;;:::i;:::-;26292:19;26315:13;;;;;;26314:14;26339:101;;;;26374:13;:20;;-1:-1:-1;;;;26374:20:0;;;;;26409:19;26390:4;26409:19;;;26339:101;40820:26:::1;:24;:26::i;:::-;40857;:24;:26::i;:::-;26470:14:::0;26466:68;;;26517:5;26501:21;;-1:-1:-1;;26501:21:0;;;40762:129;:::o;10076:568::-;10132:6;10376;10372:47;;-1:-1:-1;10406:1:0;10399:8;;10372:47;10441:1;-1:-1:-1;;10441:7:0;:27;;;;;-1:-1:-1;;;10452:1:0;:16;10441:27;10439:30;10431:82;;;;-1:-1:-1;;;10431:82:0;;;;;;;:::i;:::-;10537:5;;;10541:1;10537;:5;:1;10561:5;;;;;:10;10553:62;;;;-1:-1:-1;;;10553:62:0;;;;;;;:::i;20477:102::-;20559:12;20477:102;:::o;6870:108::-;6929:7;6956:14;6961:1;6964;6967:2;6956:4;:14::i;11640:218::-;11696:6;11726:5;;;11751:6;;;;;;:16;;;11766:1;11761;:6;;11751:16;11750:38;;;;11777:1;11773;:5;:14;;;;;11786:1;11782;:5;11773:14;11742:87;;;;-1:-1:-1;;;11742:87:0;;;;;;;:::i;13251:105::-;13308:6;13334:14;13339:1;13342;13345:2;13334:4;:14::i;12103:215::-;12159:6;12189:5;;;12214:6;;;;;;:16;;;12229:1;12224;:6;;12214:16;12213:38;;;;12240:1;12236;:5;:14;;;;;12249:1;12245;:5;12236:14;12205:84;;;;-1:-1:-1;;;12205:84:0;;;;;;;:::i;6395:108::-;6454:7;6481:14;6486:1;6489;6492:2;6481:4;:14::i;998:181::-;1056:7;1088:5;;;1112:6;;;;1104:46;;;;-1:-1:-1;;;1104:46:0;;;;;;;:::i;5805:109::-;5889:17;;5885:2;:21;;5805:109::o;16024:197::-;16109:20;;:::i;:::-;16142:22;;:::i;:::-;16190:3;;16181;;:13;;:8;:13::i;118652:675::-;118843:34;;:::i;:::-;118890:22;;118929:5;:17;;;;;;;;;118928:88;;118982:34;118928:88;;;118950:29;118928:88;118890:126;;119027:47;;:::i;:::-;119115:56;;-1:-1:-1;;;119115:56:0;;119090:82;;-1:-1:-1;;;;;119115:19:0;;;;;:56;;119135:3;;119140:12;;119154:16;;119115:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;119090:82::-;119027:145;;119225:3;119187:41;;;;;;;;:34;:41;119183:107;;;119252:26;:12;-1:-1:-1;;119252:22:0;:26::i;:::-;119245:33;;;;;;18361:304;18513:34;;:::i;:::-;18492:1;17047;:3;;;-1:-1:-1;;;;;17032:18:0;;17052:21;;;;;;;;;;;;;;;;;17024:50;;;;;-1:-1:-1;;;17024:50:0;;;;;;;;:::i;:::-;;18565:36:::1;;:::i;:::-;18616:22;18623:14;18635:1;18623:11;:14::i;:::-;18616:1:::0;;:6:::1;:22::i;113945:2789::-:0;114207:32;;:::i;:::-;114396:37;;:::i;:::-;114436:66;114458:9;114469:10;114481:14;:12;:14::i;114436:66::-;114396:106;;114602:34;:17;:25;;;:32;:34::i;:::-;:39;114594:81;;;;-1:-1:-1;;;114594:81:0;;;;;;;:::i;:::-;114744:35;;:::i;:::-;114834:43;;;;114795:83;;:33;:17;114818:9;114795:22;:33::i;:::-;:38;;:83::i;:::-;114744:134;-1:-1:-1;115065:37:0;:28;114744:134;115083:9;115065:17;:28::i;:37::-;115061:1636;;115139:17;115124:32;;115061:1636;;;115189:50;;:::i;:::-;115291:48;:17;:39;;;:46;:48::i;:::-;115258:30;:21;:28;:30::i;:::-;:81;115254:225;;;115390:73;115417:45;:17;:39;;;:43;:45::i;:::-;115390:21;;:26;:73::i;:::-;115360:103;;115254:225;115495:40;;:::i;:::-;115555:96;115580:9;115591:5;115598:12;115612:27;115641:9;115555:24;:96::i;:::-;115495:156;;115681:1004;;;;;;;;115723:20;:29;;;115681:1004;;;;115798:136;115869:20;:46;;;115798:17;:43;;;:48;;:136;;;;:::i;:::-;115681:1004;;;;115962:60;115993:20;:28;;;115962:17;:25;;;:30;;:60;;;;:::i;:::-;115681:1004;;;;116276:128;116343:20;:42;;;116276:17;:39;;;:44;;:128;;;;:::i;:::-;115681:1004;;;;116057:74;116095:20;:35;;;116057:17;:32;;;:37;;:74;;;;:::i;:::-;115681:1004;;;;116164:70;116200:20;:33;;;116164:17;:30;;;:35;;:70;;;;:::i;:::-;115681:1004;;;;116436:68;116471:20;:32;;;116436:17;:29;;;:34;;:68;;;;:::i;:::-;115681:1004;;;;116597:72;116634:20;:34;;;116597:17;:31;;;:36;;:72;;;;:::i;:::-;115681:1004;;;;116543:20;:18;:20::i;:::-;115681:1004;;115666:1019;-1:-1:-1;;;115061:1636:0;116707:19;;113945:2789;;;;;;;:::o;67616:772::-;68051:23;68077:69;68105:4;68077:69;;;;;;;;;;;;;;;;;68085:5;-1:-1:-1;;;;;68077:27:0;;;:69;;;;;:::i;:::-;68161:17;;68051:95;;-1:-1:-1;68161:21:0;68157:224;;68303:10;68292:30;;;;;;;;;;;;:::i;:::-;68284:85;;;;-1:-1:-1;;;68284:85:0;;;;;;;:::i;1901:192::-;1987:7;2023:12;2015:6;;;;2007:29;;;;-1:-1:-1;;;2007:29:0;;;;;;;;:::i;:::-;-1:-1:-1;;;2059:5:0;;;1901:192::o;28043:65::-;26178:13;;;;;;;;:33;;;26195:16;:14;:16::i;:::-;26178:50;;;-1:-1:-1;26216:12:0;;;;26215:13;26178:50;26170:109;;;;-1:-1:-1;;;26170:109:0;;;;;;;:::i;:::-;26292:19;26315:13;;;;;;26314:14;26339:101;;;;26374:13;:20;;-1:-1:-1;;;;26374:20:0;;;;;26409:19;26390:4;26409:19;;;26470:14;26466:68;;;26517:5;26501:21;;-1:-1:-1;;26501:21:0;;;28043:65;:::o;40899:196::-;26178:13;;;;;;;;:33;;;26195:16;:14;:16::i;:::-;26178:50;;;-1:-1:-1;26216:12:0;;;;26215:13;26178:50;26170:109;;;;-1:-1:-1;;;26170:109:0;;;;;;;:::i;:::-;26292:19;26315:13;;;;;;26314:14;26339:101;;;;26374:13;:20;;-1:-1:-1;;;;26374:20:0;;;;;26409:19;26390:4;26409:19;;;26339:101;40967:17:::1;40987:12;:10;:12::i;:::-;41010:6;:18:::0;;-1:-1:-1;;;;;;41010:18:0::1;-1:-1:-1::0;;;;;41010:18:0;::::1;::::0;;::::1;::::0;;;41044:43:::1;::::0;41010:18;;-1:-1:-1;41010:18:0;-1:-1:-1;;41044:43:0::1;::::0;-1:-1:-1;;41044:43:0::1;26452:1;26470:14:::0;26466:68;;;26517:5;26501:21;;-1:-1:-1;;26501:21:0;;;40899:196;:::o;7080:172::-;7189:7;7216:28;7242:1;7216:21;7222:14;7227:8;7222:4;:14::i;:::-;7216:1;;:5;:21::i;:::-;:25;;:28::i;13457:169::-;13564:6;13590:28;13603:14;13608:8;13603:4;:14::i;:::-;13590:8;:1;13596;13590:5;:8::i;:::-;:12;;:28::i;6604:172::-;6713:7;6740:28;6753:14;6758:8;6753:4;:14::i;:::-;6740:8;:1;6746;6740:5;:8::i;13720:105::-;13777:6;13803:14;13808:1;13811;13814:2;13803:4;:14::i;61199:195::-;61302:12;61334:52;61356:6;61364:4;61370:1;61373:12;61334:21;:52::i;2352:471::-;2410:7;2655:6;2651:47;;-1:-1:-1;2685:1:0;2678:8;;2651:47;2722:5;;;2726:1;2722;:5;:1;2746:5;;;;;:10;2738:56;;;;-1:-1:-1;;;2738:56:0;;;;;;;:::i;3299:132::-;3357:7;3384:39;3388:1;3391;3384:39;;;;;;;;;;;;;;;;;:3;:39::i;11118:271::-;11174:6;11201;11193:51;;;;-1:-1:-1;;;11193:51:0;;;;;;;:::i;:::-;11265:1;-1:-1:-1;;11265:7:0;:27;;;;;-1:-1:-1;;;11276:1:0;:16;11265:27;11263:30;11255:76;;;;-1:-1:-1;;;11255:76:0;;;;;;;:::i;:::-;11344:8;11359:1;11355;:5;;;;;;;11118:271;-1:-1:-1;;;;11118:271:0:o;13927:169::-;14034:6;14060:28;14086:1;14060:21;14066:14;14071:8;14066:4;:14::i;:::-;14060:1;;:5;:21::i;62251:530::-;62378:12;62436:5;62411:21;:30;;62403:81;;;;-1:-1:-1;;;62403:81:0;;;;;;;:::i;:::-;62503:18;62514:6;62503:10;:18::i;:::-;62495:60;;;;-1:-1:-1;;;62495:60:0;;;;;;;:::i;:::-;62629:12;62643:23;62670:6;-1:-1:-1;;;;;62670:11:0;62690:5;62698:4;62670:33;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62628:75;;;;62721:52;62739:7;62748:10;62760:12;62721:17;:52::i;:::-;62714:59;62251:530;-1:-1:-1;;;;;;;62251:530:0:o;3927:278::-;4013:7;4048:12;4041:5;4033:28;;;;-1:-1:-1;;;4033:28:0;;;;;;;;:::i;:::-;;4072:9;4088:1;4084;:5;;;;;;;3927:278;-1:-1:-1;;;;;3927:278:0:o;58281:422::-;58648:20;58687:8;;;58281:422::o;63787:742::-;63902:12;63931:7;63927:595;;;-1:-1:-1;63962:10:0;63955:17;;63927:595;64076:17;;:21;64072:439;;64339:10;64333:17;64400:15;64387:10;64383:2;64379:19;64372:44;64287:148;64482:12;64475:20;;-1:-1:-1;;;64475:20:0;;;;;;;;:::i;-1:-1:-1:-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;4341:157::-;;4451:2;4442:6;4437:3;4433:16;4429:25;4426:2;;;-1:-1;;4457:12;4889:341;;5013:4;5001:9;4996:3;4992:19;4988:30;4985:2;;;-1:-1;;5021:12;4985:2;5049:20;5013:4;5049:20;:::i;:::-;5846:13;;5123:86;;-1:-1;5040:29;4979:251;-1:-1;4979:251::o;5909:241::-;;6013:2;6001:9;5992:7;5988:23;5984:32;5981:2;;;-1:-1;;6019:12;5981:2;85:6;72:20;97:33;124:5;97:33;:::i;6157:263::-;;6272:2;6260:9;6251:7;6247:23;6243:32;6240:2;;;-1:-1;;6278:12;6240:2;226:6;220:13;238:33;265:5;238:33;:::i;6427:491::-;;;;6565:2;6553:9;6544:7;6540:23;6536:32;6533:2;;;-1:-1;;6571:12;6533:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;6623:63;-1:-1;6723:2;6762:22;;72:20;97:33;72:20;97:33;:::i;:::-;6731:63;-1:-1;6831:2;6870:22;;72:20;97:33;72:20;97:33;:::i;:::-;6839:63;;;;6527:391;;;;;:::o;6925:235::-;;7026:2;7014:9;7005:7;7001:23;6997:32;6994:2;;;-1:-1;;7032:12;6994:2;360:6;347:20;372:30;396:5;372:30;:::i;7167:257::-;;7279:2;7267:9;7258:7;7254:23;7250:32;7247:2;;;-1:-1;;7285:12;7247:2;495:6;489:13;507:30;531:5;507:30;:::i;8037:402::-;;;8176:2;8164:9;8155:7;8151:23;8147:32;8144:2;;;-1:-1;;8182:12;8144:2;840:6;827:20;852:51;897:5;852:51;:::i;:::-;8234:81;-1:-1;8352:2;8391:22;;72:20;97:33;72:20;97:33;:::i;:::-;8360:63;;;;8138:301;;;;;:::o;8446:563::-;;;;8620:2;8608:9;8599:7;8595:23;8591:32;8588:2;;;-1:-1;;8626:12;8588:2;840:6;827:20;852:51;897:5;852:51;:::i;:::-;8678:81;-1:-1;8796:2;8835:22;;72:20;97:33;72:20;97:33;:::i;:::-;8804:63;-1:-1;8904:2;8961:22;;1372:20;64948:1;64938:12;;64928:2;;-1:-1;;64954:12;9016:953;;;;;;9293:3;9281:9;9272:7;9268:23;9264:33;9261:2;;;-1:-1;;9300:12;9261:2;840:6;827:20;852:51;897:5;852:51;:::i;:::-;9352:81;-1:-1;9470:2;9518:22;;1536:20;65058:1;65048:12;;65038:2;;-1:-1;;65064:12;65038:2;9478:72;-1:-1;9605:79;9676:7;9587:2;9652:22;;9605:79;:::i;:::-;9595:89;;9739:79;9810:7;9721:2;9790:9;9786:22;9739:79;:::i;:::-;9729:89;;9874:79;9945:7;9855:3;9925:9;9921:22;9874:79;:::i;:::-;9864:89;;9255:714;;;;;;;;:::o;9976:454::-;;;10141:2;10129:9;10120:7;10116:23;10112:32;10109:2;;;-1:-1;;10147:12;10109:2;840:6;827:20;852:51;897:5;852:51;:::i;:::-;10199:81;-1:-1;10335:79;10406:7;10317:2;10382:22;;10335:79;:::i;:::-;10325:89;;10103:327;;;;;:::o;11049:316::-;;11190:3;11178:9;11169:7;11165:23;11161:33;11158:2;;;-1:-1;;11197:12;11158:2;1953:20;11190:3;1953:20;:::i;:::-;2055:90;2141:3;2117:22;2055:90;:::i;:::-;2037:16;2030:116;2242:84;2322:3;2209:2;2302:9;2298:22;2242:84;:::i;:::-;2209:2;2228:5;2224:16;2217:110;2429:84;2509:3;2396:2;2489:9;2485:22;2429:84;:::i;:::-;2396:2;2415:5;2411:16;2404:110;2640:90;2726:3;2607:2;2706:9;2702:22;2640:90;:::i;:::-;2607:2;2626:5;2622:16;2615:116;2859:84;2939:3;2825;2919:9;2915:22;2859:84;:::i;:::-;2825:3;2845:5;2841:16;2834:110;3022:3;3092:9;3088:22;5846:13;3022:3;3042:5;3038:16;3031:86;3185:3;3255:9;3251:22;5846:13;3185:3;3205:5;3201:16;3194:86;11249:100;;;;11152:213;;;;:::o;11372:332::-;;11521:3;11509:9;11500:7;11496:23;11492:33;11489:2;;;-1:-1;;11528:12;11489:2;3523:20;11521:3;3523:20;:::i;:::-;3633:84;3713:3;3689:22;3633:84;:::i;:::-;3615:16;3608:110;3815:84;3895:3;3782:2;3875:9;3871:22;3815:84;:::i;:::-;3782:2;3801:5;3797:16;3790:110;4004:90;4090:3;3971:2;4070:9;4066:22;4004:90;:::i;:::-;3971:2;3990:5;3986:16;3979:116;4197:84;4277:3;4164:2;4257:9;4253:22;4197:84;:::i;:::-;4164:2;4179:16;;4172:110;4183:5;11483:221;-1:-1;;;11483:221::o;11711:289::-;;11839:2;11827:9;11818:7;11814:23;11810:32;11807:2;;;-1:-1;;11845:12;11807:2;4683:20;11839:2;4683:20;:::i;:::-;5698;;4757:75;;-1:-1;4764:16;11801:199;-1:-1;11801:199::o;12007:311::-;;12146:2;12134:9;12125:7;12121:23;12117:32;12114:2;;;-1:-1;;12152:12;12114:2;12214:88;12294:7;12270:22;12214:88;:::i;12325:507::-;;;12511:2;12499:9;12490:7;12486:23;12482:32;12479:2;;;-1:-1;;12517:12;12479:2;12579:88;12659:7;12635:22;12579:88;:::i;:::-;12569:98;;12722:94;12808:7;12704:2;12788:9;12784:22;12722:94;:::i;13169:263::-;;13284:2;13272:9;13263:7;13259:23;13255:32;13252:2;;;-1:-1;;13290:12;13252:2;-1:-1;5846:13;;13246:186;-1:-1;13246:186::o;25855:1611::-;26072:16;26066:23;28506;15413:3;15406:36;26299:4;26292:5;26288:16;26282:23;27722;26299:4;26411:3;26407:14;15406:36;26509:4;26502:5;26498:16;26492:23;27722;26509:4;26621:3;26617:14;15406:36;26743:4;26736:5;26732:16;26726:23;28506;26743:4;26867:3;26863:14;15406:36;26990:4;26983:5;26979:16;26973:23;27722;26990:4;27102:3;27098:14;15406:36;27209:4;27202:5;27198:16;27192:23;27209:4;27273:3;27269:14;15406:36;27370:4;27363:5;27359:16;27353:23;27370:4;27434:3;27430:14;15406:36;25973:1493;;:::o;29267:271::-;;13979:5;59100:12;14090:52;14135:6;14130:3;14123:4;14116:5;14112:16;14090:52;:::i;:::-;14154:16;;;;;29401:137;-1:-1;;29401:137::o;29545:222::-;-1:-1;;;;;60817:54;;;;13659:37;;29672:2;29657:18;;29643:124::o;29774:458::-;-1:-1;;;;;60817:54;;;13659:37;;60817:54;;30128:2;30113:18;;13659:37;29964:2;29949:18;;60344:41;60379:5;60344:41;:::i;:::-;62698:33;30218:2;30207:9;30203:18;15278:57;29935:297;;;;;;:::o;30239:444::-;-1:-1;;;;;60817:54;;;13659:37;;60817:54;;;;30586:2;30571:18;;13659:37;30669:2;30654:18;;15406:36;;;;30422:2;30407:18;;30393:290::o;30690:429::-;-1:-1;;;;;60817:54;;;;13659:37;;27722:23;31105:2;31090:18;;15406:36;30893:2;30878:18;;30864:255::o;31126:333::-;-1:-1;;;;;60817:54;;;;13659:37;;31445:2;31430:18;;15406:36;31281:2;31266:18;;31252:207::o;31466:210::-;59759:13;;59752:21;13773:34;;31587:2;31572:18;;31558:118::o;31948:576::-;-1:-1;;;;;60817:54;;;14271:68;;60817:54;;;;32379:2;32364:18;;13659:37;27722:23;;32510:2;32495:18;;15406:36;32197:2;32182:18;;32168:356::o;32531:618::-;-1:-1;;;;;60817:54;;14271:68;;32800:3;32785:19;;32915:124;33035:2;33020:18;;33011:6;32915:124;:::i;:::-;63805:1;63798:5;63795:12;63785:2;;63811:9;63785:2;62558:42;33134:3;33123:9;33119:19;15122:66;32771:378;;;;;;:::o;33156:706::-;-1:-1;;;;;60817:54;;14271:68;;33469:3;33454:19;;33584:124;33704:2;33689:18;;33680:6;33584:124;:::i;:::-;28512:16;28506:23;33847:3;33836:9;33832:19;15406:36;33440:422;;;;;;:::o;33869:586::-;-1:-1;;;;;60817:54;;14271:68;;34122:3;34107:19;;34237:124;34357:2;34342:18;;34333:6;34237:124;:::i;36257:648::-;36542:2;36527:18;;60344:41;60379:5;60344:41;:::i;:::-;14967:56;;;27722:23;;36760:2;36745:18;;15406:36;27722:23;36891:2;36876:18;;;15406:36;36513:392;:::o;36912:748::-;37219:3;37204:19;;60344:41;60379:5;60344:41;:::i;:::-;14967:56;;;27722:23;;37438:2;37423:18;;15406:36;27722:23;;37569:2;37554:18;;15406:36;59759:13;59752:21;37646:2;37631:18;;;13773:34;37190:470;:::o;37667:436::-;15406:36;;;38006:2;37991:18;;15406:36;;;;38089:2;38074:18;;15406:36;37846:2;37831:18;;37817:286::o;39034:1504::-;15649:57;;;39668:2;39653:18;;15406:36;;;;39749:2;39734:18;;15406:36;;;;39840:2;39825:18;;15649:57;;;;39930:3;39915:19;;15649:57;;;;40012:3;39997:19;;15406:36;;;;40103:3;40088:19;;15649:57;40187:3;40172:19;;15406:36;40271:3;40256:19;;15406:36;40355:3;40340:19;;15406:36;40438:3;40423:19;;15406:36;40523:3;40508:19;;15406:36;39495:3;39480:19;;39466:1072::o;42038:310::-;;42185:2;42206:17;42199:47;16012:5;59100:12;59539:6;42185:2;42174:9;42170:18;59527:19;16106:52;16151:6;59567:14;42174:9;59567:14;42185:2;16132:5;16128:16;16106:52;:::i;:::-;63591:7;63575:14;-1:-1;;63571:28;16170:39;;;;59567:14;16170:39;;42156:192;-1:-1;;42156:192::o;42355:416::-;42555:2;42569:47;;;16446:2;42540:18;;;59527:19;-1:-1;;;59567:14;;;16462:44;16525:12;;;42526:245::o;42778:416::-;42978:2;42992:47;;;16776:2;42963:18;;;59527:19;-1:-1;;;59567:14;;;16792:40;16851:12;;;42949:245::o;43201:416::-;43401:2;43415:47;;;17102:2;43386:18;;;59527:19;-1:-1;;;59567:14;;;17118:41;17178:12;;;43372:245::o;43624:416::-;43824:2;43838:47;;;17429:2;43809:18;;;59527:19;-1:-1;;;59567:14;;;17445:43;17507:12;;;43795:245::o;44047:416::-;44247:2;44261:47;;;17758:2;44232:18;;;59527:19;17794:34;59567:14;;;17774:55;-1:-1;;;17849:12;;;17842:30;17891:12;;;44218:245::o;44470:416::-;44670:2;44684:47;;;18142:2;44655:18;;;59527:19;18178:29;59567:14;;;18158:50;18227:12;;;44641:245::o;44893:416::-;45093:2;45107:47;;;18478:2;45078:18;;;59527:19;18514:34;59567:14;;;18494:55;-1:-1;;;18569:12;;;18562:25;18606:12;;;45064:245::o;45316:416::-;45516:2;45530:47;;;18857:2;45501:18;;;59527:19;18893:34;59567:14;;;18873:55;-1:-1;;;18948:12;;;18941:30;18990:12;;;45487:245::o;45739:416::-;45939:2;45953:47;;;19241:2;45924:18;;;59527:19;19277:25;59567:14;;;19257:46;19322:12;;;45910:245::o;46162:416::-;46362:2;46376:47;;;19573:2;46347:18;;;59527:19;19609:32;59567:14;;;19589:53;19661:12;;;46333:245::o;46585:416::-;46785:2;46799:47;;;19912:2;46770:18;;;59527:19;-1:-1;;;59567:14;;;19928:39;19986:12;;;46756:245::o;47008:416::-;47208:2;47222:47;;;20237:2;47193:18;;;59527:19;20273:28;59567:14;;;20253:49;20321:12;;;47179:245::o;47431:416::-;47631:2;47645:47;;;20572:2;47616:18;;;59527:19;20608:34;59567:14;;;20588:55;-1:-1;;;20663:12;;;20656:38;20713:12;;;47602:245::o;47854:416::-;48054:2;48068:47;;;20964:2;48039:18;;;59527:19;21000:34;59567:14;;;20980:55;-1:-1;;;21055:12;;;21048:25;21092:12;;;48025:245::o;48277:416::-;48477:2;48491:47;;;21343:2;48462:18;;;59527:19;21379:34;59567:14;;;21359:55;-1:-1;;;21434:12;;;21427:25;21471:12;;;48448:245::o;48700:416::-;48900:2;48914:47;;;21722:2;48885:18;;;59527:19;-1:-1;;;59567:14;;;21738:33;21790:12;;;48871:245::o;49123:416::-;49323:2;49337:47;;;49308:18;;;59527:19;22077:34;59567:14;;;22057:55;22131:12;;;49294:245::o;49546:416::-;49746:2;49760:47;;;22382:2;49731:18;;;59527:19;22418:34;59567:14;;;22398:55;-1:-1;;;22473:12;;;22466:31;22516:12;;;49717:245::o;49969:416::-;50169:2;50183:47;;;22767:2;50154:18;;;59527:19;22803:31;59567:14;;;22783:52;22854:12;;;50140:245::o;50392:416::-;50592:2;50606:47;;;23105:2;50577:18;;;59527:19;23141:34;59567:14;;;23121:55;-1:-1;;;23196:12;;;23189:34;23242:12;;;50563:245::o;50815:416::-;51015:2;51029:47;;;23493:2;51000:18;;;59527:19;23529:31;59567:14;;;23509:52;23580:12;;;50986:245::o;51238:416::-;51438:2;51452:47;;;23831:2;51423:18;;;59527:19;23867:31;59567:14;;;23847:52;23918:12;;;51409:245::o;51661:416::-;51861:2;51875:47;;;24169:2;51846:18;;;59527:19;24205:34;59567:14;;;24185:55;-1:-1;;;24260:12;;;24253:28;24300:12;;;51832:245::o;52084:416::-;52284:2;52298:47;;;24551:2;52269:18;;;59527:19;24587:34;59567:14;;;24567:55;-1:-1;;;24642:12;;;24635:34;24688:12;;;52255:245::o;52507:416::-;52707:2;52721:47;;;52692:18;;;59527:19;24975:34;59567:14;;;24955:55;25029:12;;;52678:245::o;52930:416::-;53130:2;53144:47;;;25280:2;53115:18;;;59527:19;25316:33;59567:14;;;25296:54;25369:12;;;53101:245::o;53353:416::-;53553:2;53567:47;;;25620:2;53538:18;;;59527:19;25656:34;59567:14;;;25636:55;-1:-1;;;25711:12;;;25704:35;25758:12;;;53524:245::o;53776:327::-;53955:3;53940:19;;53970:123;53944:9;54066:6;53970:123;:::i;54110:318::-;27722:23;;15406:36;;54285:2;54270:18;;54256:172::o;54435:549::-;27722:23;;15406:36;;28506:23;54970:2;54955:18;;15406:36;54698:2;54683:18;;54669:315::o;55920:222::-;15406:36;;;56047:2;56032:18;;56018:124::o;58059:684::-;15406:36;;;58471:2;58456:18;;15406:36;;;;58554:2;58539:18;;15406:36;;;;-1:-1;;;;;60817:54;58645:2;58630:18;;13518:58;58728:3;58713:19;;15406:36;58306:3;58291:19;;58277:466::o;58750:256::-;58812:2;58806:9;58838:17;;;58913:18;58898:34;;58934:22;;;58895:62;58892:2;;;58970:1;;58960:12;58892:2;58812;58979:22;58790:216;;-1:-1;58790:216::o;63231:268::-;63296:1;63303:101;63317:6;63314:1;63311:13;63303:101;;;63384:11;;;63378:18;63365:11;;;63358:39;63339:2;63332:10;63303:101;;;63419:6;63416:1;63413:13;63410:2;;;-1:-1;;63296:1;63466:16;;63459:27;63280:219::o;63612:99::-;63689:1;63682:5;63679:12;63669:2;;63695:9;63941:117;-1:-1;;;;;60817:54;;64000:35;;63990:2;;64049:1;;64039:12;64065:111;64146:5;59759:13;59752:21;64124:5;64121:32;64111:2;;64167:1;;64157:12

Swarm Source

ipfs://a94c1db5072ba19a72807887283cced43b5cd19dfc2cce2e743d3784bfe7e909
Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading