ETH Price: $2,640.83 (-2.85%)

Contract

0xA48E4Ee9814BFe3e176A273403EAF181AFe5c286
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Remove Liquidity109288602020-09-25 1:30:171607 days ago1600997417IN
0xA48E4Ee9...1AFe5c286
0 ETH0.0075714173
Order Base To Se...109070872020-09-21 17:12:421611 days ago1600708362IN
0xA48E4Ee9...1AFe5c286
0 ETH0.0276571100
Execute Unexecut...108919952020-09-19 10:02:031613 days ago1600509723IN
0xA48E4Ee9...1AFe5c286
0 ETH0.02165912121
Order Base To Se...108914522020-09-19 8:04:521613 days ago1600502692IN
0xA48E4Ee9...1AFe5c286
0 ETH0.0237583143
Execute Unexecut...108889542020-09-18 22:49:051613 days ago1600469345IN
0xA48E4Ee9...1AFe5c286
0 ETH0.01523683104
Order Base To Se...108878092020-09-18 18:30:381614 days ago1600453838IN
0xA48E4Ee9...1AFe5c286
0 ETH0.10754818406
Remove Liquidity108822352020-09-17 21:46:101614 days ago1600379170IN
0xA48E4Ee9...1AFe5c286
0 ETH0.0466569450
Remove Liquidity108819502020-09-17 20:39:451614 days ago1600375185IN
0xA48E4Ee9...1AFe5c286
0 ETH0.04219857407
Remove Liquidity108809882020-09-17 17:11:461615 days ago1600362706IN
0xA48E4Ee9...1AFe5c286
0 ETH0.05132259495
Remove Liquidity108787252020-09-17 8:59:291615 days ago1600333169IN
0xA48E4Ee9...1AFe5c286
0 ETH0.051841500
Remove Liquidity108786202020-09-17 8:39:111615 days ago1600331951IN
0xA48E4Ee9...1AFe5c286
0 ETH0.09138514770
Order Settlement...108729022020-09-16 11:31:481616 days ago1600255908IN
0xA48E4Ee9...1AFe5c286
0 ETH0.03409853115
Order Settlement...108728862020-09-16 11:28:501616 days ago1600255730IN
0xA48E4Ee9...1AFe5c286
0 ETH0.03646742115.00000145
Order Settlement...108728332020-09-16 11:16:231616 days ago1600254983IN
0xA48E4Ee9...1AFe5c286
0 ETH0.03208467117
Order Base To Se...108728282020-09-16 11:15:251616 days ago1600254925IN
0xA48E4Ee9...1AFe5c286
0 ETH0.02073862125
Execute Unexecut...108728222020-09-16 11:13:151616 days ago1600254795IN
0xA48E4Ee9...1AFe5c286
0 ETH0.01904604130
Order Base To Se...108728202020-09-16 11:12:561616 days ago1600254776IN
0xA48E4Ee9...1AFe5c286
0 ETH0.03200437125
Order Base To Se...108728132020-09-16 11:11:381616 days ago1600254698IN
0xA48E4Ee9...1AFe5c286
0 ETH0.02156817130
Execute Unexecut...108728092020-09-16 11:10:211616 days ago1600254621IN
0xA48E4Ee9...1AFe5c286
0 ETH0.01302949107
Order Base To Se...108727972020-09-16 11:08:381616 days ago1600254518IN
0xA48E4Ee9...1AFe5c286
0 ETH0.03815933110
Order Base To Se...108727942020-09-16 11:07:571616 days ago1600254477IN
0xA48E4Ee9...1AFe5c286
0 ETH0.06142665150
Order Base To Se...108727892020-09-16 11:06:281616 days ago1600254388IN
0xA48E4Ee9...1AFe5c286
0 ETH0.00963512110
Order Base To Se...108727892020-09-16 11:06:281616 days ago1600254388IN
0xA48E4Ee9...1AFe5c286
0 ETH0.02651385110
Order Base To Se...108727832020-09-16 11:04:381616 days ago1600254278IN
0xA48E4Ee9...1AFe5c286
0 ETH0.00495001130
Order Base To Se...108727832020-09-16 11:04:381616 days ago1600254278IN
0xA48E4Ee9...1AFe5c286
0 ETH0.03026079109
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LienBoxExchange

Compiler Version
v0.6.6+commit.6c089d02

Optimization Enabled:
Yes with 200 runs

Other Settings:
constantinople EvmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2020-08-31
*/

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    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

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @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

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

// File: @openzeppelin/contracts/utils/Address.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.2;

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

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

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

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

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

    function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

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

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;





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

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;


