ETH Price: $3,286.35 (-1.90%)

Contract

0x7DB84492cfD27e47c39499D852DECC2a01476a75
 

Overview

ETH Balance

0.06 ETH

Eth Value

$197.18 (@ $3,286.35/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Exchange Bond To...122791292021-04-20 20:04:551371 days ago1618949095IN
0x7DB84492...a01476a75
0 ETH0.04685064241
Exchange Erc20To...122680062021-04-19 3:06:001373 days ago1618801560IN
0x7DB84492...a01476a75
0 ETH0.02658478127
Exchange Erc20To...122675862021-04-19 1:24:271373 days ago1618795467IN
0x7DB84492...a01476a75
0 ETH0.0198743294.00000145
Exchange Erc20To...122668942021-04-18 22:48:201373 days ago1618786100IN
0x7DB84492...a01476a75
0 ETH0.02240141107
Exchange Erc20To...122630352021-04-18 8:31:091374 days ago1618734669IN
0x7DB84492...a01476a75
0 ETH0.03106715137.2
Exchange Bond To...122620692021-04-18 4:50:331374 days ago1618721433IN
0x7DB84492...a01476a75
0 ETH0.04480881214
Exchange Erc20To...122618052021-04-18 3:52:011374 days ago1618717921IN
0x7DB84492...a01476a75
0 ETH0.09280495443
Exchange Bond To...122608352021-04-18 0:27:311374 days ago1618705651IN
0x7DB84492...a01476a75
0 ETH0.0248846128
Exchange Erc20To...122582702021-04-17 14:49:301374 days ago1618670970IN
0x7DB84492...a01476a75
0 ETH0.03645861161
Exchange Bond To...122567802021-04-17 9:26:171375 days ago1618651577IN
0x7DB84492...a01476a75
0 ETH0.03658794173
Exchange Erc20To...122548122021-04-17 2:02:391375 days ago1618624959IN
0x7DB84492...a01476a75
0 ETH0.02909673139
Exchange Erc20To...122514582021-04-16 13:52:331375 days ago1618581153IN
0x7DB84492...a01476a75
0 ETH0.0583083300
Exchange Bond To...122508142021-04-16 11:23:561375 days ago1618572236IN
0x7DB84492...a01476a75
0 ETH0.01975617124
Exchange Bond To...122508082021-04-16 11:21:351375 days ago1618572095IN
0x7DB84492...a01476a75
0 ETH0.02235726115
Exchange Bond To...122495262021-04-16 6:44:071376 days ago1618555447IN
0x7DB84492...a01476a75
0 ETH0.03643333174
Exchange Bond To...122432292021-04-15 7:10:391377 days ago1618470639IN
0x7DB84492...a01476a75
0 ETH0.0152784174
Exchange Bond To...122408762021-04-14 22:23:091377 days ago1618438989IN
0x7DB84492...a01476a75
0 ETH0.02268536115
Exchange Erc20To...122382852021-04-14 12:48:291377 days ago1618404509IN
0x7DB84492...a01476a75
0 ETH0.02635566116
Exchange Bond To...122358682021-04-14 3:46:191378 days ago1618371979IN
0x7DB84492...a01476a75
0 ETH0.02489071130
Exchange Erc20To...122221002021-04-12 0:53:261380 days ago1618188806IN
0x7DB84492...a01476a75
0 ETH0.0154894575
Exchange Erc20To...122188912021-04-11 13:29:081380 days ago1618147748IN
0x7DB84492...a01476a75
0 ETH0.0142519569
Exchange Erc20To...122187762021-04-11 13:04:111380 days ago1618146251IN
0x7DB84492...a01476a75
0 ETH0.0179698587
Deposit Eth122170142021-04-11 6:31:431381 days ago1618122703IN
0x7DB84492...a01476a75
0.01 ETH0.0018491268
Deposit Eth122170022021-04-11 6:28:241381 days ago1618122504IN
0x7DB84492...a01476a75
0.05 ETH0.0028691268
Withdraw Eth122169682021-04-11 6:20:481381 days ago1618122048IN
0x7DB84492...a01476a75
0 ETH0.001657968
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
122169682021-04-11 6:20:481381 days ago1618122048
0x7DB84492...a01476a75
0.02 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
GeneralizedDotc

Compiler Version
v0.6.6+commit.6c089d02

Optimization Enabled:
Yes with 20000 runs

Other Settings:
constantinople EvmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2021-03-12
*/

pragma solidity 0.6.6;

// File: @openzeppelin/contracts/GSN/Context.sol



/*
 * @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.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }

    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;
    }
}

// File: @openzeppelin/contracts/token/ERC20/IERC20.sol



/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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: @openzeppelin/contracts/math/SafeMath.sol



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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        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: @openzeppelin/contracts/utils/Address.sol



/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @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");
    }
}

// File: @openzeppelin/contracts/token/ERC20/ERC20.sol







/**
 * @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 {ERC20MinterPauser}.
 *
 * 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 ERC20 is Context, IERC20 {
    using SafeMath for uint256;
    using Address for address;

    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.
     */
    constructor (string memory name, string memory symbol) public {
        _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 is 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 { }
}

// File: contracts/oracle/LatestPriceOracleInterface.sol

pragma solidity 0.6.6;


/**
 * @dev Interface of the price oracle.
 */
interface LatestPriceOracleInterface {
    /**
     * @dev Returns `true`if oracle is working.
     */
    function isWorking() external returns (bool);

    /**
     * @dev Returns the last updated price. Decimals is 8.
     **/
    function latestPrice() external returns (uint256);

    /**
     * @dev Returns the timestamp of the last updated price.
     */
    function latestTimestamp() external returns (uint256);
}

// File: contracts/oracle/PriceOracleInterface.sol

pragma solidity 0.6.6;



/**
 * @dev Interface of the price oracle.
 */
interface PriceOracleInterface is LatestPriceOracleInterface {
    /**
     * @dev Returns the latest id. The id start from 1 and increments by 1.
     */
    function latestId() external returns (uint256);

    /**
     * @dev Returns the historical price specified by `id`. Decimals is 8.
     */
    function getPrice(uint256 id) external returns (uint256);

    /**
     * @dev Returns the timestamp of historical price specified by `id`.
     */
    function getTimestamp(uint256 id) external returns (uint256);
}

// File: contracts/oracle/OracleInterface.sol

pragma solidity 0.6.6;


// Oracle referenced by OracleProxy must implement this interface.
interface OracleInterface is PriceOracleInterface {
    function getVolatility() external returns (uint256);

    function lastCalculatedVolatility() external view returns (uint256);
}

// File: contracts/oracle/VolatilityOracleInterface.sol

pragma solidity 0.6.6;

interface VolatilityOracleInterface {
    function getVolatility(uint64 untilMaturity)
        external
        view
        returns (uint64 volatilityE8);
}

// File: contracts/util/TransferETHInterface.sol

pragma solidity 0.6.6;


interface TransferETHInterface {
    receive() external payable;

    event LogTransferETH(address indexed from, address indexed to, uint256 value);
}

// File: contracts/bondToken/BondTokenInterface.sol

pragma solidity 0.6.6;




interface BondTokenInterface is IERC20 {
    event LogExpire(uint128 rateNumerator, uint128 rateDenominator, bool firstTime);

    function mint(address account, uint256 amount) external returns (bool success);

    function expire(uint128 rateNumerator, uint128 rateDenominator)
        external
        returns (bool firstTime);

    function simpleBurn(address account, uint256 amount) external returns (bool success);

    function burn(uint256 amount) external returns (bool success);

    function burnAll() external returns (uint256 amount);

    function getRate() external view returns (uint128 rateNumerator, uint128 rateDenominator);
}

// File: contracts/bondMaker/BondMakerInterface.sol

pragma solidity 0.6.6;



interface BondMakerInterface {
    event LogNewBond(
        bytes32 indexed bondID,
        address indexed bondTokenAddress,
        uint256 indexed maturity,
        bytes32 fnMapID
    );

    event LogNewBondGroup(
        uint256 indexed bondGroupID,
        uint256 indexed maturity,
        uint64 indexed sbtStrikePrice,
        bytes32[] bondIDs
    );

    event LogIssueNewBonds(
        uint256 indexed bondGroupID,
        address indexed issuer,
        uint256 amount
    );

    event LogReverseBondGroupToCollateral(
        uint256 indexed bondGroupID,
        address indexed owner,
        uint256 amount
    );

    event LogExchangeEquivalentBonds(
        address indexed owner,
        uint256 indexed inputBondGroupID,
        uint256 indexed outputBondGroupID,
        uint256 amount
    );

    event LogLiquidateBond(
        bytes32 indexed bondID,
        uint128 rateNumerator,
        uint128 rateDenominator
    );

    function registerNewBond(uint256 maturity, bytes calldata fnMap)
        external
        returns (
            bytes32 bondID,
            address bondTokenAddress,
            bytes32 fnMapID
        );

    function registerNewBondGroup(
        bytes32[] calldata bondIDList,
        uint256 maturity
    ) external returns (uint256 bondGroupID);

    function reverseBondGroupToCollateral(uint256 bondGroupID, uint256 amount)
        external
        returns (bool success);

    function exchangeEquivalentBonds(
        uint256 inputBondGroupID,
        uint256 outputBondGroupID,
        uint256 amount,
        bytes32[] calldata exceptionBonds
    ) external returns (bool);

    function liquidateBond(uint256 bondGroupID, uint256 oracleHintID)
        external
        returns (uint256 totalPayment);

    function collateralAddress() external view returns (address);

    function oracleAddress() external view returns (PriceOracleInterface);

    function feeTaker() external view returns (address);

    function decimalsOfBond() external view returns (uint8);

    function decimalsOfOraclePrice() external view returns (uint8);

    function maturityScale() external view returns (uint256);

    function nextBondGroupID() external view returns (uint256);

    function getBond(bytes32 bondID)
        external
        view
        returns (
            address bondAddress,
            uint256 maturity,
            uint64 solidStrikePrice,
            bytes32 fnMapID
        );

    function getFnMap(bytes32 fnMapID)
        external
        view
        returns (bytes memory fnMap);

    function getBondGroup(uint256 bondGroupID)
        external
        view
        returns (bytes32[] memory bondIDs, uint256 maturity);

    function generateFnMapID(bytes calldata fnMap)
        external
        view
        returns (bytes32 fnMapID);

    function generateBondID(uint256 maturity, bytes calldata fnMap)
        external
        view
        returns (bytes32 bondID);
}

// File: contracts/bondPricer/Enums.sol

pragma solidity 0.6.6;

/**
    Pure SBT:
        ___________
       /
      /
     /
    /

    LBT Shape:
              /
             /
            /
           /
    ______/

    SBT Shape:
              ______
             /
            /
    _______/

    Triangle:
              /\
             /  \
            /    \
    _______/      \________
 */
enum BondType {NONE, PURE_SBT, SBT_SHAPE, LBT_SHAPE, TRIANGLE}

// File: contracts/bondPricer/BondPricerInterface.sol

pragma solidity 0.6.6;


interface BondPricerInterface {
    /**
     * @notice Calculate bond price and leverage by black-scholes formula.
     * @param bondType type of target bond.
     * @param points coodinates of polyline which is needed for price calculation
     * @param spotPrice is a oracle price.
     * @param volatilityE8 is a oracle volatility.
     * @param untilMaturity Remaining period of target bond in second
     **/
    function calcPriceAndLeverage(
        BondType bondType,
        uint256[] calldata points,
        int256 spotPrice,
        int256 volatilityE8,
        int256 untilMaturity
    ) external view returns (uint256 price, uint256 leverageE8);
}

// File: @openzeppelin/contracts/math/SignedSafeMath.sol



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

    /**
     * @dev Multiplies two signed integers, reverts on 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 Integer division of two signed integers truncating the quotient, reverts on division by 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 Subtracts two signed integers, reverts on 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 Adds two signed integers, reverts on 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: @openzeppelin/contracts/utils/SafeCast.sol




/**
 * @dev Wrappers over Solidity's uintXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such 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.
 *
 * Can be combined with {SafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and then downcasting.
 */
library SafeCast {

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        require(value < 2**255, "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

// File: contracts/math/UseSafeMath.sol

pragma solidity 0.6.6;




/**
 * @notice ((a - 1) / b) + 1 = (a + b -1) / b
 * for example a.add(10**18 -1).div(10**18) = a.sub(1).div(10**18) + 1
 */

library SafeMathDivRoundUp {
    using SafeMath for uint256;

    function divRoundUp(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }
        require(b > 0, errorMessage);
        return ((a - 1) / b) + 1;
    }

    function divRoundUp(uint256 a, uint256 b) internal pure returns (uint256) {
        return divRoundUp(a, b, "SafeMathDivRoundUp: modulo by zero");
    }
}

/**
 * @title UseSafeMath
 * @dev One can use SafeMath for not only uint256 but also uin64 or uint16,
 * and also can use SafeCast for uint256.
 * For example:
 *   uint64 a = 1;
 *   uint64 b = 2;
 *   a = a.add(b).toUint64() // `a` become 3 as uint64
 * In addition, one can use SignedSafeMath and SafeCast.toUint256(int256) for int256.
 * In the case of the operation to the uint64 value, one needs to cast the value into int256 in
 * advance to use `sub` as SignedSafeMath.sub not SafeMath.sub.
 * For example:
 *   int256 a = 1;
 *   uint64 b = 2;
 *   int256 c = 3;
 *   a = a.add(int256(b).sub(c)); // `a` becomes 0 as int256
 *   b = a.toUint256().toUint64(); // `b` becomes 0 as uint64
 */
abstract contract UseSafeMath {
    using SafeMath for uint256;
    using SafeMathDivRoundUp for uint256;
    using SafeMath for uint64;
    using SafeMathDivRoundUp for uint64;
    using SafeMath for uint16;
    using SignedSafeMath for int256;
    using SafeCast for uint256;
    using SafeCast for int256;
}

// File: contracts/util/Polyline.sol

pragma solidity 0.6.6;


contract Polyline is UseSafeMath {
    struct Point {
        uint64 x; // Value of the x-axis of the x-y plane
        uint64 y; // Value of the y-axis of the x-y plane
    }

    struct LineSegment {
        Point left; // The left end of the line definition range
        Point right; // The right end of the line definition range
    }

    /**
     * @notice Return the value of y corresponding to x on the given line. line in the form of
     * a rational number (numerator / denominator).
     * If you treat a line as a line segment instead of a line, you should run
     * includesDomain(line, x) to check whether x is included in the line's domain or not.
     * @dev To guarantee accuracy, the bit length of the denominator must be greater than or equal
     * to the bit length of x, and the bit length of the numerator must be greater than or equal
     * to the sum of the bit lengths of x and y.
     */
    function _mapXtoY(LineSegment memory line, uint64 x)
        internal
        pure
        returns (uint128 numerator, uint64 denominator)
    {
        int256 x1 = int256(line.left.x);
        int256 y1 = int256(line.left.y);
        int256 x2 = int256(line.right.x);
        int256 y2 = int256(line.right.y);

        require(x2 > x1, "must be left.x < right.x");

        denominator = uint64(x2 - x1);

        // Calculate y = ((x2 - x) * y1 + (x - x1) * y2) / (x2 - x1)
        // in the form of a fraction (numerator / denominator).
        int256 n = (x - x1) * y2 + (x2 - x) * y1;

        require(n >= 0, "underflow n");
        require(n < 2**128, "system error: overflow n");
        numerator = uint128(n);
    }

    /**
     * @notice Checking that a line segment is a valid format.
     */
    function assertLineSegment(LineSegment memory segment) internal pure {
        uint64 x1 = segment.left.x;
        uint64 x2 = segment.right.x;
        require(x1 < x2, "must be left.x < right.x");
    }

    /**
     * @notice Checking that a polyline is a valid format.
     */
    function assertPolyline(LineSegment[] memory polyline) internal pure {
        uint256 numOfSegment = polyline.length;
        require(numOfSegment != 0, "polyline must not be empty array");

        LineSegment memory leftSegment = polyline[0]; // mutable
        int256 gradientNumerator = int256(leftSegment.right.y) -
            int256(leftSegment.left.y); // mutable
        int256 gradientDenominator = int256(leftSegment.right.x) -
            int256(leftSegment.left.x); // mutable

        // The beginning of the first line segment's domain is 0.
        require(
            leftSegment.left.x == uint64(0),
            "the x coordinate of left end of the first segment must be 0"
        );
        // The value of y when x is 0 is 0.
        require(
            leftSegment.left.y == uint64(0),
            "the y coordinate of left end of the first segment must be 0"
        );

        // Making sure that the first line segment is a correct format.
        assertLineSegment(leftSegment);

        // The end of the domain of a segment and the beginning of the domain of the adjacent
        // segment must coincide.
        LineSegment memory rightSegment; // mutable
        for (uint256 i = 1; i < numOfSegment; i++) {
            rightSegment = polyline[i];

            // Make sure that the i-th line segment is a correct format.
            assertLineSegment(rightSegment);

            // Checking that the x-coordinates are same.
            require(
                leftSegment.right.x == rightSegment.left.x,
                "given polyline has an undefined domain."
            );

            // Checking that the y-coordinates are same.
            require(
                leftSegment.right.y == rightSegment.left.y,
                "given polyline is not a continuous function"
            );

            int256 nextGradientNumerator = int256(rightSegment.right.y) -
                int256(rightSegment.left.y);
            int256 nextGradientDenominator = int256(rightSegment.right.x) -
                int256(rightSegment.left.x);
            require(
                nextGradientNumerator * gradientDenominator !=
                    nextGradientDenominator * gradientNumerator,
                "the sequential segments must not have the same gradient"
            );

            leftSegment = rightSegment;
            gradientNumerator = nextGradientNumerator;
            gradientDenominator = nextGradientDenominator;
        }

        // rightSegment is lastSegment

        // About the last line segment.
        require(
            gradientNumerator >= 0 && gradientNumerator <= gradientDenominator,
            "the gradient of last line segment must be non-negative, and equal to or less than 1"
        );
    }

    /**
     * @notice zip a LineSegment structure to uint256
     * @return zip uint256( 0 ... 0 | x1 | y1 | x2 | y2 )
     */
    function zipLineSegment(LineSegment memory segment)
        internal
        pure
        returns (uint256 zip)
    {
        uint256 x1U256 = uint256(segment.left.x) << (64 + 64 + 64); // uint64
        uint256 y1U256 = uint256(segment.left.y) << (64 + 64); // uint64
        uint256 x2U256 = uint256(segment.right.x) << 64; // uint64
        uint256 y2U256 = uint256(segment.right.y); // uint64
        zip = x1U256 | y1U256 | x2U256 | y2U256;
    }

    /**
     * @notice unzip uint256 to a LineSegment structure
     */
    function unzipLineSegment(uint256 zip)
        internal
        pure
        returns (LineSegment memory)
    {
        uint64 x1 = uint64(zip >> (64 + 64 + 64));
        uint64 y1 = uint64(zip >> (64 + 64));
        uint64 x2 = uint64(zip >> 64);
        uint64 y2 = uint64(zip);
        return
            LineSegment({
                left: Point({x: x1, y: y1}),
                right: Point({x: x2, y: y2})
            });
    }

    /**
     * @notice unzip the fnMap to uint256[].
     */
    function decodePolyline(bytes memory fnMap)
        internal
        pure
        returns (uint256[] memory)
    {
        return abi.decode(fnMap, (uint256[]));
    }
}

// File: contracts/bondPricer/DetectBondShape.sol

pragma solidity 0.6.6;




contract DetectBondShape is Polyline {
    /**
     * @notice Detect bond type by polyline of bond.
     * @param bondID bondID of target bond token
     * @param submittedType if this parameter is BondType.NONE, this function checks up all bond types. Otherwise this function checks up only one bond type.
     * @param success whether bond detection succeeded or notice
     * @param points coodinates of polyline which is needed for price calculation
     **/
    function getBondTypeByID(
        BondMakerInterface bondMaker,
        bytes32 bondID,
        BondType submittedType
    )
        public
        view
        returns (
            bool success,
            BondType,
            uint256[] memory points
        )
    {
        (, , , bytes32 fnMapID) = bondMaker.getBond(bondID);
        bytes memory fnMap = bondMaker.getFnMap(fnMapID);
        return _getBondType(fnMap, submittedType);
    }

    /**
     * @notice Detect bond type by polyline of bond.
     * @param fnMap Function mapping of target bond token
     * @param submittedType If this parameter is BondType.NONE, this function checks up all bond types. Otherwise this function checks up only one bond type.
     * @param success Whether bond detection succeeded or not
     * @param points Coodinates of polyline which are needed for price calculation
     **/
    function getBondType(bytes calldata fnMap, BondType submittedType)
        external
        pure
        returns (
            bool success,
            BondType,
            uint256[] memory points
        )
    {
        uint256[] memory polyline = decodePolyline(fnMap);
        LineSegment[] memory segments = new LineSegment[](polyline.length);
        for (uint256 i = 0; i < polyline.length; i++) {
            segments[i] = unzipLineSegment(polyline[i]);
        }
        assertPolyline(segments);

        return _getBondType(fnMap, submittedType);
    }

    function _getBondType(bytes memory fnMap, BondType submittedType)
        internal
        pure
        returns (
            bool success,
            BondType,
            uint256[] memory points
        )
    {
        if (submittedType == BondType.NONE) {
            (success, points) = _isSBT(fnMap);
            if (success) {
                return (success, BondType.PURE_SBT, points);
            }

            (success, points) = _isSBTShape(fnMap);
            if (success) {
                return (success, BondType.SBT_SHAPE, points);
            }

            (success, points) = _isLBTShape(fnMap);
            if (success) {
                return (success, BondType.LBT_SHAPE, points);
            }

            (success, points) = _isTriangle(fnMap);
            if (success) {
                return (success, BondType.TRIANGLE, points);
            }

            return (false, BondType.NONE, points);
        } else if (submittedType == BondType.PURE_SBT) {
            (success, points) = _isSBT(fnMap);
            if (success) {
                return (success, BondType.PURE_SBT, points);
            }
        } else if (submittedType == BondType.SBT_SHAPE) {
            (success, points) = _isSBTShape(fnMap);
            if (success) {
                return (success, BondType.SBT_SHAPE, points);
            }
        } else if (submittedType == BondType.LBT_SHAPE) {
            (success, points) = _isLBTShape(fnMap);
            if (success) {
                return (success, BondType.LBT_SHAPE, points);
            }
        } else if (submittedType == BondType.TRIANGLE) {
            (success, points) = _isTriangle(fnMap);
            if (success) {
                return (success, BondType.TRIANGLE, points);
            }
        }

        return (false, BondType.NONE, points);
    }

    function _isLBTShape(bytes memory fnMap)
        internal
        pure
        returns (bool isOk, uint256[] memory points)
    {
        uint256[] memory zippedLines = decodePolyline(fnMap);
        if (zippedLines.length != 2) {
            return (false, points);
        }
        LineSegment memory secondLine = unzipLineSegment(zippedLines[1]);
        if (
            secondLine.left.x != 0 &&
            secondLine.left.y == 0 &&
            secondLine.right.x > secondLine.left.x &&
            secondLine.right.y != 0
        ) {
            uint256[] memory _lines = new uint256[](3);
            _lines[0] = secondLine.left.x;
            _lines[1] = secondLine.right.x;
            _lines[2] = secondLine.right.y;
            return (true, _lines);
        }
        return (false, points);
    }

    function _isTriangle(bytes memory fnMap)
        internal
        pure
        returns (bool isOk, uint256[] memory points)
    {
        uint256[] memory zippedLines = decodePolyline(fnMap);
        if (zippedLines.length != 4) {
            return (false, points);
        }
        LineSegment memory secondLine = unzipLineSegment(zippedLines[1]);
        LineSegment memory thirdLine = unzipLineSegment(zippedLines[2]);
        LineSegment memory forthLine = unzipLineSegment(zippedLines[3]);
        if (
            secondLine.left.x != 0 &&
            secondLine.left.y == 0 &&
            secondLine.right.x > secondLine.left.x &&
            secondLine.right.y != 0 &&
            thirdLine.right.x > secondLine.right.x &&
            thirdLine.right.y == 0 &&
            forthLine.right.x > thirdLine.right.x &&
            forthLine.right.y == 0
        ) {
            uint256[] memory _lines = new uint256[](4);
            _lines[0] = secondLine.left.x;
            _lines[1] = secondLine.right.x;
            _lines[2] = secondLine.right.y;
            _lines[3] = thirdLine.right.x;
            return (true, _lines);
        }
        return (false, points);
    }

    function _isSBTShape(bytes memory fnMap)
        internal
        pure
        returns (bool isOk, uint256[] memory points)
    {
        uint256[] memory zippedLines = decodePolyline(fnMap);
        if (zippedLines.length != 3) {
            return (false, points);
        }
        LineSegment memory secondLine = unzipLineSegment(zippedLines[1]);
        LineSegment memory thirdLine = unzipLineSegment(zippedLines[2]);
        if (
            secondLine.left.x != 0 &&
            secondLine.left.y == 0 &&
            secondLine.right.x > secondLine.left.x &&
            secondLine.right.y != 0 &&
            thirdLine.right.x > secondLine.right.x &&
            thirdLine.right.y == secondLine.right.y
        ) {
            uint256[] memory _lines = new uint256[](3);
            _lines[0] = secondLine.left.x;
            _lines[1] = secondLine.right.x;
            _lines[2] = secondLine.right.y;
            return (true, _lines);
        }
        return (false, points);
    }

    function _isSBT(bytes memory fnMap)
        internal
        pure
        returns (bool isOk, uint256[] memory points)
    {
        uint256[] memory zippedLines = decodePolyline(fnMap);
        if (zippedLines.length != 2) {
            return (false, points);
        }
        LineSegment memory secondLine = unzipLineSegment(zippedLines[1]);

        if (
            secondLine.left.x != 0 &&
            secondLine.left.y == secondLine.left.x &&
            secondLine.right.x > secondLine.left.x &&
            secondLine.right.y == secondLine.left.y
        ) {
            uint256[] memory _lines = new uint256[](1);
            _lines[0] = secondLine.left.x;
            return (true, _lines);
        }

        return (false, points);
    }
}

// File: contracts/util/Time.sol

pragma solidity 0.6.6;

abstract contract Time {
    function _getBlockTimestampSec() internal view returns (uint256 unixtimesec) {
        unixtimesec = block.timestamp; // solhint-disable-line not-rely-on-time
    }
}

// File: contracts/generalizedDotc/BondExchange.sol

pragma solidity 0.6.6;









abstract contract BondExchange is UseSafeMath, Time {
    uint256 internal constant MIN_EXCHANGE_RATE_E8 = 0.000001 * 10**8;
    uint256 internal constant MAX_EXCHANGE_RATE_E8 = 1000000 * 10**8;

    int256 internal constant MAX_SPREAD_E8 = 10**8; // 100%

    /**
     * @dev the sum of decimalsOfBond of the bondMaker.
     * This value is constant by the restriction of `_assertBondMakerDecimals`.
     */
    uint8 internal constant DECIMALS_OF_BOND = 8;

    /**
     * @dev the sum of decimalsOfOraclePrice of the bondMaker.
     * This value is constant by the restriction of `_assertBondMakerDecimals`.
     */
    uint8 internal constant DECIMALS_OF_ORACLE_PRICE = 8;

    BondMakerInterface internal immutable _bondMakerContract;
    PriceOracleInterface internal immutable _priceOracleContract;
    VolatilityOracleInterface internal immutable _volatilityOracleContract;
    LatestPriceOracleInterface internal immutable _volumeCalculator;
    DetectBondShape internal immutable _bondShapeDetector;

    /**
     * @param bondMakerAddress is a bond maker contract.
     * @param volumeCalculatorAddress is a contract to convert the unit of a strike price to USD.
     */
    constructor(
        BondMakerInterface bondMakerAddress,
        VolatilityOracleInterface volatilityOracleAddress,
        LatestPriceOracleInterface volumeCalculatorAddress,
        DetectBondShape bondShapeDetector
    ) public {
        _assertBondMakerDecimals(bondMakerAddress);
        _bondMakerContract = bondMakerAddress;
        _priceOracleContract = bondMakerAddress.oracleAddress();
        _volatilityOracleContract = VolatilityOracleInterface(
            volatilityOracleAddress
        );
        _volumeCalculator = volumeCalculatorAddress;
        _bondShapeDetector = bondShapeDetector;
    }

    function bondMakerAddress() external view returns (BondMakerInterface) {
        return _bondMakerContract;
    }

    function volumeCalculatorAddress()
        external
        view
        returns (LatestPriceOracleInterface)
    {
        return _volumeCalculator;
    }

    /**
     * @dev Get the latest price (USD) and historical volatility using oracle.
     * If the oracle is not working, `latestPrice` reverts.
     * @return priceE8 (10^-8 USD)
     */
    function _getLatestPrice(LatestPriceOracleInterface oracle)
        internal
        returns (uint256 priceE8)
    {
        return oracle.latestPrice();
    }

    /**
     * @dev Get the implied volatility using oracle.
     * @return volatilityE8 (10^-8)
     */
    function _getVolatility(
        VolatilityOracleInterface oracle,
        uint64 untilMaturity
    ) internal view returns (uint256 volatilityE8) {
        return oracle.getVolatility(untilMaturity);
    }

    /**
     * @dev Returns bond tokenaddress, maturity,
     */
    function _getBond(BondMakerInterface bondMaker, bytes32 bondID)
        internal
        view
        returns (
            ERC20 bondToken,
            uint256 maturity,
            uint256 sbtStrikePrice,
            bytes32 fnMapID
        )
    {
        address bondTokenAddress;
        (bondTokenAddress, maturity, sbtStrikePrice, fnMapID) = bondMaker
            .getBond(bondID);

        // Revert if `bondTokenAddress` is zero.
        bondToken = ERC20(bondTokenAddress);
    }

    /**
     * @dev Removes a decimal gap from the first argument.
     */
    function _applyDecimalGap(
        uint256 baseAmount,
        uint8 decimalsOfBase,
        uint8 decimalsOfQuote
    ) internal pure returns (uint256 quoteAmount) {
        uint256 n;
        uint256 d;

        if (decimalsOfBase > decimalsOfQuote) {
            d = decimalsOfBase - decimalsOfQuote;
        } else if (decimalsOfBase < decimalsOfQuote) {
            n = decimalsOfQuote - decimalsOfBase;
        }

        // The consequent multiplication would overflow under extreme and non-blocking circumstances.
        require(n < 19 && d < 19, "decimal gap needs to be lower than 19");
        return baseAmount.mul(10**n).div(10**d);
    }

    function _calcBondPriceAndSpread(
        BondPricerInterface bondPricer,
        bytes32 bondID,
        int16 feeBaseE4
    ) internal returns (uint256 bondPriceE8, int256 spreadE8) {
        (, uint256 maturity, , ) = _getBond(_bondMakerContract, bondID);
        (
            bool isKnownBondType,
            BondType bondType,
            uint256[] memory points
        ) = _bondShapeDetector.getBondTypeByID(
            _bondMakerContract,
            bondID,
            BondType.NONE
        );
        require(isKnownBondType, "cannot calculate the price of this bond");

        uint256 untilMaturity = maturity.sub(
            _getBlockTimestampSec(),
            "the bond should not have expired"
        );
        uint256 oraclePriceE8 = _getLatestPrice(_priceOracleContract);
        uint256 oracleVolatilityE8 = _getVolatility(
            _volatilityOracleContract,
            untilMaturity.toUint64()
        );

        uint256 leverageE8;
        (bondPriceE8, leverageE8) = bondPricer.calcPriceAndLeverage(
            bondType,
            points,
            oraclePriceE8.toInt256(),
            oracleVolatilityE8.toInt256(),
            untilMaturity.toInt256()
        );
        spreadE8 = _calcSpread(oracleVolatilityE8, leverageE8, feeBaseE4);
    }

    function _calcSpread(
        uint256 oracleVolatilityE8,
        uint256 leverageE8,
        int16 feeBaseE4
    ) internal pure returns (int256 spreadE8) {
        uint256 volE8 = oracleVolatilityE8 < 10**8
            ? 10**8
            : oracleVolatilityE8 > 2 * 10**8
            ? 2 * 10**8
            : oracleVolatilityE8;
        uint256 volTimesLevE16 = volE8 * leverageE8;
        // assert(volTimesLevE16 < 200 * 10**16);
        spreadE8 =
            (feeBaseE4 *
                (
                    feeBaseE4 < 0 || volTimesLevE16 < 10**16
                        ? 10**16
                        : volTimesLevE16
                )
                    .toInt256()) /
            10**12;
        spreadE8 = spreadE8 > MAX_SPREAD_E8 ? MAX_SPREAD_E8 : spreadE8;
    }

    /**
     * @dev Calculate the exchange volume on the USD basis.
     */
    function _calcUsdPrice(uint256 amount) internal returns (uint256) {
        return amount.mul(_getLatestPrice(_volumeCalculator)) / 10**8;
    }

    /**
     * @dev Restirct the bond maker.
     */
    function _assertBondMakerDecimals(BondMakerInterface bondMaker)
        internal
        view
    {
        require(
            bondMaker.decimalsOfOraclePrice() == DECIMALS_OF_ORACLE_PRICE,
            "the decimals of oracle price must be 8"
        );
        require(
            bondMaker.decimalsOfBond() == DECIMALS_OF_BOND,
            "the decimals of bond token must be 8"
        );
    }

    function _assertExpectedPriceRange(
        uint256 actualAmount,
        uint256 expectedAmount,
        uint256 range
    ) internal pure {
        if (expectedAmount != 0) {
            require(
                actualAmount.mul(1000 + range).div(1000) >= expectedAmount,
                "out of expected price range"
            );
        }
    }
}

// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol






/**
 * @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 ERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

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

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

    function safeApprove(IERC20 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(IERC20 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(IERC20 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(IERC20 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.

        // A Solidity high level call has three parts:
        //  1. The target address is checked to verify it contains contract code
        //  2. The call itself is made, and success asserted
        //  3. The return value is decoded, which in turn checks the size of the returned data.
        // solhint-disable-next-line max-line-length
        require(address(token).isContract(), "SafeERC20: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "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/generalizedDotc/BondVsErc20Exchange.sol

pragma solidity 0.6.6;



abstract contract BondVsErc20Exchange is BondExchange {
    using SafeERC20 for ERC20;

    struct VsErc20Pool {
        address seller;
        ERC20 swapPairToken;
        LatestPriceOracleInterface swapPairOracle;
        BondPricerInterface bondPricer;
        int16 feeBaseE4;
        bool isBondSale;
    }
    mapping(bytes32 => VsErc20Pool) internal _vsErc20Pool;

    event LogCreateErc20ToBondPool(
        bytes32 indexed poolID,
        address indexed seller,
        address indexed swapPairAddress
    );

    event LogCreateBondToErc20Pool(
        bytes32 indexed poolID,
        address indexed seller,
        address indexed swapPairAddress
    );

    event LogUpdateVsErc20Pool(
        bytes32 indexed poolID,
        address swapPairOracleAddress,
        address bondPricerAddress,
        int16 feeBase // decimal: 4
    );

    event LogDeleteVsErc20Pool(bytes32 indexed poolID);

    event LogExchangeErc20ToBond(
        address indexed buyer,
        bytes32 indexed bondID,
        bytes32 indexed poolID,
        uint256 bondAmount, // decimal: 8
        uint256 swapPairAmount, // decimal: ERC20.decimals()
        uint256 volume // USD, decimal: 8
    );

    event LogExchangeBondToErc20(
        address indexed buyer,
        bytes32 indexed bondID,
        bytes32 indexed poolID,
        uint256 bondAmount, // decimal: 8
        uint256 swapPairAmount, // decimal: ERC20.decimals()
        uint256 volume // USD, decimal: 8
    );

    /**
     * @dev Reverts when the pool ID does not exist.
     */
    modifier isExsistentVsErc20Pool(bytes32 poolID) {
        require(
            _vsErc20Pool[poolID].seller != address(0),
            "the exchange pair does not exist"
        );
        _;
    }

    /**
     * @notice Exchange buyer's ERC20 token to the seller's bond.
     * @dev Ensure the seller has approved sufficient bonds and
     * you approve ERC20 token to pay before executing this function.
     * @param bondID is the target bond ID.
     * @param poolID is the target pool ID.
     * @param swapPairAmount is the exchange pair token amount to pay.
     * @param expectedAmount is the bond amount to receive.
     * @param range (decimal: 3)
     */
    function exchangeErc20ToBond(
        bytes32 bondID,
        bytes32 poolID,
        uint256 swapPairAmount,
        uint256 expectedAmount,
        uint256 range
    ) external returns (uint256 bondAmount) {
        bondAmount = _exchangeErc20ToBond(
            msg.sender,
            bondID,
            poolID,
            swapPairAmount
        );
        // assert(bondAmount != 0);
        _assertExpectedPriceRange(bondAmount, expectedAmount, range);
    }

    /**
     * @notice Exchange buyer's bond to the seller's ERC20 token.
     * @dev Ensure the seller has approved sufficient ERC20 token and
     * you approve bonds to pay before executing this function.
     * @param bondID is the target bond ID.
     * @param poolID is the target pool ID.
     * @param bondAmount is the bond amount to pay.
     * @param expectedAmount is the exchange pair token amount to receive.
     * @param range (decimal: 3)
     */
    function exchangeBondToErc20(
        bytes32 bondID,
        bytes32 poolID,
        uint256 bondAmount,
        uint256 expectedAmount,
        uint256 range
    ) external returns (uint256 swapPairAmount) {
        swapPairAmount = _exchangeBondToErc20(
            msg.sender,
            bondID,
            poolID,
            bondAmount
        );
        // assert(swapPairAmount != 0);
        _assertExpectedPriceRange(swapPairAmount, expectedAmount, range);
    }

    /**
     * @notice Returns the exchange rate including spread.
     */
    function calcRateBondToErc20(bytes32 bondID, bytes32 poolID)
        external
        returns (uint256 rateE8)
    {
        (rateE8, , , ) = _calcRateBondToErc20(bondID, poolID);
    }

    /**
     * @notice Returns pool ID generated by the immutable pool settings.
     */
    function generateVsErc20PoolID(
        address seller,
        address swapPairAddress,
        bool isBondSale
    ) external view returns (bytes32 poolID) {
        return _generateVsErc20PoolID(seller, swapPairAddress, isBondSale);
    }

    /**
     * @notice Register a new vsErc20Pool.
     */
    function createVsErc20Pool(
        ERC20 swapPairAddress,
        LatestPriceOracleInterface swapPairOracleAddress,
        BondPricerInterface bondPricerAddress,
        int16 feeBaseE4,
        bool isBondSale
    ) external returns (bytes32 poolID) {
        return
            _createVsErc20Pool(
                msg.sender,
                swapPairAddress,
                swapPairOracleAddress,
                bondPricerAddress,
                feeBaseE4,
                isBondSale
            );
    }

    /**
     * @notice Update the mutable pool settings.
     */
    function updateVsErc20Pool(
        bytes32 poolID,
        LatestPriceOracleInterface swapPairOracleAddress,
        BondPricerInterface bondPricerAddress,
        int16 feeBaseE4
    ) external {
        require(
            _vsErc20Pool[poolID].seller == msg.sender,
            "not the owner of the pool ID"
        );

        _updateVsErc20Pool(
            poolID,
            swapPairOracleAddress,
            bondPricerAddress,
            feeBaseE4
        );
    }

    /**
     * @notice Delete the pool settings.
     */
    function deleteVsErc20Pool(bytes32 poolID) external {
        require(
            _vsErc20Pool[poolID].seller == msg.sender,
            "not the owner of the pool ID"
        );

        _deleteVsErc20Pool(poolID);
    }

    /**
     * @notice Returns the pool settings.
     */
    function getVsErc20Pool(bytes32 poolID)
        external
        view
        returns (
            address seller,
            ERC20 swapPairAddress,
            LatestPriceOracleInterface swapPairOracleAddress,
            BondPricerInterface bondPricerAddress,
            int16 feeBaseE4,
            bool isBondSale
        )
    {
        return _getVsErc20Pool(poolID);
    }

    /**
     * @dev Exchange buyer's ERC20 token to the seller's bond.
     * Ensure the seller has approved sufficient bonds and
     * buyer approve ERC20 token to pay before executing this function.
     * @param buyer is the buyer address.
     * @param bondID is the target bond ID.
     * @param poolID is the target pool ID.
     * @param swapPairAmount is the exchange pair token amount to pay.
     * @return bondAmount is the received bond amount.
     */
    function _exchangeErc20ToBond(
        address buyer,
        bytes32 bondID,
        bytes32 poolID,
        uint256 swapPairAmount
    ) internal returns (uint256 bondAmount) {
        (
            address seller,
            ERC20 swapPairToken,
            ,
            ,
            ,
            bool isBondSale
        ) = _getVsErc20Pool(poolID);
        require(isBondSale, "This pool is for buying bond");

        (ERC20 bondToken, , , ) = _getBond(_bondMakerContract, bondID);
        require(address(bondToken) != address(0), "the bond is not registered");

        uint256 volumeE8;
        {
            (
                uint256 rateE8,
                ,
                uint256 swapPairPriceE8,

            ) = _calcRateBondToErc20(bondID, poolID);
            require(
                rateE8 > MIN_EXCHANGE_RATE_E8,
                "exchange rate is too small"
            );
            require(
                rateE8 < MAX_EXCHANGE_RATE_E8,
                "exchange rate is too large"
            );
            uint8 decimalsOfSwapPair = swapPairToken.decimals();
            bondAmount =
                _applyDecimalGap(
                    swapPairAmount,
                    decimalsOfSwapPair,
                    DECIMALS_OF_BOND + 8
                ) /
                rateE8;
            require(bondAmount != 0, "must transfer non-zero bond amount");
            volumeE8 = swapPairPriceE8.mul(swapPairAmount).div(
                10**uint256(decimalsOfSwapPair)
            );
        }

        require(
            bondToken.transferFrom(seller, buyer, bondAmount),
            "fail to transfer bonds"
        );
        swapPairToken.safeTransferFrom(buyer, seller, swapPairAmount);

        emit LogExchangeErc20ToBond(
            buyer,
            bondID,
            poolID,
            bondAmount,
            swapPairAmount,
            volumeE8
        );
    }

    /**
     * @dev Exchange buyer's bond to the seller's ERC20 token.
     * Ensure the seller has approved sufficient ERC20 token and
     * buyer approve bonds to pay before executing this function.
     * @param buyer is the buyer address.
     * @param bondID is the target bond ID.
     * @param poolID is the target pool ID.
     * @param bondAmount is the bond amount to pay.
     * @return swapPairAmount is the received swap pair token amount.
     */
    function _exchangeBondToErc20(
        address buyer,
        bytes32 bondID,
        bytes32 poolID,
        uint256 bondAmount
    ) internal returns (uint256 swapPairAmount) {
        (
            address seller,
            ERC20 swapPairToken,
            ,
            ,
            ,
            bool isBondSale
        ) = _getVsErc20Pool(poolID);
        require(!isBondSale, "This pool is not for buying bond");

        (ERC20 bondToken, , , ) = _getBond(_bondMakerContract, bondID);
        require(address(bondToken) != address(0), "the bond is not registered");

        uint256 volumeE8;
        {
            (uint256 rateE8, uint256 bondPriceE8, , ) = _calcRateBondToErc20(
                bondID,
                poolID
            );
            require(
                rateE8 > MIN_EXCHANGE_RATE_E8,
                "exchange rate is too small"
            );
            require(
                rateE8 < MAX_EXCHANGE_RATE_E8,
                "exchange rate is too large"
            );
            uint8 decimalsOfSwapPair = swapPairToken.decimals();
            swapPairAmount = _applyDecimalGap(
                bondAmount.mul(rateE8),
                DECIMALS_OF_BOND + 8,
                decimalsOfSwapPair
            );
            require(swapPairAmount != 0, "must transfer non-zero token amount");
            volumeE8 = bondPriceE8.mul(bondAmount).div(
                10**uint256(DECIMALS_OF_BOND)
            );
        }

        require(
            bondToken.transferFrom(buyer, seller, bondAmount),
            "fail to transfer bonds"
        );
        swapPairToken.safeTransferFrom(seller, buyer, swapPairAmount);

        emit LogExchangeBondToErc20(
            buyer,
            bondID,
            poolID,
            bondAmount,
            swapPairAmount,
            volumeE8
        );
    }

    function _calcRateBondToErc20(bytes32 bondID, bytes32 poolID)
        internal
        returns (
            uint256 rateE8,
            uint256 bondPriceE8,
            uint256 swapPairPriceE8,
            int256 spreadE8
        )
    {
        (
            ,
            ,
            LatestPriceOracleInterface erc20Oracle,
            BondPricerInterface bondPricer,
            int16 feeBaseE4,
            bool isBondSale
        ) = _getVsErc20Pool(poolID);
        swapPairPriceE8 = _getLatestPrice(erc20Oracle);
        (bondPriceE8, spreadE8) = _calcBondPriceAndSpread(
            bondPricer,
            bondID,
            feeBaseE4
        );
        bondPriceE8 = _calcUsdPrice(bondPriceE8);
        rateE8 = bondPriceE8.mul(10**8).div(
            swapPairPriceE8,
            "ERC20 oracle price must be non-zero"
        );

        // `spreadE8` is less than 0.15 * 10**8.
        if (isBondSale) {
            rateE8 = rateE8.mul(uint256(10**8 + spreadE8)) / 10**8;
        } else {
            rateE8 = rateE8.mul(10**8) / uint256(10**8 + spreadE8);
        }
    }

    function _generateVsErc20PoolID(
        address seller,
        address swapPairAddress,
        bool isBondSale
    ) internal view returns (bytes32 poolID) {
        return
            keccak256(
                abi.encode(
                    "Bond vs ERC20 exchange",
                    address(this),
                    seller,
                    swapPairAddress,
                    isBondSale
                )
            );
    }

    function _setVsErc20Pool(
        bytes32 poolID,
        address seller,
        ERC20 swapPairToken,
        LatestPriceOracleInterface swapPairOracle,
        BondPricerInterface bondPricer,
        int16 feeBaseE4,
        bool isBondSale
    ) internal {
        require(seller != address(0), "the pool ID already exists");
        require(
            address(swapPairToken) != address(0),
            "swapPairToken should be non-zero address"
        );
        require(
            address(swapPairOracle) != address(0),
            "swapPairOracle should be non-zero address"
        );
        require(
            address(bondPricer) != address(0),
            "bondPricer should be non-zero address"
        );
        _vsErc20Pool[poolID] = VsErc20Pool({
            seller: seller,
            swapPairToken: swapPairToken,
            swapPairOracle: swapPairOracle,
            bondPricer: bondPricer,
            feeBaseE4: feeBaseE4,
            isBondSale: isBondSale
        });
    }

    function _createVsErc20Pool(
        address seller,
        ERC20 swapPairToken,
        LatestPriceOracleInterface swapPairOracle,
        BondPricerInterface bondPricer,
        int16 feeBaseE4,
        bool isBondSale
    ) internal returns (bytes32 poolID) {
        poolID = _generateVsErc20PoolID(
            seller,
            address(swapPairToken),
            isBondSale
        );
        require(
            _vsErc20Pool[poolID].seller == address(0),
            "the pool ID already exists"
        );

        {
            uint256 price = _getLatestPrice(swapPairOracle);
            require(
                price != 0,
                "swapPairOracle has latestPrice() function which returns non-zero value"
            );
        }

        _setVsErc20Pool(
            poolID,
            seller,
            swapPairToken,
            swapPairOracle,
            bondPricer,
            feeBaseE4,
            isBondSale
        );

        if (isBondSale) {
            emit LogCreateErc20ToBondPool(
                poolID,
                seller,
                address(swapPairToken)
            );
        } else {
            emit LogCreateBondToErc20Pool(
                poolID,
                seller,
                address(swapPairToken)
            );
        }

        emit LogUpdateVsErc20Pool(
            poolID,
            address(swapPairOracle),
            address(bondPricer),
            feeBaseE4
        );
    }

    function _updateVsErc20Pool(
        bytes32 poolID,
        LatestPriceOracleInterface swapPairOracle,
        BondPricerInterface bondPricer,
        int16 feeBaseE4
    ) internal isExsistentVsErc20Pool(poolID) {
        (
            address seller,
            ERC20 swapPairToken,
            ,
            ,
            ,
            bool isBondSale
        ) = _getVsErc20Pool(poolID);
        _setVsErc20Pool(
            poolID,
            seller,
            swapPairToken,
            swapPairOracle,
            bondPricer,
            feeBaseE4,
            isBondSale
        );

        emit LogUpdateVsErc20Pool(
            poolID,
            address(swapPairOracle),
            address(bondPricer),
            feeBaseE4
        );
    }

    function _deleteVsErc20Pool(bytes32 poolID)
        internal
        isExsistentVsErc20Pool(poolID)
    {
        delete _vsErc20Pool[poolID];

        emit LogDeleteVsErc20Pool(poolID);
    }

    function _getVsErc20Pool(bytes32 poolID)
        internal
        view
        isExsistentVsErc20Pool(poolID)
        returns (
            address seller,
            ERC20 swapPairToken,
            LatestPriceOracleInterface swapPairOracle,
            BondPricerInterface bondPricer,
            int16 feeBaseE4,
            bool isBondSale
        )
    {
        VsErc20Pool memory exchangePair = _vsErc20Pool[poolID];
        seller = exchangePair.seller;
        swapPairToken = exchangePair.swapPairToken;
        swapPairOracle = exchangePair.swapPairOracle;
        bondPricer = exchangePair.bondPricer;
        feeBaseE4 = exchangePair.feeBaseE4;
        isBondSale = exchangePair.isBondSale;
    }
}

// File: contracts/util/TransferETH.sol

pragma solidity 0.6.6;


abstract contract TransferETH is TransferETHInterface {
    receive() external payable override {
        emit LogTransferETH(msg.sender, address(this), msg.value);
    }

    function _hasSufficientBalance(uint256 amount) internal view returns (bool ok) {
        address thisContract = address(this);
        return amount <= thisContract.balance;
    }

    /**
     * @notice transfer `amount` ETH to the `recipient` account with emitting log
     */
    function _transferETH(
        address payable recipient,
        uint256 amount,
        string memory errorMessage
    ) internal {
        require(_hasSufficientBalance(amount), errorMessage);
        (bool success, ) = recipient.call{value: amount}(""); // solhint-disable-line avoid-low-level-calls
        require(success, "transferring Ether failed");
        emit LogTransferETH(address(this), recipient, amount);
    }

    function _transferETH(address payable recipient, uint256 amount) internal {
        _transferETH(recipient, amount, "TransferETH: transfer amount exceeds balance");
    }
}

// File: contracts/generalizedDotc/BondVsEthExchange.sol

pragma solidity 0.6.6;



abstract contract BondVsEthExchange is BondExchange, TransferETH {
    uint8 internal constant DECIMALS_OF_ETH = 18;

    struct VsEthPool {
        address seller;
        LatestPriceOracleInterface ethOracle;
        BondPricerInterface bondPricer;
        int16 feeBaseE4;
        bool isBondSale;
    }
    mapping(bytes32 => VsEthPool) internal _vsEthPool;

    mapping(address => uint256) internal _depositedEth;

    event LogCreateEthToBondPool(
        bytes32 indexed poolID,
        address indexed seller
    );

    event LogCreateBondToEthPool(
        bytes32 indexed poolID,
        address indexed seller
    );

    event LogUpdateVsEthPool(
        bytes32 indexed poolID,
        address ethOracleAddress,
        address bondPricerAddress,
        int16 feeBase // decimal: 4
    );

    event LogDeleteVsEthPool(bytes32 indexed poolID);

    event LogExchangeEthToBond(
        address indexed buyer,
        bytes32 indexed bondID,
        bytes32 indexed poolID,
        uint256 bondAmount, // decimal: 8
        uint256 swapPairAmount, // decimal: 18
        uint256 volume // USD, decimal: 8
    );

    event LogExchangeBondToEth(
        address indexed buyer,
        bytes32 indexed bondID,
        bytes32 indexed poolID,
        uint256 bondAmount, // decimal: 8
        uint256 swapPairAmount, // decimal: 18
        uint256 volume // USD, decimal: 8
    );

    /**
     * @dev Reverts when the pool ID does not exist.
     */
    modifier isExsistentVsEthPool(bytes32 poolID) {
        require(
            _vsEthPool[poolID].seller != address(0),
            "the exchange pair does not exist"
        );
        _;
    }

    /**
     * @notice Exchange buyer's ETH to the seller's bond.
     * @dev Ensure the seller has approved sufficient bonds and
     * you deposit ETH to pay before executing this function.
     * @param bondID is the target bond ID.
     * @param poolID is the target pool ID.
     * @param ethAmount is the exchange pair token amount to pay.
     * @param expectedAmount is the bond amount to receive.
     * @param range (decimal: 3)
     */
    function exchangeEthToBond(
        bytes32 bondID,
        bytes32 poolID,
        uint256 ethAmount,
        uint256 expectedAmount,
        uint256 range
    ) external returns (uint256 bondAmount) {
        bondAmount = _exchangeEthToBond(msg.sender, bondID, poolID, ethAmount);
        // assert(bondAmount != 0);
        _assertExpectedPriceRange(bondAmount, expectedAmount, range);
    }

    /**
     * @notice Exchange buyer's bond to the seller's ETH.
     * @dev Ensure the seller has deposited sufficient ETH and
     * you approve bonds to pay before executing this function.
     * @param bondID is the target bond ID.
     * @param poolID is the target pool ID.
     * @param bondAmount is the bond amount to pay.
     * @param expectedAmount is the ETH amount to receive.
     * @param range (decimal: 3)
     */
    function exchangeBondToEth(
        bytes32 bondID,
        bytes32 poolID,
        uint256 bondAmount,
        uint256 expectedAmount,
        uint256 range
    ) external returns (uint256 ethAmount) {
        ethAmount = _exchangeBondToEth(msg.sender, bondID, poolID, bondAmount);
        // assert(ethAmount != 0);
        _assertExpectedPriceRange(ethAmount, expectedAmount, range);
    }

    /**
     * @notice Returns the exchange rate including spread.
     */
    function calcRateBondToEth(bytes32 bondID, bytes32 poolID)
        external
        returns (uint256 rateE8)
    {
        (rateE8, , , ) = _calcRateBondToEth(bondID, poolID);
    }

    /**
     * @notice Returns pool ID generated by the immutable pool settings.
     */
    function generateVsEthPoolID(address seller, bool isBondSale)
        external
        view
        returns (bytes32 poolID)
    {
        return _generateVsEthPoolID(seller, isBondSale);
    }

    /**
     * @notice Register a new vsEthPool.
     */
    function createVsEthPool(
        LatestPriceOracleInterface ethOracleAddress,
        BondPricerInterface bondPricerAddress,
        int16 feeBaseE4,
        bool isBondSale
    ) external returns (bytes32 poolID) {
        return
            _createVsEthPool(
                msg.sender,
                ethOracleAddress,
                bondPricerAddress,
                feeBaseE4,
                isBondSale
            );
    }

    /**
     * @notice Update the mutable pool settings.
     */
    function updateVsEthPool(
        bytes32 poolID,
        LatestPriceOracleInterface ethOracleAddress,
        BondPricerInterface bondPricerAddress,
        int16 feeBaseE4
    ) external {
        require(
            _vsEthPool[poolID].seller == msg.sender,
            "not the owner of the pool ID"
        );

        _updateVsEthPool(
            poolID,
            ethOracleAddress,
            bondPricerAddress,
            feeBaseE4
        );
    }

    /**
     * @notice Delete the pool settings.
     */
    function deleteVsEthPool(bytes32 poolID) external {
        require(
            _vsEthPool[poolID].seller == msg.sender,
            "not the owner of the pool ID"
        );

        _deleteVsEthPool(poolID);
    }

    /**
     * @notice Returns the pool settings.
     */
    function getVsEthPool(bytes32 poolID)
        external
        view
        returns (
            address seller,
            LatestPriceOracleInterface ethOracleAddress,
            BondPricerInterface bondPricerAddress,
            int16 feeBaseE4,
            bool isBondSale
        )
    {
        return _getVsEthPool(poolID);
    }

    /**
     * @notice Transfer ETH to this contract and allow this contract to pay ETH when exchanging.
     */
    function depositEth() external payable {
        _addEthAllowance(msg.sender, msg.value);
    }

    /**
     * @notice Withdraw all deposited ETH.
     */
    function withdrawEth() external returns (uint256 amount) {
        amount = _depositedEth[msg.sender];
        _transferEthFrom(msg.sender, msg.sender, amount);
    }

    /**
     * @notice Returns deposited ETH amount.
     */
    function ethAllowance(address owner)
        external
        view
        returns (uint256 amount)
    {
        amount = _depositedEth[owner];
    }

    /**
     * @dev Exchange buyer's ETH to the seller's bond.
     * Ensure the seller has approved sufficient bonds and
     * buyer deposit ETH to pay before executing this function.
     * @param buyer is the buyer address.
     * @param bondID is the target bond ID.
     * @param poolID is the target pool ID.
     * @param swapPairAmount is the exchange pair token amount to pay.
     * @return bondAmount is the received bond amount.
     */
    function _exchangeEthToBond(
        address buyer,
        bytes32 bondID,
        bytes32 poolID,
        uint256 swapPairAmount
    ) internal returns (uint256 bondAmount) {
        (address seller, , , , bool isBondSale) = _getVsEthPool(poolID);
        require(isBondSale, "This pool is for buying bond");

        (ERC20 bondToken, , , ) = _getBond(_bondMakerContract, bondID);
        require(address(bondToken) != address(0), "the bond is not registered");

        uint256 volumeE8;
        {
            (uint256 rateE8, , uint256 swapPairPriceE8, ) = _calcRateBondToEth(
                bondID,
                poolID
            );
            require(
                rateE8 > MIN_EXCHANGE_RATE_E8,
                "exchange rate is too small"
            );
            require(
                rateE8 < MAX_EXCHANGE_RATE_E8,
                "exchange rate is too large"
            );
            bondAmount =
                _applyDecimalGap(
                    swapPairAmount,
                    DECIMALS_OF_ETH,
                    DECIMALS_OF_BOND + 8
                ) /
                rateE8;
            require(bondAmount != 0, "must transfer non-zero bond amount");
            volumeE8 = swapPairPriceE8.mul(swapPairAmount).div(
                10**uint256(DECIMALS_OF_ETH)
            );
        }

        require(
            bondToken.transferFrom(seller, buyer, bondAmount),
            "fail to transfer bonds"
        );
        _transferEthFrom(buyer, seller, swapPairAmount);

        emit LogExchangeEthToBond(
            buyer,
            bondID,
            poolID,
            bondAmount,
            swapPairAmount,
            volumeE8
        );
    }

    /**
     * @dev Exchange buyer's bond to the seller's ETH.
     * Ensure the seller has deposited sufficient ETH and
     * buyer approve bonds to pay before executing this function.
     * @param buyer is the buyer address.
     * @param bondID is the target bond ID.
     * @param poolID is the target pool ID.
     * @param bondAmount is the bond amount to pay.
     * @return swapPairAmount is the received ETH amount.
     */
    function _exchangeBondToEth(
        address buyer,
        bytes32 bondID,
        bytes32 poolID,
        uint256 bondAmount
    ) internal returns (uint256 swapPairAmount) {
        (address seller, , , , bool isBondSale) = _getVsEthPool(poolID);
        require(!isBondSale, "This pool is not for buying bond");

        (ERC20 bondToken, , , ) = _getBond(_bondMakerContract, bondID);
        require(address(bondToken) != address(0), "the bond is not registered");

        uint256 volumeE8;
        {
            (uint256 rateE8, uint256 bondPriceE8, , ) = _calcRateBondToEth(
                bondID,
                poolID
            );
            require(
                rateE8 > MIN_EXCHANGE_RATE_E8,
                "exchange rate is too small"
            );
            require(
                rateE8 < MAX_EXCHANGE_RATE_E8,
                "exchange rate is too large"
            );
            swapPairAmount = _applyDecimalGap(
                bondAmount.mul(rateE8),
                DECIMALS_OF_BOND + 8,
                DECIMALS_OF_ETH
            );
            require(swapPairAmount != 0, "must transfer non-zero token amount");
            volumeE8 = bondPriceE8.mul(bondAmount).div(
                10**uint256(DECIMALS_OF_BOND)
            );
        }

        require(
            bondToken.transferFrom(buyer, seller, bondAmount),
            "fail to transfer bonds"
        );
        _transferEthFrom(seller, buyer, swapPairAmount);

        emit LogExchangeBondToEth(
            buyer,
            bondID,
            poolID,
            bondAmount,
            swapPairAmount,
            volumeE8
        );
    }

    function _calcRateBondToEth(bytes32 bondID, bytes32 poolID)
        internal
        returns (
            uint256 rateE8,
            uint256 bondPriceE8,
            uint256 swapPairPriceE8,
            int256 spreadE8
        )
    {
        (
            ,
            LatestPriceOracleInterface ethOracle,
            BondPricerInterface bondPricer,
            int16 feeBaseE4,
            bool isBondSale
        ) = _getVsEthPool(poolID);
        swapPairPriceE8 = _getLatestPrice(ethOracle);
        (bondPriceE8, spreadE8) = _calcBondPriceAndSpread(
            bondPricer,
            bondID,
            feeBaseE4
        );
        bondPriceE8 = _calcUsdPrice(bondPriceE8);
        rateE8 = bondPriceE8.mul(10**8).div(
            swapPairPriceE8,
            "ERC20 oracle price must be non-zero"
        );

        // `spreadE8` is less than 0.15 * 10**8.
        if (isBondSale) {
            rateE8 = rateE8.mul(uint256(10**8 + spreadE8)) / 10**8;
        } else {
            rateE8 = rateE8.mul(uint256(10**8 - spreadE8)) / 10**8;
        }
    }

    function _generateVsEthPoolID(address seller, bool isBondSale)
        internal
        view
        returns (bytes32 poolID)
    {
        return
            keccak256(
                abi.encode(
                    "Bond vs ETH exchange",
                    address(this),
                    seller,
                    isBondSale
                )
            );
    }

    function _setVsEthPool(
        bytes32 poolID,
        address seller,
        LatestPriceOracleInterface ethOracle,
        BondPricerInterface bondPricer,
        int16 feeBaseE4,
        bool isBondSale
    ) internal {
        require(seller != address(0), "the pool ID already exists");
        require(
            address(ethOracle) != address(0),
            "ethOracle should be non-zero address"
        );
        require(
            address(bondPricer) != address(0),
            "bondPricer should be non-zero address"
        );
        _vsEthPool[poolID] = VsEthPool({
            seller: seller,
            ethOracle: ethOracle,
            bondPricer: bondPricer,
            feeBaseE4: feeBaseE4,
            isBondSale: isBondSale
        });
    }

    function _createVsEthPool(
        address seller,
        LatestPriceOracleInterface ethOracle,
        BondPricerInterface bondPricer,
        int16 feeBaseE4,
        bool isBondSale
    ) internal returns (bytes32 poolID) {
        poolID = _generateVsEthPoolID(seller, isBondSale);
        require(
            _vsEthPool[poolID].seller == address(0),
            "the pool ID already exists"
        );

        {
            uint256 price = ethOracle.latestPrice();
            require(
                price != 0,
                "ethOracle has latestPrice() function which returns non-zero value"
            );
        }

        _setVsEthPool(
            poolID,
            seller,
            ethOracle,
            bondPricer,
            feeBaseE4,
            isBondSale
        );

        if (isBondSale) {
            emit LogCreateEthToBondPool(poolID, seller);
        } else {
            emit LogCreateBondToEthPool(poolID, seller);
        }

        emit LogUpdateVsEthPool(
            poolID,
            address(ethOracle),
            address(bondPricer),
            feeBaseE4
        );
    }

    function _updateVsEthPool(
        bytes32 poolID,
        LatestPriceOracleInterface ethOracle,
        BondPricerInterface bondPricer,
        int16 feeBaseE4
    ) internal isExsistentVsEthPool(poolID) {
        (address seller, , , , bool isBondSale) = _getVsEthPool(poolID);
        _setVsEthPool(
            poolID,
            seller,
            ethOracle,
            bondPricer,
            feeBaseE4,
            isBondSale
        );

        emit LogUpdateVsEthPool(
            poolID,
            address(ethOracle),
            address(bondPricer),
            feeBaseE4
        );
    }

    function _deleteVsEthPool(bytes32 poolID)
        internal
        isExsistentVsEthPool(poolID)
    {
        delete _vsEthPool[poolID];

        emit LogDeleteVsEthPool(poolID);
    }

    function _getVsEthPool(bytes32 poolID)
        internal
        view
        isExsistentVsEthPool(poolID)
        returns (
            address seller,
            LatestPriceOracleInterface ethOracle,
            BondPricerInterface bondPricer,
            int16 feeBaseE4,
            bool isBondSale
        )
    {
        VsEthPool memory exchangePair = _vsEthPool[poolID];
        seller = exchangePair.seller;
        ethOracle = exchangePair.ethOracle;
        bondPricer = exchangePair.bondPricer;
        feeBaseE4 = exchangePair.feeBaseE4;
        isBondSale = exchangePair.isBondSale;
    }

    function _transferEthFrom(
        address sender,
        address recipient,
        uint256 amount
    ) internal {
        _subEthAllowance(sender, amount);
        _transferETH(payable(recipient), amount);
    }

    function _addEthAllowance(address sender, uint256 amount) internal {
        _depositedEth[sender] += amount;
        require(_depositedEth[sender] >= amount, "overflow allowance");
    }

    function _subEthAllowance(address owner, uint256 amount) internal {
        require(_depositedEth[owner] >= amount, "insufficient allowance");
        _depositedEth[owner] -= amount;
    }
}

// File: contracts/generalizedDotc/BondVsBondExchange.sol

pragma solidity 0.6.6;


abstract contract BondVsBondExchange is BondExchange {
    /**
     * @dev the sum of decimalsOfBond and decimalsOfOraclePrice of the bondMaker.
     * This value is constant by the restriction of `_assertBondMakerDecimals`.
     */
    uint8 internal constant DECIMALS_OF_BOND_VALUE = DECIMALS_OF_BOND +
        DECIMALS_OF_ORACLE_PRICE;

    struct VsBondPool {
        address seller;
        BondMakerInterface bondMakerForUser;
        VolatilityOracleInterface volatilityOracle;
        BondPricerInterface bondPricerForUser;
        BondPricerInterface bondPricer;
        int16 feeBaseE4;
    }
    mapping(bytes32 => VsBondPool) internal _vsBondPool;

    event LogCreateBondToBondPool(
        bytes32 indexed poolID,
        address indexed seller,
        address indexed bondMakerForUser
    );

    event LogUpdateVsBondPool(
        bytes32 indexed poolID,
        address bondPricerForUser,
        address bondPricer,
        int16 feeBase // decimal: 4
    );

    event LogDeleteVsBondPool(bytes32 indexed poolID);

    event LogExchangeBondToBond(
        address indexed buyer,
        bytes32 indexed bondID,
        bytes32 indexed poolID,
        uint256 bondAmount, // decimal: 8
        uint256 swapPairAmount, // USD, decimal: 8
        uint256 volume // USD, decimal: 8
    );

    /**
     * @dev Reverts when the pool ID does not exist.
     */
    modifier isExsistentVsBondPool(bytes32 poolID) {
        require(
            _vsBondPool[poolID].seller != address(0),
            "the exchange pair does not exist"
        );
        _;
    }

    /**
     * @notice Exchange the seller's bond to buyer's multiple bonds.
     * @dev Ensure the seller has approved sufficient bonds and
     * Approve bonds to pay before executing this function.
     * @param bondID is the target bond ID.
     * @param poolID is the target pool ID.
     * @param amountInDollarsE8 is the exchange pair token amount to pay. (decimals: 8)
     * @param expectedAmount is the bond amount to receive. (decimals: 8)
     * @param range (decimal: 3)
     */
    function exchangeBondToBond(
        bytes32 bondID,
        bytes32 poolID,
        bytes32[] calldata bondIDs,
        uint256 amountInDollarsE8,
        uint256 expectedAmount,
        uint256 range
    ) external returns (uint256 bondAmount) {
        uint256 amountInDollars = _applyDecimalGap(
            amountInDollarsE8,
            8,
            DECIMALS_OF_BOND_VALUE
        );
        bondAmount = _exchangeBondToBond(
            msg.sender,
            bondID,
            poolID,
            bondIDs,
            amountInDollars
        );
        _assertExpectedPriceRange(bondAmount, expectedAmount, range);
    }

    /**
     * @notice Returns the exchange rate including spread.
     */
    function calcRateBondToUsd(bytes32 bondID, bytes32 poolID)
        external
        returns (uint256 rateE8)
    {
        (rateE8, , , ) = _calcRateBondToUsd(bondID, poolID);
    }

    /**
     * @notice Returns pool ID generated by the immutable pool settings.
     */
    function generateVsBondPoolID(address seller, address bondMakerForUser)
        external
        view
        returns (bytes32 poolID)
    {
        return _generateVsBondPoolID(seller, bondMakerForUser);
    }

    /**
     * @notice Register a new vsBondPool.
     */
    function createVsBondPool(
        BondMakerInterface bondMakerForUserAddress,
        VolatilityOracleInterface volatilityOracleAddress,
        BondPricerInterface bondPricerForUserAddress,
        BondPricerInterface bondPricerAddress,
        int16 feeBaseE4
    ) external returns (bytes32 poolID) {
        return
            _createVsBondPool(
                msg.sender,
                bondMakerForUserAddress,
                volatilityOracleAddress,
                bondPricerForUserAddress,
                bondPricerAddress,
                feeBaseE4
            );
    }

    /**
     * @notice Update the mutable pool settings.
     */
    function updateVsBondPool(
        bytes32 poolID,
        VolatilityOracleInterface volatilityOracleAddress,
        BondPricerInterface bondPricerForUserAddress,
        BondPricerInterface bondPricerAddress,
        int16 feeBaseE4
    ) external {
        require(
            _vsBondPool[poolID].seller == msg.sender,
            "not the owner of the pool ID"
        );

        _updateVsBondPool(
            poolID,
            volatilityOracleAddress,
            bondPricerForUserAddress,
            bondPricerAddress,
            feeBaseE4
        );
    }

    /**
     * @notice Delete the pool settings.
     */
    function deleteVsBondPool(bytes32 poolID) external {
        require(
            _vsBondPool[poolID].seller == msg.sender,
            "not the owner of the pool ID"
        );

        _deleteVsBondPool(poolID);
    }

    /**
     * @notice Returns the pool settings.
     */
    function getVsBondPool(bytes32 poolID)
        external
        view
        returns (
            address seller,
            BondMakerInterface bondMakerForUserAddress,
            VolatilityOracleInterface volatilityOracle,
            BondPricerInterface bondPricerForUserAddress,
            BondPricerInterface bondPricerAddress,
            int16 feeBaseE4,
            bool isBondSale
        )
    {
        return _getVsBondPool(poolID);
    }

    /**
     * @notice Returns the total approved bond amount in U.S. dollars.
     * Unnecessary bond must not be included in bondIDs.
     */
    function totalBondAllowance(
        bytes32 poolID,
        bytes32[] calldata bondIDs,
        uint256 maturityBorder,
        address owner
    ) external returns (uint256 allowanceInDollarsE8) {
        (
            ,
            BondMakerInterface bondMakerForUser,
            VolatilityOracleInterface volatilityOracle,
            BondPricerInterface bondPricerForUser,
            ,
            ,

        ) = _getVsBondPool(poolID);
        uint256 allowanceInDollars = _totalBondAllowance(
            bondMakerForUser,
            volatilityOracle,
            bondPricerForUser,
            bondIDs,
            maturityBorder,
            owner
        );
        allowanceInDollarsE8 = _applyDecimalGap(
            allowanceInDollars,
            DECIMALS_OF_BOND_VALUE,
            8
        );
    }

    /**
     * @dev Exchange the seller's bond to buyer's multiple bonds.
     * Ensure the seller has approved sufficient bonds and
     * buyer approve bonds to pay before executing this function.
     * @param buyer is the buyer address.
     * @param bondID is the target bond ID.
     * @param poolID is the target pool ID.
     * @param amountInDollars is the exchange pair token amount to pay. (decimals: 16)
     * @return bondAmount is the received bond amount.
     */
    function _exchangeBondToBond(
        address buyer,
        bytes32 bondID,
        bytes32 poolID,
        bytes32[] memory bondIDs,
        uint256 amountInDollars
    ) internal returns (uint256 bondAmount) {
        require(bondIDs.length != 0, "must input bonds for payment");

        BondMakerInterface bondMakerForUser;
        {
            bool isBondSale;
            (, bondMakerForUser, , , , , isBondSale) = _getVsBondPool(poolID);
            require(isBondSale, "This pool is for buying bond");
        }

        (ERC20 bondToken, uint256 maturity, , ) = _getBond(
            _bondMakerContract,
            bondID
        );
        require(address(bondToken) != address(0), "the bond is not registered");

        {
            (uint256 rateE8, , , ) = _calcRateBondToUsd(bondID, poolID);
            require(
                rateE8 > MIN_EXCHANGE_RATE_E8,
                "exchange rate is too small"
            );
            require(
                rateE8 < MAX_EXCHANGE_RATE_E8,
                "exchange rate is too large"
            );
            bondAmount =
                _applyDecimalGap(
                    amountInDollars,
                    DECIMALS_OF_BOND_VALUE,
                    bondToken.decimals() + 8
                ) /
                rateE8;
            require(bondAmount != 0, "must transfer non-zero bond amount");
        }

        {
            (
                address seller,
                ,
                VolatilityOracleInterface volatilityOracle,
                BondPricerInterface bondPricerForUser,
                ,
                ,

            ) = _getVsBondPool(poolID);
            require(
                bondToken.transferFrom(seller, buyer, bondAmount),
                "fail to transfer bonds"
            );

            address buyerTmp = buyer; // avoid `stack too deep` error
            uint256 amountInDollarsTmp = amountInDollars; // avoid `stack too deep` error
            require(
                _batchTransferBondFrom(
                    bondMakerForUser,
                    volatilityOracle,
                    bondPricerForUser,
                    bondIDs,
                    maturity,
                    buyerTmp,
                    seller,
                    amountInDollarsTmp
                ),
                "fail to transfer ERC20 token"
            );
        }

        uint256 volumeE8 = _applyDecimalGap(
            amountInDollars,
            DECIMALS_OF_BOND_VALUE,
            8
        );
        emit LogExchangeBondToBond(
            buyer,
            bondID,
            poolID,
            bondAmount,
            amountInDollars,
            volumeE8
        );
    }

    function _calcRateBondToUsd(bytes32 bondID, bytes32 poolID)
        internal
        returns (
            uint256 rateE8,
            uint256 bondPriceE8,
            uint256 swapPairPriceE8,
            int256 spreadE8
        )
    {
        (
            ,
            ,
            ,
            ,
            BondPricerInterface bondPricer,
            int16 feeBaseE4,

        ) = _getVsBondPool(poolID);
        (bondPriceE8, spreadE8) = _calcBondPriceAndSpread(
            bondPricer,
            bondID,
            feeBaseE4
        );
        bondPriceE8 = _calcUsdPrice(bondPriceE8);
        swapPairPriceE8 = 10**8;
        rateE8 = bondPriceE8.mul(uint256(10**8 + spreadE8)) / 10**8;
    }

    function _generateVsBondPoolID(address seller, address bondMakerForUser)
        internal
        view
        returns (bytes32 poolID)
    {
        return
            keccak256(
                abi.encode(
                    "Bond vs SBT exchange",
                    address(this),
                    seller,
                    bondMakerForUser
                )
            );
    }

    function _setVsBondPool(
        bytes32 poolID,
        address seller,
        BondMakerInterface bondMakerForUser,
        VolatilityOracleInterface volatilityOracle,
        BondPricerInterface bondPricerForUser,
        BondPricerInterface bondPricer,
        int16 feeBaseE4
    ) internal {
        require(seller != address(0), "the pool ID already exists");
        require(
            address(bondMakerForUser) != address(0),
            "bondMakerForUser should be non-zero address"
        );
        require(
            address(bondPricerForUser) != address(0),
            "bondPricerForUser should be non-zero address"
        );
        require(
            address(bondPricer) != address(0),
            "bondPricer should be non-zero address"
        );
        _assertBondMakerDecimals(bondMakerForUser);
        _vsBondPool[poolID] = VsBondPool({
            seller: seller,
            bondMakerForUser: bondMakerForUser,
            volatilityOracle: volatilityOracle,
            bondPricerForUser: bondPricerForUser,
            bondPricer: bondPricer,
            feeBaseE4: feeBaseE4
        });
    }

    function _createVsBondPool(
        address seller,
        BondMakerInterface bondMakerForUser,
        VolatilityOracleInterface volatilityOracle,
        BondPricerInterface bondPricerForUser,
        BondPricerInterface bondPricer,
        int16 feeBaseE4
    ) internal returns (bytes32 poolID) {
        poolID = _generateVsBondPoolID(seller, address(bondMakerForUser));
        require(
            _vsBondPool[poolID].seller == address(0),
            "the pool ID already exists"
        );

        _assertBondMakerDecimals(bondMakerForUser);
        _setVsBondPool(
            poolID,
            seller,
            bondMakerForUser,
            volatilityOracle,
            bondPricerForUser,
            bondPricer,
            feeBaseE4
        );

        emit LogCreateBondToBondPool(poolID, seller, address(bondMakerForUser));
        emit LogUpdateVsBondPool(
            poolID,
            address(bondPricerForUser),
            address(bondPricer),
            feeBaseE4
        );
    }

    function _updateVsBondPool(
        bytes32 poolID,
        VolatilityOracleInterface volatilityOracle,
        BondPricerInterface bondPricerForUser,
        BondPricerInterface bondPricer,
        int16 feeBaseE4
    ) internal isExsistentVsBondPool(poolID) {
        (
            address seller,
            BondMakerInterface bondMakerForUser,
            ,
            ,
            ,
            ,

        ) = _getVsBondPool(poolID);
        _setVsBondPool(
            poolID,
            seller,
            bondMakerForUser,
            volatilityOracle,
            bondPricerForUser,
            bondPricer,
            feeBaseE4
        );

        emit LogUpdateVsBondPool(
            poolID,
            address(bondPricerForUser),
            address(bondPricer),
            feeBaseE4
        );
    }

    function _deleteVsBondPool(bytes32 poolID)
        internal
        isExsistentVsBondPool(poolID)
    {
        delete _vsBondPool[poolID];

        emit LogDeleteVsBondPool(poolID);
    }

    function _getVsBondPool(bytes32 poolID)
        internal
        view
        isExsistentVsBondPool(poolID)
        returns (
            address seller,
            BondMakerInterface bondMakerForUser,
            VolatilityOracleInterface volatilityOracle,
            BondPricerInterface bondPricerForUser,
            BondPricerInterface bondPricer,
            int16 feeBaseE4,
            bool isBondSale
        )
    {
        VsBondPool memory exchangePair = _vsBondPool[poolID];
        seller = exchangePair.seller;
        bondMakerForUser = exchangePair.bondMakerForUser;
        volatilityOracle = exchangePair.volatilityOracle;
        bondPricerForUser = exchangePair.bondPricerForUser;
        bondPricer = exchangePair.bondPricer;
        feeBaseE4 = exchangePair.feeBaseE4;
        isBondSale = true;
    }

    /**
     * @dev Transfer multiple bonds in one method.
     * Unnecessary bonds can be included in bondIDs.
     */
    function _batchTransferBondFrom(
        BondMakerInterface bondMaker,
        VolatilityOracleInterface volatilityOracle,
        BondPricerInterface bondPricer,
        bytes32[] memory bondIDs,
        uint256 maturityBorder,
        address sender,
        address recipient,
        uint256 amountInDollars
    ) internal returns (bool ok) {
        uint256 oraclePriceE8 = _getLatestPrice(bondMaker.oracleAddress());

        uint256 rest = amountInDollars; // mutable
        for (uint256 i = 0; i < bondIDs.length; i++) {
            ERC20 bond;
            uint256 oracleVolE8;
            {
                uint256 maturity;
                (bond, maturity, , ) = _getBond(bondMaker, bondIDs[i]);
                if (maturity > maturityBorder) continue; // skip transaction
                uint256 untilMaturity = maturity.sub(
                    _getBlockTimestampSec(),
                    "the bond should not have expired"
                );
                oracleVolE8 = _getVolatility(
                    volatilityOracle,
                    untilMaturity.toUint64()
                );
            }

            uint256 allowance = bond.allowance(sender, address(this));
            if (allowance == 0) continue; // skip transaction

            BondMakerInterface bondMakerTmp = bondMaker; // avoid `stack too deep` error
            BondPricerInterface bondPricerTmp = bondPricer; // avoid `stack too deep` error
            bytes32 bondIDTmp = bondIDs[i]; // avoid `stack too deep` error
            uint256 bondPrice = _calcBondPrice(
                bondMakerTmp,
                bondPricerTmp,
                bondIDTmp,
                oraclePriceE8,
                oracleVolE8
            );
            if (bondPrice == 0) continue; // skip transaction

            if (rest <= allowance.mul(bondPrice)) {
                // assert(ceil(rest / bondPrice) <= allowance);
                return
                    bond.transferFrom(
                        sender,
                        recipient,
                        rest.divRoundUp(bondPrice)
                    );
            }

            require(
                bond.transferFrom(sender, recipient, allowance),
                "fail to transfer bonds"
            );
            rest -= allowance * bondPrice;
        }

        revert("insufficient bond allowance");
    }

    /**
     * @dev Returns the total approved bond amount in U.S. dollars.
     * Unnecessary bond must not be included in bondIDs.
     */
    function _totalBondAllowance(
        BondMakerInterface bondMaker,
        VolatilityOracleInterface volatilityOracle,
        BondPricerInterface bondPricer,
        bytes32[] memory bondIDs,
        uint256 maturityBorder,
        address sender
    ) internal returns (uint256 allowanceInDollars) {
        uint256 oraclePriceE8 = _getLatestPrice(bondMaker.oracleAddress());

        for (uint256 i = 0; i < bondIDs.length; i++) {
            ERC20 bond;
            uint256 oracleVolE8;
            {
                uint256 maturity;
                (bond, maturity, , ) = _getBond(bondMaker, bondIDs[i]);
                if (maturity > maturityBorder) continue; // skip
                uint256 untilMaturity = maturity.sub(
                    _getBlockTimestampSec(),
                    "the bond should not have expired"
                );
                oracleVolE8 = _getVolatility(
                    volatilityOracle,
                    untilMaturity.toUint64()
                );
            }

            uint256 balance = bond.balanceOf(sender);
            require(balance != 0, "includes no bond balance");

            uint256 allowance = bond.allowance(sender, address(this));
            require(allowance != 0, "includes no approved bond");

            uint256 bondPrice = _calcBondPrice(
                bondMaker,
                bondPricer,
                bondIDs[i],
                oraclePriceE8,
                oracleVolE8
            );
            require(bondPrice != 0, "includes worthless bond");

            allowanceInDollars = allowanceInDollars.add(
                allowance.mul(bondPrice)
            );
        }
    }

    /**
     * @dev Calculate bond price by bond ID.
     */
    function _calcBondPrice(
        BondMakerInterface bondMaker,
        BondPricerInterface bondPricer,
        bytes32 bondID,
        uint256 oraclePriceE8,
        uint256 oracleVolatilityE8
    ) internal view returns (uint256) {
        int256 untilMaturity;
        {
            (, uint256 maturity, , ) = _getBond(bondMaker, bondID);
            untilMaturity = maturity
                .sub(
                _getBlockTimestampSec(),
                "the bond should not have expired"
            )
                .toInt256();
        }

        BondType bondType;
        uint256[] memory points;
        {
            bool isKnownBondType;
            (isKnownBondType, bondType, points) = _bondShapeDetector
                .getBondTypeByID(bondMaker, bondID, BondType.NONE);
            if (!isKnownBondType) {
                revert("unknown bond type");
                // return 0;
            }
        }

        try
            bondPricer.calcPriceAndLeverage(
                bondType,
                points,
                oraclePriceE8.toInt256(),
                oracleVolatilityE8.toInt256(),
                untilMaturity
            )
        returns (uint256 bondPriceE8, uint256) {
            return bondPriceE8;
        } catch {
            return 0;
        }
    }
}

// File: contracts/generalizedDotc/GeneralizedDotc.sol

pragma solidity 0.6.6;




contract GeneralizedDotc is
    BondVsBondExchange,
    BondVsErc20Exchange,
    BondVsEthExchange
{
    constructor(
        BondMakerInterface bondMakerAddress,
        VolatilityOracleInterface volatilityOracleAddress,
        LatestPriceOracleInterface volumeCalculatorAddress,
        DetectBondShape bondShapeDetector
    )
        public
        BondExchange(
            bondMakerAddress,
            volatilityOracleAddress,
            volumeCalculatorAddress,
            bondShapeDetector
        )
    {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract BondMakerInterface","name":"bondMakerAddress","type":"address"},{"internalType":"contract VolatilityOracleInterface","name":"volatilityOracleAddress","type":"address"},{"internalType":"contract LatestPriceOracleInterface","name":"volumeCalculatorAddress","type":"address"},{"internalType":"contract DetectBondShape","name":"bondShapeDetector","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":true,"internalType":"address","name":"bondMakerForUser","type":"address"}],"name":"LogCreateBondToBondPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":true,"internalType":"address","name":"swapPairAddress","type":"address"}],"name":"LogCreateBondToErc20Pool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":true,"internalType":"address","name":"seller","type":"address"}],"name":"LogCreateBondToEthPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":true,"internalType":"address","name":"swapPairAddress","type":"address"}],"name":"LogCreateErc20ToBondPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":true,"internalType":"address","name":"seller","type":"address"}],"name":"LogCreateEthToBondPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"LogDeleteVsBondPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"LogDeleteVsErc20Pool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"LogDeleteVsEthPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"bondID","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"bondAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapPairAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"volume","type":"uint256"}],"name":"LogExchangeBondToBond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"bondID","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"bondAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapPairAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"volume","type":"uint256"}],"name":"LogExchangeBondToErc20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"bondID","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"bondAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapPairAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"volume","type":"uint256"}],"name":"LogExchangeBondToEth","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"bondID","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"bondAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapPairAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"volume","type":"uint256"}],"name":"LogExchangeErc20ToBond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"bondID","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"bondAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapPairAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"volume","type":"uint256"}],"name":"LogExchangeEthToBond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"LogTransferETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":false,"internalType":"address","name":"bondPricerForUser","type":"address"},{"indexed":false,"internalType":"address","name":"bondPricer","type":"address"},{"indexed":false,"internalType":"int16","name":"feeBase","type":"int16"}],"name":"LogUpdateVsBondPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":false,"internalType":"address","name":"swapPairOracleAddress","type":"address"},{"indexed":false,"internalType":"address","name":"bondPricerAddress","type":"address"},{"indexed":false,"internalType":"int16","name":"feeBase","type":"int16"}],"name":"LogUpdateVsErc20Pool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":false,"internalType":"address","name":"ethOracleAddress","type":"address"},{"indexed":false,"internalType":"address","name":"bondPricerAddress","type":"address"},{"indexed":false,"internalType":"int16","name":"feeBase","type":"int16"}],"name":"LogUpdateVsEthPool","type":"event"},{"inputs":[],"name":"bondMakerAddress","outputs":[{"internalType":"contract BondMakerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bondID","type":"bytes32"},{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"calcRateBondToErc20","outputs":[{"internalType":"uint256","name":"rateE8","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bondID","type":"bytes32"},{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"calcRateBondToEth","outputs":[{"internalType":"uint256","name":"rateE8","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bondID","type":"bytes32"},{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"calcRateBondToUsd","outputs":[{"internalType":"uint256","name":"rateE8","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract BondMakerInterface","name":"bondMakerForUserAddress","type":"address"},{"internalType":"contract VolatilityOracleInterface","name":"volatilityOracleAddress","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerForUserAddress","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerAddress","type":"address"},{"internalType":"int16","name":"feeBaseE4","type":"int16"}],"name":"createVsBondPool","outputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"swapPairAddress","type":"address"},{"internalType":"contract LatestPriceOracleInterface","name":"swapPairOracleAddress","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerAddress","type":"address"},{"internalType":"int16","name":"feeBaseE4","type":"int16"},{"internalType":"bool","name":"isBondSale","type":"bool"}],"name":"createVsErc20Pool","outputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract LatestPriceOracleInterface","name":"ethOracleAddress","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerAddress","type":"address"},{"internalType":"int16","name":"feeBaseE4","type":"int16"},{"internalType":"bool","name":"isBondSale","type":"bool"}],"name":"createVsEthPool","outputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"deleteVsBondPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"deleteVsErc20Pool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"deleteVsEthPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositEth","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ethAllowance","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bondID","type":"bytes32"},{"internalType":"bytes32","name":"poolID","type":"bytes32"},{"internalType":"bytes32[]","name":"bondIDs","type":"bytes32[]"},{"internalType":"uint256","name":"amountInDollarsE8","type":"uint256"},{"internalType":"uint256","name":"expectedAmount","type":"uint256"},{"internalType":"uint256","name":"range","type":"uint256"}],"name":"exchangeBondToBond","outputs":[{"internalType":"uint256","name":"bondAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bondID","type":"bytes32"},{"internalType":"bytes32","name":"poolID","type":"bytes32"},{"internalType":"uint256","name":"bondAmount","type":"uint256"},{"internalType":"uint256","name":"expectedAmount","type":"uint256"},{"internalType":"uint256","name":"range","type":"uint256"}],"name":"exchangeBondToErc20","outputs":[{"internalType":"uint256","name":"swapPairAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bondID","type":"bytes32"},{"internalType":"bytes32","name":"poolID","type":"bytes32"},{"internalType":"uint256","name":"bondAmount","type":"uint256"},{"internalType":"uint256","name":"expectedAmount","type":"uint256"},{"internalType":"uint256","name":"range","type":"uint256"}],"name":"exchangeBondToEth","outputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bondID","type":"bytes32"},{"internalType":"bytes32","name":"poolID","type":"bytes32"},{"internalType":"uint256","name":"swapPairAmount","type":"uint256"},{"internalType":"uint256","name":"expectedAmount","type":"uint256"},{"internalType":"uint256","name":"range","type":"uint256"}],"name":"exchangeErc20ToBond","outputs":[{"internalType":"uint256","name":"bondAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bondID","type":"bytes32"},{"internalType":"bytes32","name":"poolID","type":"bytes32"},{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"expectedAmount","type":"uint256"},{"internalType":"uint256","name":"range","type":"uint256"}],"name":"exchangeEthToBond","outputs":[{"internalType":"uint256","name":"bondAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"seller","type":"address"},{"internalType":"address","name":"bondMakerForUser","type":"address"}],"name":"generateVsBondPoolID","outputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"seller","type":"address"},{"internalType":"address","name":"swapPairAddress","type":"address"},{"internalType":"bool","name":"isBondSale","type":"bool"}],"name":"generateVsErc20PoolID","outputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"seller","type":"address"},{"internalType":"bool","name":"isBondSale","type":"bool"}],"name":"generateVsEthPoolID","outputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"getVsBondPool","outputs":[{"internalType":"address","name":"seller","type":"address"},{"internalType":"contract BondMakerInterface","name":"bondMakerForUserAddress","type":"address"},{"internalType":"contract VolatilityOracleInterface","name":"volatilityOracle","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerForUserAddress","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerAddress","type":"address"},{"internalType":"int16","name":"feeBaseE4","type":"int16"},{"internalType":"bool","name":"isBondSale","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"getVsErc20Pool","outputs":[{"internalType":"address","name":"seller","type":"address"},{"internalType":"contract ERC20","name":"swapPairAddress","type":"address"},{"internalType":"contract LatestPriceOracleInterface","name":"swapPairOracleAddress","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerAddress","type":"address"},{"internalType":"int16","name":"feeBaseE4","type":"int16"},{"internalType":"bool","name":"isBondSale","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"getVsEthPool","outputs":[{"internalType":"address","name":"seller","type":"address"},{"internalType":"contract LatestPriceOracleInterface","name":"ethOracleAddress","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerAddress","type":"address"},{"internalType":"int16","name":"feeBaseE4","type":"int16"},{"internalType":"bool","name":"isBondSale","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"},{"internalType":"bytes32[]","name":"bondIDs","type":"bytes32[]"},{"internalType":"uint256","name":"maturityBorder","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"totalBondAllowance","outputs":[{"internalType":"uint256","name":"allowanceInDollarsE8","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"},{"internalType":"contract VolatilityOracleInterface","name":"volatilityOracleAddress","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerForUserAddress","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerAddress","type":"address"},{"internalType":"int16","name":"feeBaseE4","type":"int16"}],"name":"updateVsBondPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"},{"internalType":"contract LatestPriceOracleInterface","name":"swapPairOracleAddress","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerAddress","type":"address"},{"internalType":"int16","name":"feeBaseE4","type":"int16"}],"name":"updateVsErc20Pool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"},{"internalType":"contract LatestPriceOracleInterface","name":"ethOracleAddress","type":"address"},{"internalType":"contract BondPricerInterface","name":"bondPricerAddress","type":"address"},{"internalType":"int16","name":"feeBaseE4","type":"int16"}],"name":"updateVsEthPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"volumeCalculatorAddress","outputs":[{"internalType":"contract LatestPriceOracleInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawEth","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101206040523480156200001257600080fd5b5060405162005f2838038062005f28833981810160405260808110156200003857600080fd5b50805160208201516040830151606090930151919290918383838362000067846001600160e01b036200012216565b836001600160a01b03166080816001600160a01b031660601b81525050836001600160a01b031663a89ae4ba6040518163ffffffff1660e01b815260040160206040518083038186803b158015620000be57600080fd5b505afa158015620000d3573d6000803e3d6000fd5b505050506040513d6020811015620000ea57600080fd5b50516001600160601b0319606091821b811660a05293811b841660c05291821b831660e052901b166101005250620002b59350505050565b600860ff16816001600160a01b031663d0d6153a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200016157600080fd5b505afa15801562000176573d6000803e3d6000fd5b505050506040513d60208110156200018d57600080fd5b505160ff1614620001ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602681526020018062005ede6026913960400191505060405180910390fd5b600860ff16816001600160a01b031663f08e2a336040518163ffffffff1660e01b815260040160206040518083038186803b1580156200022957600080fd5b505afa1580156200023e573d6000803e3d6000fd5b505050506040513d60208110156200025557600080fd5b505160ff1614620002b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602481526020018062005f046024913960400191505060405180910390fd5b50565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c615bad6200033160003980613f885280614c9c525080610aa6528061434b5250806141f45250806141c75250806109e952806111055280611ac95280611fb25280612b3a52806133585280613f575280613fb75250615bad6000f3fe6080604052600436106101c65760003560e01c80638a43a1a4116100f7578063ca6aaecb11610095578063dc10d97f11610064578063dc10d97f146108e9578063dcf288771461095d578063e64851201461098d578063faf279ea146109b757610204565b8063ca6aaecb146107c4578063ccb63b7014610809578063d23070c11461085b578063d78f308d146108a757610204565b8063a291bace116100d1578063a291bace14610671578063b6263c421461069b578063bbd114f91461072e578063bd42c7061461077057610204565b80638a43a1a4146105b857806393e492a1146105e2578063a0ef91df1461065c57610204565b8063439370b1116101645780635a6969341161013e5780635a696934146104925780635c4776c4146104d457806361a72d6d1461052057806378f286d91461056257610204565b8063439370b1146103e2578063460522f4146103ec578063488abbfc1461045757610204565b806318c681fd116101a057806318c681fd1461031c5780631b1839ab1461034c578063241d92291461036157806338360dee146103af57610204565b80630b1a3554146102095780630f48fd481461023a57806311ed6077146102e157610204565b3661020457604080513481529051309133917fdd4e7375a5084e0c4cc4e1bfc7ba67beb26a368120ea78d2e0948123910bbf7c9181900360200190a3005b600080fd5b34801561021557600080fd5b5061021e6109e7565b604080516001600160a01b039092168252519081900360200190f35b34801561024657600080fd5b506102cf600480360360c081101561025d57600080fd5b81359160208101359181019060608101604082013564010000000081111561028457600080fd5b82018360208201111561029657600080fd5b803590602001918460208302840111640100000000831117156102b857600080fd5b919350915080359060208101359060400135610a0c565b60408051918252519081900360200190f35b3480156102ed57600080fd5b506102cf6004803603604081101561030457600080fd5b506001600160a01b0381351690602001351515610a78565b34801561032857600080fd5b506102cf6004803603604081101561033f57600080fd5b5080359060200135610a8d565b34801561035857600080fd5b5061021e610aa4565b34801561036d57600080fd5b506102cf6004803603608081101561038457600080fd5b506001600160a01b038135811691602081013590911690604081013560010b90606001351515610ac8565b3480156103bb57600080fd5b506102cf600480360360208110156103d257600080fd5b50356001600160a01b0316610ae0565b6103ea610afb565b005b3480156103f857600080fd5b506104166004803603602081101561040f57600080fd5b5035610b07565b604080516001600160a01b03968716815294861660208601529290941683830152600190810b900b6060830152911515608082015290519081900360a00190f35b34801561046357600080fd5b506102cf6004803603604081101561047a57600080fd5b506001600160a01b0381358116916020013516610b2a565b34801561049e57600080fd5b506102cf600480360360a08110156104b557600080fd5b5080359060208101359060408101359060608101359060800135610b36565b3480156104e057600080fd5b506103ea600480360360808110156104f757600080fd5b508035906001600160a01b0360208201358116916040810135909116906060013560010b610b51565b34801561052c57600080fd5b506102cf600480360360a081101561054357600080fd5b5080359060208101359060408101359060608101359060800135610bce565b34801561056e57600080fd5b506102cf600480360360a081101561058557600080fd5b506001600160a01b038135811691602081013582169160408201358116916060810135909116906080013560010b610bdc565b3480156105c457600080fd5b506103ea600480360360208110156105db57600080fd5b5035610bf6565b3480156105ee57600080fd5b5061060c6004803603602081101561060557600080fd5b5035610c6d565b604080516001600160a01b039889168152968816602088015294871686860152928616606086015294166080840152600193840b90930b60a083015291151560c082015290519081900360e00190f35b34801561066857600080fd5b506102cf610c98565b34801561067d57600080fd5b506103ea6004803603602081101561069457600080fd5b5035610cb4565b3480156106a757600080fd5b506102cf600480360360808110156106be57600080fd5b813591908101906040810160208201356401000000008111156106e057600080fd5b8201836020820111156106f257600080fd5b8035906020019184602083028401116401000000008311171561071457600080fd5b9193509150803590602001356001600160a01b0316610d28565b34801561073a57600080fd5b506102cf600480360360a081101561075157600080fd5b5080359060208101359060408101359060608101359060800135610da3565b34801561077c57600080fd5b506102cf600480360360a081101561079357600080fd5b506001600160a01b038135811691602081013582169160408201351690606081013560010b90608001351515610db1565b3480156107d057600080fd5b506102cf600480360360608110156107e757600080fd5b506001600160a01b038135811691602081013590911690604001351515610dc1565b34801561081557600080fd5b506103ea600480360360a081101561082c57600080fd5b508035906001600160a01b0360208201358116916040810135821691606082013516906080013560010b610dd8565b34801561086757600080fd5b506103ea6004803603608081101561087e57600080fd5b508035906001600160a01b0360208201358116916040810135909116906060013560010b610e57565b3480156108b357600080fd5b506102cf600480360360a08110156108ca57600080fd5b5080359060208101359060408101359060608101359060800135610ece565b3480156108f557600080fd5b506109136004803603602081101561090c57600080fd5b5035610edc565b604080516001600160a01b039788168152958716602087015293861685850152919094166060840152600193840b90930b608083015291151560a082015290519081900360c00190f35b34801561096957600080fd5b506102cf6004803603604081101561098057600080fd5b5080359060200135610f02565b34801561099957600080fd5b506103ea600480360360208110156109b057600080fd5b5035610f0e565b3480156109c357600080fd5b506102cf600480360360408110156109da57600080fd5b5080359060200135610f82565b7f00000000000000000000000000000000000000000000000000000000000000005b90565b600080610a1c8560086010610f8e565b9050610a5f338a8a8a8a80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250889250611038915050565b9150610a6c8285856114f0565b50979650505050505050565b6000610a848383611567565b90505b92915050565b6000610a9983836115e1565b509195945050505050565b7f000000000000000000000000000000000000000000000000000000000000000090565b6000610ad73386868686611646565b95945050505050565b6001600160a01b031660009081526003602052604090205490565b610b053334611848565b565b6000806000806000610b18866118c0565b939a9299509097509550909350915050565b6000610a8483836119de565b6000610b4433878787611a58565b9050610ad78184846114f0565b6000848152600260205260409020546001600160a01b03163314610bbc576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610bc884848484611e5d565b50505050565b6000610b4433878787611f44565b6000610bec3387878787876122c9565b9695505050505050565b6000818152600260205260409020546001600160a01b03163314610c61576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610c6a816123f7565b50565b6000806000806000806000610c81886124f9565b959e949d50929b5090995097509550909350915050565b3360008181526003602052604090205490610a09908083612614565b6000818152600160205260409020546001600160a01b03163314610d1f576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610c6a81612628565b600080600080610d37896124f9565b505050935093509350506000610d868484848c8c808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508e92508d91506127369050565b9050610d958160106008610f8e565b9a9950505050505050505050565b6000610b4433878787612ac8565b6000610bec338787878787612ed2565b6000610dce84848461308f565b90505b9392505050565b6000858152602081905260409020546001600160a01b03163314610e43576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610e508585858585613111565b5050505050565b6000848152600160205260409020546001600160a01b03163314610ec2576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610bc8848484846131fc565b6000610b44338787876132e9565b600080600080600080610eee87613671565b949c939b5091995097509550909350915050565b6000610a9983836137a1565b6000818152602081905260409020546001600160a01b03163314610f79576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610c6a81613888565b6000610a99838361399c565b60008060008360ff168560ff161115610fad575060ff83850316610fc4565b8360ff168560ff161015610fc45784840360ff1691505b601382108015610fd45750601381105b61100f5760405162461bcd60e51b81526004018080602001828103825260258152602001806158466025913960400191505060405180910390fd5b610bec81600a0a61102c84600a0a89613a4790919063ffffffff16565b9063ffffffff613aa016565b6000825160001415611091576040805162461bcd60e51b815260206004820152601c60248201527f6d75737420696e70757420626f6e647320666f72207061796d656e7400000000604482015290519081900360640190fd5b60008061109d866124f9565b9497509395508594506110fc9350505050576040805162461bcd60e51b815260206004820152601c60248201527f5468697320706f6f6c20697320666f7220627579696e6720626f6e6400000000604482015290519081900360640190fd5b5060008061112a7f000000000000000000000000000000000000000000000000000000000000000089613ae2565b509193509150506001600160a01b03821661118c576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b600061119889896115e1565b5050509050606481116111f2576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b655af3107a4000811061124c576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f206c61726765000000000000604482015290519081900360640190fd5b806112c28760088001866001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561128e57600080fd5b505afa1580156112a2573d6000803e3d6000fd5b505050506040513d60208110156112b857600080fd5b5051600801610f8e565b816112c957fe5b049450846113085760405162461bcd60e51b8152600401808060200182810382526022815260200180615b2a6022913960400191505060405180910390fd5b5060008060006113178a6124f9565b50505093509350509250846001600160a01b03166323b872dd848e8a6040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b15801561139b57600080fd5b505af11580156113af573d6000803e3d6000fd5b505050506040513d60208110156113c557600080fd5b5051611418576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b8b8861142a8885858e8a878b88613b87565b61147b576040805162461bcd60e51b815260206004820152601c60248201527f6661696c20746f207472616e7366657220455243323020746f6b656e00000000604482015290519081900360640190fd5b5050505050600061149186600880016008610f8e565b6040805187815260208101899052808201839052905191925089918b916001600160a01b038e16917fd993461e2ed05e160d9d91ad5dddc245e8fd8606ef3b59a6a4544a6b5f438b609181900360600190a45050505095945050505050565b8115611562578161150f6103e861102c8685830163ffffffff613a4716565b1015611562576040805162461bcd60e51b815260206004820152601b60248201527f6f7574206f662065787065637465642070726963652072616e67650000000000604482015290519081900360640190fd5b505050565b6040805130818301526001600160a01b03939093166060840152901515608080840191909152602080840191909152601460a08401527f426f6e64207673204554482065786368616e676500000000000000000000000060c0808501919091528251808503909101815260e0909301909152815191012090565b6000806000806000806115f3876124f9565b509550955050505050611607828983613f4d565b90955092506116158561433c565b94506305f5e1009350836116318685830163ffffffff613a4716565b8161163857fe5b049550505092959194509250565b60006116528683611567565b6000818152600260205260409020549091506001600160a01b0316156116bf576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b6000856001600160a01b031663a3e6ba946040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156116fc57600080fd5b505af1158015611710573d6000803e3d6000fd5b505050506040513d602081101561172657600080fd5b50519050806117665760405162461bcd60e51b8152600401808060200182810382526041815260200180615a4c6041913960600191505060405180910390fd5b5061177581878787878761438a565b81156117b6576040516001600160a01b0387169082907fff21af9ef13c15bda11c8778f12d707fc45e46295475a179bfc6edaa8302cc4290600090a36117ed565b6040516001600160a01b0387169082907f7830c5d14d54770e26085fb8c75218966810a41f896d2e81a59ad6e5fd358a7390600090a35b604080516001600160a01b03808816825286166020820152600185810b900b81830152905182917fa45c688b2c8530361470c35643e00bb252b627c331f3f04491631591ac20ffe3919081900360600190a295945050505050565b6001600160a01b038216600090815260036020526040902080548201908190558111156118bc576040805162461bcd60e51b815260206004820152601260248201527f6f766572666c6f7720616c6c6f77616e63650000000000000000000000000000604482015290519081900360640190fd5b5050565b600081815260026020526040812054819081908190819086906001600160a01b0316611933576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b61193b6157b7565b5050506000948552505060026020818152604094859020855160a08101875281546001600160a01b0390811680835260018085015483169584018690529390950154908116978201889052740100000000000000000000000000000000000000008104830b830b90920b6060820181905276010000000000000000000000000000000000000000000090920460ff16151560809091018190529296919594509250565b6040805130818301526001600160a01b03938416606082015291909216608080830191909152602080830191909152601460a08301527f426f6e64207673205342542065786368616e676500000000000000000000000060c0808401919091528351808403909101815260e0909201909252805191012090565b600080600080611a6786613671565b95505050509250925080611ac2576040805162461bcd60e51b815260206004820152601c60248201527f5468697320706f6f6c20697320666f7220627579696e6720626f6e6400000000604482015290519081900360640190fd5b6000611aee7f000000000000000000000000000000000000000000000000000000000000000089613ae2565b5091925050506001600160a01b038116611b4f576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b6000806000611b5e8b8b6137a1565b50925050915060648211611bb9576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b655af3107a40008210611c13576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f206c61726765000000000000604482015290519081900360640190fd5b6000866001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015611c4e57600080fd5b505afa158015611c62573d6000803e3d6000fd5b505050506040513d6020811015611c7857600080fd5b5051905082611c898b836010610f8e565b81611c9057fe5b04985088611ccf5760405162461bcd60e51b8152600401808060200182810382526022815260200180615b2a6022913960400191505060405180910390fd5b611ce960ff8216600a0a61102c848d63ffffffff613a4716565b9350505050816001600160a01b03166323b872dd868c896040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015611d6857600080fd5b505af1158015611d7c573d6000803e3d6000fd5b505050506040513d6020811015611d9257600080fd5b5051611de5576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b611e006001600160a01b0385168b878a63ffffffff6145a216565b6040805187815260208101899052808201839052905189918b916001600160a01b038e16917ff200e0baecbcae9dad1b97ab97511a8c8aeee481b3bf835ce0157bba421ce320919081900360600190a45050505050949350505050565b60008481526002602052604090205484906001600160a01b0316611ec8576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b600080611ed4876118c0565b94505050509150611ee987838888888661438a565b604080516001600160a01b03808916825287166020820152600186810b900b81830152905188917fa45c688b2c8530361470c35643e00bb252b627c331f3f04491631591ac20ffe3919081900360600190a250505050505050565b6000806000611f52856118c0565b9450505050915080611fab576040805162461bcd60e51b815260206004820152601c60248201527f5468697320706f6f6c20697320666f7220627579696e6720626f6e6400000000604482015290519081900360640190fd5b6000611fd77f000000000000000000000000000000000000000000000000000000000000000088613ae2565b5091925050506001600160a01b038116612038576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b60008060006120478a8a61399c565b509250509150606482116120a2576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b655af3107a400082106120fc576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f206c61726765000000000000604482015290519081900360640190fd5b8161210a8960126010610f8e565b8161211157fe5b049650866121505760405162461bcd60e51b8152600401808060200182810382526022815260200180615b2a6022913960400191505060405180910390fd5b61216c670de0b6b3a764000061102c838b63ffffffff613a4716565b604080517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b0389811660048301528e81166024830152604482018b9052915192955090861693506323b872dd92506064808201926020929091908290030181600087803b1580156121e557600080fd5b505af11580156121f9573d6000803e3d6000fd5b505050506040513d602081101561220f57600080fd5b5051612262576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b61226d898588612614565b6040805186815260208101889052808201839052905188918a916001600160a01b038d16917fcc3d7a17c2ae4f2fdf5afc9e62cfb5860e4c8f4d86c9e02602223f4eebdf9637919081900360600190a450505050949350505050565b60006122d587876119de565b6000818152602081905260409020549091506001600160a01b031615612342576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b61234b8661462a565b61235a8188888888888861477c565b856001600160a01b0316876001600160a01b0316827fc123eddaddec0f57780eb14c17886c4931a5304c25284c9a4ca8de01dc33d50360405160405180910390a4604080516001600160a01b03808716825285166020820152600184810b900b81830152905182917fcc1c455a31b9815a3e0c1a2fcd096b2cccc50534bdc41a4c1dbdd3fb4b3c5afb919081900360600190a29695505050505050565b60008181526002602052604090205481906001600160a01b0316612462576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b600082815260026020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590910180547fffffffffffffffffff00000000000000000000000000000000000000000000001690555183917fba8b1b1bd3050c32112db02c33208fcc66f00fc4b1ac205e4306ff362757ca3091a25050565b60008181526020819052604081205481908190819081908190819088906001600160a01b0316612570576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b6125786157e5565b50505060009687525050506020848152604094859020855160c08101875281546001600160a01b039081168083526001808501548316958401869052600285015483169984018a905260038501548316606085018190526004909501549283166080850181905274010000000000000000000000000000000000000000909304810b810b810b60a0909401849052909994989750929550935091565b61261e83826149c9565b6115628282614a59565b60008181526001602052604090205481906001600160a01b0316612693576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b600082815260016020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255928101805484169055600281018054909316909255600390910180547fffffffffffffffffff00000000000000000000000000000000000000000000001690555183917f2a9cad2d961f676aa1003ee81f580c7b4382e3d4d186d6725acd9116c84022ac91a25050565b6000806127a6886001600160a01b031663a89ae4ba6040518163ffffffff1660e01b815260040160206040518083038186803b15801561277557600080fd5b505afa158015612789573d6000803e3d6000fd5b505050506040513d602081101561279f57600080fd5b5051614a7c565b905060005b8551811015612abc5760008060006127d68c8a86815181106127c957fe5b6020026020010151613ae2565b50919450915050878111156127ed57505050612ab4565b600061283c6127fa614aeb565b6040805180820190915260208082527f74686520626f6e642073686f756c64206e6f74206861766520657870697265649082015284919063ffffffff614aef16565b90506128508c61284b83614b86565b614bd3565b925050506000826001600160a01b03166370a08231886040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156128ac57600080fd5b505afa1580156128c0573d6000803e3d6000fd5b505050506040513d60208110156128d657600080fd5b505190508061292c576040805162461bcd60e51b815260206004820152601860248201527f696e636c75646573206e6f20626f6e642062616c616e63650000000000000000604482015290519081900360640190fd5b604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b038981166004830152306024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561299657600080fd5b505afa1580156129aa573d6000803e3d6000fd5b505050506040513d60208110156129c057600080fd5b5051905080612a16576040805162461bcd60e51b815260206004820152601960248201527f696e636c75646573206e6f20617070726f76656420626f6e6400000000000000604482015290519081900360640190fd5b6000612a388e8d8d8981518110612a2957fe5b60200260200101518a88614c6a565b905080612a8c576040805162461bcd60e51b815260206004820152601760248201527f696e636c7564657320776f7274686c65737320626f6e64000000000000000000604482015290519081900360640190fd5b612aac612a9f838363ffffffff613a4716565b899063ffffffff614f8716565b975050505050505b6001016127ab565b50509695505050505050565b600080600080612ad786613671565b9550505050925092508015612b33576040805162461bcd60e51b815260206004820181905260248201527f5468697320706f6f6c206973206e6f7420666f7220627579696e6720626f6e64604482015290519081900360640190fd5b6000612b5f7f000000000000000000000000000000000000000000000000000000000000000089613ae2565b5091925050506001600160a01b038116612bc0576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b6000806000612bcf8b8b6137a1565b50509150915060648211612c2a576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b655af3107a40008210612c84576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f206c61726765000000000000604482015290519081900360640190fd5b6000866001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612cbf57600080fd5b505afa158015612cd3573d6000803e3d6000fd5b505050506040513d6020811015612ce957600080fd5b50519050612d08612d008b8563ffffffff613a4716565b601083610f8e565b985088612d465760405162461bcd60e51b81526004018080602001828103825260238152602001806159b06023913960400191505060405180910390fd5b612d5e6305f5e10061102c848d63ffffffff613a4716565b9350505050816001600160a01b03166323b872dd8b878a6040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015612ddd57600080fd5b505af1158015612df1573d6000803e3d6000fd5b505050506040513d6020811015612e0757600080fd5b5051612e5a576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b612e756001600160a01b038516868c8963ffffffff6145a216565b6040805188815260208101889052808201839052905189918b916001600160a01b038e16917f56bdd348ec3a30de53e5accb23689b87d92f38aff2892c44a2cb656ba8987702919081900360600190a45050505050949350505050565b6000612edf87878461308f565b6000818152600160205260409020549091506001600160a01b031615612f4c576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b6000612f5786614a7c565b905080612f955760405162461bcd60e51b815260040180806020018281038252604681526020018061586b6046913960600191505060405180910390fd5b50612fa581888888888888614fe1565b8115612ff157856001600160a01b0316876001600160a01b0316827f056478b0052e7cd0f5b36aae475ed2dae889099db5f84648a9a8b29b051b90bc60405160405180910390a4613033565b856001600160a01b0316876001600160a01b0316827fa10c9970baeb202d378cccfc7b179865e64a3d92c5e75cefae0f0ae885416ed160405160405180910390a45b604080516001600160a01b03808816825286166020820152600185810b900b81830152905182917f164211b1dbb064ab8f2b34d7c1ea6d5ad1b94a2f54e104251b8833ffecaf6b2a919081900360600190a29695505050505050565b6040805130818301526001600160a01b039485166060820152929093166080830152151560a080830191909152602080830191909152601660c08301527f426f6e642076732045524332302065786368616e67650000000000000000000060e08084019190915283518084039091018152610100909201909252805191012090565b60008581526020819052604090205485906001600160a01b031661317c576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b600080613188886124f9565b5050505050915091506131a08883838a8a8a8a61477c565b604080516001600160a01b03808916825287166020820152600186810b900b81830152905189917fcc1c455a31b9815a3e0c1a2fcd096b2cccc50534bdc41a4c1dbdd3fb4b3c5afb919081900360600190a25050505050505050565b60008481526001602052604090205484906001600160a01b0316613267576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b600080600061327588613671565b95505050509250925061328d8884848a8a8a87614fe1565b604080516001600160a01b03808a16825288166020820152600187810b900b81830152905189917f164211b1dbb064ab8f2b34d7c1ea6d5ad1b94a2f54e104251b8833ffecaf6b2a919081900360600190a25050505050505050565b60008060006132f7856118c0565b945050505091508015613351576040805162461bcd60e51b815260206004820181905260248201527f5468697320706f6f6c206973206e6f7420666f7220627579696e6720626f6e64604482015290519081900360640190fd5b600061337d7f000000000000000000000000000000000000000000000000000000000000000088613ae2565b5091925050506001600160a01b0381166133de576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b60008060006133ed8a8a61399c565b50509150915060648211613448576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b655af3107a400082106134a2576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f206c61726765000000000000604482015290519081900360640190fd5b6134be6134b5898463ffffffff613a4716565b60106012610f8e565b9650866134fc5760405162461bcd60e51b81526004018080602001828103825260238152602001806159b06023913960400191505060405180910390fd5b6135146305f5e10061102c838b63ffffffff613a4716565b604080517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b038e811660048301528981166024830152604482018c9052915192955090861693506323b872dd92506064808201926020929091908290030181600087803b15801561358d57600080fd5b505af11580156135a1573d6000803e3d6000fd5b505050506040513d60208110156135b757600080fd5b505161360a576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b613615848a87612614565b6040805187815260208101879052808201839052905188918a916001600160a01b038d16917f619a69796a0814903d4d55b21b24c8dd06691f79c76317bb938c51d893e8b1fa919081900360600190a450505050949350505050565b6000818152600160205260408120548190819081908190819087906001600160a01b03166136e6576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b6136ee6157e5565b5050506000958652505060016020818152604095869020865160c08101885281546001600160a01b03908116808352838601548216948301859052600284015482169983018a905260039093015490811660608301819052740100000000000000000000000000000000000000008204860b860b90950b6080830181905276010000000000000000000000000000000000000000000090910460ff16151560a09092018290529198929796509294509250565b6000806000806000806000806137b689613671565b955095509550955050506137c984614a7c565b95506137d6838b84613f4d565b90975094506137e48761433c565b9650613824866040518060600160405280602381526020016158fb602391396138178a6305f5e10063ffffffff613a4716565b919063ffffffff61525e16565b97508015613852576305f5e1006138438987830163ffffffff613a4716565b8161384a57fe5b04975061387b565b846305f5e100016138706305f5e1008a613a4790919063ffffffff16565b8161387757fe5b0497505b5050505092959194509250565b60008181526020819052604090205481906001600160a01b03166138f3576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b60008281526020819052604080822080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811682556001820180548216905560028201805482169055600382018054909116905560040180547fffffffffffffffffffff000000000000000000000000000000000000000000001690555183917ff44bf4d5e31bd57a2b12f891c33cc0884bc44746beed2864d577e1505a28f3e291a25050565b6000806000806000806000806139b1896118c0565b9450945094509450506139c384614a7c565b95506139d0838b84613f4d565b90975094506139de8761433c565b9650613a11866040518060600160405280602381526020016158fb602391396138178a6305f5e10063ffffffff613a4716565b97508015613a30576305f5e1006138438987830163ffffffff613a4716565b6305f5e1006138708987830363ffffffff613a4716565b600082613a5657506000610a87565b82820282848281613a6357fe5b0414610a845760405162461bcd60e51b81526004018080602001828103825260218152602001806159696021913960400191505060405180910390fd5b6000610a8483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061525e565b6000806000806000866001600160a01b03166326d6c97b876040518263ffffffff1660e01b81526004018082815260200191505060806040518083038186803b158015613b2e57600080fd5b505afa158015613b42573d6000803e3d6000fd5b505050506040513d6080811015613b5857600080fd5b50805160208201516040830151606090930151919a90995067ffffffffffffffff909216975095509350505050565b600080613bc68a6001600160a01b031663a89ae4ba6040518163ffffffff1660e01b815260040160206040518083038186803b15801561277557600080fd5b90508260005b8851811015613ef3576000806000613bea8f8d86815181106127c957fe5b509194509150508a811115613c0157505050613eeb565b6000613c0e6127fa614aeb565b9050613c1d8f61284b83614b86565b604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b038e81166004830152306024830152915192955060009450908616925063dd62ed3e916044808301926020929190829003018186803b158015613c8d57600080fd5b505afa158015613ca1573d6000803e3d6000fd5b505050506040513d6020811015613cb757600080fd5b5051905080613cc857505050613eeb565b8b518f908e906000908f9088908110613cdd57fe5b602002602001015190506000613cf68484848d8a614c6a565b905080613d095750505050505050613eeb565b613d19858263ffffffff613a4716565b8911613de6576001600160a01b0387166323b872dd8f8f613d408d8663ffffffff6152c316565b6040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015613da857600080fd5b505af1158015613dbc573d6000803e3d6000fd5b505050506040513d6020811015613dd257600080fd5b50519a50613f419950505050505050505050565b866001600160a01b03166323b872dd8f8f886040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015613e6057600080fd5b505af1158015613e74573d6000803e3d6000fd5b505050506040513d6020811015613e8a57600080fd5b5051613edd576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b939093029096039550505050505b600101613bcc565b506040805162461bcd60e51b815260206004820152601b60248201527f696e73756666696369656e7420626f6e6420616c6c6f77616e63650000000000604482015290519081900360640190fd5b98975050505050505050565b6000806000613f7c7f000000000000000000000000000000000000000000000000000000000000000086613ae2565b505091505060008060607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637e91c2e37f00000000000000000000000000000000000000000000000000000000000000008a60006040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b0316815260200183815260200182600481111561401657fe5b60ff168152602001935050505060006040518083038186803b15801561403b57600080fd5b505afa15801561404f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052606081101561409657600080fd5b815160208301516040808501805191519395929483019291846401000000008211156140c157600080fd5b9083019060208201858111156140d657600080fd5b82518660208202830111640100000000821117156140f357600080fd5b82525081516020918201928201910280838360005b83811015614120578181015183820152602001614108565b505050509050016040525050509250925092508261416f5760405162461bcd60e51b8152600401808060200182810382526027815260200180615b036027913960400191505060405180910390fd5b60006141be61417c614aeb565b6040805180820190915260208082527f74686520626f6e642073686f756c64206e6f74206861766520657870697265649082015287919063ffffffff614aef16565b905060006141eb7f0000000000000000000000000000000000000000000000000000000000000000614a7c565b9050600061421c7f000000000000000000000000000000000000000000000000000000000000000061284b85614b86565b905060008c6001600160a01b031663c29d90b5878761423a876152e8565b614243876152e8565b61424c8a6152e8565b6040518663ffffffff1660e01b81526004018086600481111561426b57fe5b60ff16815260200180602001858152602001848152602001838152602001828103825286818151815260200191508051906020019060200280838360005b838110156142c15781810151838201526020016142a9565b505050509050019650505050505050604080518083038186803b1580156142e757600080fd5b505afa1580156142fb573d6000803e3d6000fd5b505050506040513d604081101561431157600080fd5b508051602090910151909a50905061432a82828d615348565b98505050505050505050935093915050565b60006305f5e10061437c61436f7f0000000000000000000000000000000000000000000000000000000000000000614a7c565b849063ffffffff613a4716565b8161438357fe5b0492915050565b6001600160a01b0385166143e5576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b6001600160a01b03841661442a5760405162461bcd60e51b81526004018080602001828103825260248152602001806159fc6024913960400191505060405180910390fd5b6001600160a01b03831661446f5760405162461bcd60e51b81526004018080602001828103825260258152602001806159446025913960400191505060405180910390fd5b6040805160a0810182526001600160a01b0396871681529486166020808701918252948716868301908152600194850b60608801908152931515608088019081526000998a5260029687905292909820955186549088167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216178755905186850180549189169183169190911790559651949093018054915193511515760100000000000000000000000000000000000000000000027fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff9490930b61ffff1674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff959096169190961617929092169290921791909116179055565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052610bc89085906153e5565b600860ff16816001600160a01b031663d0d6153a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561466857600080fd5b505afa15801561467c573d6000803e3d6000fd5b505050506040513d602081101561469257600080fd5b505160ff16146146d35760405162461bcd60e51b815260040180806020018281038252602681526020018061591e6026913960400191505060405180910390fd5b600860ff16816001600160a01b031663f08e2a336040518163ffffffff1660e01b815260040160206040518083038186803b15801561471157600080fd5b505afa158015614725573d6000803e3d6000fd5b505050506040513d602081101561473b57600080fd5b505160ff1614610c6a5760405162461bcd60e51b8152600401808060200182810382526024815260200180615adf6024913960400191505060405180910390fd5b6001600160a01b0386166147d7576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b6001600160a01b03851661481c5760405162461bcd60e51b815260040180806020018281038252602b81526020018061581b602b913960400191505060405180910390fd5b6001600160a01b0383166148615760405162461bcd60e51b815260040180806020018281038252602c815260200180615b4c602c913960400191505060405180910390fd5b6001600160a01b0382166148a65760405162461bcd60e51b81526004018080602001828103825260258152602001806159446025913960400191505060405180910390fd5b6148af8561462a565b6040805160c0810182526001600160a01b03978816815295871660208088019182529588168783019081529488166060880190815293881660808801908152600193840b60a0890190815260009a8b52968a905291909820955186549088167fffffffffffffffffffffffff000000000000000000000000000000000000000091821617875597518683018054918916918a1691909117905592516002860180549188169189169190911790559051600385018054918716918816919091179055905160049093018054925190910b61ffff1674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff93909416919094161716179055565b6001600160a01b038216600090815260036020526040902054811115614a36576040805162461bcd60e51b815260206004820152601660248201527f696e73756666696369656e7420616c6c6f77616e636500000000000000000000604482015290519081900360640190fd5b6001600160a01b0390911660009081526003602052604090208054919091039055565b6118bc82826040518060600160405280602c8152602001615a20602c91396155bb565b6000816001600160a01b031663a3e6ba946040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614ab957600080fd5b505af1158015614acd573d6000803e3d6000fd5b505050506040513d6020811015614ae357600080fd5b505192915050565b4290565b60008184841115614b7e5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614b43578181015183820152602001614b2b565b50505050905090810190601f168015614b705780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000680100000000000000008210614bcf5760405162461bcd60e51b815260040180806020018281038252602681526020018061598a6026913960400191505060405180910390fd5b5090565b6000826001600160a01b031663c8f3e555836040518263ffffffff1660e01b8152600401808267ffffffffffffffff1667ffffffffffffffff16815260200191505060206040518083038186803b158015614c2d57600080fd5b505afa158015614c41573d6000803e3d6000fd5b505050506040513d6020811015614c5757600080fd5b505167ffffffffffffffff169392505050565b6000806000614c798887613ae2565b5050915050614c91614c8c6127fa614aeb565b6152e8565b9150506000606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637e91c2e38b8a60006040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001838152602001826004811115614d0a57fe5b60ff168152602001935050505060006040518083038186803b158015614d2f57600080fd5b505afa158015614d43573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526060811015614d8a57600080fd5b81516020830151604080850180519151939592948301929184640100000000821115614db557600080fd5b908301906020820185811115614dca57600080fd5b8251866020820283011164010000000082111715614de757600080fd5b82525081516020918201928201910280838360005b83811015614e14578181015183820152602001614dfc565b5050505090500160405250505080945081955082935050505080614e7f576040805162461bcd60e51b815260206004820152601160248201527f756e6b6e6f776e20626f6e642074797065000000000000000000000000000000604482015290519081900360640190fd5b50876001600160a01b031663c29d90b58383614e9a8a6152e8565b614ea38a6152e8565b886040518663ffffffff1660e01b815260040180866004811115614ec357fe5b60ff16815260200180602001858152602001848152602001838152602001828103825286818151815260200191508051906020019060200280838360005b83811015614f19578181015183820152602001614f01565b505050509050019650505050505050604080518083038186803b158015614f3f57600080fd5b505afa925050508015614f6b57506040513d6040811015614f5f57600080fd5b50805160209091015160015b614f7b5760009350505050610ad7565b509350610ad792505050565b600082820183811015610a84576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6001600160a01b03861661503c576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b6001600160a01b0385166150815760405162461bcd60e51b81526004018080602001828103825260288152602001806158b16028913960400191505060405180910390fd5b6001600160a01b0384166150c65760405162461bcd60e51b81526004018080602001828103825260298152602001806159d36029913960400191505060405180910390fd5b6001600160a01b03831661510b5760405162461bcd60e51b81526004018080602001828103825260258152602001806159446025913960400191505060405180910390fd5b6040805160c0810182526001600160a01b039788168152958716602080880191825295881687830190815294881660608801908152600194850b6080890190815293151560a0890190815260009a8b529685905291909820955186549088167fffffffffffffffffffffffff000000000000000000000000000000000000000091821617875597518684018054918916918a169190911790559251600286018054918816918916919091179055915160039094018054925193511515760100000000000000000000000000000000000000000000027fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff9490920b61ffff1674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff959096169290961691909117929092169290921791909116179055565b600081836152ad5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315614b43578181015183820152602001614b2b565b5060008385816152b957fe5b0495945050505050565b6000610a8483836040518060600160405280602281526020016158d9602291396156fe565b60007f80000000000000000000000000000000000000000000000000000000000000008210614bcf5760405162461bcd60e51b8152600401808060200182810382526028815260200180615a8d6028913960400191505060405180910390fd5b6000806305f5e100851061537257630bebc2008511615367578461536d565b630bebc2005b615378565b6305f5e1005b905083810264e8d4a510006153b66000600187900b128061539f5750662386f26fc1000083105b6153a95782614c8c565b662386f26fc100006152e8565b8560010b02816153c257fe5b0592506305f5e10083136153d65782610bec565b6305f5e1009695505050505050565b6153f7826001600160a01b0316615774565b615448576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106154a457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101615467565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114615506576040519150601f19603f3d011682016040523d82523d6000602084013e61550b565b606091505b509150915081615562576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115610bc85780806020019051602081101561557e57600080fd5b5051610bc85760405162461bcd60e51b815260040180806020018281038252602a815260200180615ab5602a913960400191505060405180910390fd5b6155c4826157b0565b81906156115760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315614b43578181015183820152602001614b2b565b506040516000906001600160a01b0385169084908381818185875af1925050503d806000811461565d576040519150601f19603f3d011682016040523d82523d6000602084013e615662565b606091505b50509050806156b8576040805162461bcd60e51b815260206004820152601960248201527f7472616e7366657272696e67204574686572206661696c656400000000000000604482015290519081900360640190fd5b6040805184815290516001600160a01b0386169130917fdd4e7375a5084e0c4cc4e1bfc7ba67beb26a368120ea78d2e0948123910bbf7c9181900360200190a350505050565b60008361570d57506000610dd1565b818361575a5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315614b43578181015183820152602001614b2b565b5082600185038161576757fe5b0460010190509392505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906157a857508115155b949350505050565b3031101590565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091529056fe626f6e644d616b6572466f72557365722073686f756c64206265206e6f6e2d7a65726f2061646472657373646563696d616c20676170206e6565647320746f206265206c6f776572207468616e20313973776170506169724f7261636c6520686173206c6174657374507269636528292066756e6374696f6e2077686963682072657475726e73206e6f6e2d7a65726f2076616c75657377617050616972546f6b656e2073686f756c64206265206e6f6e2d7a65726f2061646472657373536166654d617468446976526f756e6455703a206d6f64756c6f206279207a65726f4552433230206f7261636c65207072696365206d757374206265206e6f6e2d7a65726f74686520646563696d616c73206f66206f7261636c65207072696365206d7573742062652038626f6e645072696365722073686f756c64206265206e6f6e2d7a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7753616665436173743a2076616c756520646f65736e27742066697420696e20363420626974736d757374207472616e73666572206e6f6e2d7a65726f20746f6b656e20616d6f756e7473776170506169724f7261636c652073686f756c64206265206e6f6e2d7a65726f20616464726573736574684f7261636c652073686f756c64206265206e6f6e2d7a65726f20616464726573735472616e736665724554483a207472616e7366657220616d6f756e7420657863656564732062616c616e63656574684f7261636c6520686173206c6174657374507269636528292066756e6374696f6e2077686963682072657475726e73206e6f6e2d7a65726f2076616c756553616665436173743a2076616c756520646f65736e27742066697420696e20616e20696e743235365361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656474686520646563696d616c73206f6620626f6e6420746f6b656e206d757374206265203863616e6e6f742063616c63756c61746520746865207072696365206f66207468697320626f6e646d757374207472616e73666572206e6f6e2d7a65726f20626f6e6420616d6f756e74626f6e64507269636572466f72557365722073686f756c64206265206e6f6e2d7a65726f2061646472657373a26469706673582212207d46b6e6ab3d17a7a0bf149999e36885cb46e29bb984f9b0fb8158d023d86fd164736f6c6343000606003374686520646563696d616c73206f66206f7261636c65207072696365206d757374206265203874686520646563696d616c73206f6620626f6e6420746f6b656e206d7573742062652038000000000000000000000000da6fc5625e617bb92f5359921d43321cebc6bef0000000000000000000000000c8bbb8d57cebf834dc429ec4d65dd23ed0d65a87000000000000000000000000ad491f460d8ee6df3335e8af48de33e0468cd8c9000000000000000000000000a0d773221ca923fb48a0cf1b8309496d198cbfa1

Deployed Bytecode

0x6080604052600436106101c65760003560e01c80638a43a1a4116100f7578063ca6aaecb11610095578063dc10d97f11610064578063dc10d97f146108e9578063dcf288771461095d578063e64851201461098d578063faf279ea146109b757610204565b8063ca6aaecb146107c4578063ccb63b7014610809578063d23070c11461085b578063d78f308d146108a757610204565b8063a291bace116100d1578063a291bace14610671578063b6263c421461069b578063bbd114f91461072e578063bd42c7061461077057610204565b80638a43a1a4146105b857806393e492a1146105e2578063a0ef91df1461065c57610204565b8063439370b1116101645780635a6969341161013e5780635a696934146104925780635c4776c4146104d457806361a72d6d1461052057806378f286d91461056257610204565b8063439370b1146103e2578063460522f4146103ec578063488abbfc1461045757610204565b806318c681fd116101a057806318c681fd1461031c5780631b1839ab1461034c578063241d92291461036157806338360dee146103af57610204565b80630b1a3554146102095780630f48fd481461023a57806311ed6077146102e157610204565b3661020457604080513481529051309133917fdd4e7375a5084e0c4cc4e1bfc7ba67beb26a368120ea78d2e0948123910bbf7c9181900360200190a3005b600080fd5b34801561021557600080fd5b5061021e6109e7565b604080516001600160a01b039092168252519081900360200190f35b34801561024657600080fd5b506102cf600480360360c081101561025d57600080fd5b81359160208101359181019060608101604082013564010000000081111561028457600080fd5b82018360208201111561029657600080fd5b803590602001918460208302840111640100000000831117156102b857600080fd5b919350915080359060208101359060400135610a0c565b60408051918252519081900360200190f35b3480156102ed57600080fd5b506102cf6004803603604081101561030457600080fd5b506001600160a01b0381351690602001351515610a78565b34801561032857600080fd5b506102cf6004803603604081101561033f57600080fd5b5080359060200135610a8d565b34801561035857600080fd5b5061021e610aa4565b34801561036d57600080fd5b506102cf6004803603608081101561038457600080fd5b506001600160a01b038135811691602081013590911690604081013560010b90606001351515610ac8565b3480156103bb57600080fd5b506102cf600480360360208110156103d257600080fd5b50356001600160a01b0316610ae0565b6103ea610afb565b005b3480156103f857600080fd5b506104166004803603602081101561040f57600080fd5b5035610b07565b604080516001600160a01b03968716815294861660208601529290941683830152600190810b900b6060830152911515608082015290519081900360a00190f35b34801561046357600080fd5b506102cf6004803603604081101561047a57600080fd5b506001600160a01b0381358116916020013516610b2a565b34801561049e57600080fd5b506102cf600480360360a08110156104b557600080fd5b5080359060208101359060408101359060608101359060800135610b36565b3480156104e057600080fd5b506103ea600480360360808110156104f757600080fd5b508035906001600160a01b0360208201358116916040810135909116906060013560010b610b51565b34801561052c57600080fd5b506102cf600480360360a081101561054357600080fd5b5080359060208101359060408101359060608101359060800135610bce565b34801561056e57600080fd5b506102cf600480360360a081101561058557600080fd5b506001600160a01b038135811691602081013582169160408201358116916060810135909116906080013560010b610bdc565b3480156105c457600080fd5b506103ea600480360360208110156105db57600080fd5b5035610bf6565b3480156105ee57600080fd5b5061060c6004803603602081101561060557600080fd5b5035610c6d565b604080516001600160a01b039889168152968816602088015294871686860152928616606086015294166080840152600193840b90930b60a083015291151560c082015290519081900360e00190f35b34801561066857600080fd5b506102cf610c98565b34801561067d57600080fd5b506103ea6004803603602081101561069457600080fd5b5035610cb4565b3480156106a757600080fd5b506102cf600480360360808110156106be57600080fd5b813591908101906040810160208201356401000000008111156106e057600080fd5b8201836020820111156106f257600080fd5b8035906020019184602083028401116401000000008311171561071457600080fd5b9193509150803590602001356001600160a01b0316610d28565b34801561073a57600080fd5b506102cf600480360360a081101561075157600080fd5b5080359060208101359060408101359060608101359060800135610da3565b34801561077c57600080fd5b506102cf600480360360a081101561079357600080fd5b506001600160a01b038135811691602081013582169160408201351690606081013560010b90608001351515610db1565b3480156107d057600080fd5b506102cf600480360360608110156107e757600080fd5b506001600160a01b038135811691602081013590911690604001351515610dc1565b34801561081557600080fd5b506103ea600480360360a081101561082c57600080fd5b508035906001600160a01b0360208201358116916040810135821691606082013516906080013560010b610dd8565b34801561086757600080fd5b506103ea6004803603608081101561087e57600080fd5b508035906001600160a01b0360208201358116916040810135909116906060013560010b610e57565b3480156108b357600080fd5b506102cf600480360360a08110156108ca57600080fd5b5080359060208101359060408101359060608101359060800135610ece565b3480156108f557600080fd5b506109136004803603602081101561090c57600080fd5b5035610edc565b604080516001600160a01b039788168152958716602087015293861685850152919094166060840152600193840b90930b608083015291151560a082015290519081900360c00190f35b34801561096957600080fd5b506102cf6004803603604081101561098057600080fd5b5080359060200135610f02565b34801561099957600080fd5b506103ea600480360360208110156109b057600080fd5b5035610f0e565b3480156109c357600080fd5b506102cf600480360360408110156109da57600080fd5b5080359060200135610f82565b7f000000000000000000000000da6fc5625e617bb92f5359921d43321cebc6bef05b90565b600080610a1c8560086010610f8e565b9050610a5f338a8a8a8a80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250889250611038915050565b9150610a6c8285856114f0565b50979650505050505050565b6000610a848383611567565b90505b92915050565b6000610a9983836115e1565b509195945050505050565b7f000000000000000000000000ad491f460d8ee6df3335e8af48de33e0468cd8c990565b6000610ad73386868686611646565b95945050505050565b6001600160a01b031660009081526003602052604090205490565b610b053334611848565b565b6000806000806000610b18866118c0565b939a9299509097509550909350915050565b6000610a8483836119de565b6000610b4433878787611a58565b9050610ad78184846114f0565b6000848152600260205260409020546001600160a01b03163314610bbc576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610bc884848484611e5d565b50505050565b6000610b4433878787611f44565b6000610bec3387878787876122c9565b9695505050505050565b6000818152600260205260409020546001600160a01b03163314610c61576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610c6a816123f7565b50565b6000806000806000806000610c81886124f9565b959e949d50929b5090995097509550909350915050565b3360008181526003602052604090205490610a09908083612614565b6000818152600160205260409020546001600160a01b03163314610d1f576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610c6a81612628565b600080600080610d37896124f9565b505050935093509350506000610d868484848c8c808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508e92508d91506127369050565b9050610d958160106008610f8e565b9a9950505050505050505050565b6000610b4433878787612ac8565b6000610bec338787878787612ed2565b6000610dce84848461308f565b90505b9392505050565b6000858152602081905260409020546001600160a01b03163314610e43576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610e508585858585613111565b5050505050565b6000848152600160205260409020546001600160a01b03163314610ec2576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610bc8848484846131fc565b6000610b44338787876132e9565b600080600080600080610eee87613671565b949c939b5091995097509550909350915050565b6000610a9983836137a1565b6000818152602081905260409020546001600160a01b03163314610f79576040805162461bcd60e51b815260206004820152601c60248201527f6e6f7420746865206f776e6572206f662074686520706f6f6c20494400000000604482015290519081900360640190fd5b610c6a81613888565b6000610a99838361399c565b60008060008360ff168560ff161115610fad575060ff83850316610fc4565b8360ff168560ff161015610fc45784840360ff1691505b601382108015610fd45750601381105b61100f5760405162461bcd60e51b81526004018080602001828103825260258152602001806158466025913960400191505060405180910390fd5b610bec81600a0a61102c84600a0a89613a4790919063ffffffff16565b9063ffffffff613aa016565b6000825160001415611091576040805162461bcd60e51b815260206004820152601c60248201527f6d75737420696e70757420626f6e647320666f72207061796d656e7400000000604482015290519081900360640190fd5b60008061109d866124f9565b9497509395508594506110fc9350505050576040805162461bcd60e51b815260206004820152601c60248201527f5468697320706f6f6c20697320666f7220627579696e6720626f6e6400000000604482015290519081900360640190fd5b5060008061112a7f000000000000000000000000da6fc5625e617bb92f5359921d43321cebc6bef089613ae2565b509193509150506001600160a01b03821661118c576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b600061119889896115e1565b5050509050606481116111f2576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b655af3107a4000811061124c576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f206c61726765000000000000604482015290519081900360640190fd5b806112c28760088001866001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561128e57600080fd5b505afa1580156112a2573d6000803e3d6000fd5b505050506040513d60208110156112b857600080fd5b5051600801610f8e565b816112c957fe5b049450846113085760405162461bcd60e51b8152600401808060200182810382526022815260200180615b2a6022913960400191505060405180910390fd5b5060008060006113178a6124f9565b50505093509350509250846001600160a01b03166323b872dd848e8a6040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b15801561139b57600080fd5b505af11580156113af573d6000803e3d6000fd5b505050506040513d60208110156113c557600080fd5b5051611418576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b8b8861142a8885858e8a878b88613b87565b61147b576040805162461bcd60e51b815260206004820152601c60248201527f6661696c20746f207472616e7366657220455243323020746f6b656e00000000604482015290519081900360640190fd5b5050505050600061149186600880016008610f8e565b6040805187815260208101899052808201839052905191925089918b916001600160a01b038e16917fd993461e2ed05e160d9d91ad5dddc245e8fd8606ef3b59a6a4544a6b5f438b609181900360600190a45050505095945050505050565b8115611562578161150f6103e861102c8685830163ffffffff613a4716565b1015611562576040805162461bcd60e51b815260206004820152601b60248201527f6f7574206f662065787065637465642070726963652072616e67650000000000604482015290519081900360640190fd5b505050565b6040805130818301526001600160a01b03939093166060840152901515608080840191909152602080840191909152601460a08401527f426f6e64207673204554482065786368616e676500000000000000000000000060c0808501919091528251808503909101815260e0909301909152815191012090565b6000806000806000806115f3876124f9565b509550955050505050611607828983613f4d565b90955092506116158561433c565b94506305f5e1009350836116318685830163ffffffff613a4716565b8161163857fe5b049550505092959194509250565b60006116528683611567565b6000818152600260205260409020549091506001600160a01b0316156116bf576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b6000856001600160a01b031663a3e6ba946040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156116fc57600080fd5b505af1158015611710573d6000803e3d6000fd5b505050506040513d602081101561172657600080fd5b50519050806117665760405162461bcd60e51b8152600401808060200182810382526041815260200180615a4c6041913960600191505060405180910390fd5b5061177581878787878761438a565b81156117b6576040516001600160a01b0387169082907fff21af9ef13c15bda11c8778f12d707fc45e46295475a179bfc6edaa8302cc4290600090a36117ed565b6040516001600160a01b0387169082907f7830c5d14d54770e26085fb8c75218966810a41f896d2e81a59ad6e5fd358a7390600090a35b604080516001600160a01b03808816825286166020820152600185810b900b81830152905182917fa45c688b2c8530361470c35643e00bb252b627c331f3f04491631591ac20ffe3919081900360600190a295945050505050565b6001600160a01b038216600090815260036020526040902080548201908190558111156118bc576040805162461bcd60e51b815260206004820152601260248201527f6f766572666c6f7720616c6c6f77616e63650000000000000000000000000000604482015290519081900360640190fd5b5050565b600081815260026020526040812054819081908190819086906001600160a01b0316611933576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b61193b6157b7565b5050506000948552505060026020818152604094859020855160a08101875281546001600160a01b0390811680835260018085015483169584018690529390950154908116978201889052740100000000000000000000000000000000000000008104830b830b90920b6060820181905276010000000000000000000000000000000000000000000090920460ff16151560809091018190529296919594509250565b6040805130818301526001600160a01b03938416606082015291909216608080830191909152602080830191909152601460a08301527f426f6e64207673205342542065786368616e676500000000000000000000000060c0808401919091528351808403909101815260e0909201909252805191012090565b600080600080611a6786613671565b95505050509250925080611ac2576040805162461bcd60e51b815260206004820152601c60248201527f5468697320706f6f6c20697320666f7220627579696e6720626f6e6400000000604482015290519081900360640190fd5b6000611aee7f000000000000000000000000da6fc5625e617bb92f5359921d43321cebc6bef089613ae2565b5091925050506001600160a01b038116611b4f576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b6000806000611b5e8b8b6137a1565b50925050915060648211611bb9576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b655af3107a40008210611c13576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f206c61726765000000000000604482015290519081900360640190fd5b6000866001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015611c4e57600080fd5b505afa158015611c62573d6000803e3d6000fd5b505050506040513d6020811015611c7857600080fd5b5051905082611c898b836010610f8e565b81611c9057fe5b04985088611ccf5760405162461bcd60e51b8152600401808060200182810382526022815260200180615b2a6022913960400191505060405180910390fd5b611ce960ff8216600a0a61102c848d63ffffffff613a4716565b9350505050816001600160a01b03166323b872dd868c896040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015611d6857600080fd5b505af1158015611d7c573d6000803e3d6000fd5b505050506040513d6020811015611d9257600080fd5b5051611de5576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b611e006001600160a01b0385168b878a63ffffffff6145a216565b6040805187815260208101899052808201839052905189918b916001600160a01b038e16917ff200e0baecbcae9dad1b97ab97511a8c8aeee481b3bf835ce0157bba421ce320919081900360600190a45050505050949350505050565b60008481526002602052604090205484906001600160a01b0316611ec8576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b600080611ed4876118c0565b94505050509150611ee987838888888661438a565b604080516001600160a01b03808916825287166020820152600186810b900b81830152905188917fa45c688b2c8530361470c35643e00bb252b627c331f3f04491631591ac20ffe3919081900360600190a250505050505050565b6000806000611f52856118c0565b9450505050915080611fab576040805162461bcd60e51b815260206004820152601c60248201527f5468697320706f6f6c20697320666f7220627579696e6720626f6e6400000000604482015290519081900360640190fd5b6000611fd77f000000000000000000000000da6fc5625e617bb92f5359921d43321cebc6bef088613ae2565b5091925050506001600160a01b038116612038576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b60008060006120478a8a61399c565b509250509150606482116120a2576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b655af3107a400082106120fc576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f206c61726765000000000000604482015290519081900360640190fd5b8161210a8960126010610f8e565b8161211157fe5b049650866121505760405162461bcd60e51b8152600401808060200182810382526022815260200180615b2a6022913960400191505060405180910390fd5b61216c670de0b6b3a764000061102c838b63ffffffff613a4716565b604080517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b0389811660048301528e81166024830152604482018b9052915192955090861693506323b872dd92506064808201926020929091908290030181600087803b1580156121e557600080fd5b505af11580156121f9573d6000803e3d6000fd5b505050506040513d602081101561220f57600080fd5b5051612262576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b61226d898588612614565b6040805186815260208101889052808201839052905188918a916001600160a01b038d16917fcc3d7a17c2ae4f2fdf5afc9e62cfb5860e4c8f4d86c9e02602223f4eebdf9637919081900360600190a450505050949350505050565b60006122d587876119de565b6000818152602081905260409020549091506001600160a01b031615612342576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b61234b8661462a565b61235a8188888888888861477c565b856001600160a01b0316876001600160a01b0316827fc123eddaddec0f57780eb14c17886c4931a5304c25284c9a4ca8de01dc33d50360405160405180910390a4604080516001600160a01b03808716825285166020820152600184810b900b81830152905182917fcc1c455a31b9815a3e0c1a2fcd096b2cccc50534bdc41a4c1dbdd3fb4b3c5afb919081900360600190a29695505050505050565b60008181526002602052604090205481906001600160a01b0316612462576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b600082815260026020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590910180547fffffffffffffffffff00000000000000000000000000000000000000000000001690555183917fba8b1b1bd3050c32112db02c33208fcc66f00fc4b1ac205e4306ff362757ca3091a25050565b60008181526020819052604081205481908190819081908190819088906001600160a01b0316612570576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b6125786157e5565b50505060009687525050506020848152604094859020855160c08101875281546001600160a01b039081168083526001808501548316958401869052600285015483169984018a905260038501548316606085018190526004909501549283166080850181905274010000000000000000000000000000000000000000909304810b810b810b60a0909401849052909994989750929550935091565b61261e83826149c9565b6115628282614a59565b60008181526001602052604090205481906001600160a01b0316612693576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b600082815260016020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255928101805484169055600281018054909316909255600390910180547fffffffffffffffffff00000000000000000000000000000000000000000000001690555183917f2a9cad2d961f676aa1003ee81f580c7b4382e3d4d186d6725acd9116c84022ac91a25050565b6000806127a6886001600160a01b031663a89ae4ba6040518163ffffffff1660e01b815260040160206040518083038186803b15801561277557600080fd5b505afa158015612789573d6000803e3d6000fd5b505050506040513d602081101561279f57600080fd5b5051614a7c565b905060005b8551811015612abc5760008060006127d68c8a86815181106127c957fe5b6020026020010151613ae2565b50919450915050878111156127ed57505050612ab4565b600061283c6127fa614aeb565b6040805180820190915260208082527f74686520626f6e642073686f756c64206e6f74206861766520657870697265649082015284919063ffffffff614aef16565b90506128508c61284b83614b86565b614bd3565b925050506000826001600160a01b03166370a08231886040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156128ac57600080fd5b505afa1580156128c0573d6000803e3d6000fd5b505050506040513d60208110156128d657600080fd5b505190508061292c576040805162461bcd60e51b815260206004820152601860248201527f696e636c75646573206e6f20626f6e642062616c616e63650000000000000000604482015290519081900360640190fd5b604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b038981166004830152306024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561299657600080fd5b505afa1580156129aa573d6000803e3d6000fd5b505050506040513d60208110156129c057600080fd5b5051905080612a16576040805162461bcd60e51b815260206004820152601960248201527f696e636c75646573206e6f20617070726f76656420626f6e6400000000000000604482015290519081900360640190fd5b6000612a388e8d8d8981518110612a2957fe5b60200260200101518a88614c6a565b905080612a8c576040805162461bcd60e51b815260206004820152601760248201527f696e636c7564657320776f7274686c65737320626f6e64000000000000000000604482015290519081900360640190fd5b612aac612a9f838363ffffffff613a4716565b899063ffffffff614f8716565b975050505050505b6001016127ab565b50509695505050505050565b600080600080612ad786613671565b9550505050925092508015612b33576040805162461bcd60e51b815260206004820181905260248201527f5468697320706f6f6c206973206e6f7420666f7220627579696e6720626f6e64604482015290519081900360640190fd5b6000612b5f7f000000000000000000000000da6fc5625e617bb92f5359921d43321cebc6bef089613ae2565b5091925050506001600160a01b038116612bc0576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b6000806000612bcf8b8b6137a1565b50509150915060648211612c2a576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b655af3107a40008210612c84576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f206c61726765000000000000604482015290519081900360640190fd5b6000866001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612cbf57600080fd5b505afa158015612cd3573d6000803e3d6000fd5b505050506040513d6020811015612ce957600080fd5b50519050612d08612d008b8563ffffffff613a4716565b601083610f8e565b985088612d465760405162461bcd60e51b81526004018080602001828103825260238152602001806159b06023913960400191505060405180910390fd5b612d5e6305f5e10061102c848d63ffffffff613a4716565b9350505050816001600160a01b03166323b872dd8b878a6040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015612ddd57600080fd5b505af1158015612df1573d6000803e3d6000fd5b505050506040513d6020811015612e0757600080fd5b5051612e5a576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b612e756001600160a01b038516868c8963ffffffff6145a216565b6040805188815260208101889052808201839052905189918b916001600160a01b038e16917f56bdd348ec3a30de53e5accb23689b87d92f38aff2892c44a2cb656ba8987702919081900360600190a45050505050949350505050565b6000612edf87878461308f565b6000818152600160205260409020549091506001600160a01b031615612f4c576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b6000612f5786614a7c565b905080612f955760405162461bcd60e51b815260040180806020018281038252604681526020018061586b6046913960600191505060405180910390fd5b50612fa581888888888888614fe1565b8115612ff157856001600160a01b0316876001600160a01b0316827f056478b0052e7cd0f5b36aae475ed2dae889099db5f84648a9a8b29b051b90bc60405160405180910390a4613033565b856001600160a01b0316876001600160a01b0316827fa10c9970baeb202d378cccfc7b179865e64a3d92c5e75cefae0f0ae885416ed160405160405180910390a45b604080516001600160a01b03808816825286166020820152600185810b900b81830152905182917f164211b1dbb064ab8f2b34d7c1ea6d5ad1b94a2f54e104251b8833ffecaf6b2a919081900360600190a29695505050505050565b6040805130818301526001600160a01b039485166060820152929093166080830152151560a080830191909152602080830191909152601660c08301527f426f6e642076732045524332302065786368616e67650000000000000000000060e08084019190915283518084039091018152610100909201909252805191012090565b60008581526020819052604090205485906001600160a01b031661317c576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b600080613188886124f9565b5050505050915091506131a08883838a8a8a8a61477c565b604080516001600160a01b03808916825287166020820152600186810b900b81830152905189917fcc1c455a31b9815a3e0c1a2fcd096b2cccc50534bdc41a4c1dbdd3fb4b3c5afb919081900360600190a25050505050505050565b60008481526001602052604090205484906001600160a01b0316613267576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b600080600061327588613671565b95505050509250925061328d8884848a8a8a87614fe1565b604080516001600160a01b03808a16825288166020820152600187810b900b81830152905189917f164211b1dbb064ab8f2b34d7c1ea6d5ad1b94a2f54e104251b8833ffecaf6b2a919081900360600190a25050505050505050565b60008060006132f7856118c0565b945050505091508015613351576040805162461bcd60e51b815260206004820181905260248201527f5468697320706f6f6c206973206e6f7420666f7220627579696e6720626f6e64604482015290519081900360640190fd5b600061337d7f000000000000000000000000da6fc5625e617bb92f5359921d43321cebc6bef088613ae2565b5091925050506001600160a01b0381166133de576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b60008060006133ed8a8a61399c565b50509150915060648211613448576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b655af3107a400082106134a2576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f206c61726765000000000000604482015290519081900360640190fd5b6134be6134b5898463ffffffff613a4716565b60106012610f8e565b9650866134fc5760405162461bcd60e51b81526004018080602001828103825260238152602001806159b06023913960400191505060405180910390fd5b6135146305f5e10061102c838b63ffffffff613a4716565b604080517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b038e811660048301528981166024830152604482018c9052915192955090861693506323b872dd92506064808201926020929091908290030181600087803b15801561358d57600080fd5b505af11580156135a1573d6000803e3d6000fd5b505050506040513d60208110156135b757600080fd5b505161360a576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b613615848a87612614565b6040805187815260208101879052808201839052905188918a916001600160a01b038d16917f619a69796a0814903d4d55b21b24c8dd06691f79c76317bb938c51d893e8b1fa919081900360600190a450505050949350505050565b6000818152600160205260408120548190819081908190819087906001600160a01b03166136e6576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b6136ee6157e5565b5050506000958652505060016020818152604095869020865160c08101885281546001600160a01b03908116808352838601548216948301859052600284015482169983018a905260039093015490811660608301819052740100000000000000000000000000000000000000008204860b860b90950b6080830181905276010000000000000000000000000000000000000000000090910460ff16151560a09092018290529198929796509294509250565b6000806000806000806000806137b689613671565b955095509550955050506137c984614a7c565b95506137d6838b84613f4d565b90975094506137e48761433c565b9650613824866040518060600160405280602381526020016158fb602391396138178a6305f5e10063ffffffff613a4716565b919063ffffffff61525e16565b97508015613852576305f5e1006138438987830163ffffffff613a4716565b8161384a57fe5b04975061387b565b846305f5e100016138706305f5e1008a613a4790919063ffffffff16565b8161387757fe5b0497505b5050505092959194509250565b60008181526020819052604090205481906001600160a01b03166138f3576040805162461bcd60e51b815260206004820181905260248201527f7468652065786368616e6765207061697220646f6573206e6f74206578697374604482015290519081900360640190fd5b60008281526020819052604080822080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811682556001820180548216905560028201805482169055600382018054909116905560040180547fffffffffffffffffffff000000000000000000000000000000000000000000001690555183917ff44bf4d5e31bd57a2b12f891c33cc0884bc44746beed2864d577e1505a28f3e291a25050565b6000806000806000806000806139b1896118c0565b9450945094509450506139c384614a7c565b95506139d0838b84613f4d565b90975094506139de8761433c565b9650613a11866040518060600160405280602381526020016158fb602391396138178a6305f5e10063ffffffff613a4716565b97508015613a30576305f5e1006138438987830163ffffffff613a4716565b6305f5e1006138708987830363ffffffff613a4716565b600082613a5657506000610a87565b82820282848281613a6357fe5b0414610a845760405162461bcd60e51b81526004018080602001828103825260218152602001806159696021913960400191505060405180910390fd5b6000610a8483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061525e565b6000806000806000866001600160a01b03166326d6c97b876040518263ffffffff1660e01b81526004018082815260200191505060806040518083038186803b158015613b2e57600080fd5b505afa158015613b42573d6000803e3d6000fd5b505050506040513d6080811015613b5857600080fd5b50805160208201516040830151606090930151919a90995067ffffffffffffffff909216975095509350505050565b600080613bc68a6001600160a01b031663a89ae4ba6040518163ffffffff1660e01b815260040160206040518083038186803b15801561277557600080fd5b90508260005b8851811015613ef3576000806000613bea8f8d86815181106127c957fe5b509194509150508a811115613c0157505050613eeb565b6000613c0e6127fa614aeb565b9050613c1d8f61284b83614b86565b604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b038e81166004830152306024830152915192955060009450908616925063dd62ed3e916044808301926020929190829003018186803b158015613c8d57600080fd5b505afa158015613ca1573d6000803e3d6000fd5b505050506040513d6020811015613cb757600080fd5b5051905080613cc857505050613eeb565b8b518f908e906000908f9088908110613cdd57fe5b602002602001015190506000613cf68484848d8a614c6a565b905080613d095750505050505050613eeb565b613d19858263ffffffff613a4716565b8911613de6576001600160a01b0387166323b872dd8f8f613d408d8663ffffffff6152c316565b6040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015613da857600080fd5b505af1158015613dbc573d6000803e3d6000fd5b505050506040513d6020811015613dd257600080fd5b50519a50613f419950505050505050505050565b866001600160a01b03166323b872dd8f8f886040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015613e6057600080fd5b505af1158015613e74573d6000803e3d6000fd5b505050506040513d6020811015613e8a57600080fd5b5051613edd576040805162461bcd60e51b815260206004820152601660248201527f6661696c20746f207472616e7366657220626f6e647300000000000000000000604482015290519081900360640190fd5b939093029096039550505050505b600101613bcc565b506040805162461bcd60e51b815260206004820152601b60248201527f696e73756666696369656e7420626f6e6420616c6c6f77616e63650000000000604482015290519081900360640190fd5b98975050505050505050565b6000806000613f7c7f000000000000000000000000da6fc5625e617bb92f5359921d43321cebc6bef086613ae2565b505091505060008060607f000000000000000000000000a0d773221ca923fb48a0cf1b8309496d198cbfa16001600160a01b0316637e91c2e37f000000000000000000000000da6fc5625e617bb92f5359921d43321cebc6bef08a60006040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b0316815260200183815260200182600481111561401657fe5b60ff168152602001935050505060006040518083038186803b15801561403b57600080fd5b505afa15801561404f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052606081101561409657600080fd5b815160208301516040808501805191519395929483019291846401000000008211156140c157600080fd5b9083019060208201858111156140d657600080fd5b82518660208202830111640100000000821117156140f357600080fd5b82525081516020918201928201910280838360005b83811015614120578181015183820152602001614108565b505050509050016040525050509250925092508261416f5760405162461bcd60e51b8152600401808060200182810382526027815260200180615b036027913960400191505060405180910390fd5b60006141be61417c614aeb565b6040805180820190915260208082527f74686520626f6e642073686f756c64206e6f74206861766520657870697265649082015287919063ffffffff614aef16565b905060006141eb7f0000000000000000000000006e33f11625b2c8b7270cf8e0319b8b9ffb8f086d614a7c565b9050600061421c7f000000000000000000000000c8bbb8d57cebf834dc429ec4d65dd23ed0d65a8761284b85614b86565b905060008c6001600160a01b031663c29d90b5878761423a876152e8565b614243876152e8565b61424c8a6152e8565b6040518663ffffffff1660e01b81526004018086600481111561426b57fe5b60ff16815260200180602001858152602001848152602001838152602001828103825286818151815260200191508051906020019060200280838360005b838110156142c15781810151838201526020016142a9565b505050509050019650505050505050604080518083038186803b1580156142e757600080fd5b505afa1580156142fb573d6000803e3d6000fd5b505050506040513d604081101561431157600080fd5b508051602090910151909a50905061432a82828d615348565b98505050505050505050935093915050565b60006305f5e10061437c61436f7f000000000000000000000000ad491f460d8ee6df3335e8af48de33e0468cd8c9614a7c565b849063ffffffff613a4716565b8161438357fe5b0492915050565b6001600160a01b0385166143e5576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b6001600160a01b03841661442a5760405162461bcd60e51b81526004018080602001828103825260248152602001806159fc6024913960400191505060405180910390fd5b6001600160a01b03831661446f5760405162461bcd60e51b81526004018080602001828103825260258152602001806159446025913960400191505060405180910390fd5b6040805160a0810182526001600160a01b0396871681529486166020808701918252948716868301908152600194850b60608801908152931515608088019081526000998a5260029687905292909820955186549088167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216178755905186850180549189169183169190911790559651949093018054915193511515760100000000000000000000000000000000000000000000027fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff9490930b61ffff1674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff959096169190961617929092169290921791909116179055565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052610bc89085906153e5565b600860ff16816001600160a01b031663d0d6153a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561466857600080fd5b505afa15801561467c573d6000803e3d6000fd5b505050506040513d602081101561469257600080fd5b505160ff16146146d35760405162461bcd60e51b815260040180806020018281038252602681526020018061591e6026913960400191505060405180910390fd5b600860ff16816001600160a01b031663f08e2a336040518163ffffffff1660e01b815260040160206040518083038186803b15801561471157600080fd5b505afa158015614725573d6000803e3d6000fd5b505050506040513d602081101561473b57600080fd5b505160ff1614610c6a5760405162461bcd60e51b8152600401808060200182810382526024815260200180615adf6024913960400191505060405180910390fd5b6001600160a01b0386166147d7576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b6001600160a01b03851661481c5760405162461bcd60e51b815260040180806020018281038252602b81526020018061581b602b913960400191505060405180910390fd5b6001600160a01b0383166148615760405162461bcd60e51b815260040180806020018281038252602c815260200180615b4c602c913960400191505060405180910390fd5b6001600160a01b0382166148a65760405162461bcd60e51b81526004018080602001828103825260258152602001806159446025913960400191505060405180910390fd5b6148af8561462a565b6040805160c0810182526001600160a01b03978816815295871660208088019182529588168783019081529488166060880190815293881660808801908152600193840b60a0890190815260009a8b52968a905291909820955186549088167fffffffffffffffffffffffff000000000000000000000000000000000000000091821617875597518683018054918916918a1691909117905592516002860180549188169189169190911790559051600385018054918716918816919091179055905160049093018054925190910b61ffff1674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff93909416919094161716179055565b6001600160a01b038216600090815260036020526040902054811115614a36576040805162461bcd60e51b815260206004820152601660248201527f696e73756666696369656e7420616c6c6f77616e636500000000000000000000604482015290519081900360640190fd5b6001600160a01b0390911660009081526003602052604090208054919091039055565b6118bc82826040518060600160405280602c8152602001615a20602c91396155bb565b6000816001600160a01b031663a3e6ba946040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614ab957600080fd5b505af1158015614acd573d6000803e3d6000fd5b505050506040513d6020811015614ae357600080fd5b505192915050565b4290565b60008184841115614b7e5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614b43578181015183820152602001614b2b565b50505050905090810190601f168015614b705780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000680100000000000000008210614bcf5760405162461bcd60e51b815260040180806020018281038252602681526020018061598a6026913960400191505060405180910390fd5b5090565b6000826001600160a01b031663c8f3e555836040518263ffffffff1660e01b8152600401808267ffffffffffffffff1667ffffffffffffffff16815260200191505060206040518083038186803b158015614c2d57600080fd5b505afa158015614c41573d6000803e3d6000fd5b505050506040513d6020811015614c5757600080fd5b505167ffffffffffffffff169392505050565b6000806000614c798887613ae2565b5050915050614c91614c8c6127fa614aeb565b6152e8565b9150506000606060007f000000000000000000000000a0d773221ca923fb48a0cf1b8309496d198cbfa16001600160a01b0316637e91c2e38b8a60006040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001838152602001826004811115614d0a57fe5b60ff168152602001935050505060006040518083038186803b158015614d2f57600080fd5b505afa158015614d43573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526060811015614d8a57600080fd5b81516020830151604080850180519151939592948301929184640100000000821115614db557600080fd5b908301906020820185811115614dca57600080fd5b8251866020820283011164010000000082111715614de757600080fd5b82525081516020918201928201910280838360005b83811015614e14578181015183820152602001614dfc565b5050505090500160405250505080945081955082935050505080614e7f576040805162461bcd60e51b815260206004820152601160248201527f756e6b6e6f776e20626f6e642074797065000000000000000000000000000000604482015290519081900360640190fd5b50876001600160a01b031663c29d90b58383614e9a8a6152e8565b614ea38a6152e8565b886040518663ffffffff1660e01b815260040180866004811115614ec357fe5b60ff16815260200180602001858152602001848152602001838152602001828103825286818151815260200191508051906020019060200280838360005b83811015614f19578181015183820152602001614f01565b505050509050019650505050505050604080518083038186803b158015614f3f57600080fd5b505afa925050508015614f6b57506040513d6040811015614f5f57600080fd5b50805160209091015160015b614f7b5760009350505050610ad7565b509350610ad792505050565b600082820183811015610a84576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6001600160a01b03861661503c576040805162461bcd60e51b815260206004820152601a60248201527f74686520706f6f6c20494420616c726561647920657869737473000000000000604482015290519081900360640190fd5b6001600160a01b0385166150815760405162461bcd60e51b81526004018080602001828103825260288152602001806158b16028913960400191505060405180910390fd5b6001600160a01b0384166150c65760405162461bcd60e51b81526004018080602001828103825260298152602001806159d36029913960400191505060405180910390fd5b6001600160a01b03831661510b5760405162461bcd60e51b81526004018080602001828103825260258152602001806159446025913960400191505060405180910390fd5b6040805160c0810182526001600160a01b039788168152958716602080880191825295881687830190815294881660608801908152600194850b6080890190815293151560a0890190815260009a8b529685905291909820955186549088167fffffffffffffffffffffffff000000000000000000000000000000000000000091821617875597518684018054918916918a169190911790559251600286018054918816918916919091179055915160039094018054925193511515760100000000000000000000000000000000000000000000027fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff9490920b61ffff1674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff959096169290961691909117929092169290921791909116179055565b600081836152ad5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315614b43578181015183820152602001614b2b565b5060008385816152b957fe5b0495945050505050565b6000610a8483836040518060600160405280602281526020016158d9602291396156fe565b60007f80000000000000000000000000000000000000000000000000000000000000008210614bcf5760405162461bcd60e51b8152600401808060200182810382526028815260200180615a8d6028913960400191505060405180910390fd5b6000806305f5e100851061537257630bebc2008511615367578461536d565b630bebc2005b615378565b6305f5e1005b905083810264e8d4a510006153b66000600187900b128061539f5750662386f26fc1000083105b6153a95782614c8c565b662386f26fc100006152e8565b8560010b02816153c257fe5b0592506305f5e10083136153d65782610bec565b6305f5e1009695505050505050565b6153f7826001600160a01b0316615774565b615448576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106154a457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101615467565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114615506576040519150601f19603f3d011682016040523d82523d6000602084013e61550b565b606091505b509150915081615562576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115610bc85780806020019051602081101561557e57600080fd5b5051610bc85760405162461bcd60e51b815260040180806020018281038252602a815260200180615ab5602a913960400191505060405180910390fd5b6155c4826157b0565b81906156115760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315614b43578181015183820152602001614b2b565b506040516000906001600160a01b0385169084908381818185875af1925050503d806000811461565d576040519150601f19603f3d011682016040523d82523d6000602084013e615662565b606091505b50509050806156b8576040805162461bcd60e51b815260206004820152601960248201527f7472616e7366657272696e67204574686572206661696c656400000000000000604482015290519081900360640190fd5b6040805184815290516001600160a01b0386169130917fdd4e7375a5084e0c4cc4e1bfc7ba67beb26a368120ea78d2e0948123910bbf7c9181900360200190a350505050565b60008361570d57506000610dd1565b818361575a5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315614b43578181015183820152602001614b2b565b5082600185038161576757fe5b0460010190509392505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906157a857508115155b949350505050565b3031101590565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091529056fe626f6e644d616b6572466f72557365722073686f756c64206265206e6f6e2d7a65726f2061646472657373646563696d616c20676170206e6565647320746f206265206c6f776572207468616e20313973776170506169724f7261636c6520686173206c6174657374507269636528292066756e6374696f6e2077686963682072657475726e73206e6f6e2d7a65726f2076616c75657377617050616972546f6b656e2073686f756c64206265206e6f6e2d7a65726f2061646472657373536166654d617468446976526f756e6455703a206d6f64756c6f206279207a65726f4552433230206f7261636c65207072696365206d757374206265206e6f6e2d7a65726f74686520646563696d616c73206f66206f7261636c65207072696365206d7573742062652038626f6e645072696365722073686f756c64206265206e6f6e2d7a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7753616665436173743a2076616c756520646f65736e27742066697420696e20363420626974736d757374207472616e73666572206e6f6e2d7a65726f20746f6b656e20616d6f756e7473776170506169724f7261636c652073686f756c64206265206e6f6e2d7a65726f20616464726573736574684f7261636c652073686f756c64206265206e6f6e2d7a65726f20616464726573735472616e736665724554483a207472616e7366657220616d6f756e7420657863656564732062616c616e63656574684f7261636c6520686173206c6174657374507269636528292066756e6374696f6e2077686963682072657475726e73206e6f6e2d7a65726f2076616c756553616665436173743a2076616c756520646f65736e27742066697420696e20616e20696e743235365361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656474686520646563696d616c73206f6620626f6e6420746f6b656e206d757374206265203863616e6e6f742063616c63756c61746520746865207072696365206f66207468697320626f6e646d757374207472616e73666572206e6f6e2d7a65726f20626f6e6420616d6f756e74626f6e64507269636572466f72557365722073686f756c64206265206e6f6e2d7a65726f2061646472657373a26469706673582212207d46b6e6ab3d17a7a0bf149999e36885cb46e29bb984f9b0fb8158d023d86fd164736f6c63430006060033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000da6fc5625e617bb92f5359921d43321cebc6bef0000000000000000000000000c8bbb8d57cebf834dc429ec4d65dd23ed0d65a87000000000000000000000000ad491f460d8ee6df3335e8af48de33e0468cd8c9000000000000000000000000a0d773221ca923fb48a0cf1b8309496d198cbfa1

-----Decoded View---------------
Arg [0] : bondMakerAddress (address): 0xDA6FC5625E617bB92F5359921D43321cEbC6BEf0
Arg [1] : volatilityOracleAddress (address): 0xc8BBb8d57CEbF834DC429ec4D65DD23eD0d65a87
Arg [2] : volumeCalculatorAddress (address): 0xad491f460d8Ee6DF3335E8AF48de33E0468Cd8C9
Arg [3] : bondShapeDetector (address): 0xA0d773221cA923fb48A0Cf1B8309496D198CbfA1

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000da6fc5625e617bb92f5359921d43321cebc6bef0
Arg [1] : 000000000000000000000000c8bbb8d57cebf834dc429ec4d65dd23ed0d65a87
Arg [2] : 000000000000000000000000ad491f460d8ee6df3335e8af48de33e0468cd8c9
Arg [3] : 000000000000000000000000a0d773221ca923fb48a0cf1b8309496d198cbfa1


Deployed Bytecode Sourcemap

119461:538:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;80826:52;;;80868:9;80826:52;;;;80861:4;;80841:10;;80826:52;;;;;;;;;119461:538;;12:1:-1;9;2:12;54166:115:0;;5:9:-1;2:2;;;27:1;24;17:12;2:2;54166:115:0;;;:::i;:::-;;;;-1:-1:-1;;;;;54166:115:0;;;;;;;;;;;;;;100546:654;;5:9:-1;2:2;;;27:1;24;17:12;2:2;100546:654:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;100546:654:0;;;;;;;;;;;;;;;;;;27:11:-1;11:28;;8:2;;;52:1;49;42:12;8:2;100546:654:0;;41:9:-1;34:4;18:14;14:25;11:40;8:2;;;64:1;61;54:12;8:2;100546:654:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;100546:654:0;;-1:-1:-1;100546:654:0;-1:-1:-1;100546:654:0;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;85709:199;;5:9:-1;2:2;;;27:1;24;17:12;2:2;85709:199:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;85709:199:0;;;;;;;;;;:::i;101286:186::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;101286:186:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;101286:186:0;;;;;;;:::i;54289:161::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;54289:161:0;;;:::i;85976:447::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;85976:447:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;;;;;;85976:447:0;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;88219:156::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;88219:156:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;88219:156:0;-1:-1:-1;;;;;88219:156:0;;:::i;87811:97::-;;;:::i;:::-;;87337:350;;5:9:-1;2:2;;;27:1;24;17:12;2:2;87337:350:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;87337:350:0;;:::i;:::-;;;;-1:-1:-1;;;;;87337:350:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;101572:216;;5:9:-1;2:2;;;27:1;24;17:12;2:2;101572:216:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;101572:216:0;;;;;;;;;;:::i;65884:481::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;65884:481:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;65884:481:0;;;;;;;;;;;;;;;;;;;;;;:::i;86499:478::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;86499:478:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;86499:478:0;;;-1:-1:-1;;;;;86499:478:0;;;;;;;;;;;;;;;;;;;;;:::i;84080:404::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;84080:404:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;84080:404:0;;;;;;;;;;;;;;;;;;;;;;:::i;101857:600::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;101857:600:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;;;;;;101857:600:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;87045:223::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;87045:223:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;87045:223:0;;:::i;103484:467::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;103484:467:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;103484:467:0;;:::i;:::-;;;;-1:-1:-1;;;;;103484:467:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;87978:169;;5:9:-1;2:2;;;27:1;24;17:12;2:2;87978:169:0;;;:::i;69194:229::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;69194:229:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;69194:229:0;;:::i;104107:846::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;104107:846:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;104107:846:0;;;;;;;;;;;;;;27:11:-1;11:28;;8:2;;;52:1;49;42:12;8:2;104107:846:0;;41:9:-1;34:4;18:14;14:25;11:40;8:2;;;64:1;61;54:12;8:2;104107:846:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;104107:846:0;;-1:-1:-1;104107:846:0;-1:-1:-1;104107:846:0;;;;;;-1:-1:-1;;;;;104107:846:0;;:::i;66847:489::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;66847:489:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;66847:489:0;;;;;;;;;;;;;;;;;;;;;;:::i;68029:527::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;68029:527:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;;;;;;68029:527:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;67712:247::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;67712:247:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;67712:247:0;;;;;;;;;;;;;;;;;;;:::i;102533:588::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;102533:588:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;102533:588:0;;;-1:-1:-1;;;;;102533:588:0;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;68632:494::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;68632:494:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;68632:494:0;;;-1:-1:-1;;;;;68632:494:0;;;;;;;;;;;;;;;;;;;;;:::i;84935:402::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;84935:402:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;84935:402:0;;;;;;;;;;;;;;;;;;;;;;:::i;69492:395::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;69492:395:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;69492:395:0;;:::i;:::-;;;;-1:-1:-1;;;;;69492:395:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;67422:190;;5:9:-1;2:2;;;27:1;24;17:12;2:2;67422:190:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;67422:190:0;;;;;;;:::i;103189:226::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;103189:226:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;103189:226:0;;:::i;85423:186::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;85423:186:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;85423:186:0;;;;;;;:::i;54166:115::-;54255:18;54166:115;;:::o;100546:654::-;100779:18;;100836:112;100867:17;100899:1;98703:52;100836:16;:112::i;:::-;100810:138;;100972:149;101006:10;101031:6;101052;101073:7;;100972:149;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;101095:15:0;;-1:-1:-1;100972:19:0;;-1:-1:-1;;100972:149:0:i;:::-;100959:162;;101132:60;101158:10;101170:14;101186:5;101132:25;:60::i;:::-;100546:654;;;;;;;;;;:::o;85709:199::-;85821:14;85860:40;85881:6;85889:10;85860:20;:40::i;:::-;85853:47;;85709:199;;;;;:::o;101286:186::-;101381:14;101430:34;101449:6;101457;101430:18;:34::i;:::-;-1:-1:-1;101413:51:0;;101286:186;-1:-1:-1;;;;;101286:186:0:o;54289:161::-;54425:17;54289:161;:::o;85976:447::-;86180:14;86227:188;86262:10;86291:16;86326:17;86362:9;86390:10;86227:16;:188::i;:::-;86207:208;85976:447;-1:-1:-1;;;;;85976:447:0:o;88219:156::-;-1:-1:-1;;;;;88347:20:0;88306:14;88347:20;;;:13;:20;;;;;;;88219:156::o;87811:97::-;87861:39;87878:10;87890:9;87861:16;:39::i;:::-;87811:97::o;87337:350::-;87439:14;87468:43;87526:37;87578:15;87608;87658:21;87672:6;87658:13;:21::i;:::-;87651:28;;;;-1:-1:-1;87651:28:0;;-1:-1:-1;87651:28:0;-1:-1:-1;87651:28:0;;-1:-1:-1;87337:350:0;-1:-1:-1;;87337:350:0:o;101572:216::-;101694:14;101733:47;101755:6;101763:16;101733:21;:47::i;65884:481::-;66078:18;66122:127;66157:10;66182:6;66203;66224:14;66122:20;:127::i;:::-;66109:140;;66297:60;66323:10;66335:14;66351:5;66297:25;:60::i;86499:478::-;86726:18;;;;:10;:18;;;;;:25;-1:-1:-1;;;;;86726:25:0;86755:10;86726:39;86704:117;;;;;-1:-1:-1;;;86704:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;86834:135;86865:6;86886:16;86917:17;86949:9;86834:16;:135::i;:::-;86499:478;;;;:::o;84080:404::-;84267:18;84311:57;84330:10;84342:6;84350;84358:9;84311:18;:57::i;101857:600::-;102150:14;102197:252;102233:10;102262:23;102304;102346:24;102389:17;102425:9;102197:17;:252::i;:::-;102177:272;101857:600;-1:-1:-1;;;;;;101857:600:0:o;87045:223::-;87128:18;;;;:10;:18;;;;;:25;-1:-1:-1;;;;;87128:25:0;87157:10;87128:39;87106:117;;;;;-1:-1:-1;;;87106:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;87236:24;87253:6;87236:16;:24::i;:::-;87045:223;:::o;103484:467::-;103587:14;103616:42;103673;103730:44;103789:37;103841:15;103871;103921:22;103936:6;103921:14;:22::i;:::-;103914:29;;;;-1:-1:-1;103914:29:0;;-1:-1:-1;103914:29:0;;-1:-1:-1;103914:29:0;-1:-1:-1;103914:29:0;-1:-1:-1;103914:29:0;;-1:-1:-1;103484:467:0;-1:-1:-1;;103484:467:0:o;87978:169::-;88069:10;88019:14;88055:25;;;:13;:25;;;;;;;88091:48;;88069:10;88055:25;88091:16;:48::i;69194:229::-;69279:20;;;;:12;:20;;;;;:27;-1:-1:-1;;;;;69279:27:0;69310:10;69279:41;69257:119;;;;;-1:-1:-1;;;69257:119:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;69389:26;69408:6;69389:18;:26::i;104107:846::-;104279:28;104350:35;104400:42;104457:37;104541:22;104556:6;104541:14;:22::i;:::-;104320:243;;;;;;;;;;104574:26;104603:195;104637:16;104668;104699:17;104731:7;;104603:195;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;104753:14:0;;-1:-1:-1;104782:5:0;;-1:-1:-1;104603:19:0;;-1:-1:-1;104603:195:0:i;:::-;104574:224;-1:-1:-1;104832:113:0;104574:224;98703:52;53006:1;104832:16;:113::i;:::-;104809:136;104107:846;-1:-1:-1;;;;;;;;;;104107:846:0:o;66847:489::-;67037:22;67089:123;67124:10;67149:6;67170;67191:10;67089:20;:123::i;68029:527::-;68272:14;68319:229;68356:10;68385:15;68419:21;68459:17;68495:9;68523:10;68319:18;:229::i;67712:247::-;67858:14;67892:59;67915:6;67923:15;67940:10;67892:22;:59::i;:::-;67885:66;;67712:247;;;;;;:::o;102533:588::-;102822:11;:19;;;;;;;;;;:26;-1:-1:-1;;;;;102822:26:0;102852:10;102822:40;102800:118;;;;;-1:-1:-1;;;102800:118:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;102931:182;102963:6;102984:23;103022:24;103061:17;103093:9;102931:17;:182::i;:::-;102533:588;;;;;:::o;68632:494::-;68866:20;;;;:12;:20;;;;;:27;-1:-1:-1;;;;;68866:27:0;68897:10;68866:41;68844:119;;;;;-1:-1:-1;;;68844:119:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;68976:142;69009:6;69030:21;69066:17;69098:9;68976:18;:142::i;84935:402::-;85123:17;85165:58;85184:10;85196:6;85204;85212:10;85165:18;:58::i;69492:395::-;69596:14;69625:21;69661:48;69724:37;69776:15;69806;69856:23;69872:6;69856:15;:23::i;:::-;69849:30;;;;-1:-1:-1;69849:30:0;;-1:-1:-1;69849:30:0;-1:-1:-1;69849:30:0;-1:-1:-1;69849:30:0;;-1:-1:-1;69492:395:0;-1:-1:-1;;69492:395:0:o;67422:190::-;67519:14;67568:36;67589:6;67597;67568:20;:36::i;103189:226::-;103273:11;:19;;;;;;;;;;:26;-1:-1:-1;;;;;103273:26:0;103303:10;103273:40;103251:118;;;;;-1:-1:-1;;;103251:118:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;103382:25;103400:6;103382:17;:25::i;85423:186::-;85518:14;85567:34;85586:6;85594;85567:18;:34::i;55812:669::-;55960:19;55992:9;56012;56055:15;56038:32;;:14;:32;;;56034:208;;;-1:-1:-1;56087:36:0;56091:32;;;56087:36;56034:208;;;56162:15;56145:32;;:14;:32;;;56141:101;;;56216:14;56198:15;:32;56194:36;;;;56141:101;56369:2;56365:1;:6;:16;;;;;56379:2;56375:1;:6;56365:16;56357:66;;;;-1:-1:-1;;;56357:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56441:32;56471:1;56467:2;:5;56441:21;56460:1;56456:2;:5;56441:10;:14;;:21;;;;:::i;:::-;:25;:32;:25;:32;:::i;105450:2784::-;105647:18;105686:7;:14;105704:1;105686:19;;105678:60;;;;;-1:-1:-1;;;105678:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;105751:35;105812:15;105885:22;105900:6;105885:14;:22::i;:::-;105842:65;;-1:-1:-1;105842:65:0;;-1:-1:-1;105842:65:0;;-1:-1:-1;105922:51:0;;-1:-1:-1;;;;105922:51:0;;;;-1:-1:-1;;;105922:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;105450:2784;105998:15;106015:16;106039:73;106062:18;106095:6;106039:8;:73::i;:::-;-1:-1:-1;105997:115:0;;-1:-1:-1;105997:115:0;-1:-1:-1;;;;;;;106131:32:0;;106123:71;;;;;-1:-1:-1;;;106123:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;106223:14;106247:34;106266:6;106274;106247:18;:34::i;:::-;106222:59;;;;;52424:16;106322:6;:29;106296:117;;;;;-1:-1:-1;;;106296:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;52496:15;106454:6;:29;106428:117;;;;;-1:-1:-1;;;106428:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;106775:6;106590:165;106629:15;53006:1;52782;98703:52;106712:9;-1:-1:-1;;;;;106712:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;106712:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;106712:20:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;106712:20:0;106735:1;106712:24;106590:16;:165::i;:::-;:191;;;;;;;-1:-1:-1;106804:15:0;106796:62;;;;-1:-1:-1;;;106796:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;105450:2784;106916:14;106968:42;107029:37;107125:22;107140:6;107125:14;:22::i;:::-;106897:250;;;;;;;;;;107188:9;-1:-1:-1;;;;;107188:22:0;;107211:6;107219:5;107226:10;107188:49;;;;;;;;;;;;;-1:-1:-1;;;;;107188:49:0;-1:-1:-1;;;;;107188:49:0;;;;;;-1:-1:-1;;;;;107188:49:0;-1:-1:-1;;;;;107188:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;107188:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;107188:49:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;107188:49:0;107162:133;;;;;-1:-1:-1;;;107162:133:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;107331:5;107412:15;107500:321;107545:16;107584;107623:17;107663:7;107693:8;107331:5;107755:6;107412:15;107500:22;:321::i;:::-;107474:411;;;;;-1:-1:-1;;;107474:411:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;105450:2784;;;;;107909:16;107928:110;107959:15;53006:1;52782;98703:52;108026:1;107928:16;:110::i;:::-;108054:172;;;;;;;;;;;;;;;;;;;;107909:129;;-1:-1:-1;108131:6:0;;108110;;-1:-1:-1;;;;;108054:172:0;;;;;;;;;;;;105450:2784;;;;;;;;;;;:::o;59340:361::-;59499:19;;59495:199;;59605:14;59561:40;59596:4;59561:30;:12;59578;;;59561:30;:16;:30;:::i;:40::-;:58;;59535:147;;;;;-1:-1:-1;;;59535:147:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;59340:361;;;:::o;93864:388::-;94057:172;;;94143:4;94057:172;;;;-1:-1:-1;;;;;94057:172:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;94057:172:0;;;;;;;94029:215;;;;;;93864:388::o;108242:732::-;108352:14;108381:19;108415:23;108453:15;108571:30;108616:15;108648:22;108663:6;108648:14;:22::i;:::-;108496:174;;;;;;;;;108707:104;108745:10;108770:6;108791:9;108707:23;:104::i;:::-;108681:130;;-1:-1:-1;108681:130:0;-1:-1:-1;108836:26:0;108681:130;108836:13;:26::i;:::-;108822:40;-1:-1:-1;108891:5:0;;-1:-1:-1;108891:5:0;108916:42;108822:40;108940:16;;;108916:42;:15;:42;:::i;:::-;:50;;;;;;108907:59;;108242:732;;;;;;;;;:::o;95062:1166::-;95278:14;95314:40;95335:6;95343:10;95314:20;:40::i;:::-;95424:1;95387:18;;;:10;:18;;;;;:25;95305:49;;-1:-1:-1;;;;;;95387:25:0;:39;95365:115;;;;;-1:-1:-1;;;95365:115:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;95508:13;95524:9;-1:-1:-1;;;;;95524:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;95524:23:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;95524:23:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;95524:23:0;;-1:-1:-1;95588:10:0;95562:137;;;;-1:-1:-1;;;95562:137:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;95062:1166;95723:164;95751:6;95772;95793:9;95817:10;95842:9;95866:10;95723:13;:164::i;:::-;95904:10;95900:162;;;95936:38;;-1:-1:-1;;;;;95936:38:0;;;95959:6;;95936:38;;;;;95900:162;;;96012:38;;-1:-1:-1;;;;;96012:38:0;;;96035:6;;96012:38;;;;;95900:162;96079:141;;;-1:-1:-1;;;;;96079:141:0;;;;;;;;;;;;;;;;;;;;;;;96112:6;;96079:141;;;;;;;;;;95062:1166;;;;;;;:::o;97927:190::-;-1:-1:-1;;;;;98005:21:0;;;;;;:13;:21;;;;;:31;;;;;;;;98055;-1:-1:-1;98055:31:0;98047:62;;;;;-1:-1:-1;;;98047:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;97927:190;;:::o;97069:620::-;97210:14;83496:18;;;:10;:18;;;;;:25;97210:14;;;;;;;;97170:6;;-1:-1:-1;;;;;83496:25:0;83474:121;;;;;-1:-1:-1;;;83474:121:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;97408:29:::1;;:::i;:::-;-1:-1:-1::0;;;97440:18:0::1;::::0;;;-1:-1:-1;;97440:10:0::1;:18;::::0;;;;;;;;97408:50;;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;97408:50:0;;::::1;::::0;;;;;;::::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;::::1;::::0;;;::::1;::::0;;;;;;;;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;;;;;;;;;::::1;;;;;::::0;;;;;;;;;;;;-1:-1:-1;97408:50:0;-1:-1:-1;97069:620:0:o;108982:404::-;109185:178;;;109271:4;109185:178;;;;-1:-1:-1;;;;;109185:178:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;109185:178:0;;;;;;;109157:221;;;;;;108982:404::o;70371:1972::-;70533:18;70579:14;70608:19;70687:15;70716:23;70732:6;70716:15;:23::i;:::-;70564:175;;;;;;;;;70758:10;70750:51;;;;;-1:-1:-1;;;70750:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;70815:15;70840:36;70849:18;70869:6;70840:8;:36::i;:::-;-1:-1:-1;70814:62:0;;-1:-1:-1;;;;;;;;70895:32:0;;70887:71;;;;;-1:-1:-1;;;70887:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;70971:16;71032:14;71084:23;71128:36;71149:6;71157;71128:20;:36::i;:::-;71013:151;;;;;;52424:16;71205:6;:29;71179:117;;;;;-1:-1:-1;;;71179:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;52496:15;71337:6;:29;71311:117;;;;;-1:-1:-1;;;71311:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;71443:24;71470:13;-1:-1:-1;;;;;71470:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;71470:24:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;71470:24:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;71470:24:0;;-1:-1:-1;71715:6:0;71539:156;71578:14;71470:24;71656:20;71539:16;:156::i;:::-;:182;;;;;;;-1:-1:-1;71744:15:0;71736:62;;;;-1:-1:-1;;;71736:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71824:104;71886:27;;;71882:2;:31;71824:35;:15;71844:14;71824:35;:19;:35;:::i;:104::-;71813:115;;70371:1972;;;71974:9;-1:-1:-1;;;;;71974:22:0;;71997:6;72005:5;72012:10;71974:49;;;;;;;;;;;;;-1:-1:-1;;;;;71974:49:0;-1:-1:-1;;;;;71974:49:0;;;;;;-1:-1:-1;;;;;71974:49:0;-1:-1:-1;;;;;71974:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;71974:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;71974:49:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;71974:49:0;71952:121;;;;;-1:-1:-1;;;71952:121:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;72084:61;-1:-1:-1;;;;;72084:30:0;;72115:5;72122:6;72130:14;72084:61;:30;:61;:::i;:::-;72163:172;;;;;;;;;;;;;;;;;;;;72241:6;;72220;;-1:-1:-1;;;;;72163:172:0;;;;;;;;;;;;;70371:1972;;;;;;;;;;;:::o;96236:626::-;83533:1;83496:18;;;:10;:18;;;;;:25;96438:6;;-1:-1:-1;;;;;83496:25:0;83474:121;;;;;-1:-1:-1;;;83474:121:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;96458:14:::1;96480:15:::0;96499:21:::1;96513:6;96499:13;:21::i;:::-;96457:63;;;;;;;96531:164;96559:6;96580;96601:9;96625:10;96650:9;96674:10;96531:13;:164::i;:::-;96713:141;::::0;;-1:-1:-1;;;;;96713:141:0;;::::1;::::0;;;::::1;;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;96746:6;;96713:141:::1;::::0;;;;;;;;::::1;83606:1;;96236:626:::0;;;;;:::o;88843:1750::-;89003:18;89035:14;89057:15;89076:21;89090:6;89076:13;:21::i;:::-;89034:63;;;;;;;89116:10;89108:51;;;;;-1:-1:-1;;;89108:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;89173:15;89198:36;89207:18;89227:6;89198:8;:36::i;:::-;-1:-1:-1;89172:62:0;;-1:-1:-1;;;;;;;;89253:32:0;;89245:71;;;;;-1:-1:-1;;;89245:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;89329:16;89372:14;89390:23;89419:83;89456:6;89481;89419:18;:83::i;:::-;89371:131;;;;;;52424:16;89543:6;:29;89517:117;;;;;-1:-1:-1;;;89517:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;52496:15;89675:6;:29;89649:117;;;;;-1:-1:-1;;;89649:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;89984:6;89811:153;89850:14;82012:2;89925:20;89811:16;:153::i;:::-;:179;;;;;;;-1:-1:-1;90013:15:0;90005:62;;;;-1:-1:-1;;;90005:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90093:101;90151:28;90093:35;:15;90113:14;90093:35;:19;:35;:::i;:101::-;90240:49;;;;;;-1:-1:-1;;;;;90240:49:0;;;;;;;;;;;;;;;;;;;;;;90082:112;;-1:-1:-1;90240:22:0;;;;-1:-1:-1;90240:22:0;;-1:-1:-1;90240:49:0;;;;;;;;;;;;;;;-1:-1:-1;90240:22:0;:49;;;2:2:-1;;;;27:1;24;17:12;2:2;90240:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;90240:49:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;90240:49:0;90218:121;;;;;-1:-1:-1;;;90218:121:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;90350:47;90367:5;90374:6;90382:14;90350:16;:47::i;:::-;90415:170;;;;;;;;;;;;;;;;;;;;90491:6;;90470;;-1:-1:-1;;;;;90415:170:0;;;;;;;;;;;;;88843:1750;;;;;;;;;;:::o;110562:1044::-;110853:14;110889:56;110911:6;110927:16;110889:21;:56::i;:::-;111016:1;110978:19;;;;;;;;;;:26;110880:65;;-1:-1:-1;;;;;;110978:26:0;:40;110956:116;;;;;-1:-1:-1;;;110956:116:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;111085:42;111110:16;111085:24;:42::i;:::-;111138:210;111167:6;111188;111209:16;111240;111271:17;111303:10;111328:9;111138:14;:210::i;:::-;111414:16;-1:-1:-1;;;;;111366:66:0;111398:6;-1:-1:-1;;;;;111366:66:0;111390:6;111366:66;;;;;;;;;;111448:150;;;-1:-1:-1;;;;;111448:150:0;;;;;;;;;;;;;;;;;;;;;;;111482:6;;111448:150;;;;;;;;;;110562:1044;;;;;;;;:::o;96870:191::-;83533:1;83496:18;;;:10;:18;;;;;:25;96960:6;;-1:-1:-1;;;;;83496:25:0;83474:121;;;;;-1:-1:-1;;;83474:121:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;96991:18:::1;::::0;;;:10:::1;:18;::::0;;;;;;;96984:25;;;;;::::1;::::0;;;;::::1;::::0;;;;::::1;::::0;;;;::::1;::::0;;;;;;97027:26;97002:6;;97027:26:::1;::::0;::::1;96870:191:::0;;:::o;112677:847::-;112820:14;99916:19;;;;;;;;;;:26;112820:14;;;;;;;;;;;;112780:6;;-1:-1:-1;;;;;99916:26:0;99894:122;;;;;-1:-1:-1;;;99894:122:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;113126:30:::1;;:::i;:::-;-1:-1:-1::0;;;113159:11:0::1;:19:::0;;;-1:-1:-1;;;113159:19:0::1;::::0;;;;;;;;113126:52;;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;113126:52:0;;::::1;::::0;;;;;;::::1;::::0;;::::1;::::0;;::::1;::::0;;;::::1;::::0;::::1;::::0;;::::1;::::0;;;;;;::::1;::::0;::::1;::::0;;::::1;::::0;;;;;;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;;;;;;;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;;;;;;;;;;;;-1:-1:-1;113126:52:0;;-1:-1:-1;113126:52:0;-1:-1:-1;113126:52:0;112677:847::o;97697:222::-;97828:32;97845:6;97853;97828:16;:32::i;:::-;97871:40;97892:9;97904:6;97871:12;:40::i;79698:199::-;65316:1;65277:20;;;:12;:20;;;;;:27;79792:6;;-1:-1:-1;;;;;65277:27:0;65255:123;;;;;-1:-1:-1;;;65255:123:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79823:20:::1;::::0;;;:12:::1;:20;::::0;;;;;;;79816:27;;;;;::::1;::::0;;;;::::1;::::0;;;::::1;::::0;;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;::::1;::::0;;::::1;::::0;;;;;;79861:28;79836:6;;79861:28:::1;::::0;::::1;79698:199:::0;;:::o;116238:1713::-;116518:26;116557:21;116581:42;116597:9;-1:-1:-1;;;;;116597:23:0;;:25;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;116597:25:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116597:25:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;116597:25:0;116581:15;:42::i;:::-;116557:66;-1:-1:-1;116641:9:0;116636:1308;116660:7;:14;116656:1;:18;116636:1308;;;116696:10;116721:19;116774:16;116832:31;116841:9;116852:7;116860:1;116852:10;;;;;;;;;;;;;;116832:8;:31::i;:::-;-1:-1:-1;116809:54:0;;-1:-1:-1;116809:54:0;-1:-1:-1;;116886:25:0;;;116882:39;;;116913:8;;;;;116882:39;116948:21;116972:134;117007:23;:21;:23::i;:::-;116972:134;;;;;;;;;;;;;;;;;;:8;;:134;;:12;:134;:::i;:::-;116948:158;;117139:119;117176:16;117215:24;:13;:22;:24::i;:::-;117139:14;:119::i;:::-;117125:133;;116636:1308;;117290:15;117308:4;-1:-1:-1;;;;;117308:14:0;;117323:6;117308:22;;;;;;;;;;;;;-1:-1:-1;;;;;117308:22:0;-1:-1:-1;;;;;117308:22:0;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;117308:22:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117308:22:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;117308:22:0;;-1:-1:-1;117353:12:0;117345:49;;;;;-1:-1:-1;;;117345:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;117431:37;;;;;;-1:-1:-1;;;;;117431:37:0;;;;;;;117462:4;117431:37;;;;;;117411:17;;117431:14;;;;;:37;;;;;;;;;;;;;;:14;:37;;;2:2:-1;;;;27:1;24;17:12;2:2;117431:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117431:37:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;117431:37:0;;-1:-1:-1;117491:14:0;117483:52;;;;;-1:-1:-1;;;117483:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;117552:17;117572:177;117605:9;117633:10;117662:7;117670:1;117662:10;;;;;;;;;;;;;;117691:13;117723:11;117572:14;:177::i;:::-;117552:197;-1:-1:-1;117772:14:0;117764:50;;;;;-1:-1:-1;;;117764:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;117852:80;117893:24;:9;117907;117893:24;:13;:24;:::i;:::-;117852:18;;:80;:22;:80;:::i;:::-;117831:101;;116636:1308;;;;;;116676:3;;116636:1308;;;;116238:1713;;;;;;;;;:::o;72823:1903::-;72981:22;73031:14;73060:19;73139:15;73168:23;73184:6;73168:15;:23::i;:::-;73016:175;;;;;;;;;73211:10;73210:11;73202:56;;;;;-1:-1:-1;;;73202:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73272:15;73297:36;73306:18;73326:6;73297:8;:36::i;:::-;-1:-1:-1;73271:62:0;;-1:-1:-1;;;;;;;;73352:32:0;;73344:71;;;;;-1:-1:-1;;;73344:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;73428:16;73471:14;73487:19;73514:85;73553:6;73578;73514:20;:85::i;:::-;73470:129;;;;;;52424:16;73640:6;:29;73614:117;;;;;-1:-1:-1;;;73614:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;52496:15;73772:6;:29;73746:117;;;;;-1:-1:-1;;;73746:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;73878:24;73905:13;-1:-1:-1;;;;;73905:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;73905:24:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;73905:24:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;73905:24:0;;-1:-1:-1;73961:148:0;73996:22;:10;74011:6;73996:22;:14;:22;:::i;:::-;74037:20;74076:18;73961:16;:148::i;:::-;73944:165;-1:-1:-1;74132:19:0;74124:67;;;;-1:-1:-1;;;74124:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74217:94;74267:29;74217:27;:11;74233:10;74217:27;:15;:27;:::i;:94::-;74206:105;;72823:1903;;;74357:9;-1:-1:-1;;;;;74357:22:0;;74380:5;74387:6;74395:10;74357:49;;;;;;;;;;;;;-1:-1:-1;;;;;74357:49:0;-1:-1:-1;;;;;74357:49:0;;;;;;-1:-1:-1;;;;;74357:49:0;-1:-1:-1;;;;;74357:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;74357:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;74357:49:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;74357:49:0;74335:121;;;;;-1:-1:-1;;;74335:121:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;74467:61;-1:-1:-1;;;;;74467:30:0;;74498:6;74506:5;74513:14;74467:61;:30;:61;:::i;:::-;74546:172;;;;;;;;;;;;;;;;;;;;74624:6;;74603;;-1:-1:-1;;;;;74546:172:0;;;;;;;;;;;;;72823:1903;;;;;;;;;;;:::o;77373:1520::-;77626:14;77662:116;77699:6;77728:13;77757:10;77662:22;:116::i;:::-;77850:1;77811:20;;;:12;:20;;;;;:27;77653:125;;-1:-1:-1;;;;;;77811:27:0;:41;77789:117;;;;;-1:-1:-1;;;77789:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;77934:13;77950:31;77966:14;77950:15;:31::i;:::-;77934:47;-1:-1:-1;78022:10:0;77996:142;;;;-1:-1:-1;;;77996:142:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77373:1520;78162:199;78192:6;78213;78234:13;78262:14;78291:10;78316:9;78340:10;78162:15;:199::i;:::-;78378:10;78374:346;;;78511:13;-1:-1:-1;;;;;78410:130:0;78478:6;-1:-1:-1;;;;;78410:130:0;78453:6;78410:130;;;;;;;;;;78374:346;;;78679:13;-1:-1:-1;;;;;78578:130:0;78646:6;-1:-1:-1;;;;;78578:130:0;78621:6;78578:130;;;;;;;;;;78374:346;78737:148;;;-1:-1:-1;;;;;78737:148:0;;;;;;;;;;;;;;;;;;;;;;;78772:6;;78737:148;;;;;;;;;;77373:1520;;;;;;;;:::o;75865:457::-;76087:212;;;76175:4;76087:212;;;;-1:-1:-1;;;;;76087:212:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;76087:212:0;;;;;;;76059:255;;;;;;75865:457::o;111614:852::-;99954:1;99916:19;;;;;;;;;;:26;111872:6;;-1:-1:-1;;;;;99916:26:0;99894:122;;;;;-1:-1:-1;;;99894:122:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;111906:14:::1;111935:35:::0;112047:22:::1;112062:6;112047:14;:22::i;:::-;111891:178;;;;;;;;;112080:210;112109:6;112130;112151:16;112182;112213:17;112245:10;112270:9;112080:14;:210::i;:::-;112308:150;::::0;;-1:-1:-1;;;;;112308:150:0;;::::1;::::0;;;::::1;;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;112342:6;;112308:150:::1;::::0;;;;;;;;::::1;100027:1;;111614:852:::0;;;;;;:::o;78901:789::-;65316:1;65277:20;;;:12;:20;;;;;:27;79112:6;;-1:-1:-1;;;;;65277:27:0;65255:123;;;;;-1:-1:-1;;;65255:123:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79146:14:::1;79175:19:::0;79254:15:::1;79283:23;79299:6;79283:15;:23::i;:::-;79131:175;;;;;;;;;79317:199;79347:6;79368;79389:13;79417:14;79446:10;79471:9;79495:10;79317:15;:199::i;:::-;79534:148;::::0;;-1:-1:-1;;;;;79534:148:0;;::::1;::::0;;;::::1;;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;79569:6;;79534:148:::1;::::0;;;;;;;;::::1;65389:1;;;78901:789:::0;;;;;:::o;91046:1702::-;91202:22;91238:14;91260:15;91279:21;91293:6;91279:13;:21::i;:::-;91237:63;;;;;;;91320:10;91319:11;91311:56;;;;;-1:-1:-1;;;91311:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91381:15;91406:36;91415:18;91435:6;91406:8;:36::i;:::-;-1:-1:-1;91380:62:0;;-1:-1:-1;;;;;;;;91461:32:0;;91453:71;;;;;-1:-1:-1;;;91453:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;91537:16;91580:14;91596:19;91623:83;91660:6;91685;91623:18;:83::i;:::-;91579:127;;;;;;52424:16;91747:6;:29;91721:117;;;;;-1:-1:-1;;;91721:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;52496:15;91879:6;:29;91853:117;;;;;-1:-1:-1;;;91853:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;92002:145;92037:22;:10;92052:6;92037:22;:14;:22;:::i;:::-;92078:20;82012:2;92002:16;:145::i;:::-;91985:162;-1:-1:-1;92170:19:0;92162:67;;;;-1:-1:-1;;;92162:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;92255:94;92305:29;92255:27;:11;92271:10;92255:27;:15;:27;:::i;:94::-;92395:49;;;;;;-1:-1:-1;;;;;92395:49:0;;;;;;;;;;;;;;;;;;;;;;92244:105;;-1:-1:-1;92395:22:0;;;;-1:-1:-1;92395:22:0;;-1:-1:-1;92395:49:0;;;;;;;;;;;;;;;-1:-1:-1;92395:22:0;:49;;;2:2:-1;;;;27:1;24;17:12;2:2;92395:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;92395:49:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;92395:49:0;92373:121;;;;;-1:-1:-1;;;92373:121:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;92505:47;92522:6;92530:5;92537:14;92505:16;:47::i;:::-;92570:170;;;;;;;;;;;;;;;;;;;;92646:6;;92625;;-1:-1:-1;;;;;92570:170:0;;;;;;;;;;;;;91046:1702;;;;;;;;;;:::o;79905:730::-;80050:14;65277:20;;;:12;:20;;;;;:27;80050:14;;;;;;;;;;80010:6;;-1:-1:-1;;;;;65277:27:0;65255:123;;;;;-1:-1:-1;;;65255:123:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;80287:31:::1;;:::i;:::-;-1:-1:-1::0;;;80321:20:0::1;::::0;;;-1:-1:-1;;80321:12:0::1;:20;::::0;;;;;;;;80287:54;;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;80287:54:0;;::::1;::::0;;;;;::::1;::::0;;::::1;::::0;;::::1;::::0;;;::::1;::::0;::::1;::::0;;::::1;::::0;;;;;;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;;;;;;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;;;;;;;;;::::1;;;;;::::0;;;;;;;;;;;;-1:-1:-1;80287:54:0;;-1:-1:-1;80287:54:0;-1:-1:-1;79905:730:0:o;74734:1123::-;74846:14;74875:19;74909:23;74947:15;75035:38;75088:30;75133:15;75163;75192:23;75208:6;75192:15;:23::i;:::-;74990:225;;;;;;;;;;75244:28;75260:11;75244:15;:28::i;:::-;75226:46;;75309:104;75347:10;75372:6;75393:9;75309:23;:104::i;:::-;75283:130;;-1:-1:-1;75283:130:0;-1:-1:-1;75438:26:0;75283:130;75438:13;:26::i;:::-;75424:40;;75484:119;75525:15;75484:119;;;;;;;;;;;;;;;;;:22;:11;75500:5;75484:22;:15;:22;:::i;:::-;:26;:119;;:26;:119;:::i;:::-;75475:128;;75670:10;75666:184;;;75746:5;75706:37;:6;75725:16;;;75706:37;:10;:37;:::i;:::-;:45;;;;;;75697:54;;75666:184;;;75829:8;75821:5;:16;75793:17;75804:5;75793:6;:10;;:17;;;;:::i;:::-;:45;;;;;;75784:54;;75666:184;74734:1123;;;;;;;;;;;:::o;112474:195::-;99954:1;99916:19;;;;;;;;;;:26;112566:6;;-1:-1:-1;;;;;99916:26:0;99894:122;;;;;-1:-1:-1;;;99894:122:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;112597:11:::1;:19:::0;;;::::1;::::0;;;;;;;112590:26;;;;;::::1;::::0;;;;::::1;::::0;;;::::1;::::0;;::::1;::::0;::::1;::::0;;;::::1;::::0;;::::1;::::0;::::1;::::0;;;;::::1;::::0;;::::1;;::::0;;;;;;112634:27;112609:6;;112634:27:::1;::::0;::::1;112474:195:::0;;:::o;92756:1100::-;92866:14;92895:19;92929:23;92967:15;93040:36;93091:30;93136:15;93166;93195:21;93209:6;93195:13;:21::i;:::-;93010:206;;;;;;;;;93245:26;93261:9;93245:15;:26::i;:::-;93227:44;;93308:104;93346:10;93371:6;93392:9;93308:23;:104::i;:::-;93282:130;;-1:-1:-1;93282:130:0;-1:-1:-1;93437:26:0;93282:130;93437:13;:26::i;:::-;93423:40;;93483:119;93524:15;93483:119;;;;;;;;;;;;;;;;;:22;:11;93499:5;93483:22;:15;:22;:::i;:119::-;93474:128;;93669:10;93665:184;;;93745:5;93705:37;:6;93724:16;;;93705:37;:10;:37;:::i;93665:184::-;93832:5;93792:37;:6;93811:16;;;93792:37;:10;:37;:::i;6157:471::-;6215:7;6460:6;6456:47;;-1:-1:-1;6490:1:0;6483:8;;6456:47;6527:5;;;6531:1;6527;:5;:1;6551:5;;;;;:10;6543:56;;;;-1:-1:-1;;;6543:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7096:132;7154:7;7181:39;7185:1;7188;7181:39;;;;;;;;;;;;;;;;;:3;:39::i;55221:505::-;55349:15;55379:16;55410:22;55447:15;55490:24;55581:9;-1:-1:-1;;;;;55581:31:0;;55613:6;55581:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;55581:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;55581:39:0;;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;55581:39:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;55525:95:0;;;;;-1:-1:-1;55581:39:0;-1:-1:-1;55221:505:0;-1:-1:-1;;;;55221:505:0:o;113656:2429::-;114001:7;114021:21;114045:42;114061:9;-1:-1:-1;;;;;114061:23:0;;:25;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;114045:42:0;114021:66;-1:-1:-1;114115:15:0;114100:12;114152:1876;114176:7;:14;114172:1;:18;114152:1876;;;114212:10;114237:19;114290:16;114348:31;114357:9;114368:7;114376:1;114368:10;;;;;;;114348:31;-1:-1:-1;114325:54:0;;-1:-1:-1;114325:54:0;-1:-1:-1;;114402:25:0;;;114398:39;;;114429:8;;;;;114398:39;114476:21;114500:134;114535:23;:21;:23::i;114500:134::-;114476:158;;114667:119;114704:16;114743:24;:13;:22;:24::i;114667:119::-;114838:37;;;;;;-1:-1:-1;;;;;114838:37:0;;;;;;;114869:4;114838:37;;;;;;114653:133;;-1:-1:-1;114818:17:0;;-1:-1:-1;114838:14:0;;;;-1:-1:-1;114838:14:0;;:37;;;;;;;;;;;;;;:14;:37;;;2:2:-1;;;;27:1;24;17:12;2:2;114838:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114838:37:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;114838:37:0;;-1:-1:-1;114894:14:0;114890:28;;114910:8;;;;;114890:28;115158:10;;114989:9;;115081:10;;114955:31;;115158:7;;115166:1;;115158:10;;;;;;;;;;;;115138:30;;115215:17;115235:182;115268:12;115299:13;115331:9;115359:13;115391:11;115235:14;:182::i;:::-;115215:202;-1:-1:-1;115436:14:0;115432:28;;115452:8;;;;;;;;;115432:28;115509:24;:9;115523;115509:24;:13;:24;:::i;:::-;115501:4;:32;115497:328;;-1:-1:-1;;;;;115647:17:0;;;115691:6;115724:9;115760:26;:4;115776:9;115760:26;:15;:26;:::i;:::-;115647:162;;;;;;;;;;;;;-1:-1:-1;;;;;115647:162:0;-1:-1:-1;;;;;115647:162:0;;;;;;-1:-1:-1;;;;;115647:162:0;-1:-1:-1;;;;;115647:162:0;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;115647:162:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115647:162:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;115647:162:0;;-1:-1:-1;115619:190:0;;-1:-1:-1;;;;;;;;;;115619:190:0;115497:328;115867:4;-1:-1:-1;;;;;115867:17:0;;115885:6;115893:9;115904;115867:47;;;;;;;;;;;;;-1:-1:-1;;;;;115867:47:0;-1:-1:-1;;;;;115867:47:0;;;;;;-1:-1:-1;;;;;115867:47:0;-1:-1:-1;;;;;115867:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;115867:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115867:47:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;115867:47:0;115841:131;;;;;-1:-1:-1;;;115841:131:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;115995:21;;;;115987:29;;;;-1:-1:-1;;;;;114152:1876:0;114192:3;;114152:1876;;;-1:-1:-1;116040:37:0;;;-1:-1:-1;;;116040:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;113656:2429;;;;;;;;;;;:::o;56489:1322::-;56639:19;56660:15;56691:16;56715:36;56724:18;56744:6;56715:8;:36::i;:::-;56688:63;;;;;56777:20;56812:17;56844:23;56881:18;-1:-1:-1;;;;;56881:34:0;;56930:18;56963:6;56984:13;56881:127;;;;;;;;;;;;;-1:-1:-1;;;;;56881:127:0;-1:-1:-1;;;;;56881:127:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;56881:127:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;56881:127:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;56881:127:0;80:15:-1;;;97:9;76:31;65:43;;120:4;113:20;15:2;7:11;;4:2;;;31:1;28;21:12;4:2;56881:127:0;;;;;;;;;;;;;;;;;;;;;;;19:11:-1;11:20;;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;219:3;213:10;331:9;325:2;311:12;307:21;289:16;285:44;282:59;261:11;247:12;244:29;233:116;230:2;;;362:1;359;352:12;230:2;373:25;;-1:-1;56881:127:0;;421:4:-1;412:14;;;;56881:127:0;;;;;412:14:-1;56881:127:0;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;56881:127:0;;;;;;;;;;;56762:246;;;;;;57027:15;57019:67;;;;-1:-1:-1;;;57019:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57099:21;57123:110;57150:23;:21;:23::i;:::-;57123:110;;;;;;;;;;;;;;;;;;:8;;:110;;:12;:110;:::i;:::-;57099:134;;57244:21;57268:37;57284:20;57268:15;:37::i;:::-;57244:61;;57316:26;57345:104;57374:25;57414:24;:13;:22;:24::i;57345:104::-;57316:133;;57462:18;57519:10;-1:-1:-1;;;;;57519:31:0;;57565:8;57588:6;57609:24;:13;:22;:24::i;:::-;57648:29;:18;:27;:29::i;:::-;57692:24;:13;:22;:24::i;:::-;57519:208;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;57519:208:0;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;57519:208:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;57519:208:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;57519:208:0;;;;;;;;;-1:-1:-1;57519:208:0;-1:-1:-1;57749:54:0;57761:18;57519:208;57793:9;57749:11;:54::i;:::-;57738:65;;56489:1322;;;;;;;;;;;;;;:::o;58710:146::-;58767:7;58843:5;58794:46;58805:34;58821:17;58805:15;:34::i;:::-;58794:6;;:46;:10;:46;:::i;:::-;:54;;;;;;;58710:146;-1:-1:-1;;58710:146:0:o;94260:794::-;-1:-1:-1;;;;;94508:20:0;;94500:59;;;;;-1:-1:-1;;;94500:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;94592:32:0;;94570:118;;;;-1:-1:-1;;;94570:118:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;94721:33:0;;94699:120;;;;-1:-1:-1;;;94699:120:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94851:195;;;;;;;;-1:-1:-1;;;;;94851:195:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;94830:18:0;;;:10;:18;;;;;;;;:216;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94260:794::o;60523:205::-;60651:68;;;-1:-1:-1;;;;;60651:68:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;60651:68:0;;;;;;;;25:18:-1;;61:17;;60651:68:0;182:15:-1;60674:27:0;179:29:-1;160:49;;60624:96:0;;60644:5;;60624:19;:96::i;58920:412::-;53006:1;59054:61;;:9;-1:-1:-1;;;;;59054:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;59054:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;59054:33:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;59054:33:0;:61;;;59032:149;;;;-1:-1:-1;;;59032:149:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52782:1;59214:46;;:9;-1:-1:-1;;;;;59214:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;59214:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;59214:26:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;59214:26:0;:46;;;59192:132;;;;-1:-1:-1;;;59192:132:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;109394:1160;-1:-1:-1;;;;;109717:20:0;;109709:59;;;;;-1:-1:-1;;;109709:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;109801:39:0;;109779:132;;;;-1:-1:-1;;;109779:132:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;109944:40:0;;109922:134;;;;-1:-1:-1;;;109922:134:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;110089:33:0;;110067:120;;;;-1:-1:-1;;;110067:120:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;110198:42;110223:16;110198:24;:42::i;:::-;110273:273;;;;;;;;-1:-1:-1;;;;;110273:273:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;110251:19:0;;;;;;;;;;;:295;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;109394:1160::o;98125:191::-;-1:-1:-1;;;;;98210:20:0;;;;;;:13;:20;;;;;;:30;-1:-1:-1;98210:30:0;98202:65;;;;;-1:-1:-1;;;98202:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;98278:20:0;;;;;;;:13;:20;;;;;:30;;;;;;;;98125:191::o;81629:172::-;81714:79;81727:9;81738:6;81714:79;;;;;;;;;;;;;;;;;:12;:79::i;54653:164::-;54749:15;54789:6;-1:-1:-1;;;;;54789:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;54789:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;54789:20:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;54789:20:0;;54653:164;-1:-1:-1;;54653:164:0:o;52046:166::-;52148:15;;52046:166::o;5714:192::-;5800:7;5836:12;5828:6;;;;5820:29;;;;-1:-1:-1;;;5820:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;5820:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5872:5:0;;;5714:192::o;33685:179::-;33741:6;33776:5;33768;:13;33760:65;;;;-1:-1:-1;;;33760:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;33850:5:0;33685:179::o;54934:211::-;55062:20;55102:6;-1:-1:-1;;;;;55102:20:0;;55123:13;55102:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;55102:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;55102:35:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;55102:35:0;55095:42;;;54934:211;-1:-1:-1;;;54934:211:0:o;118023:1341::-;118251:7;118271:20;118320:16;118344:27;118353:9;118364:6;118344:8;:27::i;:::-;118317:54;;;;;118402:169;:140;118451:23;:21;:23::i;118402:140::-;:167;:169::i;:::-;118386:185;;118023:1341;118595:17;118623:23;118672:20;118745:18;-1:-1:-1;;;;;118745:52:0;;118798:9;118809:6;118817:13;118745:86;;;;;;;;;;;;;-1:-1:-1;;;;;118745:86:0;-1:-1:-1;;;;;118745:86:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;118745:86:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;118745:86:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;118745:86:0;80:15:-1;;;97:9;76:31;65:43;;120:4;113:20;15:2;7:11;;4:2;;;31:1;28;21:12;4:2;118745:86:0;;;;;;;;;;;;;;;;;;;;;;;19:11:-1;11:20;;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;219:3;213:10;331:9;325:2;311:12;307:21;289:16;285:44;282:59;261:11;247:12;244:29;233:116;230:2;;;362:1;359;352:12;230:2;373:25;;-1:-1;118745:86:0;;421:4:-1;412:14;;;;118745:86:0;;;;;412:14:-1;118745:86:0;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;118745:86:0;;;;;;;;;;;118707:124;;;;;;;;;;;;118851:15;118846:114;;118887:27;;;-1:-1:-1;;;118887:27:0;;;;;;;;;;;;;;;;;;;;;;;;;;;118846:114;118023:1341;119000:10;-1:-1:-1;;;;;119000:31:0;;119050:8;119077:6;119102:24;:13;:22;:24::i;:::-;119145:29;:18;:27;:29::i;:::-;119193:13;119000:221;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;119000:221:0;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;119000:221:0;;;;;;;;;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;119000:221:0;;;;;;;;;118983:374;;119344:1;119337:8;;;;;;;118983:374;-1:-1:-1;119292:11:0;-1:-1:-1;119285:18:0;;-1:-1:-1;;;119285:18:0;4827:181;4885:7;4917:5;;;4941:6;;;;4933:46;;;;;-1:-1:-1;;;4933:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;76330:1035;-1:-1:-1;;;;;76615:20:0;;76607:59;;;;;-1:-1:-1;;;76607:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;76699:36:0;;76677:126;;;;-1:-1:-1;;;76677:126:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;76836:37:0;;76814:128;;;;-1:-1:-1;;;76814:128:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;76975:33:0;;76953:120;;;;-1:-1:-1;;;76953:120:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77107:250;;;;;;;;-1:-1:-1;;;;;77107:250:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;77084:20:0;;;;;;;;;;;:273;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;76330:1035::o;7716:345::-;7802:7;7904:12;7897:5;7889:28;;;;-1:-1:-1;;;7889:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;7889:28:0;;7928:9;7944:1;7940;:5;;;;;;;7716:345;-1:-1:-1;;;;;7716:345:0:o;36572:154::-;36637:7;36664:54;36675:1;36678;36664:54;;;;;;;;;;;;;;;;;:10;:54::i;35826:181::-;35882:6;35917;35909:5;:14;35901:67;;;;-1:-1:-1;;;35901:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57819:804;57962:15;57990:13;58027:5;58006:18;:26;:152;;58090:9;58069:18;:30;:89;;58140:18;58069:89;;;58115:9;58069:89;58006:152;;;58048:5;58006:152;57990:168;-1:-1:-1;58194:18:0;;;58536:6;58328:191;58169:22;58351:13;;;;;;:40;;;58385:6;58368:14;:23;58351:40;:116;;58453:14;58351:116;;;58419:6;58328:189;:191::i;:::-;58299:9;:220;;;58298:244;;;;;;58274:268;;52561:5;58564:8;:24;:51;;58607:8;58564:51;;;52561:5;58553:62;57819:804;-1:-1:-1;;;;;;57819:804:0:o;62382:1115::-;62987:27;62995:5;-1:-1:-1;;;;;62987:25:0;;:27::i;:::-;62979:71;;;;;-1:-1:-1;;;62979:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;63124:12;63138:23;63173:5;-1:-1:-1;;;;;63165:19:0;63185:4;63165:25;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;139:12;;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;63165:25:0;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;19;14:27;;;;67:4;61:11;56:16;;134:4;130:9;123:4;105:16;101:27;97:43;94:1;90:51;84:4;77:65;157:16;154:1;147:27;211:16;208:1;201:4;198:1;194:12;179:49;5:228;;14:27;32:4;27:9;;5:228;;63123:67:0;;;;63209:7;63201:52;;;;;-1:-1:-1;;;63201:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63270:17;;:21;63266:224;;63412:10;63401:30;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;63401:30:0;63393:85;;;;-1:-1:-1;;;63393:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81185:436;81340:29;81362:6;81340:21;:29::i;:::-;81371:12;81332:52;;;;;-1:-1:-1;;;81332:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;81332:52:0;-1:-1:-1;81414:33:0;;81396:12;;-1:-1:-1;;;;;81414:14:0;;;81436:6;;81396:12;81414:33;81396:12;81414:33;81436:6;81414:14;:33;;;;;;;12:1:-1;19;14:27;;;;67:4;61:11;56:16;;134:4;130:9;123:4;105:16;101:27;97:43;94:1;90:51;84:4;77:65;157:16;154:1;147:27;211:16;208:1;201:4;198:1;194:12;179:49;5:228;;14:27;32:4;27:9;;5:228;;81395:52:0;;;81512:7;81504:45;;;;;-1:-1:-1;;;81504:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;81565:48;;;;;;;;-1:-1:-1;;;;;81565:48:0;;;81588:4;;81565:48;;;;;;;;;81185:436;;;;:::o;36289:275::-;36416:7;36440:6;36436:47;;-1:-1:-1;36470:1:0;36463:8;;36436:47;36508:12;36501:5;36493:28;;;;-1:-1:-1;;;36493:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;36493:28:0;;36550:1;36545;36541;:5;36540:11;;;;;;36555:1;36539:17;36532:24;;36289:275;;;;;:::o;10037:619::-;10097:4;10565:20;;10408:66;10605:23;;;;;;:42;;-1:-1:-1;10632:15:0;;;10605:42;10597:51;10037:619;-1:-1:-1;;;;10037:619:0:o;80894:182::-;81015:4;81048:20;-1:-1:-1;81038:30:0;;80894:182::o;119461:538::-;;;;;;;;;-1:-1:-1;119461:538:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;119461:538:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o

Swarm Source

ipfs://7d46b6e6ab3d17a7a0bf149999e36885cb46e29bb984f9b0fb8158d023d86fd1

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.