/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 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} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` 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 Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits");
        return int8(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/Interfaces/PriceCalculatorInterface.sol

pragma solidity >=0.6.6;

interface PriceCalculatorInterface {
    function calculatePrice(
        uint256 buyAmount,
        uint256 buyAmountLimit,
        uint256 sellAmount,
        uint256 sellAmountLimit,
        uint256 baseTokenPool,
        uint256 settlementTokenPool
    ) external view returns (uint256[5] memory);
}

// File: contracts/Libraries/Enums.sol

pragma solidity >=0.6.6;

enum Token {TOKEN0, TOKEN1}

// FLEX_0_1 => Swap TOKEN0 to TOKEN1, slippage is tolerate to 5%
// FLEX_1_0 => Swap TOKEN1 to TOKEN0, slippage is tolerate to 5%
// STRICT_0_1 => Swap TOKEN0 to TOKEN1, slippage is limited in 0.1%
// STRICT_1_0 => Swap TOKEN1 to TOKEN0, slippage is limited in 0.1%
enum OrderType {FLEX_0_1, FLEX_1_0, STRICT_0_1, STRICT_1_0}

library TokenLibrary {
    function another(Token self) internal pure returns (Token) {
        if (self == Token.TOKEN0) {
            return Token.TOKEN1;
        } else {
            return Token.TOKEN0;
        }
    }
}

library OrderTypeLibrary {
    function inToken(OrderType self) internal pure returns (Token) {
        if (self == OrderType.FLEX_0_1 || self == OrderType.STRICT_0_1) {
            return Token.TOKEN0;
        } else {
            return Token.TOKEN1;
        }
    }

    function isFlex(OrderType self) internal pure returns (bool) {
        return self == OrderType.FLEX_0_1 || self == OrderType.FLEX_1_0;
    }

    function isStrict(OrderType self) internal pure returns (bool) {
        return !isFlex(self);
    }

    function next(OrderType self) internal pure returns (OrderType) {
        return OrderType((uint256(self) + 1) % 4);
    }

    function isBuy(OrderType self) internal pure returns (bool) {
        return (self == OrderType.FLEX_0_1 || self == OrderType.STRICT_0_1);
    }
}

// File: contracts/Libraries/RateMath.sol

pragma solidity >=0.6.6;


library RateMath {
    using SafeMath for uint256;
    uint256 public constant RATE_POINT_MULTIPLIER = 1000000000000000000; // 10^18

    function getRate(uint256 a, uint256 b) internal pure returns (uint256) {
        return a.mul(RATE_POINT_MULTIPLIER).div(b);
    }

    function divByRate(uint256 self, uint256 rate)
        internal
        pure
        returns (uint256)
    {
        return self.mul(RATE_POINT_MULTIPLIER).div(rate);
    }

    function mulByRate(uint256 self, uint256 rate)
        internal
        pure
        returns (uint256)
    {
        return self.mul(rate).div(RATE_POINT_MULTIPLIER);
    }
}

// File: contracts/Libraries/ExecutionStatus.sol

pragma solidity >=0.6.6;



struct BoxExecutionStatus {
    OrderType partiallyRefundOrderType;
    uint64 partiallyRefundRate; // refundAmount/inAmount
    uint128 rate; // Token0/Token1
    uint32 boxNumber;
    bool onGoing;
}

struct BookExecutionStatus {
    OrderType executingOrderType;
    uint256 nextIndex;
}

library BoxExecutionStatusLibrary {
    using OrderTypeLibrary for OrderType;

    function refundRate(BoxExecutionStatus memory self, OrderType orderType)
        internal
        pure
        returns (uint256)
    {
        // inToken is different from refundOrderType
        if (self.partiallyRefundOrderType.inToken() != orderType.inToken()) {
            return 0;
        }

        // inToken is the same as refundOrderType
        // refund all of strict order and some of flex order
        if (self.partiallyRefundOrderType.isFlex()) {
            // orderType is flex
            if (orderType.isFlex()) {
                return self.partiallyRefundRate;
            }
            // orderType is strict
            return RateMath.RATE_POINT_MULTIPLIER;
        }

        // refund some of strict order
        if (orderType.isStrict()) {
            return self.partiallyRefundRate;
        }
        return 0;
    }
}

// File: contracts/Libraries/OrderBox.sol

pragma solidity >=0.6.6;




struct OrderBox {
    mapping(OrderType => OrderBook) orderBooks;
    uint128 spreadRate;
    uint128 expireAt;
}

struct OrderBook {
    mapping(address => uint256) inAmounts;
    address[] recipients;
    uint256 totalInAmount;
}

library OrderBoxLibrary {
    using RateMath for uint256;
    using SafeMath for uint256;
    using TokenLibrary for Token;

    function newOrderBox(uint128 spreadRate, uint128 expireAt)
        internal
        pure
        returns (OrderBox memory)
    {
        return OrderBox({spreadRate: spreadRate, expireAt: expireAt});
    }

    function addOrder(
        OrderBox storage self,
        OrderType orderType,
        uint256 inAmount,
        address recipient
    ) internal {
        OrderBook storage orderBook = self.orderBooks[orderType];
        if (orderBook.inAmounts[recipient] == 0) {
            orderBook.recipients.push(recipient);
        }
        orderBook.inAmounts[recipient] = orderBook.inAmounts[recipient].add(
            inAmount
        );
        orderBook.totalInAmount = orderBook.totalInAmount.add(inAmount);
    }
}

library OrderBookLibrary {
    function numOfOrder(OrderBook memory self) internal pure returns (uint256) {
        return self.recipients.length;
    }
}

// File: contracts/BoxExchange/BoxExchange.sol

pragma solidity ^0.6.6;


abstract contract BoxExchange is ERC20 {
    using BoxExecutionStatusLibrary for BoxExecutionStatus;
    using OrderBoxLibrary for OrderBox;
    using OrderBookLibrary for OrderBook;
    using OrderTypeLibrary for OrderType;
    using TokenLibrary for Token;
    using RateMath for uint256;
    using SafeMath for uint256;
    using SafeCast for uint256;

    uint256 internal constant MARKET_FEE_RATE = 200000000000000000; // market fee taker takes 20% of spread

    address internal immutable factory;

    address internal immutable marketFeeTaker; // Address that receives market fee (i.e. Lien Token)
    uint128 public marketFeePool0; // Total market fee in TOKEN0
    uint128 public marketFeePool1; // Total market fee in TOKEN1

    uint128 internal reserve0; // Total Liquidity of TOKEN0
    uint128 internal reserve1; // Total Liquidity of TOKEN1
    OrderBox[] internal orderBoxes; // Array of OrderBox
    PriceCalculatorInterface internal immutable priceCalc; // Price Calculator
    BoxExecutionStatus internal boxExecutionStatus; // Struct that has information about execution of current executing OrderBox
    BookExecutionStatus internal bookExecutionStatus; // Struct that has information about execution of current executing OrderBook

    event AcceptOrders(
        address indexed recipient,
        bool indexed isBuy, // if true, this order is exchange from TOKEN0 to TOKEN1
        uint32 indexed boxNumber,
        bool isLimit, // if true, this order is STRICT order
        uint256 tokenIn
    );

    event MoveLiquidity(
        address indexed liquidityProvider,
        bool indexed isAdd, // if true, this order is addtion of liquidity
        uint256 movedToken0Amount,
        uint256 movedToken1Amount,
        uint256 sharesMoved // Amount of share that is minted or burned
    );

    event Execution(
        bool indexed isBuy, // if true, this order is exchange from TOKEN0 to TOKEN1
        uint32 indexed boxNumber,
        address indexed recipient,
        uint256 orderAmount, // Amount of token that is transferred when this order is added
        uint256 refundAmount, // In the same token as orderAmount
        uint256 outAmount // In the other token than orderAmount
    );

    event UpdateReserve(uint128 reserve0, uint128 reserve1, uint256 totalShare);

    event PayMarketFee(uint256 amount0, uint256 amount1);

    event ExecutionSummary(
        uint32 indexed boxNumber,
        uint8 partiallyRefundOrderType,
        uint256 rate,
        uint256 partiallyRefundRate,
        uint256 totalInAmountFLEX_0_1,
        uint256 totalInAmountFLEX_1_0,
        uint256 totalInAmountSTRICT_0_1,
        uint256 totalInAmountSTRICT_1_0
    );

    modifier isAmountSafe(uint256 amount) {
        require(amount != 0, "Amount should be bigger than 0");
        _;
    }

    modifier isInTime(uint256 timeout) {
        require(timeout > _currentOpenBoxId(), "Time out");
        _;
    }

    constructor(
        PriceCalculatorInterface _priceCalc,
        address _marketFeeTaker,
        string memory _name
    ) public ERC20(_name, "share") {
        factory = msg.sender;
        priceCalc = _priceCalc;
        marketFeeTaker = _marketFeeTaker;
        _setupDecimals(8); // Decimal of share token is the same as iDOL, LBT, and Lien Token
    }

    /**
     * @notice Shows how many boxes and orders exist before the specific order
     * @dev If this order does not exist, return (false, 0, 0)
     * @dev If this order is already executed, return (true, 0, 0)
     * @param recipient Recipient of this order
     * @param boxNumber Box ID where the order exists
     * @param isExecuted If true, the order is already executed
     * @param boxCount Counter of boxes before this order. If current executing box number is the same as boxNumber, return 1 (i.e. indexing starts from 1)
     * @param orderCount Counter of orders before this order. If this order is on n-th top of the queue, return n (i.e. indexing starts from 1)
     **/
    function whenToExecute(
        address recipient,
        uint256 boxNumber,
        bool isBuy,
        bool isLimit
    )
        external
        view
        returns (
            bool isExecuted,
            uint256 boxCount,
            uint256 orderCount
        )
    {
        return
            _whenToExecute(recipient, _getOrderType(isBuy, isLimit), boxNumber);
    }

    /**
     * @notice Returns summary of current exchange status
     * @param boxNumber Current open box ID
     * @param _reserve0 Current reserve of TOKEN0
     * @param _reserve1 Current reserve of TOKEN1
     * @param totalShare Total Supply of share token
     * @param latestSpreadRate Spread Rate in latest OrderBox
     * @param token0PerShareE18 Amount of TOKEN0 per 1 share token and has 18 decimal
     * @param token1PerShareE18 Amount of TOKEN1 per 1 share token and has 18 decimal
     **/
    function getExchangeData()
        external
        virtual
        view
        returns (
            uint256 boxNumber,
            uint256 _reserve0,
            uint256 _reserve1,
            uint256 totalShare,
            uint256 latestSpreadRate,
            uint256 token0PerShareE18,
            uint256 token1PerShareE18
        )
    {
        boxNumber = _currentOpenBoxId();
        (_reserve0, _reserve1) = _getReserves();
        latestSpreadRate = orderBoxes[boxNumber].spreadRate;
        totalShare = totalSupply();
        token0PerShareE18 = RateMath.getRate(_reserve0, totalShare);
        token1PerShareE18 = RateMath.getRate(_reserve1, totalShare);
    }

    /**
     * @notice Gets summary of Current box information (Total order amount of each OrderTypes)
     * @param executionStatusNumber Status of execution of this box
     * @param boxNumber ID of target box.
     **/
    function getBoxSummary(uint256 boxNumber)
        public
        view
        returns (
            uint256 executionStatusNumber,
            uint256 flexToken0InAmount,
            uint256 strictToken0InAmount,
            uint256 flexToken1InAmount,
            uint256 strictToken1InAmount
        )
    {
        // `executionStatusNumber`
        // 0 => This box has not been executed
        // 1 => This box is currently executing. (Reserves and market fee pools have already been updated)
        // 2 => This box has already been executed
        uint256 nextExecutingBoxId = boxExecutionStatus.boxNumber;
        flexToken0InAmount = orderBoxes[boxNumber].orderBooks[OrderType
            .FLEX_0_1]
            .totalInAmount;
        strictToken0InAmount = orderBoxes[boxNumber].orderBooks[OrderType
            .STRICT_0_1]
            .totalInAmount;
        flexToken1InAmount = orderBoxes[boxNumber].orderBooks[OrderType
            .FLEX_1_0]
            .totalInAmount;
        strictToken1InAmount = orderBoxes[boxNumber].orderBooks[OrderType
            .STRICT_1_0]
            .totalInAmount;
        if (boxNumber < nextExecutingBoxId) {
            executionStatusNumber = 2;
        } else if (
            boxNumber == nextExecutingBoxId && boxExecutionStatus.onGoing
        ) {
            executionStatusNumber = 1;
        }
    }

    /**
     * @notice Gets amount of order in current open box
     * @param account Target Address
     * @param orderType OrderType of target order
     * @return Amount of target order
     **/
    function getOrderAmount(address account, OrderType orderType)
        public
        view
        returns (uint256)
    {
        return
            orderBoxes[_currentOpenBoxId()].orderBooks[orderType]
                .inAmounts[account];
    }

    // abstract functions
    function _feeRate() internal virtual returns (uint128);

    function _receiveTokens(
        Token token,
        address from,
        uint256 amount
    ) internal virtual;

    function _sendTokens(
        Token token,
        address to,
        uint256 amount
    ) internal virtual;

    function _payForOrderExecution(
        Token token,
        address to,
        uint256 amount
    ) internal virtual;

    function _payMarketFee(
        address _marketFeeTaker,
        uint256 amount0,
        uint256 amount1
    ) internal virtual;

    function _isCurrentOpenBoxExpired() internal virtual view returns (bool) {}

    /**
     * @notice User can determine the amount of share token to mint.
     * @dev This function can be executed only by factory
     * @param amount0 The amount of TOKEN0 to invest
     * @param amount1 The amount of TOKEN1 to invest
     * @param initialShare The amount of share token to mint. This defines approximate value of share token.
     **/
    function _init(
        uint128 amount0,
        uint128 amount1,
        uint256 initialShare
    ) internal virtual {
        require(totalSupply() == 0, "Already initialized");
        require(msg.sender == factory);
        _updateReserve(amount0, amount1);
        _mint(msg.sender, initialShare);
        _receiveTokens(Token.TOKEN0, msg.sender, amount0);
        _receiveTokens(Token.TOKEN1, msg.sender, amount1);
        _openNewBox();
    }

    /**
     * @dev Amount of share to mint is determined by `amount`
     * @param tokenType Type of token which the amount of share the LP get is calculated based on `amount`
     * @param amount The amount of token type of `tokenType`
     **/
    function _addLiquidity(
        uint256 _reserve0,
        uint256 _reserve1,
        uint256 amount,
        uint256 minShare,
        Token tokenType
    ) internal virtual {
        (uint256 amount0, uint256 amount1, uint256 share) = _calculateAmounts(
            amount,
            _reserve0,
            _reserve1,
            tokenType
        );
        require(share >= minShare, "You can't receive enough shares");
        _receiveTokens(Token.TOKEN0, msg.sender, amount0);
        _receiveTokens(Token.TOKEN1, msg.sender, amount1);
        _updateReserve(
            _reserve0.add(amount0).toUint128(),
            _reserve1.add(amount1).toUint128()
        );
        _mint(msg.sender, share);
        emit MoveLiquidity(msg.sender, true, amount0, amount1, share);
    }

    /**
     * @dev Amount of TOKEN0 and TOKEN1 is determined by amount of share to be burned
     * @param minAmount0 Minimum amount of TOKEN0 to return. If returned TOKEN0 is less than this value, revert transaction
     * @param minAmount1 Minimum amount of TOKEN1 to return. If returned TOKEN1 is less than this value, revert transaction
     * @param share Amount of share token to be burned
     **/
    function _removeLiquidity(
        uint256 minAmount0,
        uint256 minAmount1,
        uint256 share
    ) internal virtual {
        (uint256 _reserve0, uint256 _reserve1) = _getReserves(); // gas savings
        uint256 _totalSupply = totalSupply();
        uint256 amount0 = _reserve0.mul(share).div(_totalSupply);
        uint256 amount1 = _reserve1.mul(share).div(_totalSupply);
        require(
            amount0 >= minAmount0 && amount1 >= minAmount1,
            "You can't receive enough tokens"
        );
        _updateReserve(
            _reserve0.sub(amount0).toUint128(),
            _reserve1.sub(amount1).toUint128()
        );
        _burn(msg.sender, share);
        _sendTokens(Token.TOKEN0, msg.sender, amount0);
        _sendTokens(Token.TOKEN1, msg.sender, amount1);
        emit MoveLiquidity(msg.sender, false, amount0, amount1, share);
    }

    /**
     * @dev If there is some OrderBox to be executed, try execute 5 orders
     * @dev If currentBox has expired, open new box
     * @param orderType Type of order
     * @param inAmount Amount of token to be exchanged
     * @param recipient Recipient of swapped token. If this value is address(0), msg.sender is the recipient
     **/
    function _addOrder(
        OrderType orderType,
        uint256 inAmount,
        address recipient
    ) internal virtual {
        _rotateBox();
        uint256 _currentOpenBoxId = _currentOpenBoxId();
        _executeOrders(5, _currentOpenBoxId);
        if (recipient == address(0)) {
            recipient = msg.sender;
        }
        _receiveTokens(orderType.inToken(), msg.sender, inAmount);
        orderBoxes[_currentOpenBoxId].addOrder(orderType, inAmount, recipient);
        emit AcceptOrders(
            recipient,
            orderType.isBuy(),
            uint32(_currentOpenBoxId),
            orderType.isStrict(),
            inAmount
        );
    }

    /**
     * @dev Triggers executeOrders()
     * @param maxOrderNum Number of orders to execute (if no order is left, stop execution)
     **/
    function _triggerExecuteOrders(uint8 maxOrderNum) internal virtual {
        _executeOrders(maxOrderNum, _currentOpenBoxId());
    }

    /**
     * @dev Triggers PayMarketFee() and update marketFeePool to 0
     **/
    function _triggerPayMarketFee() internal virtual {
        (
            uint256 _marketFeePool0,
            uint256 _marketFeePool1
        ) = _getMarketFeePools();
        _updateMarketFeePool(0, 0);

        emit PayMarketFee(_marketFeePool0, _marketFeePool1);
        _payMarketFee(marketFeeTaker, _marketFeePool0, _marketFeePool1);
    }

    // When open new box, creates new OrderBox with spreadRate and block number of expiretion, then pushes it to orderBoxes
    function _openNewBox() internal virtual {
        orderBoxes.push(
            OrderBoxLibrary.newOrderBox(
                _feeRate(),
                (block.number + 2).toUint32()
            )
        );
    }

    function _rotateBox() private {
        // if current open box has expired
        if (_isCurrentOpenBoxExpired()) {
            _openNewBox();
        }
    }

    /**
     * @param maxOrderNum Number of orders to execute (if no order is left, stoppes execution)
     * @param _currentOpenBoxId Current box ID (_currentOpenBoxID() is already run in _addOrder() or _triggerExecuteOrders()
     **/
    function _executeOrders(uint256 maxOrderNum, uint256 _currentOpenBoxId)
        private
    {
        BoxExecutionStatus memory _boxExecutionStatus = boxExecutionStatus;
        BookExecutionStatus memory _bookExecutionStatus = bookExecutionStatus;
        // if _boxExecutionStatus.boxNumber is current open and not expired box, won't execute.
        // if _boxExecutionStatus.boxNumber is more than currentOpenBoxId, the newest box is already executed.
        if (
            _boxExecutionStatus.boxNumber >= _currentOpenBoxId &&
            (!_isCurrentOpenBoxExpired() ||
                _boxExecutionStatus.boxNumber > _currentOpenBoxId)
        ) {
            return;
        }
        if (!_boxExecutionStatus.onGoing) {
            // get rates and start new box execution
            // before start new box execution, updates reserves.
            {
                (
                    OrderType partiallyRefundOrderType,
                    uint256 partiallyRefundRate,
                    uint256 rate
                ) = _getExecutionRatesAndUpdateReserve(
                    _boxExecutionStatus.boxNumber
                );
                _boxExecutionStatus
                    .partiallyRefundOrderType = partiallyRefundOrderType;
                _boxExecutionStatus.partiallyRefundRate = partiallyRefundRate
                    .toUint64();
                _boxExecutionStatus.rate = rate.toUint128();
                _boxExecutionStatus.onGoing = true;
                _bookExecutionStatus.executingOrderType = OrderType(0);
                _bookExecutionStatus.nextIndex = 0;
            }
        }
        // execute orders in one book
        // reducing maxOrderNum to avoid stack to deep
        while (maxOrderNum != 0) {
            OrderBook storage executionBook = orderBoxes[_boxExecutionStatus
                .boxNumber]
                .orderBooks[_bookExecutionStatus.executingOrderType];
            (
                bool isBookFinished,
                uint256 nextIndex,
                uint256 executedOrderNum
            ) = _executeOrdersInBook(
                executionBook,
                _bookExecutionStatus.executingOrderType.inToken(),
                _bookExecutionStatus.nextIndex,
                _boxExecutionStatus.refundRate(
                    _bookExecutionStatus.executingOrderType
                ),
                _boxExecutionStatus.rate,
                orderBoxes[_boxExecutionStatus.boxNumber].spreadRate,
                maxOrderNum
            );
            if (isBookFinished) {
                bool isBoxFinished = _isBoxFinished(
                    orderBoxes[_boxExecutionStatus.boxNumber],
                    _bookExecutionStatus.executingOrderType
                );
                delete orderBoxes[_boxExecutionStatus.boxNumber]
                    .orderBooks[_bookExecutionStatus.executingOrderType];

                // update book execution status and box execution status
                if (isBoxFinished) {
                    _boxExecutionStatus.boxNumber += 1;
                    _boxExecutionStatus.onGoing = false;
                    boxExecutionStatus = _boxExecutionStatus;

                    return; // no need to update bookExecutionStatus;
                }
                _bookExecutionStatus.executingOrderType = _bookExecutionStatus
                    .executingOrderType
                    .next();
            }
            _bookExecutionStatus.nextIndex = nextIndex.toUint32();
            maxOrderNum -= executedOrderNum;
        }
        boxExecutionStatus = _boxExecutionStatus;
        bookExecutionStatus = _bookExecutionStatus;
    }

    /**
     * @notice Executes each OrderBook
     * @param orderBook Target OrderBook
     * @param rate Rate of swap
     * @param refundRate Refund rate in this OrderType
     * @param maxOrderNum Max number of orders to execute in this book
     * @return If execution is finished, return true
     * @return Next index to execute. If execution is finished, return 0
     * @return Number of orders executed
     **/
    function _executeOrdersInBook(
        OrderBook storage orderBook,
        Token inToken,
        uint256 initialIndex,
        uint256 refundRate,
        uint256 rate,
        uint256 spreadRate,
        uint256 maxOrderNum
    )
        private
        returns (
            bool,
            uint256,
            uint256
        )
    {
        uint256 index;
        uint256 numOfOrder = orderBook.numOfOrder();
        for (
            index = initialIndex;
            index - initialIndex < maxOrderNum;
            index++
        ) {
            if (index >= numOfOrder) {
                return (true, 0, index - initialIndex);
            }
            address recipient = orderBook.recipients[index];
            _executeOrder(
                inToken,
                recipient,
                orderBook.inAmounts[recipient],
                refundRate,
                rate,
                spreadRate
            );
        }
        if (index >= numOfOrder) {
            return (true, 0, index - initialIndex);
        }
        return (false, index, index - initialIndex);
    }

    /**
     * @dev Executes each order
     * @param inToken type of token
     * @param recipient Recipient of Token
     * @param inAmount Amount of token
     * @param refundRate Refund rate in this OrderType
     * @param rate Rate of swap
     * @param spreadRate Spread rate in this box
     **/
    function _executeOrder(
        Token inToken,
        address recipient,
        uint256 inAmount,
        uint256 refundRate,
        uint256 rate,
        uint256 spreadRate
    ) internal {
        Token outToken = inToken.another();
        // refundAmount = inAmount * refundRate
        uint256 refundAmount = inAmount.mulByRate(refundRate);
        // executingInAmountWithoutSpread = (inAmount - refundAmount) / (1+spreadRate)
        uint256 executingInAmountWithoutSpread = inAmount
            .sub(refundAmount)
            .divByRate(RateMath.RATE_POINT_MULTIPLIER.add(spreadRate));
        // spread = executingInAmountWithoutSpread * spreadRate
        // = (inAmount - refundAmount ) * ( 1 - 1 /( 1 + spreadRate))
        uint256 outAmount = _otherAmountBasedOnRate(
            inToken,
            executingInAmountWithoutSpread,
            rate
        );
        _payForOrderExecution(inToken, recipient, refundAmount);
        _payForOrderExecution(outToken, recipient, outAmount);
        emit Execution(
            (inToken == Token.TOKEN0),
            uint32(_currentOpenBoxId()),
            recipient,
            inAmount,
            refundAmount,
            outAmount
        );
    }

    /**
     * @notice Updates reserves and market fee pools
     * @param spreadRate Spread rate in the box
     * @param executingAmount0WithoutSpread Executed amount of TOKEN0 in this box
     * @param executingAmount1WithoutSpread Executed amount of TOKEN1 in this box
     * @param rate Rate of swap
     **/
    function _updateReservesAndMarketFeePoolByExecution(
        uint256 spreadRate,
        uint256 executingAmount0WithoutSpread,
        uint256 executingAmount1WithoutSpread,
        uint256 rate
    ) internal virtual {
        uint256 newReserve0;
        uint256 newReserve1;
        uint256 newMarketFeePool0;
        uint256 newMarketFeePool1;
        {
            (
                uint256 differenceOfReserve,
                uint256 differenceOfMarketFee
            ) = _calculateNewReserveAndMarketFeePool(
                spreadRate,
                executingAmount0WithoutSpread,
                executingAmount1WithoutSpread,
                rate,
                Token.TOKEN0
            );
            newReserve0 = reserve0 + differenceOfReserve;
            newMarketFeePool0 = marketFeePool0 + differenceOfMarketFee;
        }
        {
            (
                uint256 differenceOfReserve,
                uint256 differenceOfMarketFee
            ) = _calculateNewReserveAndMarketFeePool(
                spreadRate,
                executingAmount1WithoutSpread,
                executingAmount0WithoutSpread,
                rate,
                Token.TOKEN1
            );
            newReserve1 = reserve1 + differenceOfReserve;
            newMarketFeePool1 = marketFeePool1 + differenceOfMarketFee;
        }
        _updateReserve(newReserve0.toUint128(), newReserve1.toUint128());
        _updateMarketFeePool(
            newMarketFeePool0.toUint128(),
            newMarketFeePool1.toUint128()
        );
    }

    function _whenToExecute(
        address recipient,
        uint256 orderTypeCount,
        uint256 boxNumber
    )
        internal
        view
        returns (
            bool isExecuted,
            uint256 boxCount,
            uint256 orderCount
        )
    {
        if (boxNumber > _currentOpenBoxId()) {
            return (false, 0, 0);
        }
        OrderBox storage yourOrderBox = orderBoxes[boxNumber];
        address[] memory recipients = yourOrderBox.orderBooks[OrderType(
            orderTypeCount
        )]
            .recipients;
        uint256 nextExecutingBoxId = boxExecutionStatus.boxNumber;
        uint256 nextIndex = bookExecutionStatus.nextIndex;
        uint256 nextType = uint256(bookExecutionStatus.executingOrderType);
        bool onGoing = boxExecutionStatus.onGoing;
        bool isExist;
        uint256 place;
        for (uint256 j = 0; j != recipients.length; j++) {
            if (recipients[j] == recipient) {
                isExist = true;
                place = j;
                break;
            }
        }

        // If current box number exceeds boxNumber, the target box has already been executed
        // If current box number is equal to boxNumber, and OrderType or index exceeds that of the target order, the target box has already been executed
        if (
            (boxNumber < nextExecutingBoxId) ||
            ((onGoing && (boxNumber == nextExecutingBoxId)) &&
                ((orderTypeCount < nextType) ||
                    ((orderTypeCount == nextType) && (place < nextIndex))))
        ) {
            return (true, 0, 0);
        }

        if (!isExist) {
            return (false, 0, 0);
        }

        // Total number of orders before the target OrderType
        uint256 counts;
        if (boxNumber == nextExecutingBoxId && onGoing) {
            for (uint256 i = nextType; i < orderTypeCount; i++) {
                counts += yourOrderBox.orderBooks[OrderType(i)].numOfOrder();
            }
            boxCount = 1;
            orderCount = counts.add(place).sub(nextIndex) + 1;
        } else {
            for (uint256 i = 0; i != orderTypeCount; i++) {
                counts += yourOrderBox.orderBooks[OrderType(i)].numOfOrder();
            }
            boxCount = boxNumber.sub(nextExecutingBoxId) + 1;
            orderCount = counts.add(place) + 1;
        }
    }

    function _getReserves()
        internal
        view
        returns (uint256 _reserve0, uint256 _reserve1)
    {
        _reserve0 = reserve0;
        _reserve1 = reserve1;
    }

    function _getMarketFeePools()
        internal
        view
        returns (uint256 _marketFeePool0, uint256 _marketFeePool1)
    {
        _marketFeePool0 = marketFeePool0;
        _marketFeePool1 = marketFeePool1;
    }

    function _updateReserve(uint128 newReserve0, uint128 newReserve1) internal {
        reserve0 = newReserve0;
        reserve1 = newReserve1;
        emit UpdateReserve(newReserve0, newReserve1, totalSupply());
    }

    function _calculatePriceWrapper(
        uint256 flexToken0InWithoutSpread,
        uint256 strictToken0InWithoutSpread,
        uint256 flexToken1InWithoutSpread,
        uint256 strictToken1InWithoutSpread,
        uint256 _reserve0,
        uint256 _reserve1
    )
        internal
        view
        returns (
            uint256 rate,
            uint256 refundStatus,
            uint256 partiallyRefundRate,
            uint256 executingAmount0,
            uint256 executingAmount1
        )
    {
        uint256[5] memory data = priceCalc.calculatePrice(
            flexToken0InWithoutSpread,
            strictToken0InWithoutSpread,
            flexToken1InWithoutSpread,
            strictToken1InWithoutSpread,
            _reserve0,
            _reserve1
        );
        return (data[0], data[1], data[2], data[3], data[4]);
    }

    /**
     * @param rate0Per1 Token0 / Token1 * RATE_POINT_MULTIPLIER
     */
    function _otherAmountBasedOnRate(
        Token token,
        uint256 amount,
        uint256 rate0Per1
    ) internal pure returns (uint256) {
        if (token == Token.TOKEN0) {
            return amount.mulByRate(rate0Per1);
        } else {
            return amount.divByRate(rate0Per1);
        }
    }

    function _currentOpenBoxId() internal view returns (uint256) {
        return orderBoxes.length - 1;
    }

    /**
     * @notice Gets OrderType in uint
     **/
    function _getOrderType(bool isBuy, bool isLimit)
        internal
        pure
        returns (uint256 orderTypeCount)
    {
        if (isBuy && isLimit) {
            orderTypeCount = 2;
        } else if (!isBuy) {
            if (isLimit) {
                orderTypeCount = 3;
            } else {
                orderTypeCount = 1;
            }
        }
    }

    function _updateMarketFeePool(
        uint128 newMarketFeePool0,
        uint128 newMarketFeePool1
    ) private {
        marketFeePool0 = newMarketFeePool0;
        marketFeePool1 = newMarketFeePool1;
    }

    function _calculateAmounts(
        uint256 amount,
        uint256 _reserve0,
        uint256 _reserve1,
        Token tokenType
    )
        private
        view
        returns (
            uint256,
            uint256,
            uint256
        )
    {
        if (tokenType == Token.TOKEN0) {
            return (
                amount,
                amount.mul(_reserve1).div(_reserve0),
                amount.mul(totalSupply()).div(_reserve0)
            );
        } else {
            return (
                amount.mul(_reserve0).div(_reserve1),
                amount,
                amount.mul(totalSupply()).div(_reserve1)
            );
        }
    }

    function _priceCalculateRates(
        OrderBox storage orderBox,
        uint256 totalInAmountFLEX_0_1,
        uint256 totalInAmountFLEX_1_0,
        uint256 totalInAmountSTRICT_0_1,
        uint256 totalInAmountSTRICT_1_0
    )
        private
        view
        returns (
            uint256 rate,
            uint256 refundStatus,
            uint256 partiallyRefundRate,
            uint256 executingAmount0,
            uint256 executingAmount1
        )
    {
        uint256 withoutSpreadRate = RateMath.RATE_POINT_MULTIPLIER +
            orderBox.spreadRate;
        return
            _calculatePriceWrapper(
                totalInAmountFLEX_0_1.divByRate(withoutSpreadRate),
                totalInAmountSTRICT_0_1.divByRate(withoutSpreadRate),
                totalInAmountFLEX_1_0.divByRate(withoutSpreadRate),
                totalInAmountSTRICT_1_0.divByRate(withoutSpreadRate),
                reserve0,
                reserve1
            );
    }

    function _getExecutionRatesAndUpdateReserve(uint32 boxNumber)
        private
        returns (
            OrderType partiallyRefundOrderType,
            uint256 partiallyRefundRate,
            uint256 rate
        )
    {
        OrderBox storage orderBox = orderBoxes[boxNumber];
        // `refundStatus`
        // 0 => no_refund
        // 1 => refund some of strictToken0
        // 2 => refund all strictToken0 and some of flexToken0
        // 3 => refund some of strictToken1
        // 4 => refund all strictToken1 and some of flexToken1
        uint256 refundStatus;
        uint256 executingAmount0WithoutSpread;
        uint256 executingAmount1WithoutSpread;
        uint256 totalInAmountFLEX_0_1 = orderBox.orderBooks[OrderType.FLEX_0_1]
            .totalInAmount;
        uint256 totalInAmountFLEX_1_0 = orderBox.orderBooks[OrderType.FLEX_1_0]
            .totalInAmount;
        uint256 totalInAmountSTRICT_0_1 = orderBox.orderBooks[OrderType
            .STRICT_0_1]
            .totalInAmount;
        uint256 totalInAmountSTRICT_1_0 = orderBox.orderBooks[OrderType
            .STRICT_1_0]
            .totalInAmount;
        (
            rate,
            refundStatus,
            partiallyRefundRate,
            executingAmount0WithoutSpread,
            executingAmount1WithoutSpread
        ) = _priceCalculateRates(
            orderBox,
            totalInAmountFLEX_0_1,
            totalInAmountFLEX_1_0,
            totalInAmountSTRICT_0_1,
            totalInAmountSTRICT_1_0
        );

        {
            if (refundStatus == 0) {
                partiallyRefundOrderType = OrderType.STRICT_0_1;
                //refundRate = 0;
            } else if (refundStatus == 1) {
                partiallyRefundOrderType = OrderType.STRICT_0_1;
            } else if (refundStatus == 2) {
                partiallyRefundOrderType = OrderType.FLEX_0_1;
            } else if (refundStatus == 3) {
                partiallyRefundOrderType = OrderType.STRICT_1_0;
            } else if (refundStatus == 4) {
                partiallyRefundOrderType = OrderType.FLEX_1_0;
            }
        }
        emit ExecutionSummary(
            boxNumber,
            uint8(partiallyRefundOrderType),
            rate,
            partiallyRefundRate,
            totalInAmountFLEX_0_1,
            totalInAmountFLEX_1_0,
            totalInAmountSTRICT_0_1,
            totalInAmountSTRICT_1_0
        );
        _updateReservesAndMarketFeePoolByExecution(
            orderBox.spreadRate,
            executingAmount0WithoutSpread,
            executingAmount1WithoutSpread,
            rate
        );
    }

    /**
     * @notice Detects if this OrderBox is finished
     * @param orders Target OrderBox
     * @param lastFinishedOrderType Latest OrderType which is executed
     **/
    function _isBoxFinished(
        OrderBox storage orders,
        OrderType lastFinishedOrderType
    ) private view returns (bool) {
        // If orderType is STRICT_1_0, no book is left
        if (lastFinishedOrderType == OrderType.STRICT_1_0) {
            return true;
        }
        for (uint256 i = uint256(lastFinishedOrderType.next()); i != 4; i++) {
            OrderBook memory book = orders.orderBooks[OrderType(i)];
            // If OrderBook has some order return false
            if (book.numOfOrder() != 0) {
                return false;
            }
        }
        return true;
    }

    function _calculateNewReserveAndMarketFeePool(
        uint256 spreadRate,
        uint256 executingAmountWithoutSpread,
        uint256 anotherExecutingAmountWithoutSpread,
        uint256 rate,
        Token tokenType
    ) internal returns (uint256, uint256) {
        uint256 totalSpread = executingAmountWithoutSpread.mulByRate(
            spreadRate
        );
        uint256 marketFee = totalSpread.mulByRate(MARKET_FEE_RATE);
        uint256 newReserve = executingAmountWithoutSpread +
            (totalSpread - marketFee) -
            _otherAmountBasedOnRate(
                tokenType.another(),
                anotherExecutingAmountWithoutSpread,
                rate
            );
        return (newReserve, marketFee);
    }

    function _getTokenType(bool isBuy, bool isStrict)
        internal
        pure
        returns (OrderType)
    {
        if (isBuy) {
            if (isStrict) {
                return OrderType.STRICT_0_1;
            } else {
                return OrderType.FLEX_0_1;
            }
        } else {
            if (isStrict) {
                return OrderType.STRICT_1_0;
            } else {
                return OrderType.FLEX_1_0;
            }
        }
    }
}

// File: contracts/Interfaces/ERC20Interface.sol

pragma solidity >=0.6.6;


interface ERC20Interface is IERC20 {
    function name() external view returns (string memory);
}

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;




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

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(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. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

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

// File: contracts/Interfaces/OracleInterface.sol

pragma solidity >=0.6.6;

interface OracleInterface {
    function latestPrice() external returns (uint256);

    function getVolatility() external returns (uint256);

    function latestId() external returns (uint256);
}

// File: contracts/Interfaces/SpreadCalculatorInterface.sol

pragma solidity >=0.6.6;


interface SpreadCalculatorInterface {
    function calculateCurrentSpread(
        uint256 _maturity,
        uint256 _strikePrice,
        OracleInterface oracle
    ) external returns (uint128);

    function calculateSpreadByAssetVolatility(OracleInterface oracle)
        external
        returns (uint128);
}

// File: contracts/BoxExchange/TokenBoxExchange/TokenBoxExchange.sol

pragma solidity >=0.6.6;






abstract contract TokenBoxExchange is BoxExchange {
    using SafeERC20 for ERC20Interface;

    ERC20Interface public immutable idol; // token0
    ERC20Interface public immutable token;
    SpreadCalculatorInterface internal immutable spreadCalc;
    OracleInterface internal immutable oracle;

    event SpreadRate(uint128 indexed boxNumber, uint128 spreadRate);

    /**
     * @param _idol iDOL contract
     * @param _token ERC20 contract
     * @param _priceCalc Price Calculator contract
     * @param _marketFeeTaker Address of market fee taker (i.e. Lien Token)
     * @param _spreadCalc Spread Calculator contract
     * @param _oracle Oracle contract
     * @param _name Name of share token
     **/
    constructor(
        ERC20Interface _idol,
        ERC20Interface _token,
        PriceCalculatorInterface _priceCalc,
        address _marketFeeTaker,
        SpreadCalculatorInterface _spreadCalc,
        OracleInterface _oracle,
        string memory _name
    ) public BoxExchange(_priceCalc, _marketFeeTaker, _name) {
        idol = _idol;
        token = _token;
        spreadCalc = _spreadCalc;
        oracle = _oracle;
    }

    /**
     * @param IDOLAmount Amount of initial liquidity of iDOL to be provided
     * @param settlementTokenAmount Amount of initial liquidity of the other token to be provided
     * @param initialShare Initial amount of share token
     **/
    function initializeExchange(
        uint256 IDOLAmount,
        uint256 settlementTokenAmount,
        uint256 initialShare
    ) external {
        _init(
            uint128(IDOLAmount),
            uint128(settlementTokenAmount),
            initialShare
        );
    }

    /**
     * @param timeout Revert if nextBoxNumber exceeds `timeout`
     * @param recipient Recipient of swapped token. If `recipient` == address(0), recipient is msg.sender
     * @param IDOLAmount Amount of token that should be approved before executing this function
     * @param isLimit Whether the order restricts a large slippage
     * @dev if isLimit is true and reserve0/reserve1 * 1.001 >  `rate`, the order will be executed, otherwise token will be refunded
     * @dev if isLimit is false and reserve0/reserve1 * 1.05 > `rate`, the order will be executed, otherwise token will be refunded
     **/
    function orderBaseToSettlement(
        uint256 timeout,
        address recipient,
        uint256 IDOLAmount,
        bool isLimit
    ) external isAmountSafe(IDOLAmount) isInTime(timeout) {
        OrderType orderType = _getTokenType(true, isLimit);
        _addOrder(orderType, IDOLAmount, recipient);
    }

    /**
     * @param timeout Revert if nextBoxNumber exceeds `timeout`
     * @param recipient Recipient of swapped token. If `recipient` == address(0), recipient is msg.sender
     * @param settlementTokenAmount Amount of token that should be approved before executing this function
     * @param isLimit Whether the order restricts a large slippage
     * @dev if isLimit is true and reserve0/reserve1 * 0.999 > `rate`, the order will be executed, otherwise token will be refunded
     * @dev if isLimit is false and reserve0/reserve1 * 0.95 > `rate`, the order will be executed, otherwise token will be refunded
     **/
    function orderSettlementToBase(
        uint256 timeout,
        address recipient,
        uint256 settlementTokenAmount,
        bool isLimit
    ) external isAmountSafe(settlementTokenAmount) isInTime(timeout) {
        OrderType orderType = _getTokenType(false, isLimit);
        _addOrder(orderType, settlementTokenAmount, recipient);
    }

    /**
     * @notice LP provides liquidity and receives share token
     * @param timeout Revert if nextBoxNumber exceeds `timeout`
     * @param IDOLAmount Amount of iDOL to be provided. The amount of the other token required is calculated based on this amount
     * @param minShares Minimum amount of share token LP will receive. If amount of share token is less than `minShares`, revert the transaction
     **/
    function addLiquidity(
        uint256 timeout,
        uint256 IDOLAmount,
        uint256 settlementTokenAmount,
        uint256 minShares
    )
        external
        isAmountSafe(IDOLAmount)
        isAmountSafe(settlementTokenAmount)
        isInTime(timeout)
    {
        require(timeout > _currentOpenBoxId(), "Time out");
        (uint256 _reserve0, uint256 _reserve1) = _getReserves(); // gas savings
        uint256 settlementAmountInBase = settlementTokenAmount
            .mul(_reserve0)
            .div(_reserve1);
        if (IDOLAmount <= settlementAmountInBase) {
            _addLiquidity(
                _reserve0,
                _reserve1,
                IDOLAmount,
                minShares,
                Token.TOKEN0
            );
        } else {
            _addLiquidity(
                _reserve0,
                _reserve1,
                settlementTokenAmount,
                minShares,
                Token.TOKEN1
            );
        }
    }

    /**
     * @notice LP burns share token and receives iDOL and the other token
     * @param timeout Revert if nextBoxNumber exceeds `timeout`
     * @param minBaseTokens Minimum amount of iDOL LP will receive. If amount of iDOL is less than `minBaseTokens`, revert the transaction
     * @param minSettlementTokens Minimum amount of the other token LP will get. If amount is less than `minSettlementTokens`, revert the transaction
     * @param sharesBurned Amount of share token to be burned
     **/
    function removeLiquidity(
        uint256 timeout,
        uint256 minBaseTokens,
        uint256 minSettlementTokens,
        uint256 sharesBurned
    ) external isInTime(timeout) {
        require(timeout > _currentOpenBoxId(), "Time out");
        _removeLiquidity(minBaseTokens, minSettlementTokens, sharesBurned);
    }

    /**
     * @notice Executes orders that are unexecuted
     * @param maxOrderNum Max number of orders to be executed
     **/
    function executeUnexecutedBox(uint8 maxOrderNum) external {
        _triggerExecuteOrders(maxOrderNum);
    }

    /**
     * @notice Sends market fee to Lien Token
     **/
    function sendMarketFeeToLien() external {
        _triggerPayMarketFee();
    }

    // definition of abstract functions

    function _receiveTokens(
        Token tokenType,
        address from,
        uint256 amount
    ) internal override {
        _IERC20(tokenType).safeTransferFrom(from, address(this), amount);
    }

    function _sendTokens(
        Token tokenType,
        address to,
        uint256 amount
    ) internal override {
        _IERC20(tokenType).safeTransfer(to, amount);
    }

    function _payForOrderExecution(
        Token tokenType,
        address to,
        uint256 amount
    ) internal override {
        _IERC20(tokenType).safeTransfer(to, amount);
    }

    function _isCurrentOpenBoxExpired() internal override view returns (bool) {
        return block.number >= orderBoxes[_currentOpenBoxId()].expireAt;
    }

    function _openNewBox() internal override(BoxExchange) {
        super._openNewBox();
        uint256 _boxNumber = _currentOpenBoxId();
        emit SpreadRate(
            _boxNumber.toUint128(),
            orderBoxes[_boxNumber].spreadRate
        );
    }

    function _IERC20(Token tokenType) internal view returns (ERC20Interface) {
        if (tokenType == Token.TOKEN0) {
            return idol;
        }
        return token;
    }
}

// File: contracts/BoxExchange/TokenBoxExchange/IDOLvsERC20/ERC20BoxExchange.sol

pragma solidity >=0.6.6;


contract ERC20BoxExchange is TokenBoxExchange {
    /**
     * @param _idol iDOL contract
     * @param _token ERC20 contract
     * @param _priceCalc Price Calculator contract
     * @param _marketFeeTaker Address of market fee taker (i.e. Lien Token)
     * @param _spreadCalc Spread Calculator contract
     * @param _oracle Oracle contract
     * @param _name Name of share token
     **/
    constructor(
        ERC20Interface _idol,
        ERC20Interface _token,
        PriceCalculatorInterface _priceCalc,
        address _marketFeeTaker,
        SpreadCalculatorInterface _spreadCalc,
        OracleInterface _oracle,
        string memory _name
    )
        public
        TokenBoxExchange(
            _idol,
            _token,
            _priceCalc,
            _marketFeeTaker,
            _spreadCalc,
            _oracle,
            _name
        )
    {}

    // definition of abstract functions
    function _feeRate() internal override returns (uint128) {
        return spreadCalc.calculateSpreadByAssetVolatility(oracle);
    }

    function _payMarketFee(
        address _marketFeeTaker,
        uint256 amount0,
        uint256 amount1
    ) internal override {
        if (amount0 != 0) {
            idol.safeTransfer(_marketFeeTaker, amount0);
        }
    }

    /**
     * @notice Updates reserves and market fee pools
     * @param spreadRate Spread rate in the box
     * @param executingAmount0WithoutSpread Executed amount of TOKEN0 in this box
     * @param executingAmount1WithoutSpread Executed amount of TOKEN1 in this box
     * @param rate Rate of swap
     **/
    function _updateReservesAndMarketFeePoolByExecution(
        uint256 spreadRate,
        uint256 executingAmount0WithoutSpread,
        uint256 executingAmount1WithoutSpread,
        uint256 rate
    ) internal virtual override {
        uint256 newReserve0;
        uint256 newReserve1;
        uint256 newMarketFeePool0;
        uint256 marketFee1;
        {
            (
                uint256 differenceOfReserve,
                uint256 differenceOfMarketFee
            ) = _calculateNewReserveAndMarketFeePool(
                spreadRate,
                executingAmount0WithoutSpread,
                executingAmount1WithoutSpread,
                rate,
                Token.TOKEN0
            );
            newReserve0 = reserve0 + differenceOfReserve;
            newMarketFeePool0 = marketFeePool0 + differenceOfMarketFee;
        }
        {
            (newReserve1, marketFee1) = _calculateNewReserveAndMarketFeePool(
                spreadRate,
                executingAmount1WithoutSpread,
                executingAmount0WithoutSpread,
                rate,
                Token.TOKEN1
            );
            newReserve1 = newReserve1 + reserve1;
        }

        {
            uint256 convertedSpread1to0 = marketFee1
                .mulByRate(newReserve0.divByRate(newReserve1.add(marketFee1)))
                .divByRate(RateMath.RATE_POINT_MULTIPLIER);
            newReserve1 = newReserve1 + marketFee1;
            newReserve0 = newReserve0 - convertedSpread1to0;
            newMarketFeePool0 = newMarketFeePool0 + convertedSpread1to0;
        }
        _updateReserve(newReserve0.toUint128(), newReserve1.toUint128());
        _updateMarketFeePool(newMarketFeePool0.toUint128());
    }

    /**
     * updates only pool0
     */
    function _updateMarketFeePool(uint256 newMarketFeePool0) internal {
        marketFeePool0 = newMarketFeePool0.toUint128();
    }
}

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

// File: @openzeppelin/contracts/utils/Arrays.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;


/**
 * @dev Collection of functions related to array types.
 */
library Arrays {
   /**
     * @dev Searches a sorted `array` and returns the first index that contains
     * a value greater or equal to `element`. If no such index exists (i.e. all
     * values in the array are strictly less than `element`), the array length is
     * returned. Time complexity O(log n).
     *
     * `array` is expected to be sorted in ascending order, and to contain no
     * repeated elements.
     */
    function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        if (array.length == 0) {
            return 0;
        }

        uint256 low = 0;
        uint256 high = array.length;

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds down (it does integer division with truncation).
            if (array[mid] > element) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
        if (low > 0 && array[low - 1] == element) {
            return low - 1;
        } else {
            return low;
        }
    }
}

// File: @openzeppelin/contracts/utils/Counters.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;


/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
 * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
 * directly accessed.
 */
library Counters {
    using SafeMath for uint256;

    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        // The {SafeMath} overflow check can be skipped here, see the comment at the top
        counter._value += 1;
    }

    function decrement(Counter storage counter) internal {
        counter._value = counter._value.sub(1);
    }
}

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;





/**
 * @dev This contract extends an ERC20 token with a snapshot mechanism. When a snapshot is created, the balances and
 * total supply at the time are recorded for later access.
 *
 * This can be used to safely create mechanisms based on token balances such as trustless dividends or weighted voting.
 * In naive implementations it's possible to perform a "double spend" attack by reusing the same balance from different
 * accounts. By using snapshots to calculate dividends or voting power, those attacks no longer apply. It can also be
 * used to create an efficient ERC20 forking mechanism.
 *
 * Snapshots are created by the internal {_snapshot} function, which will emit the {Snapshot} event and return a
 * snapshot id. To get the total supply at the time of a snapshot, call the function {totalSupplyAt} with the snapshot
 * id. To get the balance of an account at the time of a snapshot, call the {balanceOfAt} function with the snapshot id
 * and the account address.
 *
 * ==== Gas Costs
 *
 * Snapshots are efficient. Snapshot creation is _O(1)_. Retrieval of balances or total supply from a snapshot is _O(log
 * n)_ in the number of snapshots that have been created, although _n_ for a specific account will generally be much
 * smaller since identical balances in subsequent snapshots are stored as a single entry.
 *
 * There is a constant overhead for normal ERC20 transfers due to the additional snapshot bookkeeping. This overhead is
 * only significant for the first transfer that immediately follows a snapshot for a particular account. Subsequent
 * transfers will have normal cost until the next snapshot, and so on.
 */
abstract contract ERC20Snapshot is ERC20 {
    // Inspired by Jordi Baylina's MiniMeToken to record historical balances:
    // https://github.com/Giveth/minimd/blob/ea04d950eea153a04c51fa510b068b9dded390cb/contracts/MiniMeToken.sol

    using SafeMath for uint256;
    using Arrays for uint256[];
    using Counters for Counters.Counter;

    // Snapshotted values have arrays of ids and the value corresponding to that id. These could be an array of a
    // Snapshot struct, but that would impede usage of functions that work on an array.
    struct Snapshots {
        uint256[] ids;
        uint256[] values;
    }

    mapping (address => Snapshots) private _accountBalanceSnapshots;
    Snapshots private _totalSupplySnapshots;

    // Snapshot ids increase monotonically, with the first value being 1. An id of 0 is invalid.
    Counters.Counter private _currentSnapshotId;

    /**
     * @dev Emitted by {_snapshot} when a snapshot identified by `id` is created.
     */
    event Snapshot(uint256 id);

    /**
     * @dev Creates a new snapshot and returns its snapshot id.
     *
     * Emits a {Snapshot} event that contains the same id.
     *
     * {_snapshot} is `internal` and you have to decide how to expose it externally. Its usage may be restricted to a
     * set of accounts, for example using {AccessControl}, or it may be open to the public.
     *
     * [WARNING]
     * ====
     * While an open way of calling {_snapshot} is required for certain trust minimization mechanisms such as forking,
     * you must consider that it can potentially be used by attackers in two ways.
     *
     * First, it can be used to increase the cost of retrieval of values from snapshots, although it will grow
     * logarithmically thus rendering this attack ineffective in the long term. Second, it can be used to target
     * specific accounts and increase the cost of ERC20 transfers for them, in the ways specified in the Gas Costs
     * section above.
     *
     * We haven't measured the actual numbers; if this is something you're interested in please reach out to us.
     * ====
     */
    function _snapshot() internal virtual returns (uint256) {
        _currentSnapshotId.increment();

        uint256 currentId = _currentSnapshotId.current();
        emit Snapshot(currentId);
        return currentId;
    }

    /**
     * @dev Retrieves the balance of `account` at the time `snapshotId` was created.
     */
    function balanceOfAt(address account, uint256 snapshotId) public view returns (uint256) {
        (bool snapshotted, uint256 value) = _valueAt(snapshotId, _accountBalanceSnapshots[account]);

        return snapshotted ? value : balanceOf(account);
    }

    /**
     * @dev Retrieves the total supply at the time `snapshotId` was created.
     */
    function totalSupplyAt(uint256 snapshotId) public view returns(uint256) {
        (bool snapshotted, uint256 value) = _valueAt(snapshotId, _totalSupplySnapshots);

        return snapshotted ? value : totalSupply();
    }

    // _transfer, _mint and _burn are the only functions where the balances are modified, so it is there that the
    // snapshots are updated. Note that the update happens _before_ the balance change, with the pre-modified value.
    // The same is true for the total supply and _mint and _burn.
    function _transfer(address from, address to, uint256 value) internal virtual override {
        _updateAccountSnapshot(from);
        _updateAccountSnapshot(to);

        super._transfer(from, to, value);
    }

    function _mint(address account, uint256 value) internal virtual override {
        _updateAccountSnapshot(account);
        _updateTotalSupplySnapshot();

        super._mint(account, value);
    }

    function _burn(address account, uint256 value) internal virtual override {
        _updateAccountSnapshot(account);
        _updateTotalSupplySnapshot();

        super._burn(account, value);
    }

    function _valueAt(uint256 snapshotId, Snapshots storage snapshots)
        private view returns (bool, uint256)
    {
        require(snapshotId > 0, "ERC20Snapshot: id is 0");
        // solhint-disable-next-line max-line-length
        require(snapshotId <= _currentSnapshotId.current(), "ERC20Snapshot: nonexistent id");

        // When a valid snapshot is queried, there are three possibilities:
        //  a) The queried value was not modified after the snapshot was taken. Therefore, a snapshot entry was never
        //  created for this id, and all stored snapshot ids are smaller than the requested one. The value that corresponds
        //  to this id is the current one.
        //  b) The queried value was modified after the snapshot was taken. Therefore, there will be an entry with the
        //  requested id, and its value is the one to return.
        //  c) More snapshots were created after the requested one, and the queried value was later modified. There will be
        //  no entry for the requested id: the value that corresponds to it is that of the smallest snapshot id that is
        //  larger than the requested one.
        //
        // In summary, we need to find an element in an array, returning the index of the smallest value that is larger if
        // it is not found, unless said value doesn't exist (e.g. when all values are smaller). Arrays.findUpperBound does
        // exactly this.

        uint256 index = snapshots.ids.findUpperBound(snapshotId);

        if (index == snapshots.ids.length) {
            return (false, 0);
        } else {
            return (true, snapshots.values[index]);
        }
    }

    function _updateAccountSnapshot(address account) private {
        _updateSnapshot(_accountBalanceSnapshots[account], balanceOf(account));
    }

    function _updateTotalSupplySnapshot() private {
        _updateSnapshot(_totalSupplySnapshots, totalSupply());
    }

    function _updateSnapshot(Snapshots storage snapshots, uint256 currentValue) private {
        uint256 currentId = _currentSnapshotId.current();
        if (_lastSnapshotId(snapshots.ids) < currentId) {
            snapshots.ids.push(currentId);
            snapshots.values.push(currentValue);
        }
    }

    function _lastSnapshotId(uint256[] storage ids) private view returns (uint256) {
        if (ids.length == 0) {
            return 0;
        } else {
            return ids[ids.length - 1];
        }
    }
}

// File: contracts/Interfaces/LienTokenInterface.sol

pragma solidity >=0.6.6;


interface LienTokenInterface is IERC20 {
    function currentTerm() external view returns (uint256);

    function expiration() external view returns (uint256);

    function receiveDividend(address token, address recipient) external;

    function dividendAt(
        address token,
        address account,
        uint256 term
    ) external view returns (uint256);
}

// File: contracts/BoxExchange/TokenBoxExchange/IDOLvsERC20/IDOLvsLien/ERC20Redistribution.sol

pragma solidity >=0.6.6;






abstract contract ERC20Redistribution is ERC20Snapshot {
    using SafeERC20 for ERC20Interface;

    struct Dividend {
        mapping(ERC20Interface => uint256) tokens;
        uint256 eth;
    }

    LienTokenInterface public lien;
    mapping(uint256 => uint256) private snapshotsOfTermEnd;
    mapping(uint256 => Dividend) private totalDividendsAt;
    mapping(address => mapping(ERC20Interface => uint256))
        private lastReceivedTermsOfTokens;
    mapping(address => uint256) private lastReceivedTermsOfEth;

    event ReceiveDividendETH(address indexed recipient, uint256 amount);
    event ReceiveDividendToken(
        address indexed recipient,
        address indexed tokenAddress,
        uint256 amount
    );

    modifier termValidation(uint256 _term) {
        require(_term > 0, "0 is invalid value as term");
        _;
    }

    receive() external payable {}

    constructor(LienTokenInterface _lien) public {
        lien = _lien;
    }

    /**
     * @notice Transfers ERC20 token dividend to Liquidity Provider
     * @notice Before transfer dividend, this exchange withdraws dividend in this ERC20 token from Lien Token
     * @param token Target ERC20 token to be received
     */
    function receiveDividendToken(ERC20Interface token) public {
        uint256 _currentTerm = currentTerm();
        if (_currentTerm == 1) {
            return;
        }
        _moveDividendTokenFromLIEN(token, _currentTerm);
        uint256 lastReceivedTerm = lastReceivedTermsOfTokens[msg.sender][token];
        lastReceivedTermsOfTokens[msg.sender][token] = _currentTerm - 1;
        uint256 dividend;
        for (uint256 term = lastReceivedTerm + 1; term < _currentTerm; term++) {
            dividend += dividendTokenAt(msg.sender, token, term);
        }
        emit ReceiveDividendToken(msg.sender, address(token), dividend);
        token.safeTransfer(msg.sender, dividend);
    }

    /**
     * @notice Transfers ETH dividend to Liquidity Provider
     * @notice Before transfer dividend, this exchange withdraws dividend in ETH from Lien Token
     */
    function receiveDividendEth() public {
        uint256 _currentTerm = currentTerm();
        if (_currentTerm == 1) {
            return;
        }
        _moveDividendEthFromLIEN(_currentTerm);
        uint256 lastReceivedTerm = lastReceivedTermsOfEth[msg.sender];
        lastReceivedTermsOfEth[msg.sender] = _currentTerm - 1;
        uint256 dividend;
        for (uint256 term = lastReceivedTerm + 1; term < _currentTerm; term++) {
            dividend += dividendEthAt(msg.sender, term);
        }
        emit ReceiveDividendETH(msg.sender, dividend);
        // solhint-disable-next-line avoid-low-level-calls
        (bool success, ) = msg.sender.call{value: dividend}("");
        require(success, "ETH transfer failed");
    }

    /**
     * @notice Gets current term in Lien Token
     **/
    function currentTerm() public view returns (uint256) {
        return lien.currentTerm();
    }

    /**
     * @notice Gets amount of ERC20 token dividend LP can get in the `term`
     * @param account Target account
     * @param token Target ERC20 token
     * @param term Target term
     **/
    function dividendTokenAt(
        address account,
        ERC20Interface token,
        uint256 term
    ) public view returns (uint256) {
        uint256 balanceAtTermEnd = balanceOfAtTermEnd(account, term);
        uint256 totalSupplyAtTermEnd = totalSupplyAtTermEnd(term);
        uint256 totalDividend = totalDividendTokenAt(token, term);
        return totalDividend.mul(balanceAtTermEnd).div(totalSupplyAtTermEnd);
    }

    /**
     * @notice Gets Amount of ETH dividend LP can get in the `term`
     * @param account Target account
     * @param term Target term
     **/
    function dividendEthAt(address account, uint256 term)
        public
        view
        returns (uint256)
    {
        uint256 balanceAtTermEnd = balanceOfAtTermEnd(account, term);
        uint256 totalSupplyAtTermEnd = totalSupplyAtTermEnd(term);
        uint256 totalDividend = totalDividendEthAt(term);
        return totalDividend.mul(balanceAtTermEnd).div(totalSupplyAtTermEnd);
    }

    /**
     * @notice Gets total amount of ERC20 token dividend this exchange received in the `term`
     * @param token Target ERC20 token
     * @param term Target term
     **/
    function totalDividendTokenAt(ERC20Interface token, uint256 term)
        public
        view
        returns (uint256)
    {
        return totalDividendsAt[term].tokens[token];
    }

    /**
     * @notice Gets total amount of ETH dividend this exchange received in the `term`
     * @param term Target term
     **/
    function totalDividendEthAt(uint256 term) public view returns (uint256) {
        return totalDividendsAt[term].eth;
    }

    /**
     * @notice Retrieves the balance of `account` at the end of the term `term`
     * @param account Target account
     * @param term Target term
     */
    function balanceOfAtTermEnd(address account, uint256 term)
        public
        view
        termValidation(term)
        returns (uint256)
    {
        uint256 _currentTerm = currentTerm();
        for (uint256 i = term; i < _currentTerm; i++) {
            if (_isSnapshottedOnTermEnd(i)) {
                return balanceOfAt(account, snapshotsOfTermEnd[i]);
            }
        }
        return balanceOf(account);
    }

    /**
     * @notice Retrieves the total supply at the end of the term `term`
     * @param term Target term
     */
    function totalSupplyAtTermEnd(uint256 term)
        public
        view
        termValidation(term)
        returns (uint256)
    {
        uint256 _currentTerm = currentTerm();
        for (uint256 i = term; i < _currentTerm; i++) {
            if (_isSnapshottedOnTermEnd(i)) {
                return totalSupplyAt(snapshotsOfTermEnd[i]);
            }
        }
        return totalSupply();
    }

    function _transfer(
        address from,
        address to,
        uint256 value
    ) internal virtual override {
        _snapshotOnTermEnd();
        super._transfer(from, to, value);
    }

    function _mint(address account, uint256 value) internal virtual override {
        _snapshotOnTermEnd();
        super._mint(account, value);
    }

    function _burn(address account, uint256 value) internal virtual override {
        _snapshotOnTermEnd();
        super._burn(account, value);
    }

    function _snapshotOnTermEnd() private {
        uint256 _currentTerm = currentTerm();
        if (_currentTerm > 1 && !_isSnapshottedOnTermEnd(_currentTerm - 1)) {
            snapshotsOfTermEnd[_currentTerm - 1] = _snapshot();
        }
    }

    function _isSnapshottedOnTermEnd(uint256 term) private view returns (bool) {
        return snapshotsOfTermEnd[term] != 0;
    }

    /**
     * @notice Withdraws dividends in ETH and iDOL from Lien Token
     * @dev At first, this function registers amount of dividends from Lien Token, and thereafter withdraws it
     **/
    function _moveDividendTokenFromLIEN(
        ERC20Interface token,
        uint256 _currentTerm
    ) private {
        uint256 expiration = lien.expiration();
        uint256 start;
        uint256 totalNewDividend;
        if (_currentTerm > expiration) {
            start = _currentTerm - expiration;
        } else {
            start = 1;
        }
        //get and register dividend amount in the exchange from Lien Token contract
        for (uint256 i = _currentTerm - 1; i >= start; i--) {
            if (totalDividendsAt[i].tokens[token] != 0) {
                break;
            }
            uint256 dividend = lien.dividendAt(
                address(token),
                address(this),
                i
            );
            totalDividendsAt[i].tokens[token] = dividend;
            totalNewDividend += dividend;
        }
        if (totalNewDividend == 0) {
            return;
        }
        lien.receiveDividend(address(token), address(this));
    }

    /**
     * @notice Withdraws dividends in ETH and iDOL from lienToken
     * @dev At first, this function registers amount of dividend from Lien Token, and thereafter withdraws it
     **/
    function _moveDividendEthFromLIEN(uint256 _currentTerm) private {
        uint256 expiration = lien.expiration();
        uint256 start;
        uint256 totalNewDividend;
        if (_currentTerm > expiration) {
            start = _currentTerm - expiration;
        } else {
            start = 1;
        }
        //get and register dividend amount in the exchange from Lien Token contract
        for (uint256 i = _currentTerm - 1; i >= start; i--) {
            if (totalDividendsAt[i].eth != 0) {
                break;
            }
            uint256 dividend = lien.dividendAt(address(0), address(this), i);
            totalDividendsAt[i].eth = dividend;
            totalNewDividend += dividend;
        }
        if (totalNewDividend == 0) {
            return;
        }
        lien.receiveDividend(address(0), address(this));
    }
}

// File: contracts/BoxExchange/TokenBoxExchange/IDOLvsERC20/IDOLvsLien/LienBoxExchange.sol

pragma solidity >=0.6.6;



contract LienBoxExchange is ERC20BoxExchange, ERC20Redistribution {
    /**
     * @param _idol iDOL contract
     * @param _priceCalc Price Calculator contract
     * @param _lien Lien Token contract
     * @param _spreadCalc Spread Calculator contract
     * @param _name Name of share token
     **/
    constructor(
        ERC20Interface _idol,
        PriceCalculatorInterface _priceCalc,
        LienTokenInterface _lien,
        SpreadCalculatorInterface _spreadCalc,
        string memory _name
    )
        public
        ERC20Redistribution(_lien)
        ERC20BoxExchange(
            _idol,
            ERC20Interface(address(_lien)),
            _priceCalc,
            address(_lien),
            _spreadCalc,
            OracleInterface(address(0)),
            _name
        )
    {}

    // overriding ERC20 functions
    function _transfer(
        address from,
        address to,
        uint256 value
    ) internal override(ERC20, ERC20Redistribution) {
        ERC20Redistribution._transfer(from, to, value);
    }

    function _burn(address account, uint256 value)
        internal
        override(ERC20, ERC20Redistribution)
    {
        ERC20Redistribution._burn(account, value);
    }

    function _mint(address account, uint256 value)
        internal
        override(ERC20, ERC20Redistribution)
    {
        ERC20Redistribution._mint(account, value);
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract ERC20Interface","name":"_idol","type":"address"},{"internalType":"contract PriceCalculatorInterface","name":"_priceCalc","type":"address"},{"internalType":"contract LienTokenInterface","name":"_lien","type":"address"},{"internalType":"contract SpreadCalculatorInterface","name":"_spreadCalc","type":"address"},{"internalType":"string","name":"_name","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"bool","name":"isBuy","type":"bool"},{"indexed":true,"internalType":"uint32","name":"boxNumber","type":"uint32"},{"indexed":false,"internalType":"bool","name":"isLimit","type":"bool"},{"indexed":false,"internalType":"uint256","name":"tokenIn","type":"uint256"}],"name":"AcceptOrders","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"isBuy","type":"bool"},{"indexed":true,"internalType":"uint32","name":"boxNumber","type":"uint32"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"orderAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refundAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outAmount","type":"uint256"}],"name":"Execution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"boxNumber","type":"uint32"},{"indexed":false,"internalType":"uint8","name":"partiallyRefundOrderType","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"partiallyRefundRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalInAmountFLEX_0_1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalInAmountFLEX_1_0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalInAmountSTRICT_0_1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalInAmountSTRICT_1_0","type":"uint256"}],"name":"ExecutionSummary","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidityProvider","type":"address"},{"indexed":true,"internalType":"bool","name":"isAdd","type":"bool"},{"indexed":false,"internalType":"uint256","name":"movedToken0Amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"movedToken1Amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesMoved","type":"uint256"}],"name":"MoveLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"PayMarketFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ReceiveDividendETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ReceiveDividendToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Snapshot","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"boxNumber","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"spreadRate","type":"uint128"}],"name":"SpreadRate","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":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"reserve0","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"reserve1","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"totalShare","type":"uint256"}],"name":"UpdateReserve","type":"event"},{"inputs":[{"internalType":"uint256","name":"timeout","type":"uint256"},{"internalType":"uint256","name":"IDOLAmount","type":"uint256"},{"internalType":"uint256","name":"settlementTokenAmount","type":"uint256"},{"internalType":"uint256","name":"minShares","type":"uint256"}],"name":"addLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"snapshotId","type":"uint256"}],"name":"balanceOfAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"term","type":"uint256"}],"name":"balanceOfAtTermEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentTerm","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"term","type":"uint256"}],"name":"dividendEthAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"contract ERC20Interface","name":"token","type":"address"},{"internalType":"uint256","name":"term","type":"uint256"}],"name":"dividendTokenAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"maxOrderNum","type":"uint8"}],"name":"executeUnexecutedBox","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"boxNumber","type":"uint256"}],"name":"getBoxSummary","outputs":[{"internalType":"uint256","name":"executionStatusNumber","type":"uint256"},{"internalType":"uint256","name":"flexToken0InAmount","type":"uint256"},{"internalType":"uint256","name":"strictToken0InAmount","type":"uint256"},{"internalType":"uint256","name":"flexToken1InAmount","type":"uint256"},{"internalType":"uint256","name":"strictToken1InAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExchangeData","outputs":[{"internalType":"uint256","name":"boxNumber","type":"uint256"},{"internalType":"uint256","name":"_reserve0","type":"uint256"},{"internalType":"uint256","name":"_reserve1","type":"uint256"},{"internalType":"uint256","name":"totalShare","type":"uint256"},{"internalType":"uint256","name":"latestSpreadRate","type":"uint256"},{"internalType":"uint256","name":"token0PerShareE18","type":"uint256"},{"internalType":"uint256","name":"token1PerShareE18","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"}],"name":"getOrderAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"idol","outputs":[{"internalType":"contract ERC20Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"IDOLAmount","type":"uint256"},{"internalType":"uint256","name":"settlementTokenAmount","type":"uint256"},{"internalType":"uint256","name":"initialShare","type":"uint256"}],"name":"initializeExchange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lien","outputs":[{"internalType":"contract LienTokenInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketFeePool0","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketFeePool1","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timeout","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"IDOLAmount","type":"uint256"},{"internalType":"bool","name":"isLimit","type":"bool"}],"name":"orderBaseToSettlement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"timeout","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"settlementTokenAmount","type":"uint256"},{"internalType":"bool","name":"isLimit","type":"bool"}],"name":"orderSettlementToBase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"receiveDividendEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"token","type":"address"}],"name":"receiveDividendToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"timeout","type":"uint256"},{"internalType":"uint256","name":"minBaseTokens","type":"uint256"},{"internalType":"uint256","name":"minSettlementTokens","type":"uint256"},{"internalType":"uint256","name":"sharesBurned","type":"uint256"}],"name":"removeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sendMarketFeeToLien","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract ERC20Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"term","type":"uint256"}],"name":"totalDividendEthAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"token","type":"address"},{"internalType":"uint256","name":"term","type":"uint256"}],"name":"totalDividendTokenAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"snapshotId","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"term","type":"uint256"}],"name":"totalSupplyAtTermEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"boxNumber","type":"uint256"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"bool","name":"isLimit","type":"bool"}],"name":"whenToExecute","outputs":[{"internalType":"bool","name":"isExecuted","type":"bool"},{"internalType":"uint256","name":"boxCount","type":"uint256"},{"internalType":"uint256","name":"orderCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101606040523480156200001257600080fd5b5060405162004e0c38038062004e0c833981810160405260a08110156200003857600080fd5b81516020830151604080850151606086015160808701805193519597949692959194919392820192846401000000008211156200007457600080fd5b9083019060208201858111156200008a57600080fd5b8251640100000000811182820188101715620000a557600080fd5b82525081516020918201929091019080838360005b83811015620000d4578181015183820152602001620000ba565b50505050905090810190601f168015620001025780820380516001836020036101000a031916815260200191505b5060405250505082858486868660008786868686868686848482806040518060400160405280600581526020017f736861726500000000000000000000000000000000000000000000000000000081525081600390805190602001906200016b92919062000248565b5080516200018190600490602084019062000248565b50506005805460ff191660121790555033606090811b6080526001600160601b031984821b811660c0529083901b1660a052620001c860086001600160e01b036200023216565b50505050606095861b6001600160601b031990811660e05294861b85166101005290851b84166101205290931b909116610140525050601080546001600160a01b0319166001600160a01b03999099169890981790975550620002ed9a5050505050505050505050565b6005805460ff191660ff92909216919091179055565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200028b57805160ff1916838001178555620002bb565b82800160010185558215620002bb579182015b82811115620002bb5782518255916020019190600101906200029e565b50620002c9929150620002cd565b5090565b620002ea91905b80821115620002c95760008155600101620002d4565b90565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c614aa7620003656000398061406952508061403a52508061183252806139f2525080610dac528061326d52806139cb5250806142ea5250806121be5250806120f45250614aa76000f3fe6080604052600436106102295760003560e01c806395d89b4111610123578063bb2f53b4116100ab578063dd62ed3e1161006f578063dd62ed3e14610923578063dec7bfd21461095e578063e1b4df2a146109a1578063f88bf15a146109e8578063fc0c546a14610a2457610230565b8063bb2f53b41461086a578063c48c73421461087f578063c9a01af914610894578063d5855e7a146108c1578063da84fb0b146108d657610230565b8063a3fee072116100f2578063a3fee07214610736578063a457c2d71461078b578063a9059cbb146107c4578063aebf3e41146107fd578063b196a3521461083957610230565b806395d89b41146106af578063981b24d0146106c45780639c558c4b146106ee578063a11bc81f1461070357610230565b806339509351116101b15780636d294d06116101755780636d294d06146105bc57806370a08231146105f55780637112ed021461062857806384c76abc1461065e57806392dea49c1461069a57610230565b8063395093511461047e5780634ee2cd7e146104b75780634fc0bf09146104f057806359e713141461052957806369cb06541461059257610230565b806318160ddd116101f857806318160ddd146103a05780631c67247c146103b557806323b872dd146103df578063313ce56714610422578063385a8d501461044d57610230565b8063068228591461023557806306fdde0314610280578063095ea7b31461030a5780630d96ad311461035757610230565b3661023057005b600080fd5b34801561024157600080fd5b5061026e6004803603604081101561025857600080fd5b506001600160a01b038135169060200135610a39565b60408051918252519081900360200190f35b34801561028c57600080fd5b50610295610af5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102cf5781810151838201526020016102b7565b50505050905090810190601f1680156102fc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561031657600080fd5b506103436004803603604081101561032d57600080fd5b506001600160a01b038135169060200135610b8c565b604080519115158252519081900360200190f35b34801561036357600080fd5b5061039e6004803603608081101561037a57600080fd5b508035906001600160a01b0360208201351690604081013590606001351515610baa565b005b3480156103ac57600080fd5b5061026e610c55565b3480156103c157600080fd5b5061026e600480360360208110156103d857600080fd5b5035610c5b565b3480156103eb57600080fd5b506103436004803603606081101561040257600080fd5b506001600160a01b03813581169160208101359091169060400135610d13565b34801561042e57600080fd5b50610437610da1565b6040805160ff9092168252519081900360200190f35b34801561045957600080fd5b50610462610daa565b604080516001600160a01b039092168252519081900360200190f35b34801561048a57600080fd5b50610343600480360360408110156104a157600080fd5b506001600160a01b038135169060200135610dce565b3480156104c357600080fd5b5061026e600480360360408110156104da57600080fd5b506001600160a01b038135169060200135610e22565b3480156104fc57600080fd5b5061026e6004803603604081101561051357600080fd5b506001600160a01b038135169060200135610e68565b34801561053557600080fd5b506105726004803603608081101561054c57600080fd5b506001600160a01b03813516906020810135906040810135151590606001351515610ebb565b604080519315158452602084019290925282820152519081900360600190f35b34801561059e57600080fd5b5061026e600480360360208110156105b557600080fd5b5035610ee5565b3480156105c857600080fd5b5061026e600480360360408110156105df57600080fd5b506001600160a01b038135169060200135610efd565b34801561060157600080fd5b5061026e6004803603602081101561061857600080fd5b50356001600160a01b0316610f24565b34801561063457600080fd5b5061039e6004803603606081101561064b57600080fd5b5080359060208101359060400135610f3f565b34801561066a57600080fd5b5061026e6004803603604081101561068157600080fd5b5080356001600160a01b0316906020013560ff16610f4f565b3480156106a657600080fd5b50610462610fbe565b3480156106bb57600080fd5b50610295610fcd565b3480156106d057600080fd5b5061026e600480360360208110156106e757600080fd5b503561102e565b3480156106fa57600080fd5b5061039e611054565b34801561070f57600080fd5b5061039e6004803603602081101561072657600080fd5b50356001600160a01b031661105e565b34801561074257600080fd5b506107606004803603602081101561075957600080fd5b5035611137565b6040805195865260208601949094528484019290925260608401526080830152519081900360a00190f35b34801561079757600080fd5b50610343600480360360408110156107ae57600080fd5b506001600160a01b038135169060200135611252565b3480156107d057600080fd5b50610343600480360360408110156107e757600080fd5b506001600160a01b0381351690602001356112c0565b34801561080957600080fd5b5061039e6004803603608081101561082057600080fd5b50803590602081013590604081013590606001356112d4565b34801561084557600080fd5b5061084e61143f565b604080516001600160801b039092168252519081900360200190f35b34801561087657600080fd5b5061039e61144e565b34801561088b57600080fd5b5061026e611579565b3480156108a057600080fd5b5061039e600480360360208110156108b757600080fd5b503560ff166115ef565b3480156108cd57600080fd5b5061084e6115f8565b3480156108e257600080fd5b506108eb61160c565b604080519788526020880196909652868601949094526060860192909252608085015260a084015260c0830152519081900360e00190f35b34801561092f57600080fd5b5061026e6004803603604081101561094657600080fd5b506001600160a01b0381358116916020013516611688565b34801561096a57600080fd5b5061026e6004803603606081101561098157600080fd5b506001600160a01b038135811691602081013590911690604001356116b3565b3480156109ad57600080fd5b5061039e600480360360808110156109c457600080fd5b508035906001600160a01b03602082013516906040810135906060013515156116fc565b3480156109f457600080fd5b5061039e60048036036080811015610a0b57600080fd5b5080359060208101359060408101359060600135611791565b348015610a3057600080fd5b50610462611830565b60008160008111610a91576040805162461bcd60e51b815260206004820152601a60248201527f3020697320696e76616c69642076616c7565206173207465726d000000000000604482015290519081900360640190fd5b6000610a9b611579565b9050835b81811015610ae057610ab081611854565b15610ad857600081815260116020526040902054610acf908790610e22565b93505050610aee565b600101610a9f565b50610aea85610f24565b9250505b5092915050565b60038054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610b815780601f10610b5657610100808354040283529160200191610b81565b820191906000526020600020905b815481529060010190602001808311610b6457829003601f168201915b505050505090505b90565b6000610ba0610b99611868565b848461186c565b5060015b92915050565b8180610beb576040805162461bcd60e51b815260206004820152601e6024820152600080516020614904833981519152604482015290519081900360640190fd5b84610bf4611958565b8111610c32576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b6000610c3f600185611962565b9050610c4c818688611996565b50505050505050565b60025490565b60008160008111610cb3576040805162461bcd60e51b815260206004820152601a60248201527f3020697320696e76616c69642076616c7565206173207465726d000000000000604482015290519081900360640190fd5b6000610cbd611579565b9050835b81811015610d0057610cd281611854565b15610cf857600081815260116020526040902054610cef9061102e565b93505050610d0d565b600101610cc1565b50610d09610c55565b9250505b50919050565b6000610d20848484611a91565b610d9684610d2c611868565b610d918560405180606001604052806028815260200161496b602891396001600160a01b038a16600090815260016020526040812090610d6a611868565b6001600160a01b03168152602081019190915260400160002054919063ffffffff611a9c16565b61186c565b5060015b9392505050565b60055460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610ba0610ddb611868565b84610d918560016000610dec611868565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff611b3316565b6001600160a01b0382166000908152600c6020526040812081908190610e49908590611b8d565b9150915081610e6057610e5b85610f24565b610aea565b949350505050565b600080610e758484610a39565b90506000610e8284610c5b565b90506000610e8f85610ee5565b9050610eb182610ea5838663ffffffff611c9016565b9063ffffffff611ce916565b9695505050505050565b6000806000610ed487610ece8787611d2b565b88611d57565b9250925092505b9450945094915050565b6000818152601260205260409020600101545b919050565b60009081526012602090815260408083206001600160a01b03949094168352929052205490565b6001600160a01b031660009081526020819052604090205490565b610f4a838383612099565b505050565b60006008610f5b611958565b81548110610f6557fe5b90600052602060002090600202016000016000836003811115610f8457fe5b6003811115610f8f57fe5b8152602080820192909252604090810160009081206001600160a01b0387168252909252902054905092915050565b6010546001600160a01b031681565b60048054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610b815780601f10610b5657610100808354040283529160200191610b81565b600080600061103e84600d611b8d565b9150915081610d9a5761104f610c55565b610d09565b61105c612164565b565b6000611068611579565b905080600114156110795750611134565b61108382826121e8565b3360009081526013602090815260408083206001600160a01b038616845290915281208054600019840190915590600182015b838110156110d5576110c93386836116b3565b909101906001016110b6565b506040805182815290516001600160a01b0386169133917f9b64af6bc8380496b8d368590f1460af6043202bca9d05998fcee10cd105fd5c9181900360200190a36111306001600160a01b038516338363ffffffff6123ee16565b5050505b50565b600080600080600080600960000160199054906101000a900463ffffffff1663ffffffff1690506008878154811061116b57fe5b6000918252602080832083805260029283020190526040909120015460088054919650908890811061119957fe5b600091825260208083206002808552928302019052604090912001546008805491955090889081106111c757fe5b60009182526020808320600184526002928302019052604090912001546008805491945090889081106111f657fe5b60009182526020808320600384526002928302019052604090912001549150808710156112265760029550611248565b808714801561123e5750600954600160e81b900460ff165b1561124857600195505b5091939590929450565b6000610ba061125f611868565b84610d9185604051806060016040528060258152602001614a4d6025913960016000611289611868565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff611a9c16565b6000610ba06112cd611868565b8484611a91565b8280611315576040805162461bcd60e51b815260206004820152601e6024820152600080516020614904833981519152604482015290519081900360640190fd5b8280611356576040805162461bcd60e51b815260206004820152601e6024820152600080516020614904833981519152604482015290519081900360640190fd5b8561135f611958565b811161139d576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b6113a5611958565b87116113e3576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b6000806113ee612440565b9092509050600061140982610ea58a8663ffffffff611c9016565b90508089116114255761142083838b8a600061245e565b611433565b61143383838a8a600161245e565b50505050505050505050565b6006546001600160801b031681565b6000611458611579565b90508060011415611469575061105c565b6114728161256e565b3360009081526014602052604081208054600019840190915590600182015b838110156114af576114a33382610e68565b90910190600101611491565b5060408051828152905133917fe3fdc68a57b01b663baef2bfbaa7da3ef2d8a090c25c00577be52fd50cc45859919081900360200190a2604051600090339083908381818185875af1925050503d8060008114611528576040519150601f19603f3d011682016040523d82523d6000602084013e61152d565b606091505b5050905080611130576040805162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b604482015290519081900360640190fd5b6010546040805163624639a160e11b815290516000926001600160a01b03169163c48c7342916004808301926020929190829003018186803b1580156115be57600080fd5b505afa1580156115d2573d6000803e3d6000fd5b505050506040513d60208110156115e857600080fd5b5051905090565b6111348161274c565b60055461010090046001600160801b031681565b600080600080600080600061161f611958565b9650611629612440565b80965081975050506008878154811061163e57fe5b60009182526020909120600160029092020101546001600160801b03169250611665610c55565b93506116718685612760565b915061167d8585612760565b905090919293949596565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6000806116c08584610a39565b905060006116cd84610c5b565b905060006116db8686610efd565b90506116f182610ea5838663ffffffff611c9016565b979650505050505050565b818061173d576040805162461bcd60e51b815260206004820152601e6024820152600080516020614904833981519152604482015290519081900360640190fd5b84611746611958565b8111611784576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b6000610c3f600085611962565b8361179a611958565b81116117d8576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b6117e0611958565b851161181e576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b61182984848461277e565b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600090815260116020526040902054151590565b3390565b6001600160a01b0383166118b15760405162461bcd60e51b81526004018080602001828103825260248152602001806149ff6024913960400191505060405180910390fd5b6001600160a01b0382166118f65760405162461bcd60e51b81526004018080602001828103825260228152602001806148956022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6008546000190190565b6000821561198057811561197857506002610ba4565b506000610ba4565b811561198e57506003610ba4565b506001610ba4565b61199e6128c4565b60006119a8611958565b90506119b56005826128d9565b6001600160a01b0382166119c7573391505b6119e56119de8560038111156119d957fe5b612e02565b3385612e3d565b611a16848484600885815481106119f857fe5b9060005260206000209060020201612e63909392919063ffffffff16565b8063ffffffff16611a31856003811115611a2c57fe5b612f3f565b1515836001600160a01b03167fd54c711b2fd79474dc74606062c8605c0dac9e6089a74320ccf470dc2e33e19a611a72886003811115611a6d57fe5b612f6b565b604080519115158252602082018990528051918290030190a450505050565b610f4a838383612f7d565b60008184841115611b2b5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611af0578181015183820152602001611ad8565b50505050905090810190601f168015611b1d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600082820183811015610d9a576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008060008411611bde576040805162461bcd60e51b815260206004820152601660248201527504552433230536e617073686f743a20696420697320360541b604482015290519081900360640190fd5b611be8600f612f90565b841115611c3c576040805162461bcd60e51b815260206004820152601d60248201527f4552433230536e617073686f743a206e6f6e6578697374656e74206964000000604482015290519081900360640190fd5b6000611c4e848663ffffffff612f9416565b8454909150811415611c67575060009150819050611c89565b6001846001018281548110611c7857fe5b906000526020600020015492509250505b9250929050565b600082611c9f57506000610ba4565b82820282848281611cac57fe5b0414610d9a5760405162461bcd60e51b81526004018080602001828103825260218152602001806149246021913960400191505060405180910390fd5b6000610d9a83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613035565b6000828015611d375750815b15611d4457506002610ba4565b82610ba4578115610ba057506003610ba4565b6000806000611d64611958565b841115611d7957506000915081905080612090565b600060088581548110611d8857fe5b906000526020600020906002020190506060816000016000886003811115611dac57fe5b6003811115611db757fe5b6003811115611dc257fe5b8152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015611e2757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611e09575b5050600954600b54600a54959650600160c81b90910463ffffffff16949093506000925060ff1690506003811115611e5b57fe5b600954909150600160e81b900460ff16600080805b87518114611eb9578e6001600160a01b0316888281518110611e8e57fe5b60200260200101516001600160a01b03161415611eb15760019250809150611eb9565b600101611e70565b50858c1080611eed5750828015611ecf5750858c145b8015611eed5750838d1080611eed5750838d148015611eed57508481105b15611f0b575060019950600098508897506120909650505050505050565b81611f285750600099508998508897506120909650505050505050565b6000868d148015611f365750835b1561203257845b8e81101561200357611ff78a6000836003811115611f5757fe5b6003811115611f6257fe5b6003811115611f6d57fe5b815260200190815260200160002060405180604001604052908160018201805480602002602001604051908101604052809291908181526020018280548015611fdf57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611fc1575b5050505050815260200160028201548152505061309a565b90910190600101611f3d565b5060019a506120288661201c838563ffffffff611b3316565b9063ffffffff61309f16565b6001019950612086565b60005b8e811461205a5761204e8a6000836003811115611f5757fe5b90910190600101612035565b5061206b8d8863ffffffff61309f16565b6001019a50612080818363ffffffff611b3316565b60010199505b5050505050505050505b93509350939050565b6120a1610c55565b156120e9576040805162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b604482015290519081900360640190fd5b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461211e57600080fd5b61212883836130e1565b612132338261316c565b612147600033856001600160801b0316612e3d565b61215c600133846001600160801b0316612e3d565b610f4a613176565b60008061216f6131fd565b9150915061217e600080613219565b604080518381526020810183905281517f72715c0cf03be5e4479cb972219945b83aee28f65875993b1de62bda86892d1e929181900390910190a16121e47f0000000000000000000000000000000000000000000000000000000000000000838361325a565b5050565b60105460408051634665096d60e01b815290516000926001600160a01b031691634665096d916004808301926020929190829003018186803b15801561222d57600080fd5b505afa158015612241573d6000803e3d6000fd5b505050506040513d602081101561225757600080fd5b5051905060008082841115612270578284039150612275565b600191505b60001984015b82811061236d5760008181526012602090815260408083206001600160a01b038a168452909152902054156122af5761236d565b6010546040805163021e20ab60e61b81526001600160a01b03898116600483015230602483015260448201859052915160009392909216916387882ac091606480820192602092909190829003018186803b15801561230d57600080fd5b505afa158015612321573d6000803e3d6000fd5b505050506040513d602081101561233757600080fd5b505160008381526012602090815260408083206001600160a01b038c16845290915290208190559290920191506000190161227b565b508061237b575050506121e4565b6010546040805163125bdfc160e11b81526001600160a01b038881166004830152306024830152915191909216916324b7bf8291604480830192600092919082900301818387803b1580156123cf57600080fd5b505af11580156123e3573d6000803e3d6000fd5b505050505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610f4a90849061329a565b6006546007546001600160801b03600160801b909204821692911690565b600080600061246f8689898761334b565b925092509250848110156124ca576040805162461bcd60e51b815260206004820152601f60248201527f596f752063616e2774207265636569766520656e6f7567682073686172657300604482015290519081900360640190fd5b6124d660003385612e3d565b6124e260013384612e3d565b6125156124fd6124f88a8663ffffffff611b3316565b6133c2565b6125106124f88a8663ffffffff611b3316565b6130e1565b61251f338261316c565b6040805184815260208101849052808201839052905160019133917ff13afa8e6af2cf800415b27d44406182e9ea706876b2470dac00aff3def8161c9181900360600190a35050505050505050565b60105460408051634665096d60e01b815290516000926001600160a01b031691634665096d916004808301926020929190829003018186803b1580156125b357600080fd5b505afa1580156125c7573d6000803e3d6000fd5b505050506040513d60208110156125dd57600080fd5b50519050600080828411156125f65782840391506125fb565b600191505b60001984015b8281106126ce5760008181526012602052604090206001015415612624576126ce565b6010546040805163021e20ab60e61b815260006004820181905230602483015260448201859052915191926001600160a01b0316916387882ac091606480820192602092909190829003018186803b15801561267f57600080fd5b505afa158015612693573d6000803e3d6000fd5b505050506040513d60208110156126a957600080fd5b5051600083815260126020526040902060010181905592909201915060001901612601565b50806126dc57505050611134565b6010546040805163125bdfc160e11b815260006004820181905230602483015291516001600160a01b03909316926324b7bf829260448084019391929182900301818387803b15801561272e57600080fd5b505af1158015612742573d6000803e3d6000fd5b5050505050505050565b6111348160ff1661275b611958565b6128d9565b6000610d9a82610ea585670de0b6b3a764000063ffffffff611c9016565b600080612789612440565b915091506000612797610c55565b905060006127af82610ea5868863ffffffff611c9016565b905060006127c783610ea5868963ffffffff611c9016565b90508782101580156127d95750868110155b61282a576040805162461bcd60e51b815260206004820152601f60248201527f596f752063616e2774207265636569766520656e6f75676820746f6b656e7300604482015290519081900360640190fd5b6128536128406124f8878563ffffffff61309f16565b6125106124f8878563ffffffff61309f16565b61285d338761340a565b61286960003384613414565b61287560013383613414565b6040805183815260208101839052808201889052905160009133917ff13afa8e6af2cf800415b27d44406182e9ea706876b2470dac00aff3def8161c9181900360600190a35050505050505050565b6128cc613438565b1561105c5761105c613176565b6128e1614798565b6040805160a0810190915260098054829060ff16600381111561290057fe5b600381111561290b57fe5b81529054610100810467ffffffffffffffff166020830152600160481b81046001600160801b03166040830152600160c81b810463ffffffff166060830152600160e81b900460ff16151560809091015290506129666147c8565b60408051808201909152600a8054829060ff16600381111561298457fe5b600381111561298f57fe5b8152602001600182015481525050905082826060015163ffffffff16101580156129d157506129bc613438565b15806129d1575082826060015163ffffffff16115b156129dd5750506121e4565b8160800151612a605760008060006129f8856060015161347a565b9194509250905084836003811115612a0c57fe5b90816003811115612a1957fe5b905250612a25826135e3565b67ffffffffffffffff166020860152612a3d816133c2565b6001600160801b0316604086015250506001608084015250600080825260208201525b8315612d195760006008836060015163ffffffff1681548110612a7f57fe5b600091825260208220845160029092020191906003811115612a9d57fe5b6003811115612aa857fe5b815260200190815260200160002090506000806000612b3484612ad4876000015160038111156119d957fe5b60208801518851612aec908b9063ffffffff61362c16565b8a604001516001600160801b031660088c6060015163ffffffff1681548110612b1157fe5b60009182526020909120600160029092020101546001600160801b03168e6136f6565b9250925092508215612cf8576000612b746008886060015163ffffffff1681548110612b5c57fe5b9060005260206000209060020201876000015161382d565b90506008876060015163ffffffff1681548110612b8d57fe5b600091825260208220885160029092020191906003811115612bab57fe5b6003811115612bb657fe5b81526020019081526020016000206000600182016000612bd691906147df565b600282016000905550508015612cc35760608701805163ffffffff600191820116909152600060808901528751600980548a93919291839160ff191690836003811115612c1f57fe5b021790555060208201518154604084015160608501516080909501511515600160e81b0260ff60e81b1963ffffffff909616600160c81b0263ffffffff60c81b196001600160801b03909316600160481b02600160481b600160c81b031967ffffffffffffffff9096166101000268ffffffffffffffff0019909516949094179490941692909217169190911792909216919091179055506121e495505050505050565b8551612cd9906003811115612cd457fe5b613948565b86906003811115612ce657fe5b90816003811115612cf357fe5b905250505b612d018261396e565b63ffffffff1660208601529096039550612a60915050565b815160098054849290829060ff19166001836003811115612d3657fe5b021790555060208201518154604084015160608501516080909501511515600160e81b0260ff60e81b1963ffffffff909616600160c81b0263ffffffff60c81b196001600160801b03909316600160481b02600160481b600160c81b031967ffffffffffffffff9096166101000268ffffffffffffffff00199095169490941794909416929092171691909117929092169190911790558051600a8054839290829060ff19166001836003811115612dea57fe5b02179055506020820151816001015590505050505050565b600080826003811115612e1157fe5b1480612e2857506002826003811115612e2657fe5b145b15612e3557506000610ef8565b506001610ef8565b610f4a823083612e4c876139b3565b6001600160a01b031692919063ffffffff613a1616565b60008481856003811115612e7357fe5b6003811115612e7e57fe5b8152602080820192909252604090810160009081206001600160a01b0386168252928390522054909150612edc576001818101805491820181556000908152602090200180546001600160a01b0319166001600160a01b0384161790555b6001600160a01b038216600090815260208290526040902054612f05908463ffffffff611b3316565b6001600160a01b0383166000908152602083905260409020556002810154612f33908463ffffffff611b3316565b60029091015550505050565b600080826003811115612f4e57fe5b1480610ba4575060025b826003811115612f6457fe5b1492915050565b6000612f7682613a70565b1592915050565b612f85613a8d565b610f4a838383613ad6565b5490565b8154600090612fa557506000610ba4565b82546000905b80821015612ff4576000612fbf8383613af3565b905084868281548110612fce57fe5b90600052602060002001541115612fe757809150612fee565b8060010192505b50612fab565b60008211801561301c57508385600184038154811061300f57fe5b9060005260206000200154145b1561302d5750600019019050610ba4565b509050610ba4565b600081836130845760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611af0578181015183820152602001611ad8565b50600083858161309057fe5b0495945050505050565b515190565b6000610d9a83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611a9c565b600680546001600160801b03908116600160801b8583160217909155600780546001600160801b0319169183169190911790557f17226eb45b590dffadbc03fba4681aa4c198e7e838ab8a6fb7e32a51634b3e80828261313f610c55565b604080516001600160801b0394851681529290931660208301528183015290519081900360600190a15050565b6121e48282613b18565b61317e613b2a565b6000613188611958565b9050613193816133c2565b6001600160801b03167f5ab5824685efa3ca4a723a2f94da7d225628bfae130cc14663932a3bf11140a8600883815481106131ca57fe5b600091825260209182902060016002909202010154604080516001600160801b039092168252519081900390910190a250565b6005546006546001600160801b03610100909204821692911690565b6005805470ffffffffffffffffffffffffffffffff0019166101006001600160801b0394851602179055600680546001600160801b03191691909216179055565b8115610f4a57610f4a6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016848463ffffffff6123ee16565b60606132ef826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613b9b9092919063ffffffff16565b805190915015610f4a5780806020019051602081101561330e57600080fd5b5051610f4a5760405162461bcd60e51b815260040180806020018281038252602a815260200180614a23602a913960400191505060405180910390fd5b600080808084600181111561335c57fe5b141561339e578661337787610ea5838963ffffffff611c9016565b61339388610ea5613386610c55565b8c9063ffffffff611c9016565b925092509250610edb565b6133b285610ea5898963ffffffff611c9016565b8761339387610ea5613386610c55565b6000600160801b82106134065760405162461bcd60e51b81526004018080602001828103825260278152602001806148dd6027913960400191505060405180910390fd5b5090565b6121e48282613baa565b610f4a8282613422866139b3565b6001600160a01b0316919063ffffffff6123ee16565b60006008613444611958565b8154811061344e57fe5b6000918252602090912060029091020160010154600160801b90046001600160801b0316431015919050565b60008060008060088563ffffffff168154811061349357fe5b6000918252602080832083805260029283020190819052604080842083015460018552818520840154848652828620850154600387529286209094015492955084938493919290916134e88885858585613bbc565b919d50929b509098509096509450866135045760029a50613548565b86600114156135165760029a50613548565b86600214156135285760009a50613548565b866003141561353a5760039a50613548565b86600414156135485760019a505b8b63ffffffff167f24f971a36bb1ccca6d5a24e46c30c46b44dc72fdf6b667edd669dee3585552a58c600381111561357c57fe5b6040805160ff9092168252602082018d90528181018e9052606082018890526080820187905260a0820186905260c08201859052519081900360e00190a260018801546135d4906001600160801b031687878c613c52565b50505050505050509193909250565b60006801000000000000000082106134065760405162461bcd60e51b81526004018080602001828103825260268152602001806149456026913960400191505060405180910390fd5b600061363d8260038111156119d957fe5b600181111561364857fe5b83516136599060038111156119d957fe5b600181111561366457fe5b1461367157506000610ba4565b825161368790600381111561368257fe5b613a70565b156136c45761369b82600381111561368257fe5b156136b55750602082015167ffffffffffffffff16610ba4565b50670de0b6b3a7640000610ba4565b6136d3826003811115611a6d57fe5b156136ed5750602082015167ffffffffffffffff16610ba4565b50600092915050565b600080600080600061377c8c60405180604001604052908160018201805480602002602001604051908101604052809291908181526020018280548015611fdf576020028201919060005260206000209081546001600160a01b03168152600190910190602001808311611fc1575050505050815260200160028201548152505061309a565b90508991505b858a830310156137fa578082106137a6575060019350600092508890039050613820565b60008c60010183815481106137b757fe5b60009182526020808320909101546001600160a01b0316808352908f90526040909120549091506137ee908d9083908d8d8d613d3f565b50600190910190613782565b808210613814575060019350600092508890039050613820565b50600093509150508681035b9750975097945050505050565b6000600382600381111561383d57fe5b141561384b57506001610ba4565b600061385c836003811115612cd457fe5b600381111561386757fe5b90505b80600414610d965761387a6147fd565b84600083600381111561388957fe5b600381111561389457fe5b600381111561389f57fe5b81526020019081526020016000206040518060400160405290816001820180548060200260200160405190810160405280929190818152602001828054801561391157602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116138f3575b50505050508152602001600282015481525050905061392f8161309a565b1561393f57600092505050610ba4565b5060010161386a565b6000600482600381111561395857fe5b6001018161396257fe5b066003811115610ba457fe5b600064010000000082106134065760405162461bcd60e51b81526004018080602001828103825260268152602001806149d96026913960400191505060405180910390fd5b6000808260018111156139c257fe5b14156139ef57507f0000000000000000000000000000000000000000000000000000000000000000610ef8565b507f0000000000000000000000000000000000000000000000000000000000000000919050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b17905261113090859061329a565b600080826003811115613a7f57fe5b1480610ba457506001612f58565b6000613a97611579565b9050600181118015613ab25750613ab060018203611854565b155b1561113457613abf613e36565b600019820160009081526011602052604090205550565b613adf83613e8a565b613ae882613e8a565b610f4a838383613eb4565b60006002808306600285060181613b0657fe5b04600283046002850401019392505050565b613b20613a8d565b6121e4828261401b565b6008613b4e613b37614036565b613b434360020161396e565b63ffffffff166140e4565b8154600180820184556000938452602093849020835160029093020101805492909301516001600160801b03199092166001600160801b03918216178116600160801b9190921602179055565b6060610e60848460008561410e565b613bb2613a8d565b6121e4828261427b565b600185015460009081908190819081906001600160801b0316670de0b6b3a764000001613c3b613bec8b83612760565b613bfc8a8463ffffffff61276016565b613c0c8c8563ffffffff61276016565b613c1c8b8663ffffffff61276016565b6006546007546001600160801b03600160801b90920482169116614296565b939f929e50909c509a509098509650505050505050565b600080600080600080613c698a8a8a8a60006143ad565b6006546005546001600160801b03600160801b90920482169093019850610100909204909116019350613ca4915089905087898860016143ad565b6007546001600160801b0316909101935090506000613d01670de0b6b3a7640000613cf5613ce8613cdb888763ffffffff611b3316565b899063ffffffff61276016565b859063ffffffff61441316565b9063ffffffff61276016565b948590039493820193929092019150613d25613d1c856133c2565b612510856133c2565b612742613d31836133c2565b6001600160801b0316614431565b6000613d55876001811115613d5057fe5b614463565b90506000613d69868663ffffffff61441316565b90506000613d98613d88670de0b6b3a76400008663ffffffff611b3316565b613cf5898563ffffffff61309f16565b90506000613da78a8388614488565b9050613db48a8a85613414565b613dbf848a83613414565b886001600160a01b0316613dd1611958565b63ffffffff1660008c6001811115613de557fe5b604080518d815260208101899052808201879052905192909114917fb8221d4e9feabcc28c5e0878f3196eecf38320725898780b22a503239b6bc9969181900360600190a450505050505050505050565b6000613e42600f6144c4565b6000613e4e600f612f90565b6040805182815290519192507f8030e83b04d87bef53480e26263266d6ca66863aa8506aca6f2559d18aa1cb67919081900360200190a1905090565b6001600160a01b0381166000908152600c6020526040902061113490613eaf83610f24565b6144cd565b6001600160a01b038316613ef95760405162461bcd60e51b81526004018080602001828103825260258152602001806149b46025913960400191505060405180910390fd5b6001600160a01b038216613f3e5760405162461bcd60e51b81526004018080602001828103825260238152602001806148506023913960400191505060405180910390fd5b613f49838383610f4a565b613f8c816040518060600160405280602681526020016148b7602691396001600160a01b038616600090815260208190526040902054919063ffffffff611a9c16565b6001600160a01b038085166000908152602081905260408082209390935590841681522054613fc1908263ffffffff611b3316565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b61402482613e8a565b61402c614519565b6121e48282614526565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e66ed1a7f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050602060405180830381600087803b1580156140d057600080fd5b505af11580156115d2573d6000803e3d6000fd5b6140ec6147c8565b50604080518082019091526001600160801b0392831681529116602082015290565b606061411985614622565b61416a576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106141a95780518252601f19909201916020918201910161418a565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461420b576040519150601f19603f3d011682016040523d82523d6000602084013e614210565b606091505b50915091508115614224579150610e609050565b8051156142345780518082602001fd5b60405162461bcd60e51b8152602060048201818152865160248401528651879391928392604401919085019080838360008315611af0578181015183820152602001611ad8565b61428482613e8a565b61428c614519565b6121e4828261465b565b60008060008060006142a6614817565b6040805163f5eeb35760e01b8152600481018e9052602481018d9052604481018c9052606481018b9052608481018a905260a4810189905290516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163f5eeb3579160c48083019260a0929190829003018186803b15801561433057600080fd5b505afa158015614344573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525060a081101561436957600080fd5b509050806000602002015181600160200201518260026020020151836003602002015184600460200201519550955095509550955050965096509650965096915050565b600080806143c1878963ffffffff61441316565b905060006143dd826702c68af0bb14000063ffffffff61441316565b905060006143fa6143f3876001811115613d5057fe5b8989614488565b9282900389019290920393509150509550959350505050565b6000610d9a670de0b6b3a7640000610ea5858563ffffffff611c9016565b61443a816133c2565b600560016101000a8154816001600160801b0302191690836001600160801b0316021790555050565b60008082600181111561447257fe5b141561448057506001610ef8565b506000610ef8565b60008084600181111561449757fe5b14156144b4576144ad838363ffffffff61441316565b9050610d9a565b6144ad838363ffffffff61276016565b80546001019055565b60006144d9600f612f90565b9050806144e584614763565b1015610f4a578254600180820185556000858152602080822090930193909355938401805494850181558252902090910155565b61105c600d613eaf610c55565b6001600160a01b038216614581576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b61458d60008383610f4a565b6002546145a0908263ffffffff611b3316565b6002556001600160a01b0382166000908152602081905260409020546145cc908263ffffffff611b3316565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610d09575050151592915050565b6001600160a01b0382166146a05760405162461bcd60e51b81526004018080602001828103825260218152602001806149936021913960400191505060405180910390fd5b6146ac82600083610f4a565b6146ef81604051806060016040528060228152602001614873602291396001600160a01b038516600090815260208190526040902054919063ffffffff611a9c16565b6001600160a01b03831660009081526020819052604090205560025461471b908263ffffffff61309f16565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b805460009061477457506000610ef8565b81548290600019810190811061478657fe5b90600052602060002001549050610ef8565b6040805160a081019091528060008152600060208201819052604082018190526060820181905260809091015290565b604080518082019091526000808252602082015290565b50805460008255906000526020600020908101906111349190614835565b604051806040016040528060608152602001600081525090565b6040518060a001604052806005906020820280368337509192915050565b610b8991905b80821115613406576000815560010161483b56fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636553616665436173743a2076616c756520646f65736e27742066697420696e203132382062697473416d6f756e742073686f756c6420626520626967676572207468616e20300000536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7753616665436173743a2076616c756520646f65736e27742066697420696e203634206269747345524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737353616665436173743a2076616c756520646f65736e27742066697420696e203332206269747345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa26469706673582212203c590c87bd38dd085d6955877b99a555774bfae076e5428f7abd4b10ff0f724864736f6c634300060600330000000000000000000000007591a309df68bf43ba42dd11b0344220a260020a000000000000000000000000e9aa04b8d955fd291d44c9fdb8eb1227850b3e2d000000000000000000000000ab37e1358b639fd877f015027bb62d3ddaa7557e000000000000000000000000c05cb1999ab97a9ae5337fbdc4cb0e1458bc5cbf00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000f53484152452d49444f4c2d4c49454e0000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106102295760003560e01c806395d89b4111610123578063bb2f53b4116100ab578063dd62ed3e1161006f578063dd62ed3e14610923578063dec7bfd21461095e578063e1b4df2a146109a1578063f88bf15a146109e8578063fc0c546a14610a2457610230565b8063bb2f53b41461086a578063c48c73421461087f578063c9a01af914610894578063d5855e7a146108c1578063da84fb0b146108d657610230565b8063a3fee072116100f2578063a3fee07214610736578063a457c2d71461078b578063a9059cbb146107c4578063aebf3e41146107fd578063b196a3521461083957610230565b806395d89b41146106af578063981b24d0146106c45780639c558c4b146106ee578063a11bc81f1461070357610230565b806339509351116101b15780636d294d06116101755780636d294d06146105bc57806370a08231146105f55780637112ed021461062857806384c76abc1461065e57806392dea49c1461069a57610230565b8063395093511461047e5780634ee2cd7e146104b75780634fc0bf09146104f057806359e713141461052957806369cb06541461059257610230565b806318160ddd116101f857806318160ddd146103a05780631c67247c146103b557806323b872dd146103df578063313ce56714610422578063385a8d501461044d57610230565b8063068228591461023557806306fdde0314610280578063095ea7b31461030a5780630d96ad311461035757610230565b3661023057005b600080fd5b34801561024157600080fd5b5061026e6004803603604081101561025857600080fd5b506001600160a01b038135169060200135610a39565b60408051918252519081900360200190f35b34801561028c57600080fd5b50610295610af5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102cf5781810151838201526020016102b7565b50505050905090810190601f1680156102fc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561031657600080fd5b506103436004803603604081101561032d57600080fd5b506001600160a01b038135169060200135610b8c565b604080519115158252519081900360200190f35b34801561036357600080fd5b5061039e6004803603608081101561037a57600080fd5b508035906001600160a01b0360208201351690604081013590606001351515610baa565b005b3480156103ac57600080fd5b5061026e610c55565b3480156103c157600080fd5b5061026e600480360360208110156103d857600080fd5b5035610c5b565b3480156103eb57600080fd5b506103436004803603606081101561040257600080fd5b506001600160a01b03813581169160208101359091169060400135610d13565b34801561042e57600080fd5b50610437610da1565b6040805160ff9092168252519081900360200190f35b34801561045957600080fd5b50610462610daa565b604080516001600160a01b039092168252519081900360200190f35b34801561048a57600080fd5b50610343600480360360408110156104a157600080fd5b506001600160a01b038135169060200135610dce565b3480156104c357600080fd5b5061026e600480360360408110156104da57600080fd5b506001600160a01b038135169060200135610e22565b3480156104fc57600080fd5b5061026e6004803603604081101561051357600080fd5b506001600160a01b038135169060200135610e68565b34801561053557600080fd5b506105726004803603608081101561054c57600080fd5b506001600160a01b03813516906020810135906040810135151590606001351515610ebb565b604080519315158452602084019290925282820152519081900360600190f35b34801561059e57600080fd5b5061026e600480360360208110156105b557600080fd5b5035610ee5565b3480156105c857600080fd5b5061026e600480360360408110156105df57600080fd5b506001600160a01b038135169060200135610efd565b34801561060157600080fd5b5061026e6004803603602081101561061857600080fd5b50356001600160a01b0316610f24565b34801561063457600080fd5b5061039e6004803603606081101561064b57600080fd5b5080359060208101359060400135610f3f565b34801561066a57600080fd5b5061026e6004803603604081101561068157600080fd5b5080356001600160a01b0316906020013560ff16610f4f565b3480156106a657600080fd5b50610462610fbe565b3480156106bb57600080fd5b50610295610fcd565b3480156106d057600080fd5b5061026e600480360360208110156106e757600080fd5b503561102e565b3480156106fa57600080fd5b5061039e611054565b34801561070f57600080fd5b5061039e6004803603602081101561072657600080fd5b50356001600160a01b031661105e565b34801561074257600080fd5b506107606004803603602081101561075957600080fd5b5035611137565b6040805195865260208601949094528484019290925260608401526080830152519081900360a00190f35b34801561079757600080fd5b50610343600480360360408110156107ae57600080fd5b506001600160a01b038135169060200135611252565b3480156107d057600080fd5b50610343600480360360408110156107e757600080fd5b506001600160a01b0381351690602001356112c0565b34801561080957600080fd5b5061039e6004803603608081101561082057600080fd5b50803590602081013590604081013590606001356112d4565b34801561084557600080fd5b5061084e61143f565b604080516001600160801b039092168252519081900360200190f35b34801561087657600080fd5b5061039e61144e565b34801561088b57600080fd5b5061026e611579565b3480156108a057600080fd5b5061039e600480360360208110156108b757600080fd5b503560ff166115ef565b3480156108cd57600080fd5b5061084e6115f8565b3480156108e257600080fd5b506108eb61160c565b604080519788526020880196909652868601949094526060860192909252608085015260a084015260c0830152519081900360e00190f35b34801561092f57600080fd5b5061026e6004803603604081101561094657600080fd5b506001600160a01b0381358116916020013516611688565b34801561096a57600080fd5b5061026e6004803603606081101561098157600080fd5b506001600160a01b038135811691602081013590911690604001356116b3565b3480156109ad57600080fd5b5061039e600480360360808110156109c457600080fd5b508035906001600160a01b03602082013516906040810135906060013515156116fc565b3480156109f457600080fd5b5061039e60048036036080811015610a0b57600080fd5b5080359060208101359060408101359060600135611791565b348015610a3057600080fd5b50610462611830565b60008160008111610a91576040805162461bcd60e51b815260206004820152601a60248201527f3020697320696e76616c69642076616c7565206173207465726d000000000000604482015290519081900360640190fd5b6000610a9b611579565b9050835b81811015610ae057610ab081611854565b15610ad857600081815260116020526040902054610acf908790610e22565b93505050610aee565b600101610a9f565b50610aea85610f24565b9250505b5092915050565b60038054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610b815780601f10610b5657610100808354040283529160200191610b81565b820191906000526020600020905b815481529060010190602001808311610b6457829003601f168201915b505050505090505b90565b6000610ba0610b99611868565b848461186c565b5060015b92915050565b8180610beb576040805162461bcd60e51b815260206004820152601e6024820152600080516020614904833981519152604482015290519081900360640190fd5b84610bf4611958565b8111610c32576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b6000610c3f600185611962565b9050610c4c818688611996565b50505050505050565b60025490565b60008160008111610cb3576040805162461bcd60e51b815260206004820152601a60248201527f3020697320696e76616c69642076616c7565206173207465726d000000000000604482015290519081900360640190fd5b6000610cbd611579565b9050835b81811015610d0057610cd281611854565b15610cf857600081815260116020526040902054610cef9061102e565b93505050610d0d565b600101610cc1565b50610d09610c55565b9250505b50919050565b6000610d20848484611a91565b610d9684610d2c611868565b610d918560405180606001604052806028815260200161496b602891396001600160a01b038a16600090815260016020526040812090610d6a611868565b6001600160a01b03168152602081019190915260400160002054919063ffffffff611a9c16565b61186c565b5060015b9392505050565b60055460ff1690565b7f0000000000000000000000007591a309df68bf43ba42dd11b0344220a260020a81565b6000610ba0610ddb611868565b84610d918560016000610dec611868565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff611b3316565b6001600160a01b0382166000908152600c6020526040812081908190610e49908590611b8d565b9150915081610e6057610e5b85610f24565b610aea565b949350505050565b600080610e758484610a39565b90506000610e8284610c5b565b90506000610e8f85610ee5565b9050610eb182610ea5838663ffffffff611c9016565b9063ffffffff611ce916565b9695505050505050565b6000806000610ed487610ece8787611d2b565b88611d57565b9250925092505b9450945094915050565b6000818152601260205260409020600101545b919050565b60009081526012602090815260408083206001600160a01b03949094168352929052205490565b6001600160a01b031660009081526020819052604090205490565b610f4a838383612099565b505050565b60006008610f5b611958565b81548110610f6557fe5b90600052602060002090600202016000016000836003811115610f8457fe5b6003811115610f8f57fe5b8152602080820192909252604090810160009081206001600160a01b0387168252909252902054905092915050565b6010546001600160a01b031681565b60048054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610b815780601f10610b5657610100808354040283529160200191610b81565b600080600061103e84600d611b8d565b9150915081610d9a5761104f610c55565b610d09565b61105c612164565b565b6000611068611579565b905080600114156110795750611134565b61108382826121e8565b3360009081526013602090815260408083206001600160a01b038616845290915281208054600019840190915590600182015b838110156110d5576110c93386836116b3565b909101906001016110b6565b506040805182815290516001600160a01b0386169133917f9b64af6bc8380496b8d368590f1460af6043202bca9d05998fcee10cd105fd5c9181900360200190a36111306001600160a01b038516338363ffffffff6123ee16565b5050505b50565b600080600080600080600960000160199054906101000a900463ffffffff1663ffffffff1690506008878154811061116b57fe5b6000918252602080832083805260029283020190526040909120015460088054919650908890811061119957fe5b600091825260208083206002808552928302019052604090912001546008805491955090889081106111c757fe5b60009182526020808320600184526002928302019052604090912001546008805491945090889081106111f657fe5b60009182526020808320600384526002928302019052604090912001549150808710156112265760029550611248565b808714801561123e5750600954600160e81b900460ff165b1561124857600195505b5091939590929450565b6000610ba061125f611868565b84610d9185604051806060016040528060258152602001614a4d6025913960016000611289611868565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff611a9c16565b6000610ba06112cd611868565b8484611a91565b8280611315576040805162461bcd60e51b815260206004820152601e6024820152600080516020614904833981519152604482015290519081900360640190fd5b8280611356576040805162461bcd60e51b815260206004820152601e6024820152600080516020614904833981519152604482015290519081900360640190fd5b8561135f611958565b811161139d576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b6113a5611958565b87116113e3576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b6000806113ee612440565b9092509050600061140982610ea58a8663ffffffff611c9016565b90508089116114255761142083838b8a600061245e565b611433565b61143383838a8a600161245e565b50505050505050505050565b6006546001600160801b031681565b6000611458611579565b90508060011415611469575061105c565b6114728161256e565b3360009081526014602052604081208054600019840190915590600182015b838110156114af576114a33382610e68565b90910190600101611491565b5060408051828152905133917fe3fdc68a57b01b663baef2bfbaa7da3ef2d8a090c25c00577be52fd50cc45859919081900360200190a2604051600090339083908381818185875af1925050503d8060008114611528576040519150601f19603f3d011682016040523d82523d6000602084013e61152d565b606091505b5050905080611130576040805162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b604482015290519081900360640190fd5b6010546040805163624639a160e11b815290516000926001600160a01b03169163c48c7342916004808301926020929190829003018186803b1580156115be57600080fd5b505afa1580156115d2573d6000803e3d6000fd5b505050506040513d60208110156115e857600080fd5b5051905090565b6111348161274c565b60055461010090046001600160801b031681565b600080600080600080600061161f611958565b9650611629612440565b80965081975050506008878154811061163e57fe5b60009182526020909120600160029092020101546001600160801b03169250611665610c55565b93506116718685612760565b915061167d8585612760565b905090919293949596565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6000806116c08584610a39565b905060006116cd84610c5b565b905060006116db8686610efd565b90506116f182610ea5838663ffffffff611c9016565b979650505050505050565b818061173d576040805162461bcd60e51b815260206004820152601e6024820152600080516020614904833981519152604482015290519081900360640190fd5b84611746611958565b8111611784576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b6000610c3f600085611962565b8361179a611958565b81116117d8576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b6117e0611958565b851161181e576040805162461bcd60e51b8152602060048201526008602482015267151a5b59481bdd5d60c21b604482015290519081900360640190fd5b61182984848461277e565b5050505050565b7f000000000000000000000000ab37e1358b639fd877f015027bb62d3ddaa7557e81565b600090815260116020526040902054151590565b3390565b6001600160a01b0383166118b15760405162461bcd60e51b81526004018080602001828103825260248152602001806149ff6024913960400191505060405180910390fd5b6001600160a01b0382166118f65760405162461bcd60e51b81526004018080602001828103825260228152602001806148956022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6008546000190190565b6000821561198057811561197857506002610ba4565b506000610ba4565b811561198e57506003610ba4565b506001610ba4565b61199e6128c4565b60006119a8611958565b90506119b56005826128d9565b6001600160a01b0382166119c7573391505b6119e56119de8560038111156119d957fe5b612e02565b3385612e3d565b611a16848484600885815481106119f857fe5b9060005260206000209060020201612e63909392919063ffffffff16565b8063ffffffff16611a31856003811115611a2c57fe5b612f3f565b1515836001600160a01b03167fd54c711b2fd79474dc74606062c8605c0dac9e6089a74320ccf470dc2e33e19a611a72886003811115611a6d57fe5b612f6b565b604080519115158252602082018990528051918290030190a450505050565b610f4a838383612f7d565b60008184841115611b2b5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611af0578181015183820152602001611ad8565b50505050905090810190601f168015611b1d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600082820183811015610d9a576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008060008411611bde576040805162461bcd60e51b815260206004820152601660248201527504552433230536e617073686f743a20696420697320360541b604482015290519081900360640190fd5b611be8600f612f90565b841115611c3c576040805162461bcd60e51b815260206004820152601d60248201527f4552433230536e617073686f743a206e6f6e6578697374656e74206964000000604482015290519081900360640190fd5b6000611c4e848663ffffffff612f9416565b8454909150811415611c67575060009150819050611c89565b6001846001018281548110611c7857fe5b906000526020600020015492509250505b9250929050565b600082611c9f57506000610ba4565b82820282848281611cac57fe5b0414610d9a5760405162461bcd60e51b81526004018080602001828103825260218152602001806149246021913960400191505060405180910390fd5b6000610d9a83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613035565b6000828015611d375750815b15611d4457506002610ba4565b82610ba4578115610ba057506003610ba4565b6000806000611d64611958565b841115611d7957506000915081905080612090565b600060088581548110611d8857fe5b906000526020600020906002020190506060816000016000886003811115611dac57fe5b6003811115611db757fe5b6003811115611dc257fe5b8152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015611e2757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611e09575b5050600954600b54600a54959650600160c81b90910463ffffffff16949093506000925060ff1690506003811115611e5b57fe5b600954909150600160e81b900460ff16600080805b87518114611eb9578e6001600160a01b0316888281518110611e8e57fe5b60200260200101516001600160a01b03161415611eb15760019250809150611eb9565b600101611e70565b50858c1080611eed5750828015611ecf5750858c145b8015611eed5750838d1080611eed5750838d148015611eed57508481105b15611f0b575060019950600098508897506120909650505050505050565b81611f285750600099508998508897506120909650505050505050565b6000868d148015611f365750835b1561203257845b8e81101561200357611ff78a6000836003811115611f5757fe5b6003811115611f6257fe5b6003811115611f6d57fe5b815260200190815260200160002060405180604001604052908160018201805480602002602001604051908101604052809291908181526020018280548015611fdf57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611fc1575b5050505050815260200160028201548152505061309a565b90910190600101611f3d565b5060019a506120288661201c838563ffffffff611b3316565b9063ffffffff61309f16565b6001019950612086565b60005b8e811461205a5761204e8a6000836003811115611f5757fe5b90910190600101612035565b5061206b8d8863ffffffff61309f16565b6001019a50612080818363ffffffff611b3316565b60010199505b5050505050505050505b93509350939050565b6120a1610c55565b156120e9576040805162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b604482015290519081900360640190fd5b336001600160a01b037f00000000000000000000000039a5bbc3f5536d7a9f40acfcb34738ff29540f49161461211e57600080fd5b61212883836130e1565b612132338261316c565b612147600033856001600160801b0316612e3d565b61215c600133846001600160801b0316612e3d565b610f4a613176565b60008061216f6131fd565b9150915061217e600080613219565b604080518381526020810183905281517f72715c0cf03be5e4479cb972219945b83aee28f65875993b1de62bda86892d1e929181900390910190a16121e47f000000000000000000000000ab37e1358b639fd877f015027bb62d3ddaa7557e838361325a565b5050565b60105460408051634665096d60e01b815290516000926001600160a01b031691634665096d916004808301926020929190829003018186803b15801561222d57600080fd5b505afa158015612241573d6000803e3d6000fd5b505050506040513d602081101561225757600080fd5b5051905060008082841115612270578284039150612275565b600191505b60001984015b82811061236d5760008181526012602090815260408083206001600160a01b038a168452909152902054156122af5761236d565b6010546040805163021e20ab60e61b81526001600160a01b03898116600483015230602483015260448201859052915160009392909216916387882ac091606480820192602092909190829003018186803b15801561230d57600080fd5b505afa158015612321573d6000803e3d6000fd5b505050506040513d602081101561233757600080fd5b505160008381526012602090815260408083206001600160a01b038c16845290915290208190559290920191506000190161227b565b508061237b575050506121e4565b6010546040805163125bdfc160e11b81526001600160a01b038881166004830152306024830152915191909216916324b7bf8291604480830192600092919082900301818387803b1580156123cf57600080fd5b505af11580156123e3573d6000803e3d6000fd5b505050505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610f4a90849061329a565b6006546007546001600160801b03600160801b909204821692911690565b600080600061246f8689898761334b565b925092509250848110156124ca576040805162461bcd60e51b815260206004820152601f60248201527f596f752063616e2774207265636569766520656e6f7567682073686172657300604482015290519081900360640190fd5b6124d660003385612e3d565b6124e260013384612e3d565b6125156124fd6124f88a8663ffffffff611b3316565b6133c2565b6125106124f88a8663ffffffff611b3316565b6130e1565b61251f338261316c565b6040805184815260208101849052808201839052905160019133917ff13afa8e6af2cf800415b27d44406182e9ea706876b2470dac00aff3def8161c9181900360600190a35050505050505050565b60105460408051634665096d60e01b815290516000926001600160a01b031691634665096d916004808301926020929190829003018186803b1580156125b357600080fd5b505afa1580156125c7573d6000803e3d6000fd5b505050506040513d60208110156125dd57600080fd5b50519050600080828411156125f65782840391506125fb565b600191505b60001984015b8281106126ce5760008181526012602052604090206001015415612624576126ce565b6010546040805163021e20ab60e61b815260006004820181905230602483015260448201859052915191926001600160a01b0316916387882ac091606480820192602092909190829003018186803b15801561267f57600080fd5b505afa158015612693573d6000803e3d6000fd5b505050506040513d60208110156126a957600080fd5b5051600083815260126020526040902060010181905592909201915060001901612601565b50806126dc57505050611134565b6010546040805163125bdfc160e11b815260006004820181905230602483015291516001600160a01b03909316926324b7bf829260448084019391929182900301818387803b15801561272e57600080fd5b505af1158015612742573d6000803e3d6000fd5b5050505050505050565b6111348160ff1661275b611958565b6128d9565b6000610d9a82610ea585670de0b6b3a764000063ffffffff611c9016565b600080612789612440565b915091506000612797610c55565b905060006127af82610ea5868863ffffffff611c9016565b905060006127c783610ea5868963ffffffff611c9016565b90508782101580156127d95750868110155b61282a576040805162461bcd60e51b815260206004820152601f60248201527f596f752063616e2774207265636569766520656e6f75676820746f6b656e7300604482015290519081900360640190fd5b6128536128406124f8878563ffffffff61309f16565b6125106124f8878563ffffffff61309f16565b61285d338761340a565b61286960003384613414565b61287560013383613414565b6040805183815260208101839052808201889052905160009133917ff13afa8e6af2cf800415b27d44406182e9ea706876b2470dac00aff3def8161c9181900360600190a35050505050505050565b6128cc613438565b1561105c5761105c613176565b6128e1614798565b6040805160a0810190915260098054829060ff16600381111561290057fe5b600381111561290b57fe5b81529054610100810467ffffffffffffffff166020830152600160481b81046001600160801b03166040830152600160c81b810463ffffffff166060830152600160e81b900460ff16151560809091015290506129666147c8565b60408051808201909152600a8054829060ff16600381111561298457fe5b600381111561298f57fe5b8152602001600182015481525050905082826060015163ffffffff16101580156129d157506129bc613438565b15806129d1575082826060015163ffffffff16115b156129dd5750506121e4565b8160800151612a605760008060006129f8856060015161347a565b9194509250905084836003811115612a0c57fe5b90816003811115612a1957fe5b905250612a25826135e3565b67ffffffffffffffff166020860152612a3d816133c2565b6001600160801b0316604086015250506001608084015250600080825260208201525b8315612d195760006008836060015163ffffffff1681548110612a7f57fe5b600091825260208220845160029092020191906003811115612a9d57fe5b6003811115612aa857fe5b815260200190815260200160002090506000806000612b3484612ad4876000015160038111156119d957fe5b60208801518851612aec908b9063ffffffff61362c16565b8a604001516001600160801b031660088c6060015163ffffffff1681548110612b1157fe5b60009182526020909120600160029092020101546001600160801b03168e6136f6565b9250925092508215612cf8576000612b746008886060015163ffffffff1681548110612b5c57fe5b9060005260206000209060020201876000015161382d565b90506008876060015163ffffffff1681548110612b8d57fe5b600091825260208220885160029092020191906003811115612bab57fe5b6003811115612bb657fe5b81526020019081526020016000206000600182016000612bd691906147df565b600282016000905550508015612cc35760608701805163ffffffff600191820116909152600060808901528751600980548a93919291839160ff191690836003811115612c1f57fe5b021790555060208201518154604084015160608501516080909501511515600160e81b0260ff60e81b1963ffffffff909616600160c81b0263ffffffff60c81b196001600160801b03909316600160481b02600160481b600160c81b031967ffffffffffffffff9096166101000268ffffffffffffffff0019909516949094179490941692909217169190911792909216919091179055506121e495505050505050565b8551612cd9906003811115612cd457fe5b613948565b86906003811115612ce657fe5b90816003811115612cf357fe5b905250505b612d018261396e565b63ffffffff1660208601529096039550612a60915050565b815160098054849290829060ff19166001836003811115612d3657fe5b021790555060208201518154604084015160608501516080909501511515600160e81b0260ff60e81b1963ffffffff909616600160c81b0263ffffffff60c81b196001600160801b03909316600160481b02600160481b600160c81b031967ffffffffffffffff9096166101000268ffffffffffffffff00199095169490941794909416929092171691909117929092169190911790558051600a8054839290829060ff19166001836003811115612dea57fe5b02179055506020820151816001015590505050505050565b600080826003811115612e1157fe5b1480612e2857506002826003811115612e2657fe5b145b15612e3557506000610ef8565b506001610ef8565b610f4a823083612e4c876139b3565b6001600160a01b031692919063ffffffff613a1616565b60008481856003811115612e7357fe5b6003811115612e7e57fe5b8152602080820192909252604090810160009081206001600160a01b0386168252928390522054909150612edc576001818101805491820181556000908152602090200180546001600160a01b0319166001600160a01b0384161790555b6001600160a01b038216600090815260208290526040902054612f05908463ffffffff611b3316565b6001600160a01b0383166000908152602083905260409020556002810154612f33908463ffffffff611b3316565b60029091015550505050565b600080826003811115612f4e57fe5b1480610ba4575060025b826003811115612f6457fe5b1492915050565b6000612f7682613a70565b1592915050565b612f85613a8d565b610f4a838383613ad6565b5490565b8154600090612fa557506000610ba4565b82546000905b80821015612ff4576000612fbf8383613af3565b905084868281548110612fce57fe5b90600052602060002001541115612fe757809150612fee565b8060010192505b50612fab565b60008211801561301c57508385600184038154811061300f57fe5b9060005260206000200154145b1561302d5750600019019050610ba4565b509050610ba4565b600081836130845760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611af0578181015183820152602001611ad8565b50600083858161309057fe5b0495945050505050565b515190565b6000610d9a83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611a9c565b600680546001600160801b03908116600160801b8583160217909155600780546001600160801b0319169183169190911790557f17226eb45b590dffadbc03fba4681aa4c198e7e838ab8a6fb7e32a51634b3e80828261313f610c55565b604080516001600160801b0394851681529290931660208301528183015290519081900360600190a15050565b6121e48282613b18565b61317e613b2a565b6000613188611958565b9050613193816133c2565b6001600160801b03167f5ab5824685efa3ca4a723a2f94da7d225628bfae130cc14663932a3bf11140a8600883815481106131ca57fe5b600091825260209182902060016002909202010154604080516001600160801b039092168252519081900390910190a250565b6005546006546001600160801b03610100909204821692911690565b6005805470ffffffffffffffffffffffffffffffff0019166101006001600160801b0394851602179055600680546001600160801b03191691909216179055565b8115610f4a57610f4a6001600160a01b037f0000000000000000000000007591a309df68bf43ba42dd11b0344220a260020a16848463ffffffff6123ee16565b60606132ef826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613b9b9092919063ffffffff16565b805190915015610f4a5780806020019051602081101561330e57600080fd5b5051610f4a5760405162461bcd60e51b815260040180806020018281038252602a815260200180614a23602a913960400191505060405180910390fd5b600080808084600181111561335c57fe5b141561339e578661337787610ea5838963ffffffff611c9016565b61339388610ea5613386610c55565b8c9063ffffffff611c9016565b925092509250610edb565b6133b285610ea5898963ffffffff611c9016565b8761339387610ea5613386610c55565b6000600160801b82106134065760405162461bcd60e51b81526004018080602001828103825260278152602001806148dd6027913960400191505060405180910390fd5b5090565b6121e48282613baa565b610f4a8282613422866139b3565b6001600160a01b0316919063ffffffff6123ee16565b60006008613444611958565b8154811061344e57fe5b6000918252602090912060029091020160010154600160801b90046001600160801b0316431015919050565b60008060008060088563ffffffff168154811061349357fe5b6000918252602080832083805260029283020190819052604080842083015460018552818520840154848652828620850154600387529286209094015492955084938493919290916134e88885858585613bbc565b919d50929b509098509096509450866135045760029a50613548565b86600114156135165760029a50613548565b86600214156135285760009a50613548565b866003141561353a5760039a50613548565b86600414156135485760019a505b8b63ffffffff167f24f971a36bb1ccca6d5a24e46c30c46b44dc72fdf6b667edd669dee3585552a58c600381111561357c57fe5b6040805160ff9092168252602082018d90528181018e9052606082018890526080820187905260a0820186905260c08201859052519081900360e00190a260018801546135d4906001600160801b031687878c613c52565b50505050505050509193909250565b60006801000000000000000082106134065760405162461bcd60e51b81526004018080602001828103825260268152602001806149456026913960400191505060405180910390fd5b600061363d8260038111156119d957fe5b600181111561364857fe5b83516136599060038111156119d957fe5b600181111561366457fe5b1461367157506000610ba4565b825161368790600381111561368257fe5b613a70565b156136c45761369b82600381111561368257fe5b156136b55750602082015167ffffffffffffffff16610ba4565b50670de0b6b3a7640000610ba4565b6136d3826003811115611a6d57fe5b156136ed5750602082015167ffffffffffffffff16610ba4565b50600092915050565b600080600080600061377c8c60405180604001604052908160018201805480602002602001604051908101604052809291908181526020018280548015611fdf576020028201919060005260206000209081546001600160a01b03168152600190910190602001808311611fc1575050505050815260200160028201548152505061309a565b90508991505b858a830310156137fa578082106137a6575060019350600092508890039050613820565b60008c60010183815481106137b757fe5b60009182526020808320909101546001600160a01b0316808352908f90526040909120549091506137ee908d9083908d8d8d613d3f565b50600190910190613782565b808210613814575060019350600092508890039050613820565b50600093509150508681035b9750975097945050505050565b6000600382600381111561383d57fe5b141561384b57506001610ba4565b600061385c836003811115612cd457fe5b600381111561386757fe5b90505b80600414610d965761387a6147fd565b84600083600381111561388957fe5b600381111561389457fe5b600381111561389f57fe5b81526020019081526020016000206040518060400160405290816001820180548060200260200160405190810160405280929190818152602001828054801561391157602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116138f3575b50505050508152602001600282015481525050905061392f8161309a565b1561393f57600092505050610ba4565b5060010161386a565b6000600482600381111561395857fe5b6001018161396257fe5b066003811115610ba457fe5b600064010000000082106134065760405162461bcd60e51b81526004018080602001828103825260268152602001806149d96026913960400191505060405180910390fd5b6000808260018111156139c257fe5b14156139ef57507f0000000000000000000000007591a309df68bf43ba42dd11b0344220a260020a610ef8565b507f000000000000000000000000ab37e1358b639fd877f015027bb62d3ddaa7557e919050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b17905261113090859061329a565b600080826003811115613a7f57fe5b1480610ba457506001612f58565b6000613a97611579565b9050600181118015613ab25750613ab060018203611854565b155b1561113457613abf613e36565b600019820160009081526011602052604090205550565b613adf83613e8a565b613ae882613e8a565b610f4a838383613eb4565b60006002808306600285060181613b0657fe5b04600283046002850401019392505050565b613b20613a8d565b6121e4828261401b565b6008613b4e613b37614036565b613b434360020161396e565b63ffffffff166140e4565b8154600180820184556000938452602093849020835160029093020101805492909301516001600160801b03199092166001600160801b03918216178116600160801b9190921602179055565b6060610e60848460008561410e565b613bb2613a8d565b6121e4828261427b565b600185015460009081908190819081906001600160801b0316670de0b6b3a764000001613c3b613bec8b83612760565b613bfc8a8463ffffffff61276016565b613c0c8c8563ffffffff61276016565b613c1c8b8663ffffffff61276016565b6006546007546001600160801b03600160801b90920482169116614296565b939f929e50909c509a509098509650505050505050565b600080600080600080613c698a8a8a8a60006143ad565b6006546005546001600160801b03600160801b90920482169093019850610100909204909116019350613ca4915089905087898860016143ad565b6007546001600160801b0316909101935090506000613d01670de0b6b3a7640000613cf5613ce8613cdb888763ffffffff611b3316565b899063ffffffff61276016565b859063ffffffff61441316565b9063ffffffff61276016565b948590039493820193929092019150613d25613d1c856133c2565b612510856133c2565b612742613d31836133c2565b6001600160801b0316614431565b6000613d55876001811115613d5057fe5b614463565b90506000613d69868663ffffffff61441316565b90506000613d98613d88670de0b6b3a76400008663ffffffff611b3316565b613cf5898563ffffffff61309f16565b90506000613da78a8388614488565b9050613db48a8a85613414565b613dbf848a83613414565b886001600160a01b0316613dd1611958565b63ffffffff1660008c6001811115613de557fe5b604080518d815260208101899052808201879052905192909114917fb8221d4e9feabcc28c5e0878f3196eecf38320725898780b22a503239b6bc9969181900360600190a450505050505050505050565b6000613e42600f6144c4565b6000613e4e600f612f90565b6040805182815290519192507f8030e83b04d87bef53480e26263266d6ca66863aa8506aca6f2559d18aa1cb67919081900360200190a1905090565b6001600160a01b0381166000908152600c6020526040902061113490613eaf83610f24565b6144cd565b6001600160a01b038316613ef95760405162461bcd60e51b81526004018080602001828103825260258152602001806149b46025913960400191505060405180910390fd5b6001600160a01b038216613f3e5760405162461bcd60e51b81526004018080602001828103825260238152602001806148506023913960400191505060405180910390fd5b613f49838383610f4a565b613f8c816040518060600160405280602681526020016148b7602691396001600160a01b038616600090815260208190526040902054919063ffffffff611a9c16565b6001600160a01b038085166000908152602081905260408082209390935590841681522054613fc1908263ffffffff611b3316565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b61402482613e8a565b61402c614519565b6121e48282614526565b60007f000000000000000000000000c05cb1999ab97a9ae5337fbdc4cb0e1458bc5cbf6001600160a01b0316632e66ed1a7f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050602060405180830381600087803b1580156140d057600080fd5b505af11580156115d2573d6000803e3d6000fd5b6140ec6147c8565b50604080518082019091526001600160801b0392831681529116602082015290565b606061411985614622565b61416a576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106141a95780518252601f19909201916020918201910161418a565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461420b576040519150601f19603f3d011682016040523d82523d6000602084013e614210565b606091505b50915091508115614224579150610e609050565b8051156142345780518082602001fd5b60405162461bcd60e51b8152602060048201818152865160248401528651879391928392604401919085019080838360008315611af0578181015183820152602001611ad8565b61428482613e8a565b61428c614519565b6121e4828261465b565b60008060008060006142a6614817565b6040805163f5eeb35760e01b8152600481018e9052602481018d9052604481018c9052606481018b9052608481018a905260a4810189905290516001600160a01b037f000000000000000000000000e9aa04b8d955fd291d44c9fdb8eb1227850b3e2d169163f5eeb3579160c48083019260a0929190829003018186803b15801561433057600080fd5b505afa158015614344573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525060a081101561436957600080fd5b509050806000602002015181600160200201518260026020020151836003602002015184600460200201519550955095509550955050965096509650965096915050565b600080806143c1878963ffffffff61441316565b905060006143dd826702c68af0bb14000063ffffffff61441316565b905060006143fa6143f3876001811115613d5057fe5b8989614488565b9282900389019290920393509150509550959350505050565b6000610d9a670de0b6b3a7640000610ea5858563ffffffff611c9016565b61443a816133c2565b600560016101000a8154816001600160801b0302191690836001600160801b0316021790555050565b60008082600181111561447257fe5b141561448057506001610ef8565b506000610ef8565b60008084600181111561449757fe5b14156144b4576144ad838363ffffffff61441316565b9050610d9a565b6144ad838363ffffffff61276016565b80546001019055565b60006144d9600f612f90565b9050806144e584614763565b1015610f4a578254600180820185556000858152602080822090930193909355938401805494850181558252902090910155565b61105c600d613eaf610c55565b6001600160a01b038216614581576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b61458d60008383610f4a565b6002546145a0908263ffffffff611b3316565b6002556001600160a01b0382166000908152602081905260409020546145cc908263ffffffff611b3316565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610d09575050151592915050565b6001600160a01b0382166146a05760405162461bcd60e51b81526004018080602001828103825260218152602001806149936021913960400191505060405180910390fd5b6146ac82600083610f4a565b6146ef81604051806060016040528060228152602001614873602291396001600160a01b038516600090815260208190526040902054919063ffffffff611a9c16565b6001600160a01b03831660009081526020819052604090205560025461471b908263ffffffff61309f16565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b805460009061477457506000610ef8565b81548290600019810190811061478657fe5b90600052602060002001549050610ef8565b6040805160a081019091528060008152600060208201819052604082018190526060820181905260809091015290565b604080518082019091526000808252602082015290565b50805460008255906000526020600020908101906111349190614835565b604051806040016040528060608152602001600081525090565b6040518060a001604052806005906020820280368337509192915050565b610b8991905b80821115613406576000815560010161483b56fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636553616665436173743a2076616c756520646f65736e27742066697420696e203132382062697473416d6f756e742073686f756c6420626520626967676572207468616e20300000536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7753616665436173743a2076616c756520646f65736e27742066697420696e203634206269747345524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737353616665436173743a2076616c756520646f65736e27742066697420696e203332206269747345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa26469706673582212203c590c87bd38dd085d6955877b99a555774bfae076e5428f7abd4b10ff0f724864736f6c63430006060033

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

0000000000000000000000007591a309df68bf43ba42dd11b0344220a260020a000000000000000000000000e9aa04b8d955fd291d44c9fdb8eb1227850b3e2d000000000000000000000000ab37e1358b639fd877f015027bb62d3ddaa7557e000000000000000000000000c05cb1999ab97a9ae5337fbdc4cb0e1458bc5cbf00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000f53484152452d49444f4c2d4c49454e0000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _idol (address): 0x7591a309Df68bf43ba42dD11b0344220A260020A
Arg [1] : _priceCalc (address): 0xE9aa04b8D955fD291d44C9fDb8eB1227850b3e2d
Arg [2] : _lien (address): 0xaB37e1358b639Fd877f015027Bb62d3ddAa7557E
Arg [3] : _spreadCalc (address): 0xC05CB1999aB97A9ae5337fBdC4cb0e1458bc5CbF
Arg [4] : _name (string): SHARE-IDOL-LIEN

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000007591a309df68bf43ba42dd11b0344220a260020a
Arg [1] : 000000000000000000000000e9aa04b8d955fd291d44c9fdb8eb1227850b3e2d
Arg [2] : 000000000000000000000000ab37e1358b639fd877f015027bb62d3ddaa7557e
Arg [3] : 000000000000000000000000c05cb1999ab97a9ae5337fbdc4cb0e1458bc5cbf
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [5] : 000000000000000000000000000000000000000000000000000000000000000f
Arg [6] : 53484152452d49444f4c2d4c49454e0000000000000000000000000000000000


Deployed Bytecode Sourcemap

112231:1446:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;9;2:12;107899:441:0;;5:9:-1;2:2;;;27:1;24;17:12;2:2;107899:441:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;107899:441:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;17757:83;;5:9:-1;2:2;;;27:1;24;17:12;2:2;17757:83:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;17757:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19863:169;;5:9:-1;2:2;;;27:1;24;17:12;2:2;19863:169:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;19863:169:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;80746:319;;5:9:-1;2:2;;;27:1;24;17:12;2:2;80746:319:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;80746:319:0;;;-1:-1:-1;;;;;80746:319:0;;;;;;;;;;;;;;;;;:::i;:::-;;18832:100;;5:9:-1;2:2;;;27:1;24;17:12;2:2;18832:100:0;;;:::i;108471:414::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;108471:414:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;108471:414:0;;:::i;20506:321::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;20506:321:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;20506:321:0;;;;;;;;;;;;;;;;;:::i;18684:83::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;18684:83:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;78487:36;;5:9:-1;2:2;;;27:1;24;17:12;2:2;78487:36:0;;;:::i;:::-;;;;-1:-1:-1;;;;;78487:36:0;;;;;;;;;;;;;;21236:218;;5:9:-1;2:2;;;27:1;24;17:12;2:2;21236:218:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;21236:218:0;;;;;;;;:::i;98111:258::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;98111:258:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;98111:258:0;;;;;;;;:::i;106667:401::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;106667:401:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;106667:401:0;;;;;;;;:::i;42915:396::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;42915:396:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;;;;;;42915:396:0;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;107598:124;;5:9:-1;2:2;;;27:1;24;17:12;2:2;107598:124:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;107598:124:0;;:::i;107262:190::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;107262:190:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;107262:190:0;;;;;;;;:::i;18995:119::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;18995:119:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;18995:119:0;-1:-1:-1;;;;;18995:119:0;;:::i;79830:285::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;79830:285:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;79830:285:0;;;;;;;;;;;;:::i;46376:253::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;46376:253:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;46376:253:0;;-1:-1:-1;;;;;46376:253:0;;;;;;;;:::i;102990:30::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;102990:30:0;;;:::i;17959:87::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;17959:87:0;;;:::i;98473:225::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;98473:225:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;98473:225:0;;:::i;84692:81::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;84692:81:0;;;:::i;104035:706::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;104035:706:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;104035:706:0;-1:-1:-1;;;;;104035:706:0;;:::i;44767:1397::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;44767:1397:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;44767:1397:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21957:269;;5:9:-1;2:2;;;27:1;24;17:12;2:2;21957:269:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;21957:269:0;;;;;;;;:::i;19327:175::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;19327:175:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;19327:175:0;;;;;;;;:::i;82491:1021::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;82491:1021:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;82491:1021:0;;;;;;;;;;;;;;;;;:::i;39509:29::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;39509:29:0;;;:::i;:::-;;;;-1:-1:-1;;;;;39509:29:0;;;;;;;;;;;;;;104926:753;;5:9:-1;2:2;;;27:1;24;17:12;2:2;104926:753:0;;;:::i;105754:97::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;105754:97:0;;;:::i;84507:111::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;84507:111:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;84507:111:0;;;;:::i;39443:29::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;39443:29:0;;;:::i;43835:697::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;43835:697:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19565:151;;5:9:-1;2:2;;;27:1;24;17:12;2:2;19565:151:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;19565:151:0;;;;;;;;;;:::i;106065:436::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;106065:436:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;106065:436:0;;;;;;;;;;;;;;;;;:::i;81706:353::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;81706:353:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;81706:353:0;;;-1:-1:-1;;;;;81706:353:0;;;;;;;;;;;;;;;;;:::i;84033:332::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;84033:332:0;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;84033:332:0;;;;;;;;;;;;;;;;;:::i;78540:37::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;78540:37:0;;;:::i;107899:441::-;108036:7;108012:4;103601:1;103593:5;:9;103585:48;;;;;-1:-1:-1;;;103585:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;108061:20:::1;108084:13;:11;:13::i;:::-;108061:36:::0;-1:-1:-1;108125:4:0;108108:189:::1;108135:12;108131:1;:16;108108:189;;;108173:26;108197:1;108173:23;:26::i;:::-;108169:117;;;108248:21;::::0;;;:18:::1;:21;::::0;;;;;108227:43:::1;::::0;108239:7;;108227:11:::1;:43::i;:::-;108220:50;;;;;;108169:117;108149:3;;108108:189;;;;108314:18;108324:7;108314:9;:18::i;:::-;108307:25;;;103644:1;107899:441:::0;;;;;:::o;17757:83::-;17827:5;17820:12;;;;;;;;-1:-1:-1;;17820:12:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17794:13;;17820:12;;17827:5;;17820:12;;17827:5;17820:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17757:83;;:::o;19863:169::-;19946:4;19963:39;19972:12;:10;:12::i;:::-;19986:7;19995:6;19963:8;:39::i;:::-;-1:-1:-1;20020:4:0;19863:169;;;;;:::o;80746:319::-;80912:10;41639:11;41631:54;;;;;-1:-1:-1;;;41631:54:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;41631:54:0;;;;;;;;;;;;;;;80933:7:::1;41777:19;:17;:19::i;:::-;41767:7;:29;41759:50;;;::::0;;-1:-1:-1;;;41759:50:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;41759:50:0;;;;;;;;;;;;;::::1;;80953:19:::2;80975:28;80989:4;80995:7;80975:13;:28::i;:::-;80953:50;;81014:43;81024:9;81035:10;81047:9;81014;:43::i;:::-;41820:1;41696::::1;80746:319:::0;;;;;:::o;18832:100::-;18912:12;;18832:100;:::o;108471:414::-;108593:7;108569:4;103601:1;103593:5;:9;103585:48;;;;;-1:-1:-1;;;103585:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;108618:20:::1;108641:13;:11;:13::i;:::-;108618:36:::0;-1:-1:-1;108682:4:0;108665:182:::1;108692:12;108688:1;:16;108665:182;;;108730:26;108754:1;108730:23;:26::i;:::-;108726:110;;;108798:21;::::0;;;:18:::1;:21;::::0;;;;;108784:36:::1;::::0;:13:::1;:36::i;:::-;108777:43;;;;;;108726:110;108706:3;;108665:182;;;;108864:13;:11;:13::i;:::-;108857:20;;;103644:1;108471:414:::0;;;;:::o;20506:321::-;20612:4;20629:36;20639:6;20647:9;20658:6;20629:9;:36::i;:::-;20676:121;20685:6;20693:12;:10;:12::i;:::-;20707:89;20745:6;20707:89;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;20707:19:0;;;;;;:11;:19;;;;;;20727:12;:10;:12::i;:::-;-1:-1:-1;;;;;20707:33:0;;;;;;;;;;;;-1:-1:-1;20707:33:0;;;:89;;:37;:89;:::i;:::-;20676:8;:121::i;:::-;-1:-1:-1;20815:4:0;20506:321;;;;;;:::o;18684:83::-;18750:9;;;;18684:83;:::o;78487:36::-;;;:::o;21236:218::-;21324:4;21341:83;21350:12;:10;:12::i;:::-;21364:7;21373:50;21412:10;21373:11;:25;21385:12;:10;:12::i;:::-;-1:-1:-1;;;;;21373:25:0;;;;;;;;;;;;;;;;;-1:-1:-1;21373:25:0;;;:34;;;;;;;;;;;:50;:38;:50;:::i;98111:258::-;-1:-1:-1;;;;;98267:33:0;;98190:7;98267:33;;;:24;:33;;;;;98190:7;;;;98246:55;;98255:10;;98246:8;:55::i;:::-;98210:91;;;;98321:11;:40;;98343:18;98353:7;98343:9;:18::i;:::-;98321:40;;;98335:5;98111:258;-1:-1:-1;;;;98111:258:0:o;106667:401::-;106769:7;106794:24;106821:33;106840:7;106849:4;106821:18;:33::i;:::-;106794:60;;106865:28;106896:26;106917:4;106896:20;:26::i;:::-;106865:57;;106933:21;106957:24;106976:4;106957:18;:24::i;:::-;106933:48;-1:-1:-1;106999:61:0;107039:20;106999:35;106933:48;107017:16;106999:35;:17;:35;:::i;:::-;:39;:61;:39;:61;:::i;:::-;106992:68;106667:401;-1:-1:-1;;;;;;106667:401:0:o;42915:396::-;43109:15;43139:16;43170:18;43236:67;43251:9;43262:29;43276:5;43283:7;43262:13;:29::i;:::-;43293:9;43236:14;:67::i;:::-;43216:87;;;;;;42915:396;;;;;;;;;:::o;107598:124::-;107661:7;107688:22;;;:16;:22;;;;;:26;;;107598:124;;;;:::o;107262:190::-;107376:7;107408:22;;;:16;:22;;;;;;;;-1:-1:-1;;;;;107408:36:0;;;;;;;;;;;;107262:190::o;18995:119::-;-1:-1:-1;;;;;19088:18:0;19061:7;19088:18;;;;;;;;;;;;18995:119::o;79830:285::-;79985:122;80013:10;80047:21;80084:12;79985:5;:122::i;:::-;79830:285;;;:::o;46376:253::-;46486:7;46531:10;46542:19;:17;:19::i;:::-;46531:31;;;;;;;;;;;;;;;;;;:42;;:53;46574:9;46531:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;46531:53:0;;;-1:-1:-1;;;;;46531:90:0;;;;;;;;;;;-1:-1:-1;46376:253:0;;;;:::o;102990:30::-;;;-1:-1:-1;;;;;102990:30:0;;:::o;17959:87::-;18031:7;18024:14;;;;;;;;-1:-1:-1;;18024:14:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17998:13;;18024:14;;18031:7;;18024:14;;18031:7;18024:14;;;;;;;;;;;;;;;;;;;;;;;;98473:225;98536:7;98557:16;98575:13;98592:43;98601:10;98613:21;98592:8;:43::i;:::-;98556:79;;;;98655:11;:35;;98677:13;:11;:13::i;:::-;98655:35;;84692:81;84743:22;:20;:22::i;:::-;84692:81::o;104035:706::-;104105:20;104128:13;:11;:13::i;:::-;104105:36;;104156:12;104172:1;104156:17;104152:56;;;104190:7;;;104152:56;104218:47;104245:5;104252:12;104218:26;:47::i;:::-;104329:10;104276:24;104303:37;;;:25;:37;;;;;;;;-1:-1:-1;;;;;104303:44:0;;;;;;;;;;;-1:-1:-1;;104405:16:0;;104358:63;;;104303:44;-1:-1:-1;104479:20:0;;104459:150;104508:12;104501:4;:19;104459:150;;;104557:40;104573:10;104585:5;104592:4;104557:15;:40::i;:::-;104545:52;;;;104522:6;;104459:150;;;-1:-1:-1;104624:58:0;;;;;;;;-1:-1:-1;;;;;104624:58:0;;;104645:10;;104624:58;;;;;;;;;104693:40;-1:-1:-1;;;;;104693:18:0;;104712:10;104724:8;104693:40;:18;:40;:::i;:::-;104035:706;;;;;:::o;44767:1397::-;44871:29;44915:26;44956:28;44999:26;45040:28;45340:26;45369:18;:28;;;;;;;;;;;;45340:57;;;;45429:10;45440:9;45429:21;;;;;;;;;;;;;;;;:66;;;:21;;;;;:66;;;;;;:94;;45557:10;:21;;45429:94;;-1:-1:-1;45557:10:0;45568:9;;45557:21;;;;;;;;;;;;;;;:68;;;:21;;;;:68;;;;;;:96;;45685:10;:21;;45557:96;;-1:-1:-1;45685:10:0;45696:9;;45685:21;;;;;;;;;;;;;;45718:32;45685:66;;:21;;;;;:66;;;;;;:94;;45813:10;:21;;45685:94;;-1:-1:-1;45813:10:0;45824:9;;45813:21;;;;;;;;;;;;;;45846:34;45813:68;;:21;;;;;:68;;;;;;:96;;;-1:-1:-1;45924:30:0;;;45920:237;;;45995:1;45971:25;;45920:237;;;46045:18;46032:9;:31;:61;;;;-1:-1:-1;46067:18:0;:26;-1:-1:-1;;;46067:26:0;;;;46032:61;46014:143;;;46144:1;46120:25;;46014:143;44767:1397;;;;;;;;:::o;21957:269::-;22050:4;22067:129;22076:12;:10;:12::i;:::-;22090:7;22099:96;22138:15;22099:96;;;;;;;;;;;;;;;;;:11;:25;22111:12;:10;:12::i;:::-;-1:-1:-1;;;;;22099:25:0;;;;;;;;;;;;;;;;;-1:-1:-1;22099:25:0;;;:34;;;;;;;;;;;:96;;:38;:96;:::i;19327:175::-;19413:4;19430:42;19440:12;:10;:12::i;:::-;19454:9;19465:6;19430:9;:42::i;82491:1021::-;82683:10;41639:11;41631:54;;;;;-1:-1:-1;;;41631:54:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;41631:54:0;;;;;;;;;;;;;;;82717:21;41639:11;41631:54:::1;;;::::0;;-1:-1:-1;;;41631:54:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;41631:54:0;;;;;;;;;;;;;::::1;;82758:7:::2;41777:19;:17;:19::i;:::-;41767:7;:29;41759:50;;;::::0;;-1:-1:-1;;;41759:50:0;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;-1:-1:-1;;;41759:50:0;;;;;;;;;;;;;::::2;;82801:19:::3;:17;:19::i;:::-;82791:7;:29;82783:50;;;::::0;;-1:-1:-1;;;82783:50:0;;::::3;;::::0;::::3;::::0;::::3;::::0;;;;-1:-1:-1;;;82783:50:0;;;;;;;;;;;;;::::3;;82845:17;82864::::0;82885:14:::3;:12;:14::i;:::-;82844:55:::0;;-1:-1:-1;82844:55:0;-1:-1:-1;82925:30:0::3;82958:79;82844:55:::0;82958:50:::3;:21:::0;82844:55;82958:50:::3;:39;:50;:::i;:79::-;82925:112;;83066:22;83052:10;:36;83048:457;;83105:172;83137:9;83165;83193:10;83222:9;83250:12;83105:13;:172::i;:::-;83048:457;;;83310:183;83342:9;83370;83398:21;83438:9;83466:12;83310:13;:183::i;:::-;41820:1;;;41696::::2;::::1;82491:1021:::0;;;;;:::o;39509:29::-;;;-1:-1:-1;;;;;39509:29:0;;:::o;104926:753::-;104974:20;104997:13;:11;:13::i;:::-;104974:36;;105025:12;105041:1;105025:17;105021:56;;;105059:7;;;105021:56;105087:38;105112:12;105087:24;:38::i;:::-;105186:10;105136:24;105163:34;;;:22;:34;;;;;;;-1:-1:-1;;105245:16:0;;105208:53;;;105163:34;105260:1;105319:20;;105299:141;105348:12;105341:4;:19;105299:141;;;105397:31;105411:10;105423:4;105397:13;:31::i;:::-;105385:43;;;;105362:6;;105299:141;;;-1:-1:-1;105455:40:0;;;;;;;;105474:10;;105455:40;;;;;;;;;;105585:36;;105567:12;;105585:10;;105608:8;;105567:12;105585:36;105567:12;105585:36;105608:8;105585:10;:36;;;;;;;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;;105566:55:0;;;105640:7;105632:39;;;;;-1:-1:-1;;;105632:39:0;;;;;;;;;;;;-1:-1:-1;;;105632:39:0;;;;;;;;;;;;;;105754:97;105825:4;;:18;;;-1:-1:-1;;;105825:18:0;;;;105798:7;;-1:-1:-1;;;;;105825:4:0;;:16;;:18;;;;;;;;;;;;;;:4;:18;;;2:2:-1;;;;27:1;24;17:12;2:2;105825:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;105825:18:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;105825:18:0;;-1:-1:-1;105754:97:0;:::o;84507:111::-;84576:34;84598:11;84576:21;:34::i;39443:29::-;;;;;;-1:-1:-1;;;;;39443:29:0;;:::o;43835:697::-;43943:17;43975;44007;44039:18;44072:24;44111:25;44151;44216:19;:17;:19::i;:::-;44204:31;;44271:14;:12;:14::i;:::-;44246:39;;;;;;;;44315:10;44326:9;44315:21;;;;;;;;;;;;;;;;:32;:21;;;;;:32;;-1:-1:-1;;;;;44315:32:0;;-1:-1:-1;44371:13:0;:11;:13::i;:::-;44358:26;;44415:39;44432:9;44443:10;44415:16;:39::i;:::-;44395:59;;44485:39;44502:9;44513:10;44485:16;:39::i;:::-;44465:59;;43835:697;;;;;;;:::o;19565:151::-;-1:-1:-1;;;;;19681:18:0;;;19654:7;19681:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;19565:151::o;106065:436::-;106198:7;106218:24;106245:33;106264:7;106273:4;106245:18;:33::i;:::-;106218:60;;106289:28;106320:26;106341:4;106320:20;:26::i;:::-;106289:57;;106357:21;106381:33;106402:5;106409:4;106381:20;:33::i;:::-;106357:57;-1:-1:-1;106432:61:0;106472:20;106432:35;106357:57;106450:16;106432:35;:17;:35;:::i;:61::-;106425:68;106065:436;-1:-1:-1;;;;;;;106065:436:0:o;81706:353::-;81883:21;41639:11;41631:54;;;;;-1:-1:-1;;;41631:54:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;41631:54:0;;;;;;;;;;;;;;;81915:7:::1;41777:19;:17;:19::i;:::-;41767:7;:29;41759:50;;;::::0;;-1:-1:-1;;;41759:50:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;41759:50:0;;;;;;;;;;;;;::::1;;81935:19:::2;81957:29;81971:5;81978:7;81957:13;:29::i;84033:332::-:0;84210:7;41777:19;:17;:19::i;:::-;41767:7;:29;41759:50;;;;;-1:-1:-1;;;41759:50:0;;;;;;;;;;;;-1:-1:-1;;;41759:50:0;;;;;;;;;;;;;;;84248:19:::1;:17;:19::i;:::-;84238:7;:29;84230:50;;;::::0;;-1:-1:-1;;;84230:50:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;84230:50:0;;;;;;;;;;;;;::::1;;84291:66;84308:13;84323:19;84344:12;84291:16;:66::i;:::-;84033:332:::0;;;;;:::o;78540:37::-;;;:::o;109675:130::-;109744:4;109768:24;;;:18;:24;;;;;;:29;;;109675:130::o;657:106::-;745:10;657:106;:::o;25104:346::-;-1:-1:-1;;;;;25206:19:0;;25198:68;;;;-1:-1:-1;;;25198:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;25285:21:0;;25277:68;;;;-1:-1:-1;;;25277:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;25358:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;:36;;;25410:32;;;;;;;;;;;;;;;;;25104:346;;;:::o;66324:108::-;66403:10;:17;-1:-1:-1;;66403:21:0;66324:108;:::o;73130:487::-;73230:9;73261:5;73257:353;;;73287:8;73283:142;;;-1:-1:-1;73323:20:0;73316:27;;73283:142;-1:-1:-1;73391:18:0;73384:25;;73257:353;73461:8;73457:142;;;-1:-1:-1;73497:20:0;73490:27;;73457:142;-1:-1:-1;73565:18:0;73558:25;;50899:694;51038:12;:10;:12::i;:::-;51061:25;51089:19;:17;:19::i;:::-;51061:47;;51119:36;51134:1;51137:17;51119:14;:36::i;:::-;-1:-1:-1;;;;;51170:23:0;;51166:78;;51222:10;51210:22;;51166:78;51254:57;51269:19;:9;:17;;;;;;;;;:19::i;:::-;51290:10;51302:8;51254:14;:57::i;:::-;51322:70;51361:9;51372:8;51382:9;51322:10;51333:17;51322:29;;;;;;;;;;;;;;;;;;:38;;:70;;;;;;:::i;:::-;51498:17;51408:177;;51459:17;:9;:15;;;;;;;;;:17::i;:::-;51408:177;;51435:9;-1:-1:-1;;;;;51408:177:0;;51531:20;:9;:18;;;;;;;;;:20::i;:::-;51408:177;;;;;;;;;;;;;;;;;;;;;;;50899:694;;;;:::o;113101:205::-;113252:46;113282:4;113288:2;113292:5;113252:29;:46::i;5704:192::-;5790:7;5826:12;5818:6;;;;5810:29;;;;-1:-1:-1;;;5810: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;5810:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5862:5:0;;;5704:192::o;4801:181::-;4859:7;4891:5;;;4915:6;;;;4907:46;;;;;-1:-1:-1;;;4907:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;99649:1692;99747:4;99753:7;99799:1;99786:10;:14;99778:49;;;;;-1:-1:-1;;;99778:49:0;;;;;;;;;;;;-1:-1:-1;;;99778:49:0;;;;;;;;;;;;;;;99914:28;:18;:26;:28::i;:::-;99900:10;:42;;99892:84;;;;;-1:-1:-1;;;99892:84:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;101115:13;101131:40;:9;101160:10;101131:40;:28;:40;:::i;:::-;101197:20;;101115:56;;-1:-1:-1;101188:29:0;;101184:150;;;-1:-1:-1;101242:5:0;;-1:-1:-1;101242:5:0;;-1:-1:-1;101234:17:0;;101184:150;101292:4;101298:9;:16;;101315:5;101298:23;;;;;;;;;;;;;;;;101284:38;;;;;99649:1692;;;;;;:::o;6155:471::-;6213:7;6458:6;6454:47;;-1:-1:-1;6488:1:0;6481:8;;6454:47;6525:5;;;6529:1;6525;:5;:1;6549:5;;;;;:10;6541:56;;;;-1:-1:-1;;;6541:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7102:132;7160:7;7187:39;7191:1;7194;7187:39;;;;;;;;;;;;;;;;;:3;:39::i;66498:382::-;66597:22;66641:5;:16;;;;;66650:7;66641:16;66637:236;;;-1:-1:-1;66691:1:0;66637:236;;;66715:5;66710:163;;66741:7;66737:125;;;-1:-1:-1;66786:1:0;66737:125;;61921:2440;62105:15;62135:16;62166:18;62228:19;:17;:19::i;:::-;62216:9;:31;62212:84;;;-1:-1:-1;62272:5:0;;-1:-1:-1;62272:5:0;;-1:-1:-1;62272:5:0;62264:20;;62212:84;62306:29;62338:10;62349:9;62338:21;;;;;;;;;;;;;;;;;;62306:53;;62370:27;62400:12;:23;;:74;62448:14;62424:49;;;;;;;;62400:74;;;;;;;;;;;;;;;;;;;;;;;;;;;:99;;62370:129;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;62370:129:0;;;;;;;;;;;;;;;;-1:-1:-1;;62539:18:0;:28;62598:29;;:19;62665:38;62370:129;;-1:-1:-1;;;;62539:28:0;;;;;;62598:29;;-1:-1:-1;62510:26:0;;-1:-1:-1;62665:38:0;;;-1:-1:-1;62657:47:0;;;;;;;;62730:18;:26;62638:66;;-1:-1:-1;;;;62730:26:0;;;;62715:12;;;62814:208;62839:10;:17;62834:1;:22;62814:208;;62899:9;-1:-1:-1;;;;;62882:26:0;:10;62893:1;62882:13;;;;;;;;;;;;;;-1:-1:-1;;;;;62882:26:0;;62878:133;;;62939:4;62929:14;;62970:1;62962:9;;62990:5;;62878:133;62858:3;;62814:208;;;;63314:18;63302:9;:30;63301:225;;;;63352:7;:44;;;;;63377:18;63364:9;:31;63352:44;63351:174;;;;;63437:8;63420:14;:25;63419:105;;;;63491:8;63473:14;:26;63472:51;;;;;63513:9;63505:5;:17;63472:51;63283:301;;;-1:-1:-1;63561:4:0;;-1:-1:-1;63567:1:0;;-1:-1:-1;63567:1:0;;-1:-1:-1;63553:19:0;;-1:-1:-1;;;;;;;63553:19:0;63283:301;63601:7;63596:61;;-1:-1:-1;63633:5:0;;-1:-1:-1;63633:5:0;;-1:-1:-1;63633:5:0;;-1:-1:-1;63625:20:0;;-1:-1:-1;;;;;;;63625:20:0;63596:61;63732:14;63774:18;63761:9;:31;:42;;;;;63796:7;63761:42;63757:597;;;63837:8;63820:147;63851:14;63847:1;:18;63820:147;;;63901:50;:12;:23;63935:1;63925:12;;;;;;;;63901:37;;;;;;;;;;;;;;;;;;;;;;;;;;;:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;63901:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:50::i;:::-;63891:60;;;;63867:3;;63820:147;;;-1:-1:-1;63992:1:0;;-1:-1:-1;64021:32:0;64043:9;64021:17;:6;64032:5;64021:17;:10;:17;:::i;:::-;:21;:32;:21;:32;:::i;:::-;64056:1;64021:36;64008:49;;63757:597;;;64095:9;64090:141;64115:14;64110:1;:19;64090:141;;64165:50;:12;:23;64199:1;64189:12;;;;;;;64165:50;64155:60;;;;64131:3;;64090:141;;;-1:-1:-1;64256:33:0;:9;64270:18;64256:33;:13;:33;:::i;:::-;64292:1;64256:37;;-1:-1:-1;64321:17:0;:6;64332:5;64321:17;:10;:17;:::i;:::-;64341:1;64321:21;64308:34;;63757:597;61921:2440;;;;;;;;;;;;;;;;;:::o;47695:461::-;47836:13;:11;:13::i;:::-;:18;47828:50;;;;;-1:-1:-1;;;47828:50:0;;;;;;;;;;;;-1:-1:-1;;;47828:50:0;;;;;;;;;;;;;;;47897:10;-1:-1:-1;;;;;47911:7:0;47897:21;;47889:30;;12:1:-1;9;2:12;47889:30:0;47930:32;47945:7;47954;47930:14;:32::i;:::-;47973:31;47979:10;47991:12;47973:5;:31::i;:::-;48015:49;48030:12;48044:10;48056:7;-1:-1:-1;;;;;48015:49:0;:14;:49::i;:::-;48075;48090:12;48104:10;48116:7;-1:-1:-1;;;;;48075:49:0;:14;:49::i;:::-;48135:13;:11;:13::i;51979:353::-;52054:23;52092;52129:20;:18;:20::i;:::-;52039:110;;;;52160:26;52181:1;52184;52160:20;:26::i;:::-;52204:46;;;;;;;;;;;;;;;;;;;;;;;;;52261:63;52275:14;52291:15;52308;52261:13;:63::i;:::-;51979:353;;:::o;110012:1012::-;110157:4;;:17;;;-1:-1:-1;;;110157:17:0;;;;110136:18;;-1:-1:-1;;;;;110157:4:0;;:15;;:17;;;;;;;;;;;;;;:4;:17;;;2:2:-1;;;;27:1;24;17:12;2:2;110157:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;110157:17:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;110157:17:0;;-1:-1:-1;110185:13:0;;110248:25;;;110244:133;;;110313:10;110298:12;:25;110290:33;;110244:133;;;110364:1;110356:9;;110244:133;-1:-1:-1;;110489:16:0;;110472:413;110512:5;110507:1;:10;110472:413;;110543:19;;;;:16;:19;;;;;;;;-1:-1:-1;;;;;110543:33:0;;;;;;;;;;:38;110539:84;;110602:5;;110539:84;110656:4;;:115;;;-1:-1:-1;;;110656:115:0;;-1:-1:-1;;;;;110656:115:0;;;;;;;110731:4;110656:115;;;;;;;;;;;;110637:16;;110656:4;;;;;:15;;:115;;;;;;;;;;;;;;;:4;:115;;;2:2:-1;;;;27:1;24;17:12;2:2;110656:115:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;110656:115:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;110656:115:0;110786:19;;;;:16;110656:115;110786:19;;;;;;;-1:-1:-1;;;;;110786:33:0;;;;;;;;;:44;;;110845:28;;;;;-1:-1:-1;;;110519:3:0;110472:413;;;-1:-1:-1;110899:21:0;110895:60;;110937:7;;;;;110895:60;110965:4;;:51;;;-1:-1:-1;;;110965:51:0;;-1:-1:-1;;;;;110965:51:0;;;;;;;111010:4;110965:51;;;;;;:4;;;;;:20;;:51;;;;;:4;;:51;;;;;;;:4;;:51;;;2:2:-1;;;;27:1;24;17:12;2:2;110965:51:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;110965:51:0;;;;110012:1012;;;;;:::o;74498:177::-;74608:58;;;-1:-1:-1;;;;;74608:58:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;74608:58:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;74581:86:0;;74601:5;;74581:19;:86::i;64369:187::-;64509:8;;64540;;-1:-1:-1;;;;;;;;64509:8:0;;;;;;64540;;;64369:187::o;48416:806::-;48609:15;48626;48643:13;48660:121;48692:6;48713:9;48737;48761;48660:17;:121::i;:::-;48608:173;;;;;;48809:8;48800:5;:17;;48792:61;;;;;-1:-1:-1;;;48792:61:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;48864:49;48879:12;48893:10;48905:7;48864:14;:49::i;:::-;48924;48939:12;48953:10;48965:7;48924:14;:49::i;:::-;48984:123;49013:34;:22;:9;49027:7;49013:22;:13;:22;:::i;:::-;:32;:34::i;:::-;49062;:22;:9;49076:7;49062:22;:13;:22;:::i;:34::-;48984:14;:123::i;:::-;49118:24;49124:10;49136:5;49118;:24::i;:::-;49158:56;;;;;;;;;;;;;;;;;;;;49184:4;;49172:10;;49158:56;;;;;;;;;48416:806;;;;;;;;:::o;111229:869::-;111325:4;;:17;;;-1:-1:-1;;;111325:17:0;;;;111304:18;;-1:-1:-1;;;;;111325:4:0;;:15;;:17;;;;;;;;;;;;;;:4;:17;;;2:2:-1;;;;27:1;24;17:12;2:2;111325:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;111325:17:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;111325:17:0;;-1:-1:-1;111353:13:0;;111416:25;;;111412:133;;;111481:10;111466:12;:25;111458:33;;111412:133;;;111532:1;111524:9;;111412:133;-1:-1:-1;;111657:16:0;;111640:323;111680:5;111675:1;:10;111640:323;;111711:19;;;;:16;:19;;;;;:23;;;:28;111707:74;;111760:5;;111707:74;111814:4;;:45;;;-1:-1:-1;;;111814:45:0;;111795:16;111814:45;;;;;;111850:4;111814:45;;;;;;;;;;;;111795:16;;-1:-1:-1;;;;;111814:4:0;;:15;;:45;;;;;;;;;;;;;;;:4;:45;;;2:2:-1;;;;27:1;24;17:12;2:2;111814:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;111814:45:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;111814:45:0;111874:19;;;;:16;111814:45;111874:19;;;;:23;;:34;;;111923:28;;;;;-1:-1:-1;;;111687:3:0;111640:323;;;-1:-1:-1;111977:21:0;111973:60;;112015:7;;;;;111973:60;112043:4;;:47;;;-1:-1:-1;;;112043:47:0;;:4;:47;;;;;;112084:4;112043:47;;;;;;-1:-1:-1;;;;;112043:4:0;;;;:20;;:47;;;;;:4;;:47;;;;;;:4;;:47;;;2:2:-1;;;;27:1;24;17:12;2:2;112043:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112043:47:0;;;;111229:869;;;;:::o;51751:134::-;51829:48;51844:11;51829:48;;51857:19;:17;:19::i;:::-;51829:14;:48::i;35499:132::-;35561:7;35588:35;35621:1;35588:28;:1;35462:19;35588:28;:5;:28;:::i;49642:896::-;49786:17;49805;49826:14;:12;:14::i;:::-;49785:55;;;;49866:20;49889:13;:11;:13::i;:::-;49866:36;-1:-1:-1;49913:15:0;49931:38;49866:36;49931:20;:9;49945:5;49931:20;:13;:20;:::i;:38::-;49913:56;-1:-1:-1;49980:15:0;49998:38;50023:12;49998:20;:9;50012:5;49998:20;:13;:20;:::i;:38::-;49980:56;;50080:10;50069:7;:21;;:46;;;;;50105:10;50094:7;:21;;50069:46;50047:127;;;;;-1:-1:-1;;;50047:127:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;50185:123;50214:34;:22;:9;50228:7;50214:22;:13;:22;:::i;:34::-;50263;:22;:9;50277:7;50263:22;:13;:22;:::i;50185:123::-;50319:24;50325:10;50337:5;50319;:24::i;:::-;50354:46;50366:12;50380:10;50392:7;50354:11;:46::i;:::-;50411;50423:12;50437:10;50449:7;50411:11;:46::i;:::-;50473:57;;;;;;;;;;;;;;;;;;;;50499:5;;50487:10;;50473:57;;;;;;;;;49642:896;;;;;;;;:::o;52692:164::-;52781:26;:24;:26::i;:::-;52777:72;;;52824:13;:11;:13::i;53105:3738::-;53210:45;;:::i;:::-;:66;;;;;;;;;53258:18;53210:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;53210:66:0;;-1:-1:-1;;;;;53210:66:0;;;;;-1:-1:-1;;;53210:66:0;;;;;;;;-1:-1:-1;;;53210:66:0;;;;;;;;;;;;-1:-1:-1;53287:47:0;;:::i;:::-;:69;;;;;;;;;53337:19;53287:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53627:17;53594:19;:29;;;:50;;;;:166;;;;;53663:26;:24;:26::i;:::-;53662:27;:97;;;;53742:17;53710:19;:29;;;:49;;;53662:97;53576:229;;;53787:7;;;;53576:229;53820:19;:27;;;53815:950;;54026:34;54083:27;54133:12;54167:105;54224:19;:29;;;54167:34;:105::i;:::-;54003:269;;-1:-1:-1;54003:269:0;-1:-1:-1;54003:269:0;-1:-1:-1;54291:19:0;54003:269;54291:93;;;;;;;;;;;;;;;;;;;;-1:-1:-1;54445:52:0;:19;:50;:52::i;:::-;54403:94;;:39;;;:94;54543:16;:4;:14;:16::i;:::-;-1:-1:-1;;;;;54516:43:0;:24;;;:43;-1:-1:-1;;54608:4:0;54578:27;;;:34;-1:-1:-1;;54631:54:0;;;54704:30;;;:34;53815:950;54877:16;;54870:1862;;54910:31;54944:10;54955:19;:47;;;54944:59;;;;;;;;;;;;;;;;;55033:39;;54944:59;;;;;;;:129;;;;;;;;;;;;;;;;;;;;;;;;;;;54910:163;;55107:19;55145:17;55181:24;55223:458;55262:13;55294:49;:20;:39;;;:47;;;;;;;:49;55362:30;;;;55464:39;;55411:111;;:19;;:111;:30;:111;:::i;:::-;55541:19;:24;;;-1:-1:-1;;;;;55223:458:0;55584:10;55595:19;:29;;;55584:41;;;;;;;;;;;;;;;;;;:52;:41;;;;;:52;;-1:-1:-1;;;;;55584:52:0;55655:11;55223:20;:458::i;:::-;55088:593;;;;;;55700:14;55696:911;;;55735:18;55756:159;55793:10;55804:19;:29;;;55793:41;;;;;;;;;;;;;;;;;;;;55857:20;:39;;;55756:14;:159::i;:::-;55735:180;;55941:10;55952:19;:29;;;55941:41;;;;;;;;;;;;;;;;;56016:39;;55941:41;;;;;;;:115;;;;;;;;;;;;;;;;;;;;;;;;;;;;55934:122;;;;;;;;:::i;:::-;;;;;;;;;56155:13;56151:290;;;56193:29;;;:34;;;56226:1;56193:34;;;;;;;-1:-1:-1;56250:27:0;;;:35;56308:40;;:18;:40;;56193:19;;56308:18;;:40;:18;;-1:-1:-1;;56308:40:0;;;;;;;;;;;;;;;-1:-1:-1;56308:40:0;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;56308:40:0;-1:-1:-1;;;;56308:40:0;;;;-1:-1:-1;;;56308:40:0;-1:-1:-1;;;;;;;;;56308:40:0;;;-1:-1:-1;;;56308:40:0;-1:-1:-1;;;;;;;;56308:40:0;;;;;;-1:-1:-1;;56308:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;56373:7:0;;-1:-1:-1;;;;;;56373:7:0;56151:290;56501:61;;:90;;:88;;;;;;;;;:90::i;:::-;56459:20;;:132;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;55696:911:0;56654:20;:9;:18;:20::i;:::-;56621:53;;:30;;;:53;56689:31;;;;-1:-1:-1;54870:1862:0;;-1:-1:-1;;54870:1862:0;;56742:40;;:18;:40;;56763:19;;56742:40;:18;;-1:-1:-1;;56742:40:0;;;;;;;;;;;;;;;-1:-1:-1;56742:40:0;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;56742:40:0;-1:-1:-1;;;;56742:40:0;;;;-1:-1:-1;;;56742:40:0;-1:-1:-1;;;;;;;;;56742:40:0;;;-1:-1:-1;;;56742:40:0;-1:-1:-1;;;;;;;;56742:40:0;;;;;;-1:-1:-1;;56742:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56793:42;;:19;:42;;56815:20;;56793:42;:19;;-1:-1:-1;;56793:42:0;56742:40;56793:42;;;;;;;;;;;;;;;;;;;;;;;;;53105:3738;;;;:::o;34485:243::-;34541:5;;34563:4;:26;;;;;;;;;:58;;;-1:-1:-1;34601:20:0;34593:4;:28;;;;;;;;;34563:58;34559:162;;;-1:-1:-1;34645:12:0;34638:19;;34559:162;-1:-1:-1;34697:12:0;34690:19;;84824:206;84958:64;84994:4;85008;85015:6;84958:18;84966:9;84958:7;:18::i;:::-;-1:-1:-1;;;;;84958:35:0;;:64;;;:35;:64;:::i;38043:526::-;38205:27;38235:4;38205:27;38251:9;38235:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;38235:26:0;;;-1:-1:-1;;;;;38276:30:0;;;;;;;;;;38235:26;;-1:-1:-1;38272:104:0;;38328:20;;;;27:10:-1;;23:18;;;45:23;;-1:-1;38328:36:0;;;;;;;;;-1:-1:-1;;;;;;38328:36:0;-1:-1:-1;;;;;38328:36:0;;;;;38272:104;-1:-1:-1;;;;;38419:30:0;;:19;:30;;;;;;;;;;;:68;;38468:8;38419:68;:34;:68;:::i;:::-;-1:-1:-1;;;;;38386:30:0;;:19;:30;;;;;;;;;;:101;38524:23;;;;:37;;38552:8;38524:37;:27;:37;:::i;:::-;38498:23;;;;:63;-1:-1:-1;;;;38043:526:0:o;35129:146::-;35183:4;;35208;:26;;;;;;;;;:58;;;-1:-1:-1;35246:20:0;35238:28;:4;:28;;;;;;;;;35200:67;35129:146;-1:-1:-1;;35129:146:0:o;34887:102::-;34944:4;34969:12;34976:4;34969:6;:12::i;:::-;34968:13;;34887:102;-1:-1:-1;;34887:102:0:o;108893:202::-;109024:20;:18;:20::i;:::-;109055:32;109071:4;109077:2;109081:5;109055:15;:32::i;93371:114::-;93463:14;;93371:114::o;91298:918::-;91411:12;;91387:7;;91407:58;;-1:-1:-1;91452:1:0;91445:8;;91407:58;91518:12;;91477:11;;91543:424;91556:4;91550:3;:10;91543:424;;;91577:11;91591:23;91604:3;91609:4;91591:12;:23::i;:::-;91577:37;;91848:7;91835:5;91841:3;91835:10;;;;;;;;;;;;;;;;:20;91831:125;;;91883:3;91876:10;;91831:125;;;91933:3;91939:1;91933:7;91927:13;;91831:125;91543:424;;;;92093:1;92087:3;:7;:36;;;;;92116:7;92098:5;92110:1;92104:3;:7;92098:14;;;;;;;;;;;;;;;;:25;92087:36;92083:126;;;-1:-1:-1;;;92147:7:0;;-1:-1:-1;92140:14:0;;92083:126;-1:-1:-1;92194:3:0;-1:-1:-1;92187:10:0;;7730:278;7816:7;7851:12;7844:5;7836:28;;;;-1:-1:-1;;;7836:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;7836:28:0;;7875:9;7891:1;7887;:5;;;;;;;7730:278;-1:-1:-1;;;;;7730:278:0:o;38608:123::-;38701:15;:22;;38608:123::o;5265:136::-;5323:7;5350:43;5354:1;5357;5350:43;;;;;;;;;;;;;;;;;:3;:43::i;64801:219::-;64887:8;:22;;-1:-1:-1;;;;;64887:22:0;;;-1:-1:-1;;;64887:22:0;;;;;;;;64920:8;:22;;-1:-1:-1;;;;;;64920:22:0;;;;;;;;;;64958:54;64887:22;64920;64998:13;:11;:13::i;:::-;64958:54;;;-1:-1:-1;;;;;64958:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;64801:219;;:::o;113498:176::-;113625:41;113651:7;113660:5;113625:25;:41::i;85588:265::-;85653:19;:17;:19::i;:::-;85683:18;85704:19;:17;:19::i;:::-;85683:40;;85764:22;:10;:20;:22::i;:::-;-1:-1:-1;;;;;85739:106:0;;85801:10;85812;85801:22;;;;;;;;;;;;;;;;;:33;:22;;;;;:33;;85739:106;;;-1:-1:-1;;;;;85801:33:0;;;85739:106;;;;;;;;;;;;85588:265;:::o;64564:229::-;64728:14;;64771;;-1:-1:-1;;;;;64728:14:0;;;;;;;64771;;;64564:229::o;66888:215::-;67016:14;:34;;-1:-1:-1;;67016:34:0;;-1:-1:-1;;;;;67016:34:0;;;;;;;67061:14;:34;;-1:-1:-1;;;;;;67061:34:0;;;;;;;;66888:215::o;87260:240::-;87409:12;;87405:88;;87438:43;-1:-1:-1;;;;;87438:4:0;:17;87456:15;87473:7;87438:43;:17;:43;:::i;76803:761::-;77227:23;77253:69;77281:4;77253:69;;;;;;;;;;;;;;;;;77261:5;-1:-1:-1;;;;;77253:27:0;;;:69;;;;;:::i;:::-;77337:17;;77227:95;;-1:-1:-1;77337:21:0;77333:224;;77479:10;77468:30;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;77468:30:0;77460:85;;;;-1:-1:-1;;;77460:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;67111:703;67315:7;;;;67398:9;:25;;;;;;;;;67394:413;;;67466:6;67491:36;67517:9;67491:21;67466:6;67502:9;67491:21;:10;:21;:::i;:36::-;67546:40;67576:9;67546:25;67557:13;:11;:13::i;:::-;67546:6;;:25;:10;:25;:::i;:40::-;67440:161;;;;;;;;67394:413;67660:36;67686:9;67660:21;:6;67671:9;67660:21;:10;:21;:::i;:36::-;67715:6;67740:40;67770:9;67740:25;67751:13;:11;:13::i;27739:184::-;27796:7;-1:-1:-1;;;27824:5:0;:14;27816:67;;;;-1:-1:-1;;;27816:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;27909:5:0;27739:184::o;113314:176::-;113441:41;113467:7;113476:5;113441:25;:41::i;85038:180::-;85167:43;85199:2;85203:6;85167:18;85175:9;85167:7;:18::i;:::-;-1:-1:-1;;;;;85167:31:0;;:43;;:31;:43;:::i;85424:156::-;85492:4;85532:10;85543:19;:17;:19::i;:::-;85532:31;;;;;;;;;;;;;;;;;;;;;:40;;;-1:-1:-1;;;85532:40:0;;-1:-1:-1;;;;;85532:40:0;85516:12;:56;;;85424:156;-1:-1:-1;85424:156:0:o;68828:2706::-;68939:34;68988:27;69030:12;69070:25;69098:10;69109:9;69098:21;;;;;;;;;;;;;;;;;;69561:39;;;69098:21;;;;;69561:39;;;;;;;;:67;;;69691:18;69671:39;;;;;:67;;;69783:55;;;;;;:83;;;69931:34;69911:55;;;;;:83;;;;69098:21;;-1:-1:-1;69098:21:0;;;;69561:67;;69671;;70187:202;69098:21;69561:67;69671;69783:83;69911;70187:20;:202::i;:::-;70005:384;;-1:-1:-1;70005:384:0;;-1:-1:-1;70005:384:0;;-1:-1:-1;70005:384:0;;-1:-1:-1;70005:384:0;-1:-1:-1;70421:17:0;70417:580;;70486:20;70459:47;;70417:580;;;70567:12;70583:1;70567:17;70563:434;;;70632:20;70605:47;;70563:434;;;70678:12;70694:1;70678:17;70674:323;;;70743:18;70716:45;;70674:323;;;70787:12;70803:1;70787:17;70783:214;;;70852:20;70825:47;;70783:214;;;70898:12;70914:1;70898:17;70894:103;;;70963:18;70936:45;;70894:103;71054:9;71023:298;;;71084:24;71078:31;;;;;;;;71023:298;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71389:19;;;;71332:194;;-1:-1:-1;;;;;71389:19:0;71423:29;71467;71511:4;71332:42;:194::i;:::-;68828:2706;;;;;;;;;;;;;:::o;28222:179::-;28278:6;28313:5;28305;:13;28297:65;;;;-1:-1:-1;;;28297:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;36485:874;36608:7;36734:19;:9;:17;;;;;;;:19;36691:62;;;;;;;;:29;;:39;;:37;;;;;;;:39;:62;;;;;;;;;36687:103;;-1:-1:-1;36777:1:0;36770:8;;36687:103;36919:29;;:38;;:36;;;;;;;;;:38::i;:::-;36915:282;;;37012:18;:9;:16;;;;;;;:18;37008:90;;;-1:-1:-1;37058:24:0;;;;37051:31;;;;37008:90;-1:-1:-1;35462:19:0;37148:37;;36915:282;37253:20;:9;:18;;;;;;;:20;37249:84;;;-1:-1:-1;37297:24:0;;;;37290:31;;;;37249:84;-1:-1:-1;37350:1:0;36485:874;;;;:::o;57283:1140::-;57573:4;57592:7;57614;57649:13;57673:18;57694:22;:9;:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;57694:20:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:22::i;:::-;57673:43;;57754:12;57746:20;;57727:535;57804:11;57789:12;57781:5;:20;:34;57727:535;;;57877:10;57868:5;:19;57864:98;;-1:-1:-1;57916:4:0;;-1:-1:-1;57922:1:0;;-1:-1:-1;57925:20:0;;;;-1:-1:-1;57908:38:0;;57864:98;57976:17;57996:9;:20;;58017:5;57996:27;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;57996:27:0;58124:30;;;;;;;;;;;;57996:27;;-1:-1:-1;58038:212:0;;58070:7;;57996:27;;58173:10;58202:4;58225:10;58038:13;:212::i;:::-;-1:-1:-1;57830:7:0;;;;;57727:535;;;58285:10;58276:5;:19;58272:90;;-1:-1:-1;58320:4:0;;-1:-1:-1;58326:1:0;;-1:-1:-1;58329:20:0;;;;-1:-1:-1;58312:38:0;;58272:90;-1:-1:-1;58380:5:0;;-1:-1:-1;58387:5:0;-1:-1:-1;;58394:20:0;;;57283:1140;;;;;;;;;;;;:::o;71724:627::-;71853:4;71955:20;71930:21;:45;;;;;;;;;71926:89;;;-1:-1:-1;71999:4:0;71992:11;;71926:89;72030:9;72050:28;:21;:26;;;;;;;:28;72042:37;;;;;;;;72030:49;;72025:297;72081:1;72086;72081:6;72025:297;;72109:21;;:::i;:::-;72133:6;:17;72161:1;72151:12;;;;;;;;72133:31;;;;;;;;;;;;;;;;;;;;;;;;;;;72109:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;72109:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;72240:17;:4;:15;:17::i;:::-;:22;72236:75;;72290:5;72283:12;;;;;;72236:75;-1:-1:-1;72089:3:0;;72025:297;;34997:124;35050:9;35111:1;35098:4;35090:13;;;;;;;;35106:1;35090:17;35089:23;;;;;;35079:34;;;;;;;28700:179;28756:6;28791:5;28783;:13;28775:65;;;;-1:-1:-1;;;28775:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85861:183;85918:14;;85949:9;:25;;;;;;;;;85945:69;;;-1:-1:-1;85998:4:0;85991:11;;85945:69;-1:-1:-1;86031:5:0;85861:183;;;:::o;74683:205::-;74811:68;;;-1:-1:-1;;;;;74811:68:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;74811:68:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;74784:96:0;;74804:5;;74784:19;:96::i;34736:143::-;34791:4;;34815;:26;;;;;;;;;:56;;;-1:-1:-1;34853:18:0;34845:26;;109419:248;109468:20;109491:13;:11;:13::i;:::-;109468:36;;109534:1;109519:12;:16;:62;;;;;109540:41;109579:1;109564:12;:16;109540:23;:41::i;:::-;109539:42;109519:62;109515:145;;;109637:11;:9;:11::i;:::-;-1:-1:-1;;109617:16:0;;109598:36;;;;:18;:36;;;;;:50;109419:248;:::o;99006:215::-;99103:28;99126:4;99103:22;:28::i;:::-;99142:26;99165:2;99142:22;:26::i;:::-;99181:32;99197:4;99203:2;99207:5;99181:15;:32::i;90472:193::-;90534:7;90655:1;;90646;:5;90642:1;90638;:5;:13;90637:19;;;;;;90631:1;90627;:5;90621:1;90617;:5;90616:17;:41;;90472:193;-1:-1:-1;;;90472:193:0:o;109103:150::-;109187:20;:18;:20::i;:::-;109218:27;109230:7;109239:5;109218:11;:27::i;52465:219::-;52516:10;52546:119;52592:10;:8;:10::i;:::-;52621:29;52622:12;52637:1;52622:16;52621:27;:29::i;:::-;52546:119;;:27;:119::i;:::-;27:10:-1;;39:1;23:18;;;45:23;;-1:-1;52516:160:0;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;52516:160:0;;;-1:-1:-1;;;;;52516:160:0;;;;;;-1:-1:-1;;;52516:160:0;;;;;;;;52465:219::o;13173:196::-;13276:12;13308:53;13331:6;13339:4;13345:1;13348:12;13308:22;:53::i;109261:150::-;109345:20;:18;:20::i;:::-;109376:27;109388:7;109397:5;109376:11;:27::i;67822:998::-;68391:19;;;;68122:12;;;;;;;;;;-1:-1:-1;;;;;68391:19:0;35462;68345:65;68441:371;68482:50;:21;68345:65;68482:31;:50::i;:::-;68551:52;:23;68585:17;68551:52;:33;:52;:::i;:::-;68622:50;:21;68654:17;68622:50;:31;:50;:::i;:::-;68691:52;:23;68725:17;68691:52;:33;:52;:::i;:::-;68762:8;;68789;;-1:-1:-1;;;;;;;;68762:8:0;;;;;;68789;68441:22;:371::i;:::-;68421:391;;;;-1:-1:-1;68421:391:0;;-1:-1:-1;68421:391:0;-1:-1:-1;68421:391:0;;-1:-1:-1;67822:998:0;-1:-1:-1;;;;;;;67822:998:0:o;87829:1768::-;88073:19;88103;88133:25;88169:18;88232:27;88278:29;88325:230;88380:10;88409:29;88457;88505:4;88528:12;88325:36;:230::i;:::-;88584:8;;88649:14;;-1:-1:-1;;;;;;;;88584:8:0;;;;;:30;;;;-1:-1:-1;88584:8:0;88649:14;;;;;;:38;;-1:-1:-1;88752:230:0;;-1:-1:-1;88807:10:0;;-1:-1:-1;88836:29:0;88884;88932:4;88649:14;88752:36;:230::i;:::-;89025:8;;-1:-1:-1;;;;;89025:8:0;89011:22;;;;-1:-1:-1;88724:258:0;-1:-1:-1;89025:8:0;89102:150;35462:19;89102:90;89141:50;89163:27;89011:22;88724:258;89163:27;:15;:27;:::i;:::-;89141:11;;:50;:21;:50;:::i;:::-;89102:10;;:90;:38;:90;:::i;:::-;:118;:150;:118;:150;:::i;:::-;89334:33;;;;;89281:24;;;;89402:39;;;;;-1:-1:-1;89463:64:0;89478:23;89334:33;89478:21;:23::i;:::-;89503;:11;:21;:23::i;89463:64::-;89538:51;89559:29;:17;:27;:29::i;:::-;-1:-1:-1;;;;;89538:51:0;:20;:51::i;58743:1250::-;58953:14;58970:17;:7;:15;;;;;;;;;:17::i;:::-;58953:34;-1:-1:-1;59047:20:0;59070:30;:8;59089:10;59070:30;:18;:30;:::i;:::-;59047:53;-1:-1:-1;59199:38:0;59240:112;59305:46;35462:19;59340:10;59305:46;:34;:46;:::i;:::-;59240:40;:8;59267:12;59240:40;:26;:40;:::i;:112::-;59199:153;;59499:17;59519:120;59557:7;59579:30;59624:4;59519:23;:120::i;:::-;59499:140;;59650:55;59672:7;59681:9;59692:12;59650:21;:55::i;:::-;59716:53;59738:8;59748:9;59759;59716:21;:53::i;:::-;59891:9;-1:-1:-1;;;;;59785:200:0;59856:19;:17;:19::i;:::-;59785:200;;59821:12;59810:7;:23;;;;;;;;59785:200;;;;;;;;;;;;;;;;;;;;59810:23;;;;;59785:200;;;;;;;;;58743:1250;;;;;;;;;;:::o;97771:228::-;97818:7;97838:30;:18;:28;:30::i;:::-;97881:17;97901:28;:18;:26;:28::i;:::-;97945:19;;;;;;;;97881:48;;-1:-1:-1;97945:19:0;;;;;;;;;;97982:9;-1:-1:-1;97771:228:0;:::o;101349:146::-;-1:-1:-1;;;;;101433:33:0;;;;;;:24;:33;;;;;101417:70;;101468:18;101458:7;101468:9;:18::i;:::-;101417:15;:70::i;22716:539::-;-1:-1:-1;;;;;22822:20:0;;22814:70;;;;-1:-1:-1;;;22814:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;22903:23:0;;22895:71;;;;-1:-1:-1;;;22895:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22979:47;23000:6;23008:9;23019:6;22979:20;:47::i;:::-;23059:71;23081:6;23059:71;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;23059:17:0;;:9;:17;;;;;;;;;;;;:71;;:21;:71;:::i;:::-;-1:-1:-1;;;;;23039:17:0;;;:9;:17;;;;;;;;;;;:91;;;;23164:20;;;;;;;:32;;23189:6;23164:32;:24;:32;:::i;:::-;-1:-1:-1;;;;;23141:20:0;;;:9;:20;;;;;;;;;;;;:55;;;;23212:35;;;;;;;23141:20;;23212:35;;;;;;;;;;;;;22716:539;;;:::o;99229:202::-;99313:31;99336:7;99313:22;:31::i;:::-;99355:28;:26;:28::i;:::-;99396:27;99408:7;99417:5;99396:11;:27::i;87119:133::-;87166:7;87193:10;-1:-1:-1;;;;;87193:43:0;;87237:6;87193:51;;;;;;;;;;;;;-1:-1:-1;;;;;87193:51:0;-1:-1:-1;;;;;87193:51:0;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;87193:51:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;37824:211:0;37933:15;;:::i;:::-;-1:-1:-1;37973:54:0;;;;;;;;;-1:-1:-1;;;;;37973:54:0;;;;;;;;;;;;37824:211::o;14550:979::-;14680:12;14713:18;14724:6;14713:10;:18::i;:::-;14705:60;;;;;-1:-1:-1;;;14705:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;14839:12;14853:23;14880:6;-1:-1:-1;;;;;14880:11:0;14900:8;14911:4;14880:36;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;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;;;14880:36: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;;14838:78:0;;;;14931:7;14927:595;;;14962:10;-1:-1:-1;14955:17:0;;-1:-1:-1;14955:17:0;14927:595;15076:17;;:21;15072:439;;15339:10;15333:17;15400:15;15387:10;15383:2;15379:19;15372:44;15287:148;15475:20;;-1:-1:-1;;;15475:20:0;;;;;;;;;;;;;;;;;15482:12;;15475:20;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;99439:202:0;99523:31;99546:7;99523:22;:31::i;:::-;99565:28;:26;:28::i;:::-;99606:27;99618:7;99627:5;99606:11;:27::i;65028:877::-;65367:12;65394:20;65429:27;65471:24;65510;65562:22;;:::i;:::-;65587:247;;;-1:-1:-1;;;65587:247:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65587:9:0;:24;;;;:247;;;;;;;;;;;;;;:24;:247;;;2:2:-1;;;;27:1;24;17:12;2:2;65587:247:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;65587:247:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;15:3;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;65587:247:0;-1:-1:-1;65587:247:0;65858:1;65853:7;;;;65862:4;65867:1;65862:7;;;;65871:4;65876:1;65871:7;;;;65880:4;65885:1;65880:7;;;;65889:4;65894:1;65889:7;;;;65845:52;;;;;;;;;;;65028:877;;;;;;;;;;;;:::o;72359:763::-;72609:7;;;72660:74;:28;72713:10;72660:74;:38;:74;:::i;:::-;72638:96;-1:-1:-1;72745:17:0;72765:38;72638:96;39231:18;72765:38;:21;:38;:::i;:::-;72745:58;;72814:18;72920:153;72962:19;:9;:17;;;;;;;:19;73000:35;73054:4;72920:23;:153::i;:::-;72880:23;;;;72835:69;;:238;;;;;-1:-1:-1;72894:9:0;-1:-1:-1;;72359:763:0;;;;;;;;:::o;35825:178::-;35922:7;35954:41;35462:19;35954:14;:4;35963;35954:14;:8;:14;:::i;89650:131::-;89744:29;:17;:27;:29::i;:::-;89727:14;;:46;;;;;-1:-1:-1;;;;;89727:46:0;;;;;-1:-1:-1;;;;;89727:46:0;;;;;;89650:131;:::o;34245:201::-;34297:5;;34319:4;:20;;;;;;;;;34315:124;;;-1:-1:-1;34363:12:0;34356:19;;34315:124;-1:-1:-1;34415:12:0;34408:19;;65996:320;66134:7;;66158:5;:21;;;;;;;;;66154:155;;;66203:27;:6;66220:9;66203:27;:16;:27;:::i;:::-;66196:34;;;;66154:155;66270:27;:6;66287:9;66270:27;:16;:27;:::i;93493:181::-;93647:19;;93665:1;93647:19;;;93493:181::o;101629:315::-;101724:17;101744:28;:18;:26;:28::i;:::-;101724:48;-1:-1:-1;101724:48:0;101787:30;101803:9;101787:15;:30::i;:::-;:42;101783:154;;;27:10:-1;;39:1;23:18;;;45:23;;-1:-1;101846:29:0;;;;;;;;;;;;;;101890:16;;;27:10:-1;;23:18;;;45:23;;101890:35:0;;;;;;;;101629:315::o;101503:118::-;101560:53;101576:21;101599:13;:11;:13::i;23536:378::-;-1:-1:-1;;;;;23620:21:0;;23612:65;;;;;-1:-1:-1;;;23612:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;23690:49;23719:1;23723:7;23732:6;23690:20;:49::i;:::-;23767:12;;:24;;23784:6;23767:24;:16;:24;:::i;:::-;23752:12;:39;-1:-1:-1;;;;;23823:18:0;;:9;:18;;;;;;;;;;;:30;;23846:6;23823:30;:22;:30;:::i;:::-;-1:-1:-1;;;;;23802:18:0;;:9;:18;;;;;;;;;;;:51;;;;23869:37;;;;;;;23802:18;;:9;;23869:37;;;;;;;;;;23536:378;;:::o;10058:619::-;10118:4;10586:20;;10429:66;10626:23;;;;;;:42;;-1:-1:-1;;10653:15:0;;;10058:619;-1:-1:-1;;10058:619:0:o;24246:418::-;-1:-1:-1;;;;;24330:21:0;;24322:67;;;;-1:-1:-1;;;24322:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24402:49;24423:7;24440:1;24444:6;24402:20;:49::i;:::-;24485:68;24508:6;24485:68;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;24485:18:0;;:9;:18;;;;;;;;;;;;:68;;:22;:68;:::i;:::-;-1:-1:-1;;;;;24464:18:0;;:9;:18;;;;;;;;;;:89;24579:12;;:24;;24596:6;24579:24;:16;:24;:::i;:::-;24564:12;:39;24619:37;;;;;;;;24645:1;;-1:-1:-1;;;;;24619:37:0;;;;;;;;;;;;24246:418;;:::o;101952:212::-;102046:10;;102022:7;;102042:115;;-1:-1:-1;102085:1:0;102078:8;;102042:115;102130:10;;102126:3;;-1:-1:-1;;102130:14:0;;;102126:19;;;;;;;;;;;;;;102119:26;;;;112231:1446;;;;;;;;;;;-1:-1:-1;112231:1446:0;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;-1:-1:-1;112231:1446:0;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;125:4;109:14;101:6;88:42;-1:-1;112231:1446:0;;;-1:-1:-1;;112231:1446:0:o;:::-;;;;;;;;;;;;;;;;;

Swarm Source

ipfs://3c590c87bd38dd085d6955877b99a555774bfae076e5428f7abd4b10ff0f7248

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  ]

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.