ETH Price: $2,634.72 (+7.99%)
Gas: 0.18 GWei

Contract

0xEFB0697700E5c489073a9BDF7EF94a2B2bc884a5

Overview

ETH Balance

Scroll LogoScroll LogoScroll Logo0 ETH

ETH Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Enter Markets101549682024-10-14 12:48:352 hrs ago1728910115IN
0xEFB06977...B2bc884a5
0 ETH0.000024210.04654071
Enter Markets101549562024-10-14 12:48:022 hrs ago1728910082IN
0xEFB06977...B2bc884a5
0 ETH0.000023240.0461921
Enter Markets101549392024-10-14 12:47:132 hrs ago1728910033IN
0xEFB06977...B2bc884a5
0 ETH0.000024630.04669328
Enter Markets101549012024-10-14 12:45:222 hrs ago1728909922IN
0xEFB06977...B2bc884a5
0 ETH0.000021670.04535547
Enter Markets101465682024-10-14 6:18:089 hrs ago1728886688IN
0xEFB06977...B2bc884a5
0 ETH0.000007720.04067171
Enter Markets101465512024-10-14 6:17:219 hrs ago1728886641IN
0xEFB06977...B2bc884a5
0 ETH0.000007730.0406745
Enter Markets101465462024-10-14 6:17:089 hrs ago1728886628IN
0xEFB06977...B2bc884a5
0 ETH0.000007540.04060641
Enter Markets101465402024-10-14 6:16:519 hrs ago1728886611IN
0xEFB06977...B2bc884a5
0 ETH0.000007870.04048265
Enter Markets101435692024-10-14 3:53:3811 hrs ago1728878018IN
0xEFB06977...B2bc884a5
0 ETH0.000008850.04159548
Enter Markets101435502024-10-14 3:52:4611 hrs ago1728877966IN
0xEFB06977...B2bc884a5
0 ETH0.000009230.04177353
Enter Markets101434342024-10-14 3:47:1811 hrs ago1728877638IN
0xEFB06977...B2bc884a5
0 ETH0.00000940.041824
Enter Markets101433612024-10-14 3:43:4811 hrs ago1728877428IN
0xEFB06977...B2bc884a5
0 ETH0.000009540.04168743
Enter Markets101324712024-10-13 18:46:4620 hrs ago1728845206IN
0xEFB06977...B2bc884a5
0 ETH0.000013440.07
Enter Markets101270332024-10-13 14:22:5125 hrs ago1728829371IN
0xEFB06977...B2bc884a5
0 ETH0.000011220.04440516
Enter Markets101259942024-10-13 13:32:3026 hrs ago1728826350IN
0xEFB06977...B2bc884a5
0 ETH0.000010820.0416786
Enter Markets101259882024-10-13 13:32:1226 hrs ago1728826332IN
0xEFB06977...B2bc884a5
0 ETH0.000010810.0416786
Enter Markets101259362024-10-13 13:29:4026 hrs ago1728826180IN
0xEFB06977...B2bc884a5
0 ETH0.000010110.04142584
Enter Markets101259252024-10-13 13:29:0826 hrs ago1728826148IN
0xEFB06977...B2bc884a5
0 ETH0.000010820.04142584
Enter Markets101217172024-10-13 10:05:5629 hrs ago1728813956IN
0xEFB06977...B2bc884a5
0 ETH0.000007720.04057167
Enter Markets101216902024-10-13 10:04:3729 hrs ago1728813877IN
0xEFB06977...B2bc884a5
0 ETH0.000007740.04057169
Enter Markets101216362024-10-13 10:01:5629 hrs ago1728813716IN
0xEFB06977...B2bc884a5
0 ETH0.0000080.040665
Enter Markets101216182024-10-13 10:01:0229 hrs ago1728813662IN
0xEFB06977...B2bc884a5
0 ETH0.000008630.04064167
Enter Markets101209022024-10-13 9:26:1530 hrs ago1728811575IN
0xEFB06977...B2bc884a5
0 ETH0.000007940.04064599
Enter Markets101208702024-10-13 9:24:4430 hrs ago1728811484IN
0xEFB06977...B2bc884a5
0 ETH0.000007690.04055932
Enter Markets101208612024-10-13 9:24:1730 hrs ago1728811457IN
0xEFB06977...B2bc884a5
0 ETH0.000008390.04055951
View all transactions

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Comptroller

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, BSD-3-Clause license

Contract Source Code (Solidity)

/**
 *Submitted for verification at scrollscan.com on 2023-10-18
*/

/**
 *Submitted for verification at scrollscan.com on 2023-10-17
*/

// SPDX-License-Identifier: BSD-3-Clause

pragma solidity ^0.8.4;

library SignatureLib {
  uint256 constant ECDSA_SIG_R_BS = 32;
  uint256 constant ECDSA_SIG_S_BS = 32;

  function recoverSignerAddress(bytes32 signedHash, uint256 signatureCalldataNegativeOffset)
    internal
    pure
    returns (address)
  {
    bytes32 r;
    bytes32 s;
    uint8 v;
    assembly {
      let signatureCalldataStartPos := sub(calldatasize(), signatureCalldataNegativeOffset)
      r := calldataload(signatureCalldataStartPos)
      signatureCalldataStartPos := add(signatureCalldataStartPos, ECDSA_SIG_R_BS)
      s := calldataload(signatureCalldataStartPos)
      signatureCalldataStartPos := add(signatureCalldataStartPos, ECDSA_SIG_S_BS)
      v := byte(0, calldataload(signatureCalldataStartPos)) // last byte of the signature memory array
    }
    return ecrecover(signedHash, v, r, s);
  }
}

// File: @redstone-finance/evm-connector/contracts/libs/BitmapLib.sol



pragma solidity ^0.8.4;

library BitmapLib {
  function setBitInBitmap(uint256 bitmap, uint256 bitIndex) internal pure returns (uint256) {
    return bitmap | (1 << bitIndex);
  }

  function getBitFromBitmap(uint256 bitmap, uint256 bitIndex) internal pure returns (bool) {
    uint256 bitAtIndex = bitmap & (1 << bitIndex);
    return bitAtIndex > 0;
  }
}

// File: @redstone-finance/evm-connector/contracts/core/RedstoneConstants.sol



pragma solidity ^0.8.4;

/**
 * @title The base contract with helpful constants
 * @author The Redstone Oracles team
 * @dev It mainly contains redstone-related values, which improve readability
 * of other contracts (e.g. CalldataExtractor and RedstoneConsumerBase)
 */
contract RedstoneConstants {
  // === Abbreviations ===
  // BS - Bytes size
  // PTR - Pointer (memory location)
  // SIG - Signature

  // Solidity and YUL constants
  uint256 internal constant STANDARD_SLOT_BS = 32;
  uint256 internal constant FREE_MEMORY_PTR = 0x40;
  uint256 internal constant BYTES_ARR_LEN_VAR_BS = 32;
  uint256 internal constant FUNCTION_SIGNATURE_BS = 4;
  uint256 internal constant REVERT_MSG_OFFSET = 68; // Revert message structure described here: https://ethereum.stackexchange.com/a/66173/106364
  uint256 internal constant STRING_ERR_MESSAGE_MASK = 0x08c379a000000000000000000000000000000000000000000000000000000000;

  // RedStone protocol consts
  uint256 internal constant SIG_BS = 65;
  uint256 internal constant TIMESTAMP_BS = 6;
  uint256 internal constant DATA_PACKAGES_COUNT_BS = 2;
  uint256 internal constant DATA_POINTS_COUNT_BS = 3;
  uint256 internal constant DATA_POINT_VALUE_BYTE_SIZE_BS = 4;
  uint256 internal constant DATA_POINT_SYMBOL_BS = 32;
  uint256 internal constant DEFAULT_DATA_POINT_VALUE_BS = 32;
  uint256 internal constant UNSIGNED_METADATA_BYTE_SIZE_BS = 3;
  uint256 internal constant REDSTONE_MARKER_BS = 9; // byte size of 0x000002ed57011e0000
  uint256 internal constant REDSTONE_MARKER_MASK = 0x0000000000000000000000000000000000000000000000000002ed57011e0000;

  // Derived values (based on consts)
  uint256 internal constant TIMESTAMP_NEGATIVE_OFFSET_IN_DATA_PACKAGE_WITH_STANDARD_SLOT_BS = 104; // SIG_BS + DATA_POINTS_COUNT_BS + DATA_POINT_VALUE_BYTE_SIZE_BS + STANDARD_SLOT_BS
  uint256 internal constant DATA_PACKAGE_WITHOUT_DATA_POINTS_BS = 78; // DATA_POINT_VALUE_BYTE_SIZE_BS + TIMESTAMP_BS + DATA_POINTS_COUNT_BS + SIG_BS
  uint256 internal constant DATA_PACKAGE_WITHOUT_DATA_POINTS_AND_SIG_BS = 13; // DATA_POINT_VALUE_BYTE_SIZE_BS + TIMESTAMP_BS + DATA_POINTS_COUNT_BS
  uint256 internal constant REDSTONE_MARKER_BS_PLUS_STANDARD_SLOT_BS = 41; // REDSTONE_MARKER_BS + STANDARD_SLOT_BS

  // Error messages
  error CalldataOverOrUnderFlow();
  error IncorrectUnsignedMetadataSize();
  error InsufficientNumberOfUniqueSigners(uint256 receivedSignersCount, uint256 requiredSignersCount);
  error EachSignerMustProvideTheSameValue();
  error EmptyCalldataPointersArr();
  error InvalidCalldataPointer();
  error CalldataMustHaveValidPayload();
  error SignerNotAuthorised(address receivedSigner);
}

// File: @openzeppelin/contracts/utils/math/SafeMath.sol


// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // 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 (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @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) {
        return a + b;
    }

    /**
     * @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 a - b;
    }

    /**
     * @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) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting 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 a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting 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) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * 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) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

// File: @redstone-finance/evm-connector/contracts/core/CalldataExtractor.sol



pragma solidity ^0.8.4;



/**
 * @title The base contract with the main logic of data extraction from calldata
 * @author The Redstone Oracles team
 * @dev This contract was created to reuse the same logic in the RedstoneConsumerBase
 * and the ProxyConnector contracts
 */
contract CalldataExtractor is RedstoneConstants {
  using SafeMath for uint256;

  function _extractByteSizeOfUnsignedMetadata() internal pure returns (uint256) {
    // Checking if the calldata ends with the RedStone marker
    bool hasValidRedstoneMarker;
    assembly {
      let calldataLast32Bytes := calldataload(sub(calldatasize(), STANDARD_SLOT_BS))
      hasValidRedstoneMarker := eq(
        REDSTONE_MARKER_MASK,
        and(calldataLast32Bytes, REDSTONE_MARKER_MASK)
      )
    }
    if (!hasValidRedstoneMarker) {
      revert CalldataMustHaveValidPayload();
    }

    // Using uint24, because unsigned metadata byte size number has 3 bytes
    uint24 unsignedMetadataByteSize;
    if (REDSTONE_MARKER_BS_PLUS_STANDARD_SLOT_BS > msg.data.length) {
      revert CalldataOverOrUnderFlow();
    }
    assembly {
      unsignedMetadataByteSize := calldataload(
        sub(calldatasize(), REDSTONE_MARKER_BS_PLUS_STANDARD_SLOT_BS)
      )
    }
    uint256 calldataNegativeOffset = unsignedMetadataByteSize
      + UNSIGNED_METADATA_BYTE_SIZE_BS
      + REDSTONE_MARKER_BS;
    if (calldataNegativeOffset + DATA_PACKAGES_COUNT_BS > msg.data.length) {
      revert IncorrectUnsignedMetadataSize();
    }
    return calldataNegativeOffset;
  }

  // We return uint16, because unsigned metadata byte size number has 2 bytes
  function _extractDataPackagesCountFromCalldata(uint256 calldataNegativeOffset)
    internal
    pure
    returns (uint16 dataPackagesCount)
  {
    uint256 calldataNegativeOffsetWithStandardSlot = calldataNegativeOffset + STANDARD_SLOT_BS;
    if (calldataNegativeOffsetWithStandardSlot > msg.data.length) {
      revert CalldataOverOrUnderFlow();
    }
    assembly {
      dataPackagesCount := calldataload(
        sub(calldatasize(), calldataNegativeOffsetWithStandardSlot)
      )
    }
    return dataPackagesCount;
  }

  function _extractDataPointValueAndDataFeedId(
    uint256 calldataNegativeOffsetForDataPackage,
    uint256 defaultDataPointValueByteSize,
    uint256 dataPointIndex
  ) internal pure virtual returns (bytes32 dataPointDataFeedId, uint256 dataPointValue) {
    uint256 negativeOffsetToDataPoints = calldataNegativeOffsetForDataPackage + DATA_PACKAGE_WITHOUT_DATA_POINTS_BS;
    uint256 dataPointNegativeOffset = negativeOffsetToDataPoints.add(
      (1 + dataPointIndex).mul((defaultDataPointValueByteSize + DATA_POINT_SYMBOL_BS))
    );
    uint256 dataPointCalldataOffset = msg.data.length.sub(dataPointNegativeOffset);
    assembly {
      dataPointDataFeedId := calldataload(dataPointCalldataOffset)
      dataPointValue := calldataload(add(dataPointCalldataOffset, DATA_POINT_SYMBOL_BS))
    }
  }

  function _extractDataPointsDetailsForDataPackage(uint256 calldataNegativeOffsetForDataPackage)
    internal
    pure
    returns (uint256 dataPointsCount, uint256 eachDataPointValueByteSize)
  {
    // Using uint24, because data points count byte size number has 3 bytes
    uint24 dataPointsCount_;

    // Using uint32, because data point value byte size has 4 bytes
    uint32 eachDataPointValueByteSize_;

    // Extract data points count
    uint256 negativeCalldataOffset = calldataNegativeOffsetForDataPackage + SIG_BS;
    uint256 calldataOffset = msg.data.length.sub(negativeCalldataOffset + STANDARD_SLOT_BS);
    assembly {
      dataPointsCount_ := calldataload(calldataOffset)
    }

    // Extract each data point value size
    calldataOffset = calldataOffset.sub(DATA_POINTS_COUNT_BS);
    assembly {
      eachDataPointValueByteSize_ := calldataload(calldataOffset)
    }

    // Prepare returned values
    dataPointsCount = dataPointsCount_;
    eachDataPointValueByteSize = eachDataPointValueByteSize_;
  }
}

// File: @redstone-finance/evm-connector/contracts/libs/NumericArrayLib.sol



pragma solidity ^0.8.4;


library NumericArrayLib {
  // This function sort array in memory using bubble sort algorithm,
  // which performs even better than quick sort for small arrays

  uint256 constant BYTES_ARR_LEN_VAR_BS = 32;
  uint256 constant UINT256_VALUE_BS = 32;

  error CanNotPickMedianOfEmptyArray();

  // This function modifies the array
  function pickMedian(uint256[] memory arr) internal pure returns (uint256) {
    if (arr.length == 0) {
      revert CanNotPickMedianOfEmptyArray();
    }
    sort(arr);
    uint256 middleIndex = arr.length / 2;
    if (arr.length % 2 == 0) {
      uint256 sum = SafeMath.add(arr[middleIndex - 1], arr[middleIndex]);
      return sum / 2;
    } else {
      return arr[middleIndex];
    }
  }

  function sort(uint256[] memory arr) internal pure {
    assembly {
      let arrLength := mload(arr)
      let valuesPtr := add(arr, BYTES_ARR_LEN_VAR_BS)
      let endPtr := add(valuesPtr, mul(arrLength, UINT256_VALUE_BS))
      for {
        let arrIPtr := valuesPtr
      } lt(arrIPtr, endPtr) {
        arrIPtr := add(arrIPtr, UINT256_VALUE_BS) // arrIPtr += 32
      } {
        for {
          let arrJPtr := valuesPtr
        } lt(arrJPtr, arrIPtr) {
          arrJPtr := add(arrJPtr, UINT256_VALUE_BS) // arrJPtr += 32
        } {
          let arrI := mload(arrIPtr)
          let arrJ := mload(arrJPtr)
          if lt(arrI, arrJ) {
            mstore(arrIPtr, arrJ)
            mstore(arrJPtr, arrI)
          }
        }
      }
    }
  }
}

// File: @redstone-finance/evm-connector/contracts/core/RedstoneDefaultsLib.sol



pragma solidity ^0.8.4;


/**
 * @title Default implementations of virtual redstone consumer base functions
 * @author The Redstone Oracles team
 */
library RedstoneDefaultsLib {
  uint256 constant DEFAULT_MAX_DATA_TIMESTAMP_DELAY_SECONDS = 3 minutes;
  uint256 constant DEFAULT_MAX_DATA_TIMESTAMP_AHEAD_SECONDS = 1 minutes;

  error TimestampFromTooLongFuture(uint256 receivedTimestampSeconds, uint256 blockTimestamp);
  error TimestampIsTooOld(uint256 receivedTimestampSeconds, uint256 blockTimestamp);

  function validateTimestamp(uint256 receivedTimestampMilliseconds) internal view {
    // Getting data timestamp from future seems quite unlikely
    // But we've already spent too much time with different cases
    // Where block.timestamp was less than dataPackage.timestamp.
    // Some blockchains may case this problem as well.
    // That's why we add MAX_BLOCK_TIMESTAMP_DELAY
    // and allow data "from future" but with a small delay
    uint256 receivedTimestampSeconds = receivedTimestampMilliseconds / 1000;

    if (block.timestamp < receivedTimestampSeconds) {
      if ((receivedTimestampSeconds - block.timestamp) > DEFAULT_MAX_DATA_TIMESTAMP_AHEAD_SECONDS) {
        revert TimestampFromTooLongFuture(receivedTimestampSeconds, block.timestamp);
      }
    } else if ((block.timestamp - receivedTimestampSeconds) > DEFAULT_MAX_DATA_TIMESTAMP_DELAY_SECONDS) {
      revert TimestampIsTooOld(receivedTimestampSeconds, block.timestamp);
    }
  }

  function aggregateValues(uint256[] memory values) internal pure returns (uint256) {
    return NumericArrayLib.pickMedian(values);
  }
}

// File: @redstone-finance/evm-connector/contracts/core/RedstoneConsumerBase.sol



pragma solidity ^0.8.4;







/**
 * @title The base contract with the main Redstone logic
 * @author The Redstone Oracles team
 * @dev Do not use this contract directly in consumer contracts, take a
 * look at `RedstoneConsumerNumericBase` and `RedstoneConsumerBytesBase` instead
 */
abstract contract RedstoneConsumerBase is CalldataExtractor {
  using SafeMath for uint256;

  /* ========== VIRTUAL FUNCTIONS (MAY BE OVERRIDDEN IN CHILD CONTRACTS) ========== */

  /**
   * @dev This function must be implemented by the child consumer contract.
   * It should return a unique index for a given signer address if the signer
   * is authorised, otherwise it should revert
   * @param receivedSigner The address of a signer, recovered from ECDSA signature
   * @return Unique index for a signer in the range [0..255]
   */
  function getAuthorisedSignerIndex(address receivedSigner) public view virtual returns (uint8);

  /**
   * @dev This function may be overridden by the child consumer contract.
   * It should validate the timestamp against the current time (block.timestamp)
   * It should revert with a helpful message if the timestamp is not valid
   * @param receivedTimestampMilliseconds Timestamp extracted from calldata
   */
  function validateTimestamp(uint256 receivedTimestampMilliseconds) public view virtual {
    RedstoneDefaultsLib.validateTimestamp(receivedTimestampMilliseconds);
  }

  /**
   * @dev This function should be overridden by the child consumer contract.
   * @return The minimum required value of unique authorised signers
   */
  function getUniqueSignersThreshold() public view virtual returns (uint8) {
    return 1;
  }

  /**
   * @dev This function may be overridden by the child consumer contract.
   * It should aggregate values from different signers to a single uint value.
   * By default, it calculates the median value
   * @param values An array of uint256 values from different signers
   * @return Result of the aggregation in the form of a single number
   */
  function aggregateValues(uint256[] memory values) public view virtual returns (uint256) {
    return RedstoneDefaultsLib.aggregateValues(values);
  }

  /* ========== FUNCTIONS WITH IMPLEMENTATION (CAN NOT BE OVERRIDDEN) ========== */

  /**
   * @dev This is an internal helpful function for secure extraction oracle values
   * from the tx calldata. Security is achieved by signatures verification, timestamp
   * validation, and aggregating values from different authorised signers into a
   * single numeric value. If any of the required conditions (e.g. too old timestamp or
   * insufficient number of authorised signers) do not match, the function will revert.
   *
   * Note! You should not call this function in a consumer contract. You can use
   * `getOracleNumericValuesFromTxMsg` or `getOracleNumericValueFromTxMsg` instead.
   *
   * @param dataFeedIds An array of unique data feed identifiers
   * @return An array of the extracted and verified oracle values in the same order
   * as they are requested in dataFeedIds array
   */
  function _securelyExtractOracleValuesFromTxMsg(bytes32[] memory dataFeedIds)
    internal
    view
    returns (uint256[] memory)
  {
    // Initializing helpful variables and allocating memory
    uint256[] memory uniqueSignerCountForDataFeedIds = new uint256[](dataFeedIds.length);
    uint256[] memory signersBitmapForDataFeedIds = new uint256[](dataFeedIds.length);
    uint256[][] memory valuesForDataFeeds = new uint256[][](dataFeedIds.length);
    for (uint256 i = 0; i < dataFeedIds.length; i++) {
      // The line below is commented because newly allocated arrays are filled with zeros
      // But we left it for better readability
      // signersBitmapForDataFeedIds[i] = 0; // <- setting to an empty bitmap
      valuesForDataFeeds[i] = new uint256[](getUniqueSignersThreshold());
    }

    // Extracting the number of data packages from calldata
    uint256 calldataNegativeOffset = _extractByteSizeOfUnsignedMetadata();
    uint256 dataPackagesCount = _extractDataPackagesCountFromCalldata(calldataNegativeOffset);
    calldataNegativeOffset += DATA_PACKAGES_COUNT_BS;

    // Saving current free memory pointer
    uint256 freeMemPtr;
    assembly {
      freeMemPtr := mload(FREE_MEMORY_PTR)
    }

    // Data packages extraction in a loop
    for (uint256 dataPackageIndex = 0; dataPackageIndex < dataPackagesCount; dataPackageIndex++) {
      // Extract data package details and update calldata offset
      uint256 dataPackageByteSize = _extractDataPackage(
        dataFeedIds,
        uniqueSignerCountForDataFeedIds,
        signersBitmapForDataFeedIds,
        valuesForDataFeeds,
        calldataNegativeOffset
      );
      calldataNegativeOffset += dataPackageByteSize;

      // Shifting memory pointer back to the "safe" value
      assembly {
        mstore(FREE_MEMORY_PTR, freeMemPtr)
      }
    }

    // Validating numbers of unique signers and calculating aggregated values for each dataFeedId
    return _getAggregatedValues(valuesForDataFeeds, uniqueSignerCountForDataFeedIds);
  }

  /**
   * @dev This is a private helpful function, which extracts data for a data package based
   * on the given negative calldata offset, verifies them, and in the case of successful
   * verification updates the corresponding data package values in memory
   *
   * @param dataFeedIds an array of unique data feed identifiers
   * @param uniqueSignerCountForDataFeedIds an array with the numbers of unique signers
   * for each data feed
   * @param signersBitmapForDataFeedIds an array of signer bitmaps for data feeds
   * @param valuesForDataFeeds 2-dimensional array, valuesForDataFeeds[i][j] contains
   * j-th value for the i-th data feed
   * @param calldataNegativeOffset negative calldata offset for the given data package
   *
   * @return An array of the aggregated values
   */
  function _extractDataPackage(
    bytes32[] memory dataFeedIds,
    uint256[] memory uniqueSignerCountForDataFeedIds,
    uint256[] memory signersBitmapForDataFeedIds,
    uint256[][] memory valuesForDataFeeds,
    uint256 calldataNegativeOffset
  ) private view returns (uint256) {
    uint256 signerIndex;

    (
      uint256 dataPointsCount,
      uint256 eachDataPointValueByteSize
    ) = _extractDataPointsDetailsForDataPackage(calldataNegativeOffset);

    // We use scopes to resolve problem with too deep stack
    {
      uint48 extractedTimestamp;
      address signerAddress;
      bytes32 signedHash;
      bytes memory signedMessage;
      uint256 signedMessageBytesCount;

      signedMessageBytesCount = dataPointsCount.mul(eachDataPointValueByteSize + DATA_POINT_SYMBOL_BS)
        + DATA_PACKAGE_WITHOUT_DATA_POINTS_AND_SIG_BS; //DATA_POINT_VALUE_BYTE_SIZE_BS + TIMESTAMP_BS + DATA_POINTS_COUNT_BS

      uint256 timestampCalldataOffset = msg.data.length.sub(
        calldataNegativeOffset + TIMESTAMP_NEGATIVE_OFFSET_IN_DATA_PACKAGE_WITH_STANDARD_SLOT_BS);

      uint256 signedMessageCalldataOffset = msg.data.length.sub(
        calldataNegativeOffset + SIG_BS + signedMessageBytesCount);

      assembly {
        // Extracting the signed message
        signedMessage := extractBytesFromCalldata(
          signedMessageCalldataOffset,
          signedMessageBytesCount
        )

        // Hashing the signed message
        signedHash := keccak256(add(signedMessage, BYTES_ARR_LEN_VAR_BS), signedMessageBytesCount)

        // Extracting timestamp
        extractedTimestamp := calldataload(timestampCalldataOffset)

        function initByteArray(bytesCount) -> ptr {
          ptr := mload(FREE_MEMORY_PTR)
          mstore(ptr, bytesCount)
          ptr := add(ptr, BYTES_ARR_LEN_VAR_BS)
          mstore(FREE_MEMORY_PTR, add(ptr, bytesCount))
        }

        function extractBytesFromCalldata(offset, bytesCount) -> extractedBytes {
          let extractedBytesStartPtr := initByteArray(bytesCount)
          calldatacopy(
            extractedBytesStartPtr,
            offset,
            bytesCount
          )
          extractedBytes := sub(extractedBytesStartPtr, BYTES_ARR_LEN_VAR_BS)
        }
      }

      // Validating timestamp
      validateTimestamp(extractedTimestamp);

      // Verifying the off-chain signature against on-chain hashed data
      signerAddress = SignatureLib.recoverSignerAddress(
        signedHash,
        calldataNegativeOffset + SIG_BS
      );
      signerIndex = getAuthorisedSignerIndex(signerAddress);
    }

    // Updating helpful arrays
    {
      bytes32 dataPointDataFeedId;
      uint256 dataPointValue;
      for (uint256 dataPointIndex = 0; dataPointIndex < dataPointsCount; dataPointIndex++) {
        // Extracting data feed id and value for the current data point
        (dataPointDataFeedId, dataPointValue) = _extractDataPointValueAndDataFeedId(
          calldataNegativeOffset,
          eachDataPointValueByteSize,
          dataPointIndex
        );

        for (
          uint256 dataFeedIdIndex = 0;
          dataFeedIdIndex < dataFeedIds.length;
          dataFeedIdIndex++
        ) {
          if (dataPointDataFeedId == dataFeedIds[dataFeedIdIndex]) {
            uint256 bitmapSignersForDataFeedId = signersBitmapForDataFeedIds[dataFeedIdIndex];

            if (
              !BitmapLib.getBitFromBitmap(bitmapSignersForDataFeedId, signerIndex) && /* current signer was not counted for current dataFeedId */
              uniqueSignerCountForDataFeedIds[dataFeedIdIndex] < getUniqueSignersThreshold()
            ) {
              // Increase unique signer counter
              uniqueSignerCountForDataFeedIds[dataFeedIdIndex]++;

              // Add new value
              valuesForDataFeeds[dataFeedIdIndex][
                uniqueSignerCountForDataFeedIds[dataFeedIdIndex] - 1
              ] = dataPointValue;

              // Update signers bitmap
              signersBitmapForDataFeedIds[dataFeedIdIndex] = BitmapLib.setBitInBitmap(
                bitmapSignersForDataFeedId,
                signerIndex
              );
            }

            // Breaking, as there couldn't be several indexes for the same feed ID
            break;
          }
        }
      }
    }

    // Return total data package byte size
    return
      DATA_PACKAGE_WITHOUT_DATA_POINTS_BS +
      (eachDataPointValueByteSize + DATA_POINT_SYMBOL_BS) *
      dataPointsCount;
  }

  /**
   * @dev This is a private helpful function, which aggregates values from different
   * authorised signers for the given arrays of values for each data feed
   *
   * @param valuesForDataFeeds 2-dimensional array, valuesForDataFeeds[i][j] contains
   * j-th value for the i-th data feed
   * @param uniqueSignerCountForDataFeedIds an array with the numbers of unique signers
   * for each data feed
   *
   * @return An array of the aggregated values
   */
  function _getAggregatedValues(
    uint256[][] memory valuesForDataFeeds,
    uint256[] memory uniqueSignerCountForDataFeedIds
  ) private view returns (uint256[] memory) {
    uint256[] memory aggregatedValues = new uint256[](valuesForDataFeeds.length);
    uint256 uniqueSignersThreshold = getUniqueSignersThreshold();

    for (uint256 dataFeedIndex = 0; dataFeedIndex < valuesForDataFeeds.length; dataFeedIndex++) {
      if (uniqueSignerCountForDataFeedIds[dataFeedIndex] < uniqueSignersThreshold) {
        revert InsufficientNumberOfUniqueSigners(
          uniqueSignerCountForDataFeedIds[dataFeedIndex],
          uniqueSignersThreshold);
      }
      uint256 aggregatedValueForDataFeedId = aggregateValues(valuesForDataFeeds[dataFeedIndex]);
      aggregatedValues[dataFeedIndex] = aggregatedValueForDataFeedId;
    }

    return aggregatedValues;
  }
}

// File: @redstone-finance/evm-connector/contracts/core/RedstoneConsumerNumericBase.sol



pragma solidity ^0.8.4;


/**
 * @title The base contract for Redstone consumers' contracts that allows to
 * securely calculate numeric redstone oracle values
 * @author The Redstone Oracles team
 * @dev This contract can extend other contracts to allow them
 * securely fetch Redstone oracle data from transactions calldata
 */
abstract contract RedstoneConsumerNumericBase is RedstoneConsumerBase {
    error GetDataServiceIdNotImplemented();
    function getDataServiceId() public view virtual returns (string memory) {
     revert GetDataServiceIdNotImplemented();
    }

  /**
   * @dev This function can be used in a consumer contract to securely extract an
   * oracle value for a given data feed id. Security is achieved by
   * signatures verification, timestamp validation, and aggregating values
   * from different authorised signers into a single numeric value. If any of the
   * required conditions do not match, the function will revert.
   * Note! This function expects that tx calldata contains redstone payload in the end
   * Learn more about redstone payload here: https://github.com/redstone-finance/redstone-oracles-monorepo/tree/main/packages/evm-connector#readme
   * @param dataFeedId bytes32 value that uniquely identifies the data feed
   * @return Extracted and verified numeric oracle value for the given data feed id
   */
  function getOracleNumericValueFromTxMsg(bytes32 dataFeedId)
    internal
    view
    virtual
    returns (uint256)
  {
    bytes32[] memory dataFeedIds = new bytes32[](1);
    dataFeedIds[0] = dataFeedId;
    return getOracleNumericValuesFromTxMsg(dataFeedIds)[0];
  }

  /**
   * @dev This function can be used in a consumer contract to securely extract several
   * numeric oracle values for a given array of data feed ids. Security is achieved by
   * signatures verification, timestamp validation, and aggregating values
   * from different authorised signers into a single numeric value. If any of the
   * required conditions do not match, the function will revert.
   * Note! This function expects that tx calldata contains redstone payload in the end
   * Learn more about redstone payload here: https://github.com/redstone-finance/redstone-oracles-monorepo/tree/main/packages/evm-connector#readme
   * @param dataFeedIds An array of unique data feed identifiers
   * @return An array of the extracted and verified oracle values in the same order
   * as they are requested in the dataFeedIds array
   */
  function getOracleNumericValuesFromTxMsg(bytes32[] memory dataFeedIds)
    internal
    view
    virtual
    returns (uint256[] memory)
  {
    return _securelyExtractOracleValuesFromTxMsg(dataFeedIds);
  }

  /**
   * @dev This function works similarly to the `getOracleNumericValuesFromTxMsg` with the
   * only difference that it allows to request oracle data for an array of data feeds
   * that may contain duplicates
   * 
   * @param dataFeedIdsWithDuplicates An array of data feed identifiers (duplicates are allowed)
   * @return An array of the extracted and verified oracle values in the same order
   * as they are requested in the dataFeedIdsWithDuplicates array
   */
  function getOracleNumericValuesWithDuplicatesFromTxMsg(bytes32[] memory dataFeedIdsWithDuplicates) internal view returns (uint256[] memory) {
    // Building an array without duplicates
    bytes32[] memory dataFeedIdsWithoutDuplicates = new bytes32[](dataFeedIdsWithDuplicates.length);
    bool alreadyIncluded;
    uint256 uniqueDataFeedIdsCount = 0;

    for (uint256 indexWithDup = 0; indexWithDup < dataFeedIdsWithDuplicates.length; indexWithDup++) {
      // Checking if current element is already included in `dataFeedIdsWithoutDuplicates`
      alreadyIncluded = false;
      for (uint256 indexWithoutDup = 0; indexWithoutDup < uniqueDataFeedIdsCount; indexWithoutDup++) {
        if (dataFeedIdsWithoutDuplicates[indexWithoutDup] == dataFeedIdsWithDuplicates[indexWithDup]) {
          alreadyIncluded = true;
          break;
        }
      }

      // Adding if not included
      if (!alreadyIncluded) {
        dataFeedIdsWithoutDuplicates[uniqueDataFeedIdsCount] = dataFeedIdsWithDuplicates[indexWithDup];
        uniqueDataFeedIdsCount++;
      }
    }

    // Overriding dataFeedIdsWithoutDuplicates.length
    // Equivalent to: dataFeedIdsWithoutDuplicates.length = uniqueDataFeedIdsCount;
    assembly {
      mstore(dataFeedIdsWithoutDuplicates, uniqueDataFeedIdsCount)
    }

    // Requesting oracle values (without duplicates)
    uint256[] memory valuesWithoutDuplicates = getOracleNumericValuesFromTxMsg(dataFeedIdsWithoutDuplicates);

    // Preparing result values array
    uint256[] memory valuesWithDuplicates = new uint256[](dataFeedIdsWithDuplicates.length);
    for (uint256 indexWithDup = 0; indexWithDup < dataFeedIdsWithDuplicates.length; indexWithDup++) {
      for (uint256 indexWithoutDup = 0; indexWithoutDup < dataFeedIdsWithoutDuplicates.length; indexWithoutDup++) {
        if (dataFeedIdsWithDuplicates[indexWithDup] == dataFeedIdsWithoutDuplicates[indexWithoutDup]) {
          valuesWithDuplicates[indexWithDup] = valuesWithoutDuplicates[indexWithoutDup];
          break;
        }
      }
    }

    return valuesWithDuplicates;
  }
}

// File: @redstone-finance/evm-connector/contracts/data-services/PrimaryProdDataServiceConsumerBase.sol



pragma solidity ^0.8.4;


contract PrimaryProdDataServiceConsumerBase is RedstoneConsumerNumericBase {
  function getDataServiceId() public view virtual override returns (string memory) {
    return "redstone-primary-prod";
  }

  function getUniqueSignersThreshold() public view virtual override returns (uint8) {
    return 3;
  }

  function getAuthorisedSignerIndex(
    address signerAddress
  ) public view virtual override returns (uint8) {
    if (signerAddress == 0x8BB8F32Df04c8b654987DAaeD53D6B6091e3B774) {
      return 0;
    } else if (signerAddress == 0xdEB22f54738d54976C4c0fe5ce6d408E40d88499) {
      return 1;
    } else if (signerAddress == 0x51Ce04Be4b3E32572C4Ec9135221d0691Ba7d202) {
      return 2;
    } else if (signerAddress == 0xDD682daEC5A90dD295d14DA4b0bec9281017b5bE) {
      return 3;
    } else if (signerAddress == 0x9c5AE89C4Af6aA32cE58588DBaF90d18a855B6de) {
      return 4;
    } else {
      revert SignerNotAuthorised(signerAddress);
    }
  }
}

// File: ComptrollerRedstone.sol

pragma solidity ^0.8.10;


abstract contract ComptrollerInterface {

    bool public constant isComptroller = true;

    function enterMarkets(address[] calldata cTokens) virtual external returns (uint[] memory);
    function exitMarket(address cToken) virtual external returns (uint);

    function mintAllowed(address cToken, address minter, uint mintAmount) virtual external returns (uint);
    function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) virtual external;

    function redeemAllowed(address cToken, address redeemer, uint redeemTokens) virtual external returns (uint);
    function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) virtual external;

    function borrowAllowed(address cToken, address borrower, uint borrowAmount) virtual external returns (uint);
    function borrowVerify(address cToken, address borrower, uint borrowAmount) virtual external;

    function repayBorrowAllowed(
        address cToken,
        address payer,
        address borrower,
        uint repayAmount) virtual external returns (uint);
    function repayBorrowVerify(
        address cToken,
        address payer,
        address borrower,
        uint repayAmount,
        uint borrowerIndex) virtual external;

    function liquidateBorrowAllowed(
        address cTokenBorrowed,
        address cTokenCollateral,
        address liquidator,
        address borrower,
        uint repayAmount) virtual external returns (uint);
    function liquidateBorrowVerify(
        address cTokenBorrowed,
        address cTokenCollateral,
        address liquidator,
        address borrower,
        uint repayAmount,
        uint seizeTokens) virtual external;

    function seizeAllowed(
        address cTokenCollateral,
        address cTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) virtual external returns (uint);
    function seizeVerify(
        address cTokenCollateral,
        address cTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) virtual external;

    function transferAllowed(address cToken, address src, address dst, uint transferTokens) virtual external returns (uint);
    function transferVerify(address cToken, address src, address dst, uint transferTokens) virtual external;

    function liquidateCalculateSeizeTokens(
        address cTokenBorrowed,
        address cTokenCollateral,
        uint repayAmount) virtual external view returns (uint, uint);
}



abstract contract InterestRateModel {

    bool public constant isInterestRateModel = true;

    function getBorrowRate(uint cash, uint borrows, uint reserves) virtual external view returns (uint);

    function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) virtual external view returns (uint);
}



interface EIP20NonStandardInterface {

    function totalSupply() external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256 balance);

    function transfer(address dst, uint256 amount) external;

    function transferFrom(address src, address dst, uint256 amount) external;

    function approve(address spender, uint256 amount) external returns (bool success);

    function allowance(address owner, address spender) external view returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}



contract ComptrollerErrorReporter {
    enum Error {
        NO_ERROR,
        UNAUTHORIZED,
        COMPTROLLER_MISMATCH,
        INSUFFICIENT_SHORTFALL,
        INSUFFICIENT_LIQUIDITY,
        INVALID_CLOSE_FACTOR,
        INVALID_COLLATERAL_FACTOR,
        INVALID_LIQUIDATION_INCENTIVE,
        MARKET_NOT_ENTERED, 
        MARKET_NOT_LISTED,
        MARKET_ALREADY_LISTED,
        MATH_ERROR,
        NONZERO_BORROW_BALANCE,
        PRICE_ERROR,
        REJECTION,
        SNAPSHOT_ERROR,
        TOO_MANY_ASSETS,
        TOO_MUCH_REPAY
    }

    enum FailureInfo {
        ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
        ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,
        EXIT_MARKET_BALANCE_OWED,
        EXIT_MARKET_REJECTION,
        SET_CLOSE_FACTOR_OWNER_CHECK,
        SET_CLOSE_FACTOR_VALIDATION,
        SET_COLLATERAL_FACTOR_OWNER_CHECK,
        SET_COLLATERAL_FACTOR_NO_EXISTS,
        SET_COLLATERAL_FACTOR_VALIDATION,
        SET_COLLATERAL_FACTOR_WITHOUT_PRICE,
        SET_IMPLEMENTATION_OWNER_CHECK,
        SET_LIQUIDATION_INCENTIVE_OWNER_CHECK,
        SET_LIQUIDATION_INCENTIVE_VALIDATION,
        SET_MAX_ASSETS_OWNER_CHECK,
        SET_PENDING_ADMIN_OWNER_CHECK,
        SET_PENDING_IMPLEMENTATION_OWNER_CHECK,
        SET_PRICE_ORACLE_OWNER_CHECK,
        SUPPORT_MARKET_EXISTS,
        SUPPORT_MARKET_OWNER_CHECK,
        SET_PAUSE_GUARDIAN_OWNER_CHECK
    }

    event Failure(uint error, uint info, uint detail);

    function fail(Error err, FailureInfo info) internal returns (uint) {
        emit Failure(uint(err), uint(info), 0);

        return uint(err);
    }

    function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
        emit Failure(uint(err), uint(info), opaqueError);

        return uint(err);
    }
}

contract TokenErrorReporter {
    uint public constant NO_ERROR = 0; 

    error TransferComptrollerRejection(uint256 errorCode);
    error TransferNotAllowed();
    error TransferNotEnough();
    error TransferTooMuch();

    error MintComptrollerRejection(uint256 errorCode);
    error MintFreshnessCheck();

    error RedeemComptrollerRejection(uint256 errorCode);
    error RedeemFreshnessCheck();
    error RedeemTransferOutNotPossible();

    error BorrowComptrollerRejection(uint256 errorCode);
    error BorrowFreshnessCheck();
    error BorrowCashNotAvailable();

    error RepayBorrowComptrollerRejection(uint256 errorCode);
    error RepayBorrowFreshnessCheck();

    error LiquidateComptrollerRejection(uint256 errorCode);
    error LiquidateFreshnessCheck();
    error LiquidateCollateralFreshnessCheck();
    error LiquidateAccrueBorrowInterestFailed(uint256 errorCode);
    error LiquidateAccrueCollateralInterestFailed(uint256 errorCode);
    error LiquidateLiquidatorIsBorrower();
    error LiquidateCloseAmountIsZero();
    error LiquidateCloseAmountIsUintMax();
    error LiquidateRepayBorrowFreshFailed(uint256 errorCode);

    error LiquidateSeizeComptrollerRejection(uint256 errorCode);
    error LiquidateSeizeLiquidatorIsBorrower();

    error AcceptAdminPendingAdminCheck();

    error SetComptrollerOwnerCheck();
    error SetPendingAdminOwnerCheck();

    error SetReserveFactorAdminCheck();
    error SetReserveFactorFreshCheck();
    error SetReserveFactorBoundsCheck();

    error AddReservesFactorFreshCheck(uint256 actualAddAmount);

    error ReduceReservesAdminCheck();
    error ReduceReservesFreshCheck();
    error ReduceReservesCashNotAvailable();
    error ReduceReservesCashValidation();

    error SetInterestRateModelOwnerCheck();
    error SetInterestRateModelFreshCheck();
}



contract CTokenStorage {

    bool internal _notEntered;

    string public name;

    string public symbol;

    uint8 public decimals;

    uint internal constant borrowRateMaxMantissa = 0.0005e16;

    uint internal constant reserveFactorMaxMantissa = 1e18;

    address payable public admin;

    address payable public pendingAdmin;

    ComptrollerInterface public comptroller;

    InterestRateModel public interestRateModel;

    uint internal initialExchangeRateMantissa;

    uint public reserveFactorMantissa;

    uint public accrualBlockNumber;

    uint public borrowIndex;

    uint public totalBorrows;

    uint public totalReserves;

    uint public totalSupply;

    mapping (address => uint) internal accountTokens;

    mapping (address => mapping (address => uint)) internal transferAllowances;

    struct BorrowSnapshot {
        uint principal;
        uint interestIndex;
    }

    mapping(address => BorrowSnapshot) internal accountBorrows;

    uint public constant protocolSeizeShareMantissa = 2.8e16; 
}

abstract contract CTokenInterface is CTokenStorage {

    bool public constant isCToken = true;

    event AccrueInterest(uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows);

    event Mint(address minter, uint mintAmount, uint mintTokens);

    event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);

    event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows);

    event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows);

    event LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens);

    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

    event NewAdmin(address oldAdmin, address newAdmin);

    event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller);

    event NewMarketInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel);

    event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa);

    event ReservesAdded(address benefactor, uint addAmount, uint newTotalReserves);

    event ReservesReduced(address admin, uint reduceAmount, uint newTotalReserves);

    event Transfer(address indexed from, address indexed to, uint amount);

    event Approval(address indexed owner, address indexed spender, uint amount);

    function transfer(address dst, uint amount) virtual external returns (bool);
    function transferFrom(address src, address dst, uint amount) virtual external returns (bool);
    function approve(address spender, uint amount) virtual external returns (bool);
    function allowance(address owner, address spender) virtual external view returns (uint);
    function balanceOf(address owner) virtual external view returns (uint);
    function balanceOfUnderlying(address owner) virtual external returns (uint);
    function getAccountSnapshot(address account) virtual external view returns (uint, uint, uint, uint);
    function borrowRatePerBlock() virtual external view returns (uint);
    function supplyRatePerBlock() virtual external view returns (uint);
    function totalBorrowsCurrent() virtual external returns (uint);
    function borrowBalanceCurrent(address account) virtual external returns (uint);
    function borrowBalanceStored(address account) virtual external view returns (uint);
    function exchangeRateCurrent() virtual external returns (uint);
    function exchangeRateStored() virtual external view returns (uint);
    function getCash() virtual external view returns (uint);
    function accrueInterest() virtual external returns (uint);
    function seize(address liquidator, address borrower, uint seizeTokens) virtual external returns (uint);

    function _setPendingAdmin(address payable newPendingAdmin) virtual external returns (uint);
    function _acceptAdmin() virtual external returns (uint);
    function _setComptroller(ComptrollerInterface newComptroller) virtual external returns (uint);
    function _setReserveFactor(uint newReserveFactorMantissa) virtual external returns (uint);
    function _reduceReserves(uint reduceAmount) virtual external returns (uint);
    function _setInterestRateModel(InterestRateModel newInterestRateModel) virtual external returns (uint);
}

contract CErc20Storage {

    address public underlying;
}

abstract contract CErc20Interface is CErc20Storage {

    function mint(uint mintAmount) virtual external returns (uint);
    function redeem(uint redeemTokens) virtual external returns (uint);
    function redeemUnderlying(uint redeemAmount) virtual external returns (uint);
    function borrow(uint borrowAmount) virtual external returns (uint);
    function repayBorrow(uint repayAmount) virtual external returns (uint);
    function repayBorrowBehalf(address borrower, uint repayAmount) virtual external returns (uint);
    function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) virtual external returns (uint);
    function sweepToken(EIP20NonStandardInterface token) virtual external;

    function _addReserves(uint addAmount) virtual external returns (uint);
}

contract CDelegationStorage {

    address public implementation;
}

abstract contract CDelegatorInterface is CDelegationStorage {

    event NewImplementation(address oldImplementation, address newImplementation);

    function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) virtual external;
}

abstract contract CDelegateInterface is CDelegationStorage {

    function _becomeImplementation(bytes memory data) virtual external;

    function _resignImplementation() virtual external;
}



interface EIP20Interface {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256 balance);

    function transfer(address dst, uint256 amount) external returns (bool success);

    function transferFrom(address src, address dst, uint256 amount) external returns (bool success);

    function approve(address spender, uint256 amount) external returns (bool success);

    function allowance(address owner, address spender) external view returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}



contract ExponentialNoError {
    uint constant expScale = 1e18;
    uint constant doubleScale = 1e36;
    uint constant halfExpScale = expScale/2;
    uint constant mantissaOne = expScale;

    struct Exp {
        uint mantissa;
    }

    struct Double {
        uint mantissa;
    }

    function truncate(Exp memory exp) pure internal returns (uint) {

        return exp.mantissa / expScale;
    }

    function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {
        Exp memory product = mul_(a, scalar);
        return truncate(product);
    }

    function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {
        Exp memory product = mul_(a, scalar);
        return add_(truncate(product), addend);
    }

    function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa < right.mantissa;
    }

    function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa <= right.mantissa;
    }

    function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa > right.mantissa;
    }

    function isZeroExp(Exp memory value) pure internal returns (bool) {
        return value.mantissa == 0;
    }

    function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {
        require(n < 2**224, errorMessage);
        return uint224(n);
    }

    function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {
        require(n < 2**32, errorMessage);
        return uint32(n);
    }

    function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(uint a, uint b) pure internal returns (uint) {
        return a + b;
    }

    function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(uint a, uint b) pure internal returns (uint) {
        return a - b;
    }

    function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});
    }

    function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Exp memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / expScale;
    }

    function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});
    }

    function mul_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Double memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / doubleScale;
    }

    function mul_(uint a, uint b) pure internal returns (uint) {
        return a * b;
    }

    function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});
    }

    function div_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Exp memory b) pure internal returns (uint) {
        return div_(mul_(a, expScale), b.mantissa);
    }

    function div_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});
    }

    function div_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Double memory b) pure internal returns (uint) {
        return div_(mul_(a, doubleScale), b.mantissa);
    }

    function div_(uint a, uint b) pure internal returns (uint) {
        return a / b;
    }

    function fraction(uint a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: div_(mul_(a, doubleScale), b)});
    }
}



abstract contract CToken is CTokenInterface, ExponentialNoError, TokenErrorReporter {

    function initialize(ComptrollerInterface comptroller_,
                        InterestRateModel interestRateModel_,
                        uint initialExchangeRateMantissa_,
                        string memory name_,
                        string memory symbol_,
                        uint8 decimals_) public {
        require(msg.sender == admin, "only admin may initialize the market");
        require(accrualBlockNumber == 0 && borrowIndex == 0, "market may only be initialized once");

        initialExchangeRateMantissa = initialExchangeRateMantissa_;
        require(initialExchangeRateMantissa > 0, "initial exchange rate must be greater than zero.");

        uint err = _setComptroller(comptroller_);
        require(err == NO_ERROR, "setting comptroller failed");

        accrualBlockNumber = getBlockNumber();
        borrowIndex = mantissaOne;

        err = _setInterestRateModelFresh(interestRateModel_);
        require(err == NO_ERROR, "setting interest rate model failed");

        name = name_;
        symbol = symbol_;
        decimals = decimals_;

        _notEntered = true;
    }

    function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) {

        uint allowed = comptroller.transferAllowed(address(this), src, dst, tokens);
        if (allowed != 0) {
            revert TransferComptrollerRejection(allowed);
        }

        if (src == dst) {
            revert TransferNotAllowed();
        }

        uint startingAllowance = 0;
        if (spender == src) {
            startingAllowance = type(uint).max;
        } else {
            startingAllowance = transferAllowances[src][spender];
        }

        uint allowanceNew = startingAllowance - tokens;
        uint srcTokensNew = accountTokens[src] - tokens;
        uint dstTokensNew = accountTokens[dst] + tokens;

        accountTokens[src] = srcTokensNew;
        accountTokens[dst] = dstTokensNew;

        if (startingAllowance != type(uint).max) {
            transferAllowances[src][spender] = allowanceNew;
        }

        emit Transfer(src, dst, tokens);

        return NO_ERROR;
    }

    function transfer(address dst, uint256 amount) override external nonReentrant returns (bool) {
        return transferTokens(msg.sender, msg.sender, dst, amount) == NO_ERROR;
    }

    function transferFrom(address src, address dst, uint256 amount) override external nonReentrant returns (bool) {
        return transferTokens(msg.sender, src, dst, amount) == NO_ERROR;
    }

    function approve(address spender, uint256 amount) override external returns (bool) {
        address src = msg.sender;
        transferAllowances[src][spender] = amount;
        emit Approval(src, spender, amount);
        return true;
    }

    function allowance(address owner, address spender) override external view returns (uint256) {
        return transferAllowances[owner][spender];
    }

    function balanceOf(address owner) override external view returns (uint256) {
        return accountTokens[owner];
    }

    function balanceOfUnderlying(address owner) override external returns (uint) {
        Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});
        return mul_ScalarTruncate(exchangeRate, accountTokens[owner]);
    }

    function getAccountSnapshot(address account) override external view returns (uint, uint, uint, uint) {
        return (
            NO_ERROR,
            accountTokens[account],
            borrowBalanceStoredInternal(account),
            exchangeRateStoredInternal()
        );
    }

    function getBlockNumber() virtual internal view returns (uint) {
        return block.number;
    }

    function borrowRatePerBlock() override external view returns (uint) {
        return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves);
    }

    function supplyRatePerBlock() override external view returns (uint) {
        return interestRateModel.getSupplyRate(getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa);
    }

    function totalBorrowsCurrent() override external nonReentrant returns (uint) {
        accrueInterest();
        return totalBorrows;
    }

    function borrowBalanceCurrent(address account) override external nonReentrant returns (uint) {
        accrueInterest();
        return borrowBalanceStored(account);
    }

    function borrowBalanceStored(address account) override public view returns (uint) {
        return borrowBalanceStoredInternal(account);
    }

    function borrowBalanceStoredInternal(address account) internal view returns (uint) {

        BorrowSnapshot storage borrowSnapshot = accountBorrows[account];

        if (borrowSnapshot.principal == 0) {
            return 0;
        }

        uint principalTimesIndex = borrowSnapshot.principal * borrowIndex;
        return principalTimesIndex / borrowSnapshot.interestIndex;
    }

    function exchangeRateCurrent() override public nonReentrant returns (uint) {
        accrueInterest();
        return exchangeRateStored();
    }

    function exchangeRateStored() override public view returns (uint) {
        return exchangeRateStoredInternal();
    }

    function exchangeRateStoredInternal() virtual internal view returns (uint) {
        uint _totalSupply = totalSupply;
        if (_totalSupply == 0) {

            return initialExchangeRateMantissa;
        } else {

            uint totalCash = getCashPrior();
            uint cashPlusBorrowsMinusReserves = totalCash + totalBorrows - totalReserves;
            uint exchangeRate = cashPlusBorrowsMinusReserves * expScale / _totalSupply;

            return exchangeRate;
        }
    }

    function getCash() override external view returns (uint) {
        return getCashPrior();
    }

    function accrueInterest() virtual override public returns (uint) {

        uint currentBlockNumber = getBlockNumber();
        uint accrualBlockNumberPrior = accrualBlockNumber;

        if (accrualBlockNumberPrior == currentBlockNumber) {
            return NO_ERROR;
        }

        uint cashPrior = getCashPrior();
        uint borrowsPrior = totalBorrows;
        uint reservesPrior = totalReserves;
        uint borrowIndexPrior = borrowIndex;

        uint borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior);
        require(borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high");

        uint blockDelta = currentBlockNumber - accrualBlockNumberPrior;

        Exp memory simpleInterestFactor = mul_(Exp({mantissa: borrowRateMantissa}), blockDelta);
        uint interestAccumulated = mul_ScalarTruncate(simpleInterestFactor, borrowsPrior);
        uint totalBorrowsNew = interestAccumulated + borrowsPrior;
        uint totalReservesNew = mul_ScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior);
        uint borrowIndexNew = mul_ScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);

        accrualBlockNumber = currentBlockNumber;
        borrowIndex = borrowIndexNew;
        totalBorrows = totalBorrowsNew;
        totalReserves = totalReservesNew;

        emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);

        return NO_ERROR;
    }

    function mintInternal(uint mintAmount) internal nonReentrant {
        accrueInterest();

        mintFresh(msg.sender, mintAmount);
    }

    function mintFresh(address minter, uint mintAmount) internal {

        uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount);
        if (allowed != 0) {
            revert MintComptrollerRejection(allowed);
        }

        if (accrualBlockNumber != getBlockNumber()) {
            revert MintFreshnessCheck();
        }

        Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal()});

        uint actualMintAmount = doTransferIn(minter, mintAmount);

        uint mintTokens = div_(actualMintAmount, exchangeRate);

        totalSupply = totalSupply + mintTokens;
        accountTokens[minter] = accountTokens[minter] + mintTokens;

        emit Mint(minter, actualMintAmount, mintTokens);
        emit Transfer(address(this), minter, mintTokens);

    }

    function redeemInternal(uint redeemTokens) internal nonReentrant {
        accrueInterest();

        redeemFresh(payable(msg.sender), redeemTokens, 0);
    }

    function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant {
        accrueInterest();

        redeemFresh(payable(msg.sender), 0, redeemAmount);
    }

    function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal {
        require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero");

        Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal() });

        uint redeemTokens;
        uint redeemAmount;

        if (redeemTokensIn > 0) {

            redeemTokens = redeemTokensIn;
            redeemAmount = mul_ScalarTruncate(exchangeRate, redeemTokensIn);
        } else {

            redeemTokens = div_(redeemAmountIn, exchangeRate);
            redeemAmount = redeemAmountIn;
        }

        uint allowed = comptroller.redeemAllowed(address(this), redeemer, redeemTokens);
        if (allowed != 0) {
            revert RedeemComptrollerRejection(allowed);
        }

        if (accrualBlockNumber != getBlockNumber()) {
            revert RedeemFreshnessCheck();
        }

        if (getCashPrior() < redeemAmount) {
            revert RedeemTransferOutNotPossible();
        }

        totalSupply = totalSupply - redeemTokens;
        accountTokens[redeemer] = accountTokens[redeemer] - redeemTokens;

        doTransferOut(redeemer, redeemAmount);

        emit Transfer(redeemer, address(this), redeemTokens);
        emit Redeem(redeemer, redeemAmount, redeemTokens);

        comptroller.redeemVerify(address(this), redeemer, redeemAmount, redeemTokens);
    }

    function borrowInternal(uint borrowAmount) internal nonReentrant {
        accrueInterest();

        borrowFresh(payable(msg.sender), borrowAmount);
    }

    function borrowFresh(address payable borrower, uint borrowAmount) internal {

        uint allowed = comptroller.borrowAllowed(address(this), borrower, borrowAmount);
        if (allowed != 0) {
            revert BorrowComptrollerRejection(allowed);
        }

        if (accrualBlockNumber != getBlockNumber()) {
            revert BorrowFreshnessCheck();
        }

        if (getCashPrior() < borrowAmount) {
            revert BorrowCashNotAvailable();
        }

        uint accountBorrowsPrev = borrowBalanceStoredInternal(borrower);
        uint accountBorrowsNew = accountBorrowsPrev + borrowAmount;
        uint totalBorrowsNew = totalBorrows + borrowAmount;

        accountBorrows[borrower].principal = accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = totalBorrowsNew;

        doTransferOut(borrower, borrowAmount);

        emit Borrow(borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew);
    }

    function repayBorrowInternal(uint repayAmount) internal nonReentrant {
        accrueInterest();

        repayBorrowFresh(msg.sender, msg.sender, repayAmount);
    }

    function repayBorrowBehalfInternal(address borrower, uint repayAmount) internal nonReentrant {
        accrueInterest();

        repayBorrowFresh(msg.sender, borrower, repayAmount);
    }

    function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint) {

        uint allowed = comptroller.repayBorrowAllowed(address(this), payer, borrower, repayAmount);
        if (allowed != 0) {
            revert RepayBorrowComptrollerRejection(allowed);
        }

        if (accrualBlockNumber != getBlockNumber()) {
            revert RepayBorrowFreshnessCheck();
        }

        uint accountBorrowsPrev = borrowBalanceStoredInternal(borrower);

        uint repayAmountFinal = repayAmount == type(uint).max ? accountBorrowsPrev : repayAmount;

        uint actualRepayAmount = doTransferIn(payer, repayAmountFinal);

        uint accountBorrowsNew = accountBorrowsPrev - actualRepayAmount;
        uint totalBorrowsNew = totalBorrows - actualRepayAmount;

        accountBorrows[borrower].principal = accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = totalBorrowsNew;

        emit RepayBorrow(payer, borrower, actualRepayAmount, accountBorrowsNew, totalBorrowsNew);

        return actualRepayAmount;
    }

    function liquidateBorrowInternal(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal nonReentrant {
        accrueInterest();

        uint error = cTokenCollateral.accrueInterest();
        if (error != NO_ERROR) {

            revert LiquidateAccrueCollateralInterestFailed(error);
        }

        liquidateBorrowFresh(msg.sender, borrower, repayAmount, cTokenCollateral);
    }

    function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal {

        uint allowed = comptroller.liquidateBorrowAllowed(address(this), address(cTokenCollateral), liquidator, borrower, repayAmount);
        if (allowed != 0) {
            revert LiquidateComptrollerRejection(allowed);
        }

        if (accrualBlockNumber != getBlockNumber()) {
            revert LiquidateFreshnessCheck();
        }

        if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {
            revert LiquidateCollateralFreshnessCheck();
        }

        if (borrower == liquidator) {
            revert LiquidateLiquidatorIsBorrower();
        }

        if (repayAmount == 0) {
            revert LiquidateCloseAmountIsZero();
        }

        if (repayAmount == type(uint).max) {
            revert LiquidateCloseAmountIsUintMax();
        }

        uint actualRepayAmount = repayBorrowFresh(liquidator, borrower, repayAmount);

        (uint amountSeizeError, uint seizeTokens) = comptroller.liquidateCalculateSeizeTokens(address(this), address(cTokenCollateral), actualRepayAmount);
        require(amountSeizeError == NO_ERROR, "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED");

        require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "LIQUIDATE_SEIZE_TOO_MUCH");

        if (address(cTokenCollateral) == address(this)) {
            seizeInternal(address(this), liquidator, borrower, seizeTokens);
        } else {
            require(cTokenCollateral.seize(liquidator, borrower, seizeTokens) == NO_ERROR, "token seizure failed");
        }

        emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(cTokenCollateral), seizeTokens);
    }

    function seize(address liquidator, address borrower, uint seizeTokens) override external nonReentrant returns (uint) {
        seizeInternal(msg.sender, liquidator, borrower, seizeTokens);

        return NO_ERROR;
    }

    function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal {

        uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens);
        if (allowed != 0) {
            revert LiquidateSeizeComptrollerRejection(allowed);
        }

        if (borrower == liquidator) {
            revert LiquidateSeizeLiquidatorIsBorrower();
        }

        uint protocolSeizeTokens = mul_(seizeTokens, Exp({mantissa: protocolSeizeShareMantissa}));
        uint liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens;
        Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal()});
        uint protocolSeizeAmount = mul_ScalarTruncate(exchangeRate, protocolSeizeTokens);
        uint totalReservesNew = totalReserves + protocolSeizeAmount;

        totalReserves = totalReservesNew;
        totalSupply = totalSupply - protocolSeizeTokens;
        accountTokens[borrower] = accountTokens[borrower] - seizeTokens;
        accountTokens[liquidator] = accountTokens[liquidator] + liquidatorSeizeTokens;

        emit Transfer(borrower, liquidator, liquidatorSeizeTokens);
        emit Transfer(borrower, address(this), protocolSeizeTokens);
        emit ReservesAdded(address(this), protocolSeizeAmount, totalReservesNew);
    }

    function _setPendingAdmin(address payable newPendingAdmin) override external returns (uint) {

        if (msg.sender != admin) {
            revert SetPendingAdminOwnerCheck();
        }

        address oldPendingAdmin = pendingAdmin;

        pendingAdmin = newPendingAdmin;

        emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);

        return NO_ERROR;
    }

    function _acceptAdmin() override external returns (uint) {

        if (msg.sender != pendingAdmin || msg.sender == address(0)) {
            revert AcceptAdminPendingAdminCheck();
        }

        address oldAdmin = admin;
        address oldPendingAdmin = pendingAdmin;

        admin = pendingAdmin;

        pendingAdmin = payable(address(0));

        emit NewAdmin(oldAdmin, admin);
        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);

        return NO_ERROR;
    }

    function _setComptroller(ComptrollerInterface newComptroller) override public returns (uint) {

        if (msg.sender != admin) {
            revert SetComptrollerOwnerCheck();
        }

        ComptrollerInterface oldComptroller = comptroller;

        require(newComptroller.isComptroller(), "marker method returned false");

        comptroller = newComptroller;

        emit NewComptroller(oldComptroller, newComptroller);

        return NO_ERROR;
    }

    function _setReserveFactor(uint newReserveFactorMantissa) override external nonReentrant returns (uint) {
        accrueInterest();

        return _setReserveFactorFresh(newReserveFactorMantissa);
    }

    function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) {

        if (msg.sender != admin) {
            revert SetReserveFactorAdminCheck();
        }

        if (accrualBlockNumber != getBlockNumber()) {
            revert SetReserveFactorFreshCheck();
        }

        if (newReserveFactorMantissa > reserveFactorMaxMantissa) {
            revert SetReserveFactorBoundsCheck();
        }

        uint oldReserveFactorMantissa = reserveFactorMantissa;
        reserveFactorMantissa = newReserveFactorMantissa;

        emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);

        return NO_ERROR;
    }

    function _addReservesInternal(uint addAmount) internal nonReentrant returns (uint) {
        accrueInterest();

        _addReservesFresh(addAmount);
        return NO_ERROR;
    }

    function _addReservesFresh(uint addAmount) internal returns (uint, uint) {

        uint totalReservesNew;
        uint actualAddAmount;

        if (accrualBlockNumber != getBlockNumber()) {
            revert AddReservesFactorFreshCheck(actualAddAmount);
        }

        actualAddAmount = doTransferIn(msg.sender, addAmount);

        totalReservesNew = totalReserves + actualAddAmount;

        totalReserves = totalReservesNew;

        emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);

        return (NO_ERROR, actualAddAmount);
    }

    function _reduceReserves(uint reduceAmount) override external nonReentrant returns (uint) {
        accrueInterest();

        return _reduceReservesFresh(reduceAmount);
    }

    function _reduceReservesFresh(uint reduceAmount) internal returns (uint) {

        uint totalReservesNew;

        if (msg.sender != admin) {
            revert ReduceReservesAdminCheck();
        }

        if (accrualBlockNumber != getBlockNumber()) {
            revert ReduceReservesFreshCheck();
        }

        if (getCashPrior() < reduceAmount) {
            revert ReduceReservesCashNotAvailable();
        }

        if (reduceAmount > totalReserves) {
            revert ReduceReservesCashValidation();
        }

        totalReservesNew = totalReserves - reduceAmount;

        totalReserves = totalReservesNew;

        doTransferOut(admin, reduceAmount);

        emit ReservesReduced(admin, reduceAmount, totalReservesNew);

        return NO_ERROR;
    }

    function _setInterestRateModel(InterestRateModel newInterestRateModel) override public returns (uint) {
        accrueInterest();

        return _setInterestRateModelFresh(newInterestRateModel);
    }

    function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) {

        InterestRateModel oldInterestRateModel;

        if (msg.sender != admin) {
            revert SetInterestRateModelOwnerCheck();
        }

        if (accrualBlockNumber != getBlockNumber()) {
            revert SetInterestRateModelFreshCheck();
        }

        oldInterestRateModel = interestRateModel;

        require(newInterestRateModel.isInterestRateModel(), "marker method returned false");

        interestRateModel = newInterestRateModel;

        emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);

        return NO_ERROR;
    }

    function getCashPrior() virtual internal view returns (uint);

    function doTransferIn(address from, uint amount) virtual internal returns (uint);

    function doTransferOut(address payable to, uint amount) virtual internal;

    modifier nonReentrant() {
        require(_notEntered, "re-entered");
        _notEntered = false;
        _;
        _notEntered = true; 
    }
}

contract UnitrollerAdminStorage {

    address public admin;

    address public pendingAdmin;

    address public comptrollerImplementation;

    address public pendingComptrollerImplementation;
}

contract ComptrollerV1Storage is UnitrollerAdminStorage {

    uint public closeFactorMantissa;

    uint public liquidationIncentiveMantissa;

    uint public maxAssets;

    mapping(address => CToken[]) public accountAssets;

}

contract ComptrollerV2Storage is ComptrollerV1Storage {
    struct Market {

        bool isListed;

        uint collateralFactorMantissa;

        mapping(address => bool) accountMembership;

        bool isComped;
    }

    mapping(address => Market) public markets;

    address public pauseGuardian;
    bool public _mintGuardianPaused;
    bool public _borrowGuardianPaused;
    bool public transferGuardianPaused;
    bool public seizeGuardianPaused;
    mapping(address => bool) public mintGuardianPaused;
    mapping(address => bool) public borrowGuardianPaused;
}

contract ComptrollerV3Storage is ComptrollerV2Storage {
    struct CompMarketState {

        uint224 index;

        uint32 block;
    }

    CToken[] public allMarkets;

    uint public compRate;

    mapping(address => uint) public compSpeeds;

    mapping(address => CompMarketState) public compSupplyState;

    mapping(address => CompMarketState) public compBorrowState;

    mapping(address => mapping(address => uint)) public compSupplierIndex;

    mapping(address => mapping(address => uint)) public compBorrowerIndex;

    mapping(address => uint) public compAccrued;
}

contract ComptrollerV4Storage is ComptrollerV3Storage {

    address public borrowCapGuardian;

    mapping(address => uint) public borrowCaps;
}

contract ComptrollerV5Storage is ComptrollerV4Storage {

    mapping(address => uint) public compContributorSpeeds;

    mapping(address => uint) public lastContributorBlock;
}

contract ComptrollerV6Storage is ComptrollerV5Storage {

    mapping(address => uint) public compBorrowSpeeds;

    mapping(address => uint) public compSupplySpeeds;
}

contract ComptrollerV7Storage is ComptrollerV6Storage {

    bool public proposal65FixExecuted;

    mapping(address => uint) public compReceivable;
}



contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter {

    event NewPendingImplementation(address oldPendingImplementation, address newPendingImplementation);

    event NewImplementation(address oldImplementation, address newImplementation);

    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

    event NewAdmin(address oldAdmin, address newAdmin);

    constructor() public {

        admin = msg.sender;
    }

    function _setPendingImplementation(address newPendingImplementation) public returns (uint) {

        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK);
        }

        address oldPendingImplementation = pendingComptrollerImplementation;

        pendingComptrollerImplementation = newPendingImplementation;

        emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation);

        return uint(Error.NO_ERROR);
    }

    function _acceptImplementation() public returns (uint) {

        if (msg.sender != pendingComptrollerImplementation || pendingComptrollerImplementation == address(0)) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK);
        }

        address oldImplementation = comptrollerImplementation;
        address oldPendingImplementation = pendingComptrollerImplementation;

        comptrollerImplementation = pendingComptrollerImplementation;

        pendingComptrollerImplementation = address(0);

        emit NewImplementation(oldImplementation, comptrollerImplementation);
        emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation);

        return uint(Error.NO_ERROR);
    }

    function _setPendingAdmin(address newPendingAdmin) public returns (uint) {

        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK);
        }

        address oldPendingAdmin = pendingAdmin;

        pendingAdmin = newPendingAdmin;

        emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);

        return uint(Error.NO_ERROR);
    }

    function _acceptAdmin() public returns (uint) {

        if (msg.sender != pendingAdmin || msg.sender == address(0)) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK);
        }

        address oldAdmin = admin;
        address oldPendingAdmin = pendingAdmin;

        admin = pendingAdmin;

        pendingAdmin = address(0);

        emit NewAdmin(oldAdmin, admin);
        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);

        return uint(Error.NO_ERROR);
    }

    fallback() payable external {

        (bool success, ) = comptrollerImplementation.delegatecall(msg.data);

        assembly {
              let free_mem_ptr := mload(0x40)
              returndatacopy(free_mem_ptr, 0, returndatasize())

              switch success
              case 0 { revert(free_mem_ptr, returndatasize()) }
              default { return(free_mem_ptr, returndatasize()) }
        }
    }
}

interface CompLike {
    function delegate(address delegatee) external;
}

contract CErc20 is CToken, CErc20Interface {

    function initialize(address underlying_,
                        ComptrollerInterface comptroller_,
                        InterestRateModel interestRateModel_,
                        uint initialExchangeRateMantissa_,
                        string memory name_,
                        string memory symbol_,
                        uint8 decimals_) public {

        super.initialize(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);

        underlying = underlying_;
        EIP20Interface(underlying).totalSupply();
    }

    function mint(uint mintAmount) override external returns (uint) {
        mintInternal(mintAmount);
        return NO_ERROR;
    }

    function redeem(uint redeemTokens) override external returns (uint) {
        redeemInternal(redeemTokens);
        return NO_ERROR;
    }

    function redeemUnderlying(uint redeemAmount) override external returns (uint) {
        redeemUnderlyingInternal(redeemAmount);
        return NO_ERROR;
    }

    function borrow(uint borrowAmount) override external returns (uint) {
        borrowInternal(borrowAmount);
        return NO_ERROR;
    }

    function repayBorrow(uint repayAmount) override external returns (uint) {
        repayBorrowInternal(repayAmount);
        return NO_ERROR;
    }

    function repayBorrowBehalf(address borrower, uint repayAmount) override external returns (uint) {
        repayBorrowBehalfInternal(borrower, repayAmount);
        return NO_ERROR;
    }

    function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) override external returns (uint) {
        liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral);
        return NO_ERROR;
    }

    function sweepToken(EIP20NonStandardInterface token) override external {
        require(msg.sender == admin, "CErc20::sweepToken: only admin can sweep tokens");
        require(address(token) != underlying, "CErc20::sweepToken: can not sweep underlying token");
        uint256 balance = token.balanceOf(address(this));
        token.transfer(admin, balance);
    }

    function _addReserves(uint addAmount) override external returns (uint) {
        return _addReservesInternal(addAmount);
    }

    function getCashPrior() virtual override internal view returns (uint) {
        EIP20Interface token = EIP20Interface(underlying);
        return token.balanceOf(address(this));
    }

    function doTransferIn(address from, uint amount) virtual override internal returns (uint) {

        address underlying_ = underlying;
        EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying_);
        uint balanceBefore = EIP20Interface(underlying_).balanceOf(address(this));
        token.transferFrom(from, address(this), amount);

        bool success;
        assembly {
            switch returndatasize()
                case 0 {                       
                    success := not(0)          
                }
                case 32 {                      
                    returndatacopy(0, 0, 32)
                    success := mload(0)        
                }
                default {                      
                    revert(0, 0)
                }
        }
        require(success, "TOKEN_TRANSFER_IN_FAILED");

        uint balanceAfter = EIP20Interface(underlying_).balanceOf(address(this));
        return balanceAfter - balanceBefore;   
    }

    function doTransferOut(address payable to, uint amount) virtual override internal {
        EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);
        token.transfer(to, amount);

        bool success;
        assembly {
            switch returndatasize()
                case 0 {                      
                    success := not(0)          
                }
                case 32 {                     
                    returndatacopy(0, 0, 32)
                    success := mload(0)        
                }
                default {                     
                    revert(0, 0)
                }
        }
        require(success, "TOKEN_TRANSFER_OUT_FAILED");
    }

    function _delegateCompLikeTo(address compLikeDelegatee) external {
        require(msg.sender == admin, "only the admin may set the comp-like delegate");
        CompLike(underlying).delegate(compLikeDelegatee);
    }
}



contract Comptroller is ComptrollerV7Storage, ComptrollerInterface, ComptrollerErrorReporter, ExponentialNoError, PrimaryProdDataServiceConsumerBase {

    event MarketListed(CToken cToken);

    event MarketEntered(CToken cToken, address account);

    event MarketExited(CToken cToken, address account);

    event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);

    event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);

    event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);

    event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);

    event ActionPaused(string action, bool pauseState);

    event ActionPaused(CToken cToken, string action, bool pauseState);

    event CompBorrowSpeedUpdated(CToken indexed cToken, uint newSpeed);

    event CompSupplySpeedUpdated(CToken indexed cToken, uint newSpeed);

    event ContributorCompSpeedUpdated(address indexed contributor, uint newSpeed);

    event DistributedSupplierComp(CToken indexed cToken, address indexed supplier, uint compDelta, uint compSupplyIndex);

    event DistributedBorrowerComp(CToken indexed cToken, address indexed borrower, uint compDelta, uint compBorrowIndex);

    event NewBorrowCap(CToken indexed cToken, uint newBorrowCap);

    event NewBorrowCapGuardian(address oldBorrowCapGuardian, address newBorrowCapGuardian);

    event CompGranted(address recipient, uint amount);

    event CompAccruedAdjusted(address indexed user, uint oldCompAccrued, uint newCompAccrued);

    event CompReceivableUpdated(address indexed user, uint oldCompReceivable, uint newCompReceivable);

    uint224 public constant compInitialIndex = 1e36;

    uint internal constant closeFactorMinMantissa = 0.05e18; 

    uint internal constant closeFactorMaxMantissa = 0.9e18; 

    uint internal constant collateralFactorMaxMantissa = 0.9e18; 

    constructor() {
        admin = msg.sender;
    }

    function getAssetsIn(address account) external view returns (CToken[] memory) {
        CToken[] memory assetsIn = accountAssets[account];

        return assetsIn;
    }

    function checkMembership(address account, CToken cToken) external view returns (bool) {
        return markets[address(cToken)].accountMembership[account];
    }

    function enterMarkets(address[] memory cTokens) override public returns (uint[] memory) {
        uint len = cTokens.length;

        uint[] memory results = new uint[](len);
        for (uint i = 0; i < len; i++) {
            CToken cToken = CToken(cTokens[i]);

            results[i] = uint(addToMarketInternal(cToken, msg.sender));
        }

        return results;
    }

    function addToMarketInternal(CToken cToken, address borrower) internal returns (Error) {
        Market storage marketToJoin = markets[address(cToken)];

        if (!marketToJoin.isListed) {

            return Error.MARKET_NOT_LISTED;
        }

        if (marketToJoin.accountMembership[borrower] == true) {

            return Error.NO_ERROR;
        }

        marketToJoin.accountMembership[borrower] = true;
        accountAssets[borrower].push(cToken);

        emit MarketEntered(cToken, borrower);

        return Error.NO_ERROR;
    }

    function exitMarket(address cTokenAddress) override external returns (uint) {
        CToken cToken = CToken(cTokenAddress);

        (uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender);
        require(oErr == 0, "exitMarket: getAccountSnapshot failed"); 

        if (amountOwed != 0) {
            return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED);
        }

        uint allowed = redeemAllowedInternal(cTokenAddress, msg.sender, tokensHeld);
        if (allowed != 0) {
            return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed);
        }

        Market storage marketToExit = markets[address(cToken)];

        if (!marketToExit.accountMembership[msg.sender]) {
            return uint(Error.NO_ERROR);
        }

        delete marketToExit.accountMembership[msg.sender];

        CToken[] memory userAssetList = accountAssets[msg.sender];
        uint len = userAssetList.length;
        uint assetIndex = len;
        for (uint i = 0; i < len; i++) {
            if (userAssetList[i] == cToken) {
                assetIndex = i;
                break;
            }
        }

        assert(assetIndex < len);

        CToken[] storage storedList = accountAssets[msg.sender];
        storedList[assetIndex] = storedList[storedList.length - 1];
        storedList.pop();

        emit MarketExited(cToken, msg.sender);

        return uint(Error.NO_ERROR);
    }

    function mintAllowed(address cToken, address minter, uint mintAmount) override external returns (uint) {

        require(!mintGuardianPaused[cToken], "mint is paused");

        minter;
        mintAmount;

        if (!markets[cToken].isListed) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        return uint(Error.NO_ERROR);
    }

    function mintVerify(address cToken, address minter, uint actualMintAmount, uint mintTokens) override external {

        cToken;
        minter;
        actualMintAmount;
        mintTokens;

        if (false) {
            maxAssets = maxAssets;
        }
    }

    function redeemAllowed(address cToken, address redeemer, uint redeemTokens) override external returns (uint) {
        uint allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens);
        if (allowed != uint(Error.NO_ERROR)) {
            return allowed;
        }

        return uint(Error.NO_ERROR);
    }

    function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) {
        if (!markets[cToken].isListed) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        if (!markets[cToken].accountMembership[redeemer]) {
            return uint(Error.NO_ERROR);
        }

        (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0);
        if (err != Error.NO_ERROR) {
            return uint(err);
        }
        if (shortfall > 0) {
            return uint(Error.INSUFFICIENT_LIQUIDITY);
        }

        return uint(Error.NO_ERROR);
    }

    function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) override external {

        cToken;
        redeemer;

        if (redeemTokens == 0 && redeemAmount > 0) {
            revert("redeemTokens zero");
        }
    }

    function getUnderlyingPrice(CToken cToken) public view returns (uint) {
        uint256 ethPrice;

        bytes32 asset;
        if (keccak256(abi.encodePacked(cToken.symbol())) == keccak256(abi.encodePacked("cETH"))) {
            ethPrice = getOracleNumericValueFromTxMsg(bytes32("ETH"));
        } else if (keccak256(abi.encodePacked(cToken.symbol())) == keccak256(abi.encodePacked("cWETH"))) {
            ethPrice = getOracleNumericValueFromTxMsg(bytes32("ETH"));
        } else if (keccak256(abi.encodePacked(cToken.symbol())) == keccak256(abi.encodePacked("cUSDC"))) {
            ethPrice = getOracleNumericValueFromTxMsg(bytes32("USDC")) * 1e12;
        } else if (keccak256(abi.encodePacked(cToken.symbol())) == keccak256(abi.encodePacked("cUSDT"))) {
            ethPrice = getOracleNumericValueFromTxMsg(bytes32("USDT")) * 1e12;
        } else if (keccak256(abi.encodePacked(cToken.symbol())) == keccak256(abi.encodePacked("cWBTC"))) {
            ethPrice = getOracleNumericValueFromTxMsg(bytes32("BTC")) * 1e10;
        } else {
            string memory underlyingSymbol = EIP20Interface(address(CErc20(address(cToken)).underlying())).symbol();
            bytes32 result;
            bytes memory tempEmptyStringTest = bytes(underlyingSymbol);
            if (tempEmptyStringTest.length == 0) {
                result = 0x0;
            }
            assembly {
                result := mload(add(underlyingSymbol, 32))
            }
            asset = bytes32(result);

            ethPrice = getOracleNumericValueFromTxMsg(asset);
        }
        return ethPrice;
    }

    function borrowAllowed(address cToken, address borrower, uint borrowAmount) override external returns (uint) {

        require(!borrowGuardianPaused[cToken], "borrow is paused");

        if (!markets[cToken].isListed) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        if (!markets[cToken].accountMembership[borrower]) {

            require(msg.sender == cToken, "sender must be cToken");

            Error err = addToMarketInternal(CToken(msg.sender), borrower);
            if (err != Error.NO_ERROR) {
                return uint(err);
            }

            assert(markets[cToken].accountMembership[borrower]);
        }

        if (getUnderlyingPrice(CToken(cToken)) == 0) {
            return uint(Error.PRICE_ERROR);
        }

        uint borrowCap = borrowCaps[cToken];

        if (borrowCap != 0) {
            uint totalBorrows = CToken(cToken).totalBorrows();
            uint nextTotalBorrows = add_(totalBorrows, borrowAmount);
            require(nextTotalBorrows < borrowCap, "market borrow cap reached");
        }

        (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, CToken(cToken), 0, borrowAmount);
        if (err != Error.NO_ERROR) {
            return uint(err);
        }
        if (shortfall > 0) {
            return uint(Error.INSUFFICIENT_LIQUIDITY);
        }

        return uint(Error.NO_ERROR);
    }

    function borrowVerify(address cToken, address borrower, uint borrowAmount) override external {

        cToken;
        borrower;
        borrowAmount;

        if (false) {
            maxAssets = maxAssets;
        }
    }

    function repayBorrowAllowed(
        address cToken,
        address payer,
        address borrower,
        uint repayAmount) override external returns (uint) {

        payer;
        borrower;
        repayAmount;

        if (!markets[cToken].isListed) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        return uint(Error.NO_ERROR);
    }

    function repayBorrowVerify(
        address cToken,
        address payer,
        address borrower,
        uint actualRepayAmount,
        uint borrowerIndex) override external {

        cToken;
        payer;
        borrower;
        actualRepayAmount;
        borrowerIndex;

        if (false) {
            maxAssets = maxAssets;
        }
    }

    function liquidateBorrowAllowed(
        address cTokenBorrowed,
        address cTokenCollateral,
        address liquidator,
        address borrower,
        uint repayAmount) override external returns (uint) {

        liquidator;

        if (!markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        uint borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(borrower);

        if (isDeprecated(CToken(cTokenBorrowed))) {
            require(borrowBalance >= repayAmount, "Can not repay more than the total borrow");
        } else {

            (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower);
            if (err != Error.NO_ERROR) {
                return uint(err);
            }

            if (shortfall == 0) {
                return uint(Error.INSUFFICIENT_SHORTFALL);
            }

            uint maxClose = mul_ScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance);
            if (repayAmount > maxClose) {
                return uint(Error.TOO_MUCH_REPAY);
            }
        }
        return uint(Error.NO_ERROR);
    }

    function liquidateBorrowVerify(
        address cTokenBorrowed,
        address cTokenCollateral,
        address liquidator,
        address borrower,
        uint actualRepayAmount,
        uint seizeTokens) override external {

        cTokenBorrowed;
        cTokenCollateral;
        liquidator;
        borrower;
        actualRepayAmount;
        seizeTokens;

        if (false) {
            maxAssets = maxAssets;
        }
    }

    function seizeAllowed(
        address cTokenCollateral,
        address cTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) override external returns (uint) {

        require(!seizeGuardianPaused, "seize is paused");

        seizeTokens;

        if (!markets[cTokenCollateral].isListed || !markets[cTokenBorrowed].isListed) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        if (CToken(cTokenCollateral).comptroller() != CToken(cTokenBorrowed).comptroller()) {
            return uint(Error.COMPTROLLER_MISMATCH);
        }

        return uint(Error.NO_ERROR);
    }

    function seizeVerify(
        address cTokenCollateral,
        address cTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) override external {

        cTokenCollateral;
        cTokenBorrowed;
        liquidator;
        borrower;
        seizeTokens;

        if (false) {
            maxAssets = maxAssets;
        }
    }

    function transferAllowed(address cToken, address src, address dst, uint transferTokens) override external returns (uint) {

        require(!transferGuardianPaused, "transfer is paused");

        uint allowed = redeemAllowedInternal(cToken, src, transferTokens);
        if (allowed != uint(Error.NO_ERROR)) {
            return allowed;
        }

        return uint(Error.NO_ERROR);
    }

    function transferVerify(address cToken, address src, address dst, uint transferTokens) override external {

        cToken;
        src;
        dst;
        transferTokens;

        if (false) {
            maxAssets = maxAssets;
        }
    }

    struct AccountLiquidityLocalVars {
        uint sumCollateral;
        uint sumBorrowPlusEffects;
        uint cTokenBalance;
        uint borrowBalance;
        uint exchangeRateMantissa;
        uint oraclePriceMantissa;
        Exp collateralFactor;
        Exp exchangeRate;
        Exp oraclePrice;
        Exp tokensToDenom;
    }

    function getAccountLiquidity(address account) public view returns (uint, uint, uint) {
        (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(address(0)), 0, 0);

        return (uint(err), liquidity, shortfall);
    }

    function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) {
        return getHypotheticalAccountLiquidityInternal(account, CToken(address(0)), 0, 0);
    }

    function getHypotheticalAccountLiquidity(
        address account,
        address cTokenModify,
        uint redeemTokens,
        uint borrowAmount) public view returns (uint, uint, uint) {
        (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(cTokenModify), redeemTokens, borrowAmount);
        return (uint(err), liquidity, shortfall);
    }

    function getHypotheticalAccountLiquidityInternal(
        address account,
        CToken cTokenModify,
        uint redeemTokens,
        uint borrowAmount) internal view returns (Error, uint, uint) {

        AccountLiquidityLocalVars memory vars; 
        uint oErr;

        CToken[] memory assets = accountAssets[account];
        for (uint i = 0; i < assets.length; i++) {
            CToken asset = assets[i];

            (oErr, vars.cTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot(account);
            if (oErr != 0) { 
                return (Error.SNAPSHOT_ERROR, 0, 0);
            }
            vars.collateralFactor = Exp({mantissa: markets[address(asset)].collateralFactorMantissa});
            vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa});

            vars.oraclePriceMantissa = getUnderlyingPrice(asset);
            if (vars.oraclePriceMantissa == 0) {
                return (Error.PRICE_ERROR, 0, 0);
            }
            vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa});

            vars.tokensToDenom = mul_(mul_(vars.collateralFactor, vars.exchangeRate), vars.oraclePrice);

            vars.sumCollateral = mul_ScalarTruncateAddUInt(vars.tokensToDenom, vars.cTokenBalance, vars.sumCollateral);

            vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects);

            if (asset == cTokenModify) {

                vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.tokensToDenom, redeemTokens, vars.sumBorrowPlusEffects);

                vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects);
            }
        }

        if (vars.sumCollateral > vars.sumBorrowPlusEffects) {
            return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0);
        } else {
            return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral);
        }
    }

    function liquidateCalculateSeizeTokens(address cTokenBorrowed, address cTokenCollateral, uint actualRepayAmount) override external view returns (uint, uint) {

        uint priceBorrowedMantissa = getUnderlyingPrice(CToken(cTokenBorrowed));
        uint priceCollateralMantissa = getUnderlyingPrice(CToken(cTokenCollateral));
        if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {
            return (uint(Error.PRICE_ERROR), 0);
        }

        uint exchangeRateMantissa = CToken(cTokenCollateral).exchangeRateStored(); 
        uint seizeTokens;
        Exp memory numerator;
        Exp memory denominator;
        Exp memory ratio;

        numerator = mul_(Exp({mantissa: liquidationIncentiveMantissa}), Exp({mantissa: priceBorrowedMantissa}));
        denominator = mul_(Exp({mantissa: priceCollateralMantissa}), Exp({mantissa: exchangeRateMantissa}));
        ratio = div_(numerator, denominator);

        seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);

        return (uint(Error.NO_ERROR), seizeTokens);
    }

    function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint) {

    	require(msg.sender == admin, "only admin can set close factor");

        uint oldCloseFactorMantissa = closeFactorMantissa;
        closeFactorMantissa = newCloseFactorMantissa;
        emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);

        return uint(Error.NO_ERROR);
    }

    function _setCollateralFactor(CToken cToken, uint newCollateralFactorMantissa) external returns (uint) {

        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK);
        }

        Market storage market = markets[address(cToken)];
        if (!market.isListed) {
            return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS);
        }

        Exp memory newCollateralFactorExp = Exp({mantissa: newCollateralFactorMantissa});

        Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});
        if (lessThanExp(highLimit, newCollateralFactorExp)) {
            return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION);
        }

        if (newCollateralFactorMantissa != 0 && getUnderlyingPrice(cToken) == 0) {
            return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE);
        }

        uint oldCollateralFactorMantissa = market.collateralFactorMantissa;
        market.collateralFactorMantissa = newCollateralFactorMantissa;

        emit NewCollateralFactor(cToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);

        return uint(Error.NO_ERROR);
    }

    function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) {

        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK);
        }

        uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;

        liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;

        emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);

        return uint(Error.NO_ERROR);
    }

    function _supportMarket(CToken cToken) external returns (uint) {
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK);
        }

        if (markets[address(cToken)].isListed) {
            return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS);
        }

        cToken.isCToken(); 

        Market storage newMarket = markets[address(cToken)];
        newMarket.isListed = true;
        newMarket.isComped = false;
        newMarket.collateralFactorMantissa = 0;

        _addMarketInternal(address(cToken));
        _initializeMarket(address(cToken));

        emit MarketListed(cToken);

        return uint(Error.NO_ERROR);
    }

    function _addMarketInternal(address cToken) internal {
        for (uint i = 0; i < allMarkets.length; i ++) {
            require(allMarkets[i] != CToken(cToken), "market already added");
        }
        allMarkets.push(CToken(cToken));
    }

    function _initializeMarket(address cToken) internal {
        uint32 blockNumber = safe32(getBlockNumber(), "block number exceeds 32 bits");

        CompMarketState storage supplyState = compSupplyState[cToken];
        CompMarketState storage borrowState = compBorrowState[cToken];

        if (supplyState.index == 0) {

            supplyState.index = compInitialIndex;
        }

        if (borrowState.index == 0) {

            borrowState.index = compInitialIndex;
        }

         supplyState.block = borrowState.block = blockNumber;
    }

    function _setMarketBorrowCaps(CToken[] calldata cTokens, uint[] calldata newBorrowCaps) external {
    	require(msg.sender == admin || msg.sender == borrowCapGuardian, "only admin or borrow cap guardian can set borrow caps");

        uint numMarkets = cTokens.length;
        uint numBorrowCaps = newBorrowCaps.length;

        require(numMarkets != 0 && numMarkets == numBorrowCaps, "invalid input");

        for(uint i = 0; i < numMarkets; i++) {
            borrowCaps[address(cTokens[i])] = newBorrowCaps[i];
            emit NewBorrowCap(cTokens[i], newBorrowCaps[i]);
        }
    }

    function _setBorrowCapGuardian(address newBorrowCapGuardian) external {
        require(msg.sender == admin, "only admin can set borrow cap guardian");

        address oldBorrowCapGuardian = borrowCapGuardian;

        borrowCapGuardian = newBorrowCapGuardian;

        emit NewBorrowCapGuardian(oldBorrowCapGuardian, newBorrowCapGuardian);
    }

    function _setPauseGuardian(address newPauseGuardian) public returns (uint) {
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK);
        }

        address oldPauseGuardian = pauseGuardian;

        pauseGuardian = newPauseGuardian;

        emit NewPauseGuardian(oldPauseGuardian, pauseGuardian);

        return uint(Error.NO_ERROR);
    }

    function _setMintPaused(CToken cToken, bool state) public returns (bool) {
        require(markets[address(cToken)].isListed, "cannot pause a market that is not listed");
        require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause");
        require(msg.sender == admin || state == true, "only admin can unpause");

        mintGuardianPaused[address(cToken)] = state;
        emit ActionPaused(cToken, "Mint", state);
        return state;
    }

    function _setBorrowPaused(CToken cToken, bool state) public returns (bool) {
        require(markets[address(cToken)].isListed, "cannot pause a market that is not listed");
        require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause");
        require(msg.sender == admin || state == true, "only admin can unpause");

        borrowGuardianPaused[address(cToken)] = state;
        emit ActionPaused(cToken, "Borrow", state);
        return state;
    }

    function _setTransferPaused(bool state) public returns (bool) {
        require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause");
        require(msg.sender == admin || state == true, "only admin can unpause");

        transferGuardianPaused = state;
        emit ActionPaused("Transfer", state);
        return state;
    }

    function _setSeizePaused(bool state) public returns (bool) {
        require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause");
        require(msg.sender == admin || state == true, "only admin can unpause");

        seizeGuardianPaused = state;
        emit ActionPaused("Seize", state);
        return state;
    }

    function _become(Unitroller unitroller) public {
        require(msg.sender == unitroller.admin(), "only unitroller admin can change brains");
        require(unitroller._acceptImplementation() == 0, "change not authorized");
    }

    function fixBadAccruals(address[] calldata affectedUsers, uint[] calldata amounts) external {
        require(msg.sender == admin, "Only admin can call this function"); 
        require(!proposal65FixExecuted, "Already executed this one-off function"); 
        require(affectedUsers.length == amounts.length, "Invalid input");

        address user;
        uint currentAccrual;
        uint amountToSubtract;
        uint newAccrual;

        for (uint i = 0; i < affectedUsers.length; ++i) {
            user = affectedUsers[i];
            currentAccrual = compAccrued[user];

            amountToSubtract = amounts[i];

            if (amountToSubtract > currentAccrual) {

                uint accountReceivable = amountToSubtract - currentAccrual; 

                uint oldReceivable = compReceivable[user];
                uint newReceivable = add_(oldReceivable, accountReceivable);

                compReceivable[user] = newReceivable;

                emit CompReceivableUpdated(user, oldReceivable, newReceivable);

                amountToSubtract = currentAccrual;
            }

            if (amountToSubtract > 0) {

                compAccrued[user] = newAccrual = sub_(currentAccrual, amountToSubtract);

                emit CompAccruedAdjusted(user, currentAccrual, newAccrual);
            }
        }

        proposal65FixExecuted = true; 
    }

    function adminOrInitializing() internal view returns (bool) {
        return msg.sender == admin || msg.sender == comptrollerImplementation;
    }

    function getAllMarkets() public view returns (CToken[] memory) {
        return allMarkets;
    }

    function isDeprecated(CToken cToken) public view returns (bool) {
        return
            markets[address(cToken)].collateralFactorMantissa == 0 &&
            borrowGuardianPaused[address(cToken)] == true &&
            cToken.reserveFactorMantissa() == 1e18
        ;
    }

    function getBlockNumber() virtual public view returns (uint) {
        return block.number;
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CalldataMustHaveValidPayload","type":"error"},{"inputs":[],"name":"CalldataOverOrUnderFlow","type":"error"},{"inputs":[],"name":"CanNotPickMedianOfEmptyArray","type":"error"},{"inputs":[],"name":"EachSignerMustProvideTheSameValue","type":"error"},{"inputs":[],"name":"EmptyCalldataPointersArr","type":"error"},{"inputs":[],"name":"GetDataServiceIdNotImplemented","type":"error"},{"inputs":[],"name":"IncorrectUnsignedMetadataSize","type":"error"},{"inputs":[{"internalType":"uint256","name":"receivedSignersCount","type":"uint256"},{"internalType":"uint256","name":"requiredSignersCount","type":"uint256"}],"name":"InsufficientNumberOfUniqueSigners","type":"error"},{"inputs":[],"name":"InvalidCalldataPointer","type":"error"},{"inputs":[{"internalType":"address","name":"receivedSigner","type":"address"}],"name":"SignerNotAuthorised","type":"error"},{"inputs":[{"internalType":"uint256","name":"receivedTimestampSeconds","type":"uint256"},{"internalType":"uint256","name":"blockTimestamp","type":"uint256"}],"name":"TimestampFromTooLongFuture","type":"error"},{"inputs":[{"internalType":"uint256","name":"receivedTimestampSeconds","type":"uint256"},{"internalType":"uint256","name":"blockTimestamp","type":"uint256"}],"name":"TimestampIsTooOld","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldCompAccrued","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCompAccrued","type":"uint256"}],"name":"CompAccruedAdjusted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"CompBorrowSpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CompGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldCompReceivable","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCompReceivable","type":"uint256"}],"name":"CompReceivableUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"CompSupplySpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contributor","type":"address"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"ContributorCompSpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"compDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"compBorrowIndex","type":"uint256"}],"name":"DistributedBorrowerComp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":true,"internalType":"address","name":"supplier","type":"address"},{"indexed":false,"internalType":"uint256","name":"compDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"compSupplyIndex","type":"uint256"}],"name":"DistributedSupplierComp","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketEntered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketExited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"MarketListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newBorrowCap","type":"uint256"}],"name":"NewBorrowCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldBorrowCapGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newBorrowCapGuardian","type":"address"}],"name":"NewBorrowCapGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCloseFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCloseFactorMantissa","type":"uint256"}],"name":"NewCloseFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldCollateralFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"NewCollateralFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLiquidationIncentiveMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidationIncentiveMantissa","type":"uint256"}],"name":"NewLiquidationIncentive","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPauseGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newPauseGuardian","type":"address"}],"name":"NewPauseGuardian","type":"event"},{"inputs":[{"internalType":"contract Unitroller","name":"unitroller","type":"address"}],"name":"_become","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"_borrowGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_mintGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newBorrowCapGuardian","type":"address"}],"name":"_setBorrowCapGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"_setBorrowPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCloseFactorMantissa","type":"uint256"}],"name":"_setCloseFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"},{"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"_setCollateralFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLiquidationIncentiveMantissa","type":"uint256"}],"name":"_setLiquidationIncentive","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken[]","name":"cTokens","type":"address[]"},{"internalType":"uint256[]","name":"newBorrowCaps","type":"uint256[]"}],"name":"_setMarketBorrowCaps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"_setMintPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPauseGuardian","type":"address"}],"name":"_setPauseGuardian","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"_setSeizePaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"_setTransferPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"_supportMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"accountAssets","outputs":[{"internalType":"contract CToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"aggregateValues","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allMarkets","outputs":[{"internalType":"contract CToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowCapGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"closeFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compAccrued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compBorrowSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compBorrowState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"compBorrowerIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compContributorSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compInitialIndex","outputs":[{"internalType":"uint224","name":"","type":"uint224"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compReceivable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"compSupplierIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compSupplySpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compSupplyState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"comptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"cTokens","type":"address[]"}],"name":"enterMarkets","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenAddress","type":"address"}],"name":"exitMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"affectedUsers","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"fixBadAccruals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllMarkets","outputs":[{"internalType":"contract CToken[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAssetsIn","outputs":[{"internalType":"contract CToken[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"signerAddress","type":"address"}],"name":"getAuthorisedSignerIndex","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDataServiceId","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"cTokenModify","type":"address"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"getHypotheticalAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"getUnderlyingPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUniqueSignersThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isComptroller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"isDeprecated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastContributorBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"liquidateBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"liquidateBorrowVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"}],"name":"liquidateCalculateSeizeTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationIncentiveMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"markets","outputs":[{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint256","name":"collateralFactorMantissa","type":"uint256"},{"internalType":"bool","name":"isComped","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mintAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mintGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"actualMintAmount","type":"uint256"},{"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"mintVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingComptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposal65FixExecuted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"borrowerIndex","type":"uint256"}],"name":"repayBorrowVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"seizeGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transferGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"receivedTimestampMilliseconds","type":"uint256"}],"name":"validateTimestamp","outputs":[],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b50600080546001600160a01b03191633179055614d58806100326000396000f3fe608060405234801561001057600080fd5b506004361061045e5760003560e01c806387f763031161024c578063c274583a11610146578063e6653f3d116100c3578063f4a433c011610087578063f4a433c014610bc9578063f50b2efe14610be9578063f851a44014610bfc578063f90c492414610c0f578063fc57d4df14610c1657600080fd5b8063e6653f3d14610b79578063e875544614610b8d578063eabe7d9114610b96578063ede4edd014610ba9578063f00a7a9214610bbc57600080fd5b8063d02f73511161010a578063d02f735114610b1a578063da3d454c14610b2d578063dce1544914610b40578063dcfbc0c714610b53578063e4028eee14610b6657600080fd5b8063c274583a14610a50578063c299823814610a87578063c488847b14610aa7578063ca0af04314610acf578063cc7ebdc414610afa57600080fd5b8063a7f0e231116101d4578063b21be7fd11610198578063b21be7fd146109cc578063b24ebfcc146109f7578063bb82aa5e14610a0a578063bdcdc25814610a1d578063bea6b8b814610a3057600080fd5b8063a7f0e23114610959578063aa90075414610987578063abfceffc14610990578063ac0b0bb7146109b0578063b0772d0b146109c457600080fd5b8063929fe9a11161021b578063929fe9a1146108c957806394543c151461090a57806394b2294b1461091d578063986ab83814610926578063a76b3fda1461094657600080fd5b806387f76303146108175780638c57804e1461082b5780638e8f294b146108635780638ebf6364146108b657600080fd5b80634a5844321161035d5780635f5af1aa116102e55780636b79c38d116102a95780636b79c38d146107475780636d154ea5146107a35780636d35bf91146107c6578063731f0c2b146107d457806385b7beb8146107f757600080fd5b80635f5af1aa146106e05780635fc7e71e146106f3578063607ef6c1146107065780636a56947e146107195780636aa875b51461072757600080fd5b80634fd42e171161032c5780634fd42e171461068157806351dff9891461069457806352d84d1e146106a75780635c778605146106ba5780635ec88c79146106cd57600080fd5b80634a584432146106175780634ada90af146106375780634e79238f146106405780634ef4c3e11461066e57600080fd5b806326782247116103eb5780633c94786f116103af5780633c94786f146105ae5780633ce142f5146105c257806341c728b9146105e757806342cbb15c146105fb57806347ef3b3b1461060157600080fd5b8063267822471461054f5780632d70db7814610562578063317b0b7714610575578063391957d7146105885780633bcf7ec11461059b57600080fd5b80631d7b33d7116104325780631d7b33d7146104bb5780631ededc91146104e957806321af4569146104fe57806324008a621461052957806324a3d6221461053c57600080fd5b80627e3dd21461046357806316b95e8f1461048057806318c882a5146104955780631d504dc6146104a8575b600080fd5b61046b600181565b60405190151581526020015b60405180910390f35b61049361048e36600461444d565b610c29565b005b61046b6104a33660046144dc565b610ed2565b6104936104b6366004614515565b61100b565b6104db6104c9366004614515565b600e6020526000908152604090205481565b604051908152602001610477565b6104936104f7366004614532565b5050505050565b601454610511906001600160a01b031681565b6040516001600160a01b039091168152602001610477565b6104db61053736600461458d565b611189565b600954610511906001600160a01b031681565b600154610511906001600160a01b031681565b61046b6105703660046145de565b6111bd565b6104db6105833660046145fb565b6112ad565b610493610596366004614515565b611354565b61046b6105a93660046144dc565b61141e565b60095461046b90600160a01b900460ff1681565b6105d56105d0366004614515565b611548565b60405160ff9091168152602001610477565b6104936105f5366004614614565b50505050565b436104db565b61049361060f36600461465a565b505050505050565b6104db610625366004614515565b60156020526000908152604090205481565b6104db60055481565b61065361064e366004614614565b61164a565b60408051938452602084019290925290820152606001610477565b6104db61067c3660046146c8565b61168a565b6104db61068f3660046145fb565b611718565b6104936106a2366004614614565b611775565b6105116106b53660046145fb565b6117c4565b6104936106c83660046146c8565b505050565b6106536106db366004614515565b6117ee565b6104db6106ee366004614515565b611829565b6104db610701366004614709565b6118a2565b61049361071436600461444d565b611a74565b6104936105f536600461458d565b6104db610735366004614515565b60196020526000908152604090205481565b61077f610755366004614515565b600f602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b604080516001600160e01b03909316835263ffffffff909116602083015201610477565b61046b6107b1366004614515565b600b6020526000908152604090205460ff1681565b6104936104f7366004614709565b61046b6107e2366004614515565b600a6020526000908152604090205460ff1681565b6104db610805366004614515565b601b6020526000908152604090205481565b60095461046b90600160b01b900460ff1681565b61077f610839366004614515565b6010602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b610897610871366004614515565b60086020526000908152604090208054600182015460039092015460ff91821692911683565b6040805193151584526020840192909252151590820152606001610477565b61046b6108c43660046145de565b611c52565b61046b6108d736600461476d565b6001600160a01b038082166000908152600860209081526040808320938616835260029093019052205460ff1692915050565b61046b610918366004614515565b611d39565b6104db60065481565b6104db610934366004614515565b60166020526000908152604090205481565b6104db610954366004614515565b611df8565b61096f6ec097ce7bc90715b34b9f100000000081565b6040516001600160e01b039091168152602001610477565b6104db600d5481565b6109a361099e366004614515565b611f2a565b604051610477919061479b565b60095461046b90600160b81b900460ff1681565b6109a3611fa0565b6104db6109da36600461476d565b601160209081526000928352604080842090915290825290205481565b6104db610a05366004614853565b612002565b600254610511906001600160a01b031681565b6104db610a2b36600461458d565b61200d565b6104db610a3e366004614515565b60176020526000908152604090205481565b60408051808201825260158152741c99591cdd1bdb994b5c1c9a5b585c9e4b5c1c9bd9605a1b602082015290516104779190614902565b610a9a610a95366004614935565b612087565b60405161047791906149c4565b610aba610ab53660046146c8565b61214f565b60408051928352602083019190915201610477565b6104db610add36600461476d565b601260209081526000928352604080842090915290825290205481565b6104db610b08366004614515565b60136020526000908152604090205481565b6104db610b28366004614709565b61229b565b6104db610b3b3660046146c8565b612419565b610511610b4e3660046149fc565b6126fc565b600354610511906001600160a01b031681565b6104db610b743660046149fc565b612734565b60095461046b90600160a81b900460ff1681565b6104db60045481565b6104db610ba43660046146c8565b612860565b6104db610bb7366004614515565b612888565b601a5461046b9060ff1681565b6104db610bd7366004614515565b60186020526000908152604090205481565b610493610bf73660046145fb565b612be3565b600054610511906001600160a01b031681565b60036105d5565b6104db610c24366004614515565b612bec565b6000546001600160a01b03163314610c925760405162461bcd60e51b815260206004820152602160248201527f4f6e6c792061646d696e2063616e2063616c6c20746869732066756e6374696f6044820152603760f91b60648201526084015b60405180910390fd5b601a5460ff1615610cf45760405162461bcd60e51b815260206004820152602660248201527f416c72656164792065786563757465642074686973206f6e652d6f66662066756044820152653731ba34b7b760d11b6064820152608401610c89565b828114610d335760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b6044820152606401610c89565b60008060008060005b87811015610eba57888882818110610d5657610d56614a28565b9050602002016020810190610d6b9190614515565b6001600160a01b0381166000908152601360205260409020549095509350868682818110610d9b57610d9b614a28565b90506020020135925083831115610e3f576000610db88585614a54565b6001600160a01b0387166000908152601b6020526040812054919250610dde8284613109565b6001600160a01b0389166000818152601b6020908152604091829020849055815186815290810184905292935090917f17fea09d9a7ca41b2f9f9118f18f44848a62e9c70d55dd4385131eb2cf1b7e47910160405180910390a28695505050505b8215610eaa57610e4f8484613115565b6001600160a01b038616600081815260136020908152604091829020849055815188815290810184905292945090917f4a5c134e28b537a76546993ea37f3b60d9190476df7356d3842aa40902e20f04910160405180910390a25b610eb381614a67565b9050610d3c565b5050601a805460ff1916600117905550505050505050565b6001600160a01b03821660009081526008602052604081205460ff16610f0a5760405162461bcd60e51b8152600401610c8990614a80565b6009546001600160a01b0316331480610f2d57506000546001600160a01b031633145b610f495760405162461bcd60e51b8152600401610c8990614ac8565b6000546001600160a01b0316331480610f6457506001821515145b610f805760405162461bcd60e51b8152600401610c8990614b0f565b6001600160a01b0383166000818152600b6020908152604091829020805460ff19168615159081179091558251938452606091840182905260069184019190915265426f72726f7760d01b6080840152908201527f71aec636243f9709bb0007ae15e9afb8150ab01716d75fd7573be5cc096e03b09060a0015b60405180910390a150805b92915050565b806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611049573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106d9190614b3f565b6001600160a01b0316336001600160a01b0316146110dd5760405162461bcd60e51b815260206004820152602760248201527f6f6e6c7920756e6974726f6c6c65722061646d696e2063616e206368616e676560448201526620627261696e7360c81b6064820152608401610c89565b806001600160a01b031663c1e803346040518163ffffffff1660e01b81526004016020604051808303816000875af115801561111d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111419190614b5c565b156111865760405162461bcd60e51b815260206004820152601560248201527418da185b99d9481b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610c89565b50565b6001600160a01b03841660009081526008602052604081205460ff166111b1575060096111b5565b5060005b949350505050565b6009546000906001600160a01b03163314806111e357506000546001600160a01b031633145b6111ff5760405162461bcd60e51b8152600401610c8990614ac8565b6000546001600160a01b031633148061121a57506001821515145b6112365760405162461bcd60e51b8152600401610c8990614b0f565b60098054831515600160b81b0260ff60b81b199091161790556040517fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de0906112a19084906040808252600590820152645365697a6560d81b6060820152901515602082015260800190565b60405180910390a15090565b600080546001600160a01b031633146113085760405162461bcd60e51b815260206004820152601f60248201527f6f6e6c792061646d696e2063616e2073657420636c6f736520666163746f72006044820152606401610c89565b600480549083905560408051828152602081018590527f3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd991015b60405180910390a160005b9392505050565b6000546001600160a01b031633146113bd5760405162461bcd60e51b815260206004820152602660248201527f6f6e6c792061646d696e2063616e2073657420626f72726f772063617020677560448201526530b93234b0b760d11b6064820152608401610c89565b601480546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527feda98690e518e9a05f8ec6837663e188211b2da8f4906648b323f2c1d4434e29910160405180910390a15050565b6001600160a01b03821660009081526008602052604081205460ff166114565760405162461bcd60e51b8152600401610c8990614a80565b6009546001600160a01b031633148061147957506000546001600160a01b031633145b6114955760405162461bcd60e51b8152600401610c8990614ac8565b6000546001600160a01b03163314806114b057506001821515145b6114cc5760405162461bcd60e51b8152600401610c8990614b0f565b6001600160a01b0383166000818152600a6020908152604091829020805460ff19168615159081179091558251938452606091840182905260049184019190915263135a5b9d60e21b6080840152908201527f71aec636243f9709bb0007ae15e9afb8150ab01716d75fd7573be5cc096e03b09060a001610ffa565b60006001600160a01b038216738bb8f32df04c8b654987daaed53d6b6091e3b7740361157657506000919050565b6001600160a01b03821673deb22f54738d54976c4c0fe5ce6d408e40d88499036115a257506001919050565b6001600160a01b0382167351ce04be4b3e32572c4ec9135221d0691ba7d202036115ce57506002919050565b6001600160a01b03821673dd682daec5a90dd295d14da4b0bec9281017b5be036115fa57506003919050565b6001600160a01b038216739c5ae89c4af6aa32ce58588dbaf90d18a855b6de0361162657506004919050565b6040516303b1166f60e61b81526001600160a01b0383166004820152602401610c89565b60008060008060008061165f8a8a8a8a613121565b92509250925082601181111561167757611677614b75565b95509093509150505b9450945094915050565b6001600160a01b0383166000908152600a602052604081205460ff16156116e45760405162461bcd60e51b815260206004820152600e60248201526d1b5a5b9d081a5cc81c185d5cd95960921b6044820152606401610c89565b6001600160a01b03841660009081526008602052604090205460ff1661170e5760095b905061134d565b6000949350505050565b600080546001600160a01b03163314611737576110056001600b6133f4565b600580549083905560408051828152602081018590527faeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec13169101611342565b801580156117835750600082115b156105f55760405162461bcd60e51b815260206004820152601160248201527072656465656d546f6b656e73207a65726f60781b6044820152606401610c89565b600c81815481106117d457600080fd5b6000918252602090912001546001600160a01b0316905081565b600080600080600080611805876000806000613121565b92509250925082601181111561181d5761181d614b75565b97919650945092505050565b600080546001600160a01b0316331461184857611005600160136133f4565b600980546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f0613b6ee6a04f0d09f390e4d9318894b9f6ac7fd83897cd8d18896ba579c401e9101611342565b6001600160a01b03851660009081526008602052604081205460ff1615806118e357506001600160a01b03851660009081526008602052604090205460ff16155b156118f25760095b9050611a6b565b6040516395dd919360e01b81526001600160a01b038481166004830152600091908816906395dd919390602401602060405180830381865afa15801561193c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119609190614b5c565b905061196b87611d39565b156119d657828110156119d15760405162461bcd60e51b815260206004820152602860248201527f43616e206e6f74207265706179206d6f7265207468616e2074686520746f74616044820152676c20626f72726f7760c01b6064820152608401610c89565b611a65565b6000806119e28661346d565b919350909150600090508260118111156119fe576119fe614b75565b14611a1f57816011811115611a1557611a15614b75565b9350505050611a6b565b80600003611a2e576003611a15565b6000611a4a60405180602001604052806004548152508561348d565b905080861115611a61576011945050505050611a6b565b5050505b60009150505b95945050505050565b6000546001600160a01b0316331480611a9757506014546001600160a01b031633145b611b015760405162461bcd60e51b815260206004820152603560248201527f6f6e6c792061646d696e206f7220626f72726f772063617020677561726469616044820152746e2063616e2073657420626f72726f77206361707360581b6064820152608401610c89565b82818115801590611b1157508082145b611b4d5760405162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081a5b9c1d5d609a1b6044820152606401610c89565b60005b82811015611c4957848482818110611b6a57611b6a614a28565b9050602002013560156000898985818110611b8757611b87614a28565b9050602002016020810190611b9c9190614515565b6001600160a01b03168152602081019190915260400160002055868682818110611bc857611bc8614a28565b9050602002016020810190611bdd9190614515565b6001600160a01b03167f6f1951b2aad10f3fc81b86d91105b413a5b3f847a34bbc5ce1904201b14438f6868684818110611c1957611c19614a28565b90506020020135604051611c2f91815260200190565b60405180910390a280611c4181614a67565b915050611b50565b50505050505050565b6009546000906001600160a01b0316331480611c7857506000546001600160a01b031633145b611c945760405162461bcd60e51b8152600401610c8990614ac8565b6000546001600160a01b0316331480611caf57506001821515145b611ccb5760405162461bcd60e51b8152600401610c8990614b0f565b60098054831515600160b01b0260ff60b01b199091161790556040517fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de0906112a19084906040808252600890820152672a3930b739b332b960c11b6060820152901515602082015260800190565b6001600160a01b038116600090815260086020526040812060010154158015611d7f57506001600160a01b0382166000908152600b602052604090205460ff1615156001145b80156110055750816001600160a01b031663173b99046040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de89190614b5c565b670de0b6b3a76400001492915050565b600080546001600160a01b03163314611e1757611005600160126133f4565b6001600160a01b03821660009081526008602052604090205460ff1615611e4457611005600a60116133f4565b816001600160a01b031663fe9c44ae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea69190614b8b565b506001600160a01b03821660009081526008602052604081208054600160ff1991821681178355600383018054909216909155810191909155611ee8836134a5565b611ef18361358d565b6040516001600160a01b03841681527fcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f90602001611342565b6001600160a01b0381166000908152600760209081526040808320805482518185028101850190935280835260609493830182828015611f9357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f75575b5093979650505050505050565b6060600c805480602002602001604051908101604052809291908181526020018280548015611ff857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611fda575b5050505050905090565b600061100582613689565b600954600090600160b01b900460ff161561205f5760405162461bcd60e51b81526020600482015260126024820152711d1c985b9cd9995c881a5cc81c185d5cd95960721b6044820152606401610c89565b600061206c868685613694565b9050801561207b5790506111b5565b60009695505050505050565b805160609060008167ffffffffffffffff8111156120a7576120a76147e8565b6040519080825280602002602001820160405280156120d0578160200160208202803683370190505b50905060005b828110156121475760008582815181106120f2576120f2614a28565b60200260200101519050612106813361374c565b601181111561211757612117614b75565b83838151811061212957612129614a28565b6020908102919091010152508061213f81614a67565b9150506120d6565b509392505050565b600080600061215d86612bec565b9050600061216a86612bec565b9050811580612177575080155b1561218b57600d6000935093505050612293565b6000866001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ef9190614b5c565b905060006122096040518060200160405280600081525090565b60408051602080820183526000808352835180830185529081528351808301855260055481528451928301909452888252919261224591613840565b925061226d604051806020016040528088815250604051806020016040528088815250613840565b91506122798383613888565b9050612285818b61348d565b600099509750505050505050505b935093915050565b600954600090600160b81b900460ff16156122ea5760405162461bcd60e51b815260206004820152600f60248201526e1cd95a5e99481a5cc81c185d5cd959608a1b6044820152606401610c89565b6001600160a01b03861660009081526008602052604090205460ff16158061232b57506001600160a01b03851660009081526008602052604090205460ff16155b156123375760096118eb565b846001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612375573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123999190614b3f565b6001600160a01b0316866001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124049190614b3f565b6001600160a01b03161461207b5760026118eb565b6001600160a01b0383166000908152600b602052604081205460ff16156124755760405162461bcd60e51b815260206004820152601060248201526f189bdc9c9bddc81a5cc81c185d5cd95960821b6044820152606401610c89565b6001600160a01b03841660009081526008602052604090205460ff1661249c576009611707565b6001600160a01b038085166000908152600860209081526040808320938716835260029093019052205460ff1661259957336001600160a01b0385161461251d5760405162461bcd60e51b815260206004820152601560248201527439b2b73232b91036bab9ba1031329031aa37b5b2b760591b6044820152606401610c89565b6000612529338561374c565b9050600081601181111561253f5761253f614b75565b1461255e5780601181111561255657612556614b75565b91505061134d565b6001600160a01b038086166000908152600860209081526040808320938816835260029093019052205460ff1661259757612597614ba8565b505b6125a284612bec565b6000036125b057600d611707565b6001600160a01b0384166000908152601560205260409020548015612695576000856001600160a01b03166347bd37186040518163ffffffff1660e01b8152600401602060405180830381865afa15801561260f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126339190614b5c565b905060006126418286613109565b90508281106126925760405162461bcd60e51b815260206004820152601960248201527f6d61726b657420626f72726f77206361702072656163686564000000000000006044820152606401610c89565b50505b6000806126a58688600088613121565b919350909150600090508260118111156126c1576126c1614b75565b146126e2578160118111156126d8576126d8614b75565b935050505061134d565b80156126ef5760046126d8565b6000979650505050505050565b6007602052816000526040600020818154811061271857600080fd5b6000918252602090912001546001600160a01b03169150829050565b600080546001600160a01b0316331461275a57612753600160066133f4565b9050611005565b6001600160a01b0383166000908152600860205260409020805460ff1661278f57612787600960076133f4565b915050611005565b60408051602080820183528582528251908101909252670c7d713b49da00008252906127bd81835190511090565b156127d8576127ce600660086133f4565b9350505050611005565b84158015906127ed57506127eb86612bec565b155b156127fe576127ce600d60096133f4565b60018301805490869055604080516001600160a01b0389168152602081018390529081018790527f70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc59060600160405180910390a160005b979650505050505050565b60008061286e858585613694565b9050801561287d57905061134d565b600095945050505050565b6040516361bfb47160e11b815233600482015260009082908290819081906001600160a01b0385169063c37f68e290602401608060405180830381865afa1580156128d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fb9190614bbe565b50925092509250826000146129605760405162461bcd60e51b815260206004820152602560248201527f657869744d61726b65743a206765744163636f756e74536e617073686f742066604482015264185a5b195960da1b6064820152608401610c89565b801561297c57612972600c60026133f4565b9695505050505050565b6000612989873385613694565b9050801561299e57612855600e6003836138c2565b6001600160a01b0385166000908152600860209081526040808320338452600281019092529091205460ff166129dd5760005b98975050505050505050565b3360009081526002820160209081526040808320805460ff191690556007825280832080548251818502810185019093528083529192909190830182828015612a4f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a31575b5050835193945083925060009150505b82811015612ab357896001600160a01b0316848281518110612a8357612a83614a28565b60200260200101516001600160a01b031603612aa157809150612ab3565b80612aab81614a67565b915050612a5f565b50818110612ac357612ac3614ba8565b33600090815260076020526040902080548190612ae290600190614a54565b81548110612af257612af2614a28565b9060005260206000200160009054906101000a90046001600160a01b0316818381548110612b2257612b22614a28565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555080805480612b6057612b60614bf4565b600082815260209020810160001990810180546001600160a01b03191690550190556040517fe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d90612bc9908c9033906001600160a01b0392831681529116602082015260400190565b60405180910390a160009c9b505050505050505050505050565b6111868161393a565b6000806000604051602001612c0b90630c68aa8960e31b815260040190565b60405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612c5f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612c879190810190614c0a565b604051602001612c979190614c9e565b6040516020818303038152906040528051906020012003612cc857612cc16208aa8960eb1b6139be565b9150613102565b604051640c6ae8aa8960db1b602082015260250160405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612d30573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d589190810190614c0a565b604051602001612d689190614c9e565b6040516020818303038152906040528051906020012003612d9257612cc16208aa8960eb1b6139be565b60405164635553444360d81b602082015260250160405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612dfa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e229190810190614c0a565b604051602001612e329190614c9e565b6040516020818303038152906040528051906020012003612e6c57612e5d635553444360e01b6139be565b612cc19064e8d4a51000614cba565b6040516418d554d11560da1b602082015260250160405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612ed4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612efc9190810190614c0a565b604051602001612f0c9190614c9e565b6040516020818303038152906040528051906020012003612f3757612e5d631554d11560e21b6139be565b60405164635742544360d81b602082015260250160405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612f9f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fc79190810190614c0a565b604051602001612fd79190614c9e565b6040516020818303038152906040528051906020012003613010576130016242544360e81b6139be565b612cc1906402540be400614cba565b6000846001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015613050573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130749190614b3f565b6001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156130b1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130d99190810190614c0a565b905060008082905080516000036130ef57600091505b60208301519150819350612855846139be565b5092915050565b600061134d8284614cd1565b600061134d8284614a54565b600080600061312e61435f565b6001600160a01b03881660009081526007602090815260408083208054825181850281018501909352808352849383018282801561319557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613177575b5050505050905060005b815181101561339e5760008282815181106131bc576131bc614a28565b60209081029190910101516040516361bfb47160e11b81526001600160a01b038e811660048301529192509082169063c37f68e290602401608060405180830381865afa158015613211573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132359190614bbe565b6080890152606088015260408701529350831561326157600f6000809750975097505050505050611680565b60408051602080820183526001600160a01b03841660009081526008825283902060010154825260c088019190915281519081019091526080860151815260e08601526132ad81612bec565b60a086018190526000036132d057600d6000809750975097505050505050611680565b604080516020810190915260a0860151815261010086015260c085015160e086015161330a916132ff91613840565b866101000151613840565b610120860181905260408601518651613324929190613a2e565b855261010085015160608601516020870151613341929190613a2e565b60208601526001600160a01b03808c169082160361338b5761336d8561012001518b8760200151613a2e565b60208601819052610100860151613385918b90613a2e565b60208601525b508061339681614a67565b91505061319f565b506020830151835111156133cf57602083015183516000916133bf91614a54565b6000955095509550505050611680565b600080846000015185602001516133e69190614a54565b955095509550505050611680565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601181111561342957613429614b75565b83601381111561343b5761343b614b75565b60408051928352602083019190915260009082015260600160405180910390a182601181111561134d5761134d614b75565b6000806000613480846000806000613121565b9250925092509193909250565b60008061349a8484613a4f565b90506111b581613a77565b60005b600c5481101561353a57816001600160a01b0316600c82815481106134cf576134cf614a28565b6000918252602090912001546001600160a01b0316036135285760405162461bcd60e51b81526020600482015260146024820152731b585c9ad95d08185b1c9958591e48185919195960621b6044820152606401610c89565b8061353281614a67565b9150506134a8565b50600c80546001810182556000919091527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180546001600160a01b0319166001600160a01b0392909216919091179055565b60006135ce436040518060400160405280601c81526020017f626c6f636b206e756d6265722065786365656473203332206269747300000000815250613a8f565b6001600160a01b0383166000908152600f60209081526040808320601090925282208154939450909290916001600160e01b03909116900361362a5781546001600160e01b0319166ec097ce7bc90715b34b9f10000000001782555b80546001600160e01b031660000361365c5780546001600160e01b0319166ec097ce7bc90715b34b9f10000000001781555b805463ffffffff909316600160e01b026001600160e01b0393841681179091558154909216909117905550565b600061100582613abf565b6001600160a01b03831660009081526008602052604081205460ff166136bb576009611707565b6001600160a01b038085166000908152600860209081526040808320938716835260029093019052205460ff166136f3576000611707565b6000806137038587866000613121565b9193509091506000905082601181111561371f5761371f614b75565b1461373f5781601181111561373657613736614b75565b9250505061134d565b801561207b576004613736565b6001600160a01b0382166000908152600860205260408120805460ff16613777576009915050611005565b6001600160a01b038316600090815260028201602052604090205460ff1615156001036137a8576000915050611005565b6001600160a01b03838116600081815260028401602090815260408083208054600160ff199091168117909155600783528184208054918201815584529282902090920180546001600160a01b031916948916948517905581519384528301919091527f3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5910160405180910390a15060009392505050565b6040805160208101909152600081526040518060200160405280670de0b6b3a764000061387586600001518660000151613b7a565b61387f9190614cfa565b90529392505050565b604080516020810190915260008152604051806020016040528061387f6138bb8660000151670de0b6b3a7640000613b7a565b8551613b86565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08460118111156138f7576138f7614b75565b84601381111561390957613909614b75565b604080519283526020830191909152810184905260600160405180910390a18360118111156111b5576111b5614b75565b60006139486103e883614cfa565b90508042101561398a57603c61395e4283614a54565b11156139865760405163b6b0916d60e01b815260048101829052426024820152604401610c89565b5050565b60b46139968242614a54565b111561398657604051630321d0b560e01b815260048101829052426024820152604401610c89565b6040805160018082528183019092526000918291906020808301908036833701905050905082816000815181106139f7576139f7614a28565b602002602001018181525050613a0c81613b92565b600081518110613a1e57613a1e614a28565b6020026020010151915050919050565b600080613a3b8585613a4f565b9050611a6b613a4982613a77565b84613109565b604080516020810190915260008152604051806020016040528061387f856000015185613b7a565b805160009061100590670de0b6b3a764000090614cfa565b6000816401000000008410613ab75760405162461bcd60e51b8152600401610c899190614902565b509192915050565b60008151600003613ae357604051639e198af960e01b815260040160405180910390fd5b613aec82613b9d565b600060028351613afc9190614cfa565b905060028351613b0c9190614d0e565b600003613b68576000613b5b84613b24600185614a54565b81518110613b3457613b34614a28565b6020026020010151858481518110613b4e57613b4e614a28565b6020026020010151613109565b90506111b5600282614cfa565b828181518110613a1e57613a1e614a28565b600061134d8284614cba565b600061134d8284614cfa565b606061100582613be5565b8051602082016020820281019150805b828110156105f557815b81811015613bdc578151815180821015613bd2578084528183525b5050602001613bb7565b50602001613bad565b60606000825167ffffffffffffffff811115613c0357613c036147e8565b604051908082528060200260200182016040528015613c2c578160200160208202803683370190505b5090506000835167ffffffffffffffff811115613c4b57613c4b6147e8565b604051908082528060200260200182016040528015613c74578160200160208202803683370190505b5090506000845167ffffffffffffffff811115613c9357613c936147e8565b604051908082528060200260200182016040528015613cc657816020015b6060815260200190600190039081613cb15790505b50905060005b8551811015613d245760408051600380825260808201909252906020820160608036833701905050828281518110613d0657613d06614a28565b60200260200101819052508080613d1c90614a67565b915050613ccc565b506000613d2f613d9e565b90506000613d3c82613e45565b61ffff169050613d4d600283614cd1565b60405190925060005b82811015613d93576000613d6d8a89898989613e7f565b9050613d798186614cd1565b945082604052508080613d8b90614a67565b915050613d56565b506129d1848761411f565b60006602ed57011e0000601f1936013581161480613dcf576040516373bb264f60e11b815260040160405180910390fd5b60003660291115613df357604051632bcb7bc560e11b815260040160405180910390fd5b5060281936013560006009613e0e600362ffffff8516614cd1565b613e189190614cd1565b905036613e26600283614cd1565b111561134d5760405163c30a7bd760e01b815260040160405180910390fd5b600080613e53602084614cd1565b905036811115613e7657604051632bcb7bc560e11b815260040160405180910390fd5b36033592915050565b600080600080613e8e85614238565b909250905060008080606081600d613eb1613eaa602089614cd1565b8990613b7a565b613ebb9190614cd1565b90506000613ed4613ecd60688d614cd1565b3690613115565b90506000613ef183613ee760418f614cd1565b613ecd9190614cd1565b9050613efd8382613f10565b9350826020850120945081359650613f34565b60408051838152602081850181019092526000910183838237601f19019392505050565b613f458765ffffffffffff16612be3565b613f5985613f5460418f614cd1565b614288565b9550613f6486611548565b60ff1699505050505050505060008060005b848110156140ec57613f89888583614300565b909350915060005b8c518110156140d9578c8181518110613fac57613fac614a28565b602002602001015184036140c75760008b8281518110613fce57613fce614a28565b60200260200101519050613fe781896001901b16151590565b1580156140105750600360ff168d838151811061400657614006614a28565b6020026020010151105b156140c1578c828151811061402757614027614a28565b60200260200101805180919061403c90614a67565b81525050838b838151811061405357614053614a28565b602002602001015160018f858151811061406f5761406f614a28565b60200260200101516140819190614a54565b8151811061409157614091614a28565b60209081029190910101526001881b81178c83815181106140b4576140b4614a28565b6020026020010181815250505b506140d9565b806140d181614a67565b915050613f91565b50806140e481614a67565b915050613f76565b505050816020826140fd9190614cd1565b6141079190614cba565b61411290604e614cd1565b9998505050505050505050565b60606000835167ffffffffffffffff81111561413d5761413d6147e8565b604051908082528060200260200182016040528015614166578160200160208202803683370190505b509050600360005b855181101561422e578185828151811061418a5761418a614a28565b602002602001015110156141d7578481815181106141aa576141aa614a28565b602002602001015182604051632b13aef560e01b8152600401610c89929190918252602082015260400190565b60006141fb8783815181106141ee576141ee614a28565b6020026020010151612002565b90508084838151811061421057614210614a28565b6020908102919091010152508061422681614a67565b91505061416e565b5090949350505050565b600080808080614249604187614cd1565b9050600061425b613ecd602084614cd1565b80359450905061426c816003613115565b62ffffff9490941697933563ffffffff16965092945050505050565b60408051600080825260208083018085528690523685900380850135831a948401859052803560608501819052910135608084018190529193909260019060a0016020604051602081039080840390855afa1580156142eb573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6000808061430f604e87614cd1565b9050600061433c614335614324602089614cd1565b61432f886001614cd1565b90613b7a565b8390613109565b9050600061434a3683613115565b80359960209091013598509650505050505050565b6040518061014001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016143ab6040518060200160405280600081525090565b81526020016143c66040518060200160405280600081525090565b81526020016143e16040518060200160405280600081525090565b81526020016143fc6040518060200160405280600081525090565b905290565b60008083601f84011261441357600080fd5b50813567ffffffffffffffff81111561442b57600080fd5b6020830191508360208260051b850101111561444657600080fd5b9250929050565b6000806000806040858703121561446357600080fd5b843567ffffffffffffffff8082111561447b57600080fd5b61448788838901614401565b909650945060208701359150808211156144a057600080fd5b506144ad87828801614401565b95989497509550505050565b6001600160a01b038116811461118657600080fd5b801515811461118657600080fd5b600080604083850312156144ef57600080fd5b82356144fa816144b9565b9150602083013561450a816144ce565b809150509250929050565b60006020828403121561452757600080fd5b813561134d816144b9565b600080600080600060a0868803121561454a57600080fd5b8535614555816144b9565b94506020860135614565816144b9565b93506040860135614575816144b9565b94979396509394606081013594506080013592915050565b600080600080608085870312156145a357600080fd5b84356145ae816144b9565b935060208501356145be816144b9565b925060408501356145ce816144b9565b9396929550929360600135925050565b6000602082840312156145f057600080fd5b813561134d816144ce565b60006020828403121561460d57600080fd5b5035919050565b6000806000806080858703121561462a57600080fd5b8435614635816144b9565b93506020850135614645816144b9565b93969395505050506040820135916060013590565b60008060008060008060c0878903121561467357600080fd5b863561467e816144b9565b9550602087013561468e816144b9565b9450604087013561469e816144b9565b935060608701356146ae816144b9565b9598949750929560808101359460a0909101359350915050565b6000806000606084860312156146dd57600080fd5b83356146e8816144b9565b925060208401356146f8816144b9565b929592945050506040919091013590565b600080600080600060a0868803121561472157600080fd5b853561472c816144b9565b9450602086013561473c816144b9565b9350604086013561474c816144b9565b9250606086013561475c816144b9565b949793965091946080013592915050565b6000806040838503121561478057600080fd5b823561478b816144b9565b9150602083013561450a816144b9565b6020808252825182820181905260009190848201906040850190845b818110156147dc5783516001600160a01b0316835292840192918401916001016147b7565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614827576148276147e8565b604052919050565b600067ffffffffffffffff821115614849576148496147e8565b5060051b60200190565b6000602080838503121561486657600080fd5b823567ffffffffffffffff81111561487d57600080fd5b8301601f8101851361488e57600080fd5b80356148a161489c8261482f565b6147fe565b81815260059190911b820183019083810190878311156148c057600080fd5b928401925b82841015612855578335825292840192908401906148c5565b60005b838110156148f95781810151838201526020016148e1565b50506000910152565b60208152600082518060208401526149218160408501602087016148de565b601f01601f19169190910160400192915050565b6000602080838503121561494857600080fd5b823567ffffffffffffffff81111561495f57600080fd5b8301601f8101851361497057600080fd5b803561497e61489c8261482f565b81815260059190911b8201830190838101908783111561499d57600080fd5b928401925b828410156128555783356149b5816144b9565b825292840192908401906149a2565b6020808252825182820181905260009190848201906040850190845b818110156147dc578351835292840192918401916001016149e0565b60008060408385031215614a0f57600080fd5b8235614a1a816144b9565b946020939093013593505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8181038181111561100557611005614a3e565b600060018201614a7957614a79614a3e565b5060010190565b60208082526028908201527f63616e6e6f742070617573652061206d61726b65742074686174206973206e6f6040820152671d081b1a5cdd195960c21b606082015260800190565b60208082526027908201527f6f6e6c7920706175736520677561726469616e20616e642061646d696e2063616040820152666e20706175736560c81b606082015260800190565b6020808252601690820152756f6e6c792061646d696e2063616e20756e706175736560501b604082015260600190565b600060208284031215614b5157600080fd5b815161134d816144b9565b600060208284031215614b6e57600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215614b9d57600080fd5b815161134d816144ce565b634e487b7160e01b600052600160045260246000fd5b60008060008060808587031215614bd457600080fd5b505082516020840151604085015160609095015191969095509092509050565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614c1c57600080fd5b815167ffffffffffffffff80821115614c3457600080fd5b818401915084601f830112614c4857600080fd5b815181811115614c5a57614c5a6147e8565b614c6d601f8201601f19166020016147fe565b9150808252856020828501011115614c8457600080fd5b614c958160208401602086016148de565b50949350505050565b60008251614cb08184602087016148de565b9190910192915050565b808202811582820484141761100557611005614a3e565b8082018082111561100557611005614a3e565b634e487b7160e01b600052601260045260246000fd5b600082614d0957614d09614ce4565b500490565b600082614d1d57614d1d614ce4565b50069056fea2646970667358221220bafd5e6394cb5564fc079ac4bc62f2bead18ad908f73aa6a16a21b14bd82f29564736f6c63430008120033

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061045e5760003560e01c806387f763031161024c578063c274583a11610146578063e6653f3d116100c3578063f4a433c011610087578063f4a433c014610bc9578063f50b2efe14610be9578063f851a44014610bfc578063f90c492414610c0f578063fc57d4df14610c1657600080fd5b8063e6653f3d14610b79578063e875544614610b8d578063eabe7d9114610b96578063ede4edd014610ba9578063f00a7a9214610bbc57600080fd5b8063d02f73511161010a578063d02f735114610b1a578063da3d454c14610b2d578063dce1544914610b40578063dcfbc0c714610b53578063e4028eee14610b6657600080fd5b8063c274583a14610a50578063c299823814610a87578063c488847b14610aa7578063ca0af04314610acf578063cc7ebdc414610afa57600080fd5b8063a7f0e231116101d4578063b21be7fd11610198578063b21be7fd146109cc578063b24ebfcc146109f7578063bb82aa5e14610a0a578063bdcdc25814610a1d578063bea6b8b814610a3057600080fd5b8063a7f0e23114610959578063aa90075414610987578063abfceffc14610990578063ac0b0bb7146109b0578063b0772d0b146109c457600080fd5b8063929fe9a11161021b578063929fe9a1146108c957806394543c151461090a57806394b2294b1461091d578063986ab83814610926578063a76b3fda1461094657600080fd5b806387f76303146108175780638c57804e1461082b5780638e8f294b146108635780638ebf6364146108b657600080fd5b80634a5844321161035d5780635f5af1aa116102e55780636b79c38d116102a95780636b79c38d146107475780636d154ea5146107a35780636d35bf91146107c6578063731f0c2b146107d457806385b7beb8146107f757600080fd5b80635f5af1aa146106e05780635fc7e71e146106f3578063607ef6c1146107065780636a56947e146107195780636aa875b51461072757600080fd5b80634fd42e171161032c5780634fd42e171461068157806351dff9891461069457806352d84d1e146106a75780635c778605146106ba5780635ec88c79146106cd57600080fd5b80634a584432146106175780634ada90af146106375780634e79238f146106405780634ef4c3e11461066e57600080fd5b806326782247116103eb5780633c94786f116103af5780633c94786f146105ae5780633ce142f5146105c257806341c728b9146105e757806342cbb15c146105fb57806347ef3b3b1461060157600080fd5b8063267822471461054f5780632d70db7814610562578063317b0b7714610575578063391957d7146105885780633bcf7ec11461059b57600080fd5b80631d7b33d7116104325780631d7b33d7146104bb5780631ededc91146104e957806321af4569146104fe57806324008a621461052957806324a3d6221461053c57600080fd5b80627e3dd21461046357806316b95e8f1461048057806318c882a5146104955780631d504dc6146104a8575b600080fd5b61046b600181565b60405190151581526020015b60405180910390f35b61049361048e36600461444d565b610c29565b005b61046b6104a33660046144dc565b610ed2565b6104936104b6366004614515565b61100b565b6104db6104c9366004614515565b600e6020526000908152604090205481565b604051908152602001610477565b6104936104f7366004614532565b5050505050565b601454610511906001600160a01b031681565b6040516001600160a01b039091168152602001610477565b6104db61053736600461458d565b611189565b600954610511906001600160a01b031681565b600154610511906001600160a01b031681565b61046b6105703660046145de565b6111bd565b6104db6105833660046145fb565b6112ad565b610493610596366004614515565b611354565b61046b6105a93660046144dc565b61141e565b60095461046b90600160a01b900460ff1681565b6105d56105d0366004614515565b611548565b60405160ff9091168152602001610477565b6104936105f5366004614614565b50505050565b436104db565b61049361060f36600461465a565b505050505050565b6104db610625366004614515565b60156020526000908152604090205481565b6104db60055481565b61065361064e366004614614565b61164a565b60408051938452602084019290925290820152606001610477565b6104db61067c3660046146c8565b61168a565b6104db61068f3660046145fb565b611718565b6104936106a2366004614614565b611775565b6105116106b53660046145fb565b6117c4565b6104936106c83660046146c8565b505050565b6106536106db366004614515565b6117ee565b6104db6106ee366004614515565b611829565b6104db610701366004614709565b6118a2565b61049361071436600461444d565b611a74565b6104936105f536600461458d565b6104db610735366004614515565b60196020526000908152604090205481565b61077f610755366004614515565b600f602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b604080516001600160e01b03909316835263ffffffff909116602083015201610477565b61046b6107b1366004614515565b600b6020526000908152604090205460ff1681565b6104936104f7366004614709565b61046b6107e2366004614515565b600a6020526000908152604090205460ff1681565b6104db610805366004614515565b601b6020526000908152604090205481565b60095461046b90600160b01b900460ff1681565b61077f610839366004614515565b6010602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b610897610871366004614515565b60086020526000908152604090208054600182015460039092015460ff91821692911683565b6040805193151584526020840192909252151590820152606001610477565b61046b6108c43660046145de565b611c52565b61046b6108d736600461476d565b6001600160a01b038082166000908152600860209081526040808320938616835260029093019052205460ff1692915050565b61046b610918366004614515565b611d39565b6104db60065481565b6104db610934366004614515565b60166020526000908152604090205481565b6104db610954366004614515565b611df8565b61096f6ec097ce7bc90715b34b9f100000000081565b6040516001600160e01b039091168152602001610477565b6104db600d5481565b6109a361099e366004614515565b611f2a565b604051610477919061479b565b60095461046b90600160b81b900460ff1681565b6109a3611fa0565b6104db6109da36600461476d565b601160209081526000928352604080842090915290825290205481565b6104db610a05366004614853565b612002565b600254610511906001600160a01b031681565b6104db610a2b36600461458d565b61200d565b6104db610a3e366004614515565b60176020526000908152604090205481565b60408051808201825260158152741c99591cdd1bdb994b5c1c9a5b585c9e4b5c1c9bd9605a1b602082015290516104779190614902565b610a9a610a95366004614935565b612087565b60405161047791906149c4565b610aba610ab53660046146c8565b61214f565b60408051928352602083019190915201610477565b6104db610add36600461476d565b601260209081526000928352604080842090915290825290205481565b6104db610b08366004614515565b60136020526000908152604090205481565b6104db610b28366004614709565b61229b565b6104db610b3b3660046146c8565b612419565b610511610b4e3660046149fc565b6126fc565b600354610511906001600160a01b031681565b6104db610b743660046149fc565b612734565b60095461046b90600160a81b900460ff1681565b6104db60045481565b6104db610ba43660046146c8565b612860565b6104db610bb7366004614515565b612888565b601a5461046b9060ff1681565b6104db610bd7366004614515565b60186020526000908152604090205481565b610493610bf73660046145fb565b612be3565b600054610511906001600160a01b031681565b60036105d5565b6104db610c24366004614515565b612bec565b6000546001600160a01b03163314610c925760405162461bcd60e51b815260206004820152602160248201527f4f6e6c792061646d696e2063616e2063616c6c20746869732066756e6374696f6044820152603760f91b60648201526084015b60405180910390fd5b601a5460ff1615610cf45760405162461bcd60e51b815260206004820152602660248201527f416c72656164792065786563757465642074686973206f6e652d6f66662066756044820152653731ba34b7b760d11b6064820152608401610c89565b828114610d335760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b6044820152606401610c89565b60008060008060005b87811015610eba57888882818110610d5657610d56614a28565b9050602002016020810190610d6b9190614515565b6001600160a01b0381166000908152601360205260409020549095509350868682818110610d9b57610d9b614a28565b90506020020135925083831115610e3f576000610db88585614a54565b6001600160a01b0387166000908152601b6020526040812054919250610dde8284613109565b6001600160a01b0389166000818152601b6020908152604091829020849055815186815290810184905292935090917f17fea09d9a7ca41b2f9f9118f18f44848a62e9c70d55dd4385131eb2cf1b7e47910160405180910390a28695505050505b8215610eaa57610e4f8484613115565b6001600160a01b038616600081815260136020908152604091829020849055815188815290810184905292945090917f4a5c134e28b537a76546993ea37f3b60d9190476df7356d3842aa40902e20f04910160405180910390a25b610eb381614a67565b9050610d3c565b5050601a805460ff1916600117905550505050505050565b6001600160a01b03821660009081526008602052604081205460ff16610f0a5760405162461bcd60e51b8152600401610c8990614a80565b6009546001600160a01b0316331480610f2d57506000546001600160a01b031633145b610f495760405162461bcd60e51b8152600401610c8990614ac8565b6000546001600160a01b0316331480610f6457506001821515145b610f805760405162461bcd60e51b8152600401610c8990614b0f565b6001600160a01b0383166000818152600b6020908152604091829020805460ff19168615159081179091558251938452606091840182905260069184019190915265426f72726f7760d01b6080840152908201527f71aec636243f9709bb0007ae15e9afb8150ab01716d75fd7573be5cc096e03b09060a0015b60405180910390a150805b92915050565b806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611049573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106d9190614b3f565b6001600160a01b0316336001600160a01b0316146110dd5760405162461bcd60e51b815260206004820152602760248201527f6f6e6c7920756e6974726f6c6c65722061646d696e2063616e206368616e676560448201526620627261696e7360c81b6064820152608401610c89565b806001600160a01b031663c1e803346040518163ffffffff1660e01b81526004016020604051808303816000875af115801561111d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111419190614b5c565b156111865760405162461bcd60e51b815260206004820152601560248201527418da185b99d9481b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610c89565b50565b6001600160a01b03841660009081526008602052604081205460ff166111b1575060096111b5565b5060005b949350505050565b6009546000906001600160a01b03163314806111e357506000546001600160a01b031633145b6111ff5760405162461bcd60e51b8152600401610c8990614ac8565b6000546001600160a01b031633148061121a57506001821515145b6112365760405162461bcd60e51b8152600401610c8990614b0f565b60098054831515600160b81b0260ff60b81b199091161790556040517fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de0906112a19084906040808252600590820152645365697a6560d81b6060820152901515602082015260800190565b60405180910390a15090565b600080546001600160a01b031633146113085760405162461bcd60e51b815260206004820152601f60248201527f6f6e6c792061646d696e2063616e2073657420636c6f736520666163746f72006044820152606401610c89565b600480549083905560408051828152602081018590527f3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd991015b60405180910390a160005b9392505050565b6000546001600160a01b031633146113bd5760405162461bcd60e51b815260206004820152602660248201527f6f6e6c792061646d696e2063616e2073657420626f72726f772063617020677560448201526530b93234b0b760d11b6064820152608401610c89565b601480546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527feda98690e518e9a05f8ec6837663e188211b2da8f4906648b323f2c1d4434e29910160405180910390a15050565b6001600160a01b03821660009081526008602052604081205460ff166114565760405162461bcd60e51b8152600401610c8990614a80565b6009546001600160a01b031633148061147957506000546001600160a01b031633145b6114955760405162461bcd60e51b8152600401610c8990614ac8565b6000546001600160a01b03163314806114b057506001821515145b6114cc5760405162461bcd60e51b8152600401610c8990614b0f565b6001600160a01b0383166000818152600a6020908152604091829020805460ff19168615159081179091558251938452606091840182905260049184019190915263135a5b9d60e21b6080840152908201527f71aec636243f9709bb0007ae15e9afb8150ab01716d75fd7573be5cc096e03b09060a001610ffa565b60006001600160a01b038216738bb8f32df04c8b654987daaed53d6b6091e3b7740361157657506000919050565b6001600160a01b03821673deb22f54738d54976c4c0fe5ce6d408e40d88499036115a257506001919050565b6001600160a01b0382167351ce04be4b3e32572c4ec9135221d0691ba7d202036115ce57506002919050565b6001600160a01b03821673dd682daec5a90dd295d14da4b0bec9281017b5be036115fa57506003919050565b6001600160a01b038216739c5ae89c4af6aa32ce58588dbaf90d18a855b6de0361162657506004919050565b6040516303b1166f60e61b81526001600160a01b0383166004820152602401610c89565b60008060008060008061165f8a8a8a8a613121565b92509250925082601181111561167757611677614b75565b95509093509150505b9450945094915050565b6001600160a01b0383166000908152600a602052604081205460ff16156116e45760405162461bcd60e51b815260206004820152600e60248201526d1b5a5b9d081a5cc81c185d5cd95960921b6044820152606401610c89565b6001600160a01b03841660009081526008602052604090205460ff1661170e5760095b905061134d565b6000949350505050565b600080546001600160a01b03163314611737576110056001600b6133f4565b600580549083905560408051828152602081018590527faeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec13169101611342565b801580156117835750600082115b156105f55760405162461bcd60e51b815260206004820152601160248201527072656465656d546f6b656e73207a65726f60781b6044820152606401610c89565b600c81815481106117d457600080fd5b6000918252602090912001546001600160a01b0316905081565b600080600080600080611805876000806000613121565b92509250925082601181111561181d5761181d614b75565b97919650945092505050565b600080546001600160a01b0316331461184857611005600160136133f4565b600980546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f0613b6ee6a04f0d09f390e4d9318894b9f6ac7fd83897cd8d18896ba579c401e9101611342565b6001600160a01b03851660009081526008602052604081205460ff1615806118e357506001600160a01b03851660009081526008602052604090205460ff16155b156118f25760095b9050611a6b565b6040516395dd919360e01b81526001600160a01b038481166004830152600091908816906395dd919390602401602060405180830381865afa15801561193c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119609190614b5c565b905061196b87611d39565b156119d657828110156119d15760405162461bcd60e51b815260206004820152602860248201527f43616e206e6f74207265706179206d6f7265207468616e2074686520746f74616044820152676c20626f72726f7760c01b6064820152608401610c89565b611a65565b6000806119e28661346d565b919350909150600090508260118111156119fe576119fe614b75565b14611a1f57816011811115611a1557611a15614b75565b9350505050611a6b565b80600003611a2e576003611a15565b6000611a4a60405180602001604052806004548152508561348d565b905080861115611a61576011945050505050611a6b565b5050505b60009150505b95945050505050565b6000546001600160a01b0316331480611a9757506014546001600160a01b031633145b611b015760405162461bcd60e51b815260206004820152603560248201527f6f6e6c792061646d696e206f7220626f72726f772063617020677561726469616044820152746e2063616e2073657420626f72726f77206361707360581b6064820152608401610c89565b82818115801590611b1157508082145b611b4d5760405162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081a5b9c1d5d609a1b6044820152606401610c89565b60005b82811015611c4957848482818110611b6a57611b6a614a28565b9050602002013560156000898985818110611b8757611b87614a28565b9050602002016020810190611b9c9190614515565b6001600160a01b03168152602081019190915260400160002055868682818110611bc857611bc8614a28565b9050602002016020810190611bdd9190614515565b6001600160a01b03167f6f1951b2aad10f3fc81b86d91105b413a5b3f847a34bbc5ce1904201b14438f6868684818110611c1957611c19614a28565b90506020020135604051611c2f91815260200190565b60405180910390a280611c4181614a67565b915050611b50565b50505050505050565b6009546000906001600160a01b0316331480611c7857506000546001600160a01b031633145b611c945760405162461bcd60e51b8152600401610c8990614ac8565b6000546001600160a01b0316331480611caf57506001821515145b611ccb5760405162461bcd60e51b8152600401610c8990614b0f565b60098054831515600160b01b0260ff60b01b199091161790556040517fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de0906112a19084906040808252600890820152672a3930b739b332b960c11b6060820152901515602082015260800190565b6001600160a01b038116600090815260086020526040812060010154158015611d7f57506001600160a01b0382166000908152600b602052604090205460ff1615156001145b80156110055750816001600160a01b031663173b99046040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de89190614b5c565b670de0b6b3a76400001492915050565b600080546001600160a01b03163314611e1757611005600160126133f4565b6001600160a01b03821660009081526008602052604090205460ff1615611e4457611005600a60116133f4565b816001600160a01b031663fe9c44ae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea69190614b8b565b506001600160a01b03821660009081526008602052604081208054600160ff1991821681178355600383018054909216909155810191909155611ee8836134a5565b611ef18361358d565b6040516001600160a01b03841681527fcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f90602001611342565b6001600160a01b0381166000908152600760209081526040808320805482518185028101850190935280835260609493830182828015611f9357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f75575b5093979650505050505050565b6060600c805480602002602001604051908101604052809291908181526020018280548015611ff857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611fda575b5050505050905090565b600061100582613689565b600954600090600160b01b900460ff161561205f5760405162461bcd60e51b81526020600482015260126024820152711d1c985b9cd9995c881a5cc81c185d5cd95960721b6044820152606401610c89565b600061206c868685613694565b9050801561207b5790506111b5565b60009695505050505050565b805160609060008167ffffffffffffffff8111156120a7576120a76147e8565b6040519080825280602002602001820160405280156120d0578160200160208202803683370190505b50905060005b828110156121475760008582815181106120f2576120f2614a28565b60200260200101519050612106813361374c565b601181111561211757612117614b75565b83838151811061212957612129614a28565b6020908102919091010152508061213f81614a67565b9150506120d6565b509392505050565b600080600061215d86612bec565b9050600061216a86612bec565b9050811580612177575080155b1561218b57600d6000935093505050612293565b6000866001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ef9190614b5c565b905060006122096040518060200160405280600081525090565b60408051602080820183526000808352835180830185529081528351808301855260055481528451928301909452888252919261224591613840565b925061226d604051806020016040528088815250604051806020016040528088815250613840565b91506122798383613888565b9050612285818b61348d565b600099509750505050505050505b935093915050565b600954600090600160b81b900460ff16156122ea5760405162461bcd60e51b815260206004820152600f60248201526e1cd95a5e99481a5cc81c185d5cd959608a1b6044820152606401610c89565b6001600160a01b03861660009081526008602052604090205460ff16158061232b57506001600160a01b03851660009081526008602052604090205460ff16155b156123375760096118eb565b846001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612375573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123999190614b3f565b6001600160a01b0316866001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124049190614b3f565b6001600160a01b03161461207b5760026118eb565b6001600160a01b0383166000908152600b602052604081205460ff16156124755760405162461bcd60e51b815260206004820152601060248201526f189bdc9c9bddc81a5cc81c185d5cd95960821b6044820152606401610c89565b6001600160a01b03841660009081526008602052604090205460ff1661249c576009611707565b6001600160a01b038085166000908152600860209081526040808320938716835260029093019052205460ff1661259957336001600160a01b0385161461251d5760405162461bcd60e51b815260206004820152601560248201527439b2b73232b91036bab9ba1031329031aa37b5b2b760591b6044820152606401610c89565b6000612529338561374c565b9050600081601181111561253f5761253f614b75565b1461255e5780601181111561255657612556614b75565b91505061134d565b6001600160a01b038086166000908152600860209081526040808320938816835260029093019052205460ff1661259757612597614ba8565b505b6125a284612bec565b6000036125b057600d611707565b6001600160a01b0384166000908152601560205260409020548015612695576000856001600160a01b03166347bd37186040518163ffffffff1660e01b8152600401602060405180830381865afa15801561260f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126339190614b5c565b905060006126418286613109565b90508281106126925760405162461bcd60e51b815260206004820152601960248201527f6d61726b657420626f72726f77206361702072656163686564000000000000006044820152606401610c89565b50505b6000806126a58688600088613121565b919350909150600090508260118111156126c1576126c1614b75565b146126e2578160118111156126d8576126d8614b75565b935050505061134d565b80156126ef5760046126d8565b6000979650505050505050565b6007602052816000526040600020818154811061271857600080fd5b6000918252602090912001546001600160a01b03169150829050565b600080546001600160a01b0316331461275a57612753600160066133f4565b9050611005565b6001600160a01b0383166000908152600860205260409020805460ff1661278f57612787600960076133f4565b915050611005565b60408051602080820183528582528251908101909252670c7d713b49da00008252906127bd81835190511090565b156127d8576127ce600660086133f4565b9350505050611005565b84158015906127ed57506127eb86612bec565b155b156127fe576127ce600d60096133f4565b60018301805490869055604080516001600160a01b0389168152602081018390529081018790527f70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc59060600160405180910390a160005b979650505050505050565b60008061286e858585613694565b9050801561287d57905061134d565b600095945050505050565b6040516361bfb47160e11b815233600482015260009082908290819081906001600160a01b0385169063c37f68e290602401608060405180830381865afa1580156128d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fb9190614bbe565b50925092509250826000146129605760405162461bcd60e51b815260206004820152602560248201527f657869744d61726b65743a206765744163636f756e74536e617073686f742066604482015264185a5b195960da1b6064820152608401610c89565b801561297c57612972600c60026133f4565b9695505050505050565b6000612989873385613694565b9050801561299e57612855600e6003836138c2565b6001600160a01b0385166000908152600860209081526040808320338452600281019092529091205460ff166129dd5760005b98975050505050505050565b3360009081526002820160209081526040808320805460ff191690556007825280832080548251818502810185019093528083529192909190830182828015612a4f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a31575b5050835193945083925060009150505b82811015612ab357896001600160a01b0316848281518110612a8357612a83614a28565b60200260200101516001600160a01b031603612aa157809150612ab3565b80612aab81614a67565b915050612a5f565b50818110612ac357612ac3614ba8565b33600090815260076020526040902080548190612ae290600190614a54565b81548110612af257612af2614a28565b9060005260206000200160009054906101000a90046001600160a01b0316818381548110612b2257612b22614a28565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555080805480612b6057612b60614bf4565b600082815260209020810160001990810180546001600160a01b03191690550190556040517fe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d90612bc9908c9033906001600160a01b0392831681529116602082015260400190565b60405180910390a160009c9b505050505050505050505050565b6111868161393a565b6000806000604051602001612c0b90630c68aa8960e31b815260040190565b60405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612c5f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612c879190810190614c0a565b604051602001612c979190614c9e565b6040516020818303038152906040528051906020012003612cc857612cc16208aa8960eb1b6139be565b9150613102565b604051640c6ae8aa8960db1b602082015260250160405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612d30573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d589190810190614c0a565b604051602001612d689190614c9e565b6040516020818303038152906040528051906020012003612d9257612cc16208aa8960eb1b6139be565b60405164635553444360d81b602082015260250160405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612dfa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e229190810190614c0a565b604051602001612e329190614c9e565b6040516020818303038152906040528051906020012003612e6c57612e5d635553444360e01b6139be565b612cc19064e8d4a51000614cba565b6040516418d554d11560da1b602082015260250160405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612ed4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612efc9190810190614c0a565b604051602001612f0c9190614c9e565b6040516020818303038152906040528051906020012003612f3757612e5d631554d11560e21b6139be565b60405164635742544360d81b602082015260250160405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612f9f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fc79190810190614c0a565b604051602001612fd79190614c9e565b6040516020818303038152906040528051906020012003613010576130016242544360e81b6139be565b612cc1906402540be400614cba565b6000846001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015613050573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130749190614b3f565b6001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156130b1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130d99190810190614c0a565b905060008082905080516000036130ef57600091505b60208301519150819350612855846139be565b5092915050565b600061134d8284614cd1565b600061134d8284614a54565b600080600061312e61435f565b6001600160a01b03881660009081526007602090815260408083208054825181850281018501909352808352849383018282801561319557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613177575b5050505050905060005b815181101561339e5760008282815181106131bc576131bc614a28565b60209081029190910101516040516361bfb47160e11b81526001600160a01b038e811660048301529192509082169063c37f68e290602401608060405180830381865afa158015613211573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132359190614bbe565b6080890152606088015260408701529350831561326157600f6000809750975097505050505050611680565b60408051602080820183526001600160a01b03841660009081526008825283902060010154825260c088019190915281519081019091526080860151815260e08601526132ad81612bec565b60a086018190526000036132d057600d6000809750975097505050505050611680565b604080516020810190915260a0860151815261010086015260c085015160e086015161330a916132ff91613840565b866101000151613840565b610120860181905260408601518651613324929190613a2e565b855261010085015160608601516020870151613341929190613a2e565b60208601526001600160a01b03808c169082160361338b5761336d8561012001518b8760200151613a2e565b60208601819052610100860151613385918b90613a2e565b60208601525b508061339681614a67565b91505061319f565b506020830151835111156133cf57602083015183516000916133bf91614a54565b6000955095509550505050611680565b600080846000015185602001516133e69190614a54565b955095509550505050611680565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601181111561342957613429614b75565b83601381111561343b5761343b614b75565b60408051928352602083019190915260009082015260600160405180910390a182601181111561134d5761134d614b75565b6000806000613480846000806000613121565b9250925092509193909250565b60008061349a8484613a4f565b90506111b581613a77565b60005b600c5481101561353a57816001600160a01b0316600c82815481106134cf576134cf614a28565b6000918252602090912001546001600160a01b0316036135285760405162461bcd60e51b81526020600482015260146024820152731b585c9ad95d08185b1c9958591e48185919195960621b6044820152606401610c89565b8061353281614a67565b9150506134a8565b50600c80546001810182556000919091527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180546001600160a01b0319166001600160a01b0392909216919091179055565b60006135ce436040518060400160405280601c81526020017f626c6f636b206e756d6265722065786365656473203332206269747300000000815250613a8f565b6001600160a01b0383166000908152600f60209081526040808320601090925282208154939450909290916001600160e01b03909116900361362a5781546001600160e01b0319166ec097ce7bc90715b34b9f10000000001782555b80546001600160e01b031660000361365c5780546001600160e01b0319166ec097ce7bc90715b34b9f10000000001781555b805463ffffffff909316600160e01b026001600160e01b0393841681179091558154909216909117905550565b600061100582613abf565b6001600160a01b03831660009081526008602052604081205460ff166136bb576009611707565b6001600160a01b038085166000908152600860209081526040808320938716835260029093019052205460ff166136f3576000611707565b6000806137038587866000613121565b9193509091506000905082601181111561371f5761371f614b75565b1461373f5781601181111561373657613736614b75565b9250505061134d565b801561207b576004613736565b6001600160a01b0382166000908152600860205260408120805460ff16613777576009915050611005565b6001600160a01b038316600090815260028201602052604090205460ff1615156001036137a8576000915050611005565b6001600160a01b03838116600081815260028401602090815260408083208054600160ff199091168117909155600783528184208054918201815584529282902090920180546001600160a01b031916948916948517905581519384528301919091527f3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5910160405180910390a15060009392505050565b6040805160208101909152600081526040518060200160405280670de0b6b3a764000061387586600001518660000151613b7a565b61387f9190614cfa565b90529392505050565b604080516020810190915260008152604051806020016040528061387f6138bb8660000151670de0b6b3a7640000613b7a565b8551613b86565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08460118111156138f7576138f7614b75565b84601381111561390957613909614b75565b604080519283526020830191909152810184905260600160405180910390a18360118111156111b5576111b5614b75565b60006139486103e883614cfa565b90508042101561398a57603c61395e4283614a54565b11156139865760405163b6b0916d60e01b815260048101829052426024820152604401610c89565b5050565b60b46139968242614a54565b111561398657604051630321d0b560e01b815260048101829052426024820152604401610c89565b6040805160018082528183019092526000918291906020808301908036833701905050905082816000815181106139f7576139f7614a28565b602002602001018181525050613a0c81613b92565b600081518110613a1e57613a1e614a28565b6020026020010151915050919050565b600080613a3b8585613a4f565b9050611a6b613a4982613a77565b84613109565b604080516020810190915260008152604051806020016040528061387f856000015185613b7a565b805160009061100590670de0b6b3a764000090614cfa565b6000816401000000008410613ab75760405162461bcd60e51b8152600401610c899190614902565b509192915050565b60008151600003613ae357604051639e198af960e01b815260040160405180910390fd5b613aec82613b9d565b600060028351613afc9190614cfa565b905060028351613b0c9190614d0e565b600003613b68576000613b5b84613b24600185614a54565b81518110613b3457613b34614a28565b6020026020010151858481518110613b4e57613b4e614a28565b6020026020010151613109565b90506111b5600282614cfa565b828181518110613a1e57613a1e614a28565b600061134d8284614cba565b600061134d8284614cfa565b606061100582613be5565b8051602082016020820281019150805b828110156105f557815b81811015613bdc578151815180821015613bd2578084528183525b5050602001613bb7565b50602001613bad565b60606000825167ffffffffffffffff811115613c0357613c036147e8565b604051908082528060200260200182016040528015613c2c578160200160208202803683370190505b5090506000835167ffffffffffffffff811115613c4b57613c4b6147e8565b604051908082528060200260200182016040528015613c74578160200160208202803683370190505b5090506000845167ffffffffffffffff811115613c9357613c936147e8565b604051908082528060200260200182016040528015613cc657816020015b6060815260200190600190039081613cb15790505b50905060005b8551811015613d245760408051600380825260808201909252906020820160608036833701905050828281518110613d0657613d06614a28565b60200260200101819052508080613d1c90614a67565b915050613ccc565b506000613d2f613d9e565b90506000613d3c82613e45565b61ffff169050613d4d600283614cd1565b60405190925060005b82811015613d93576000613d6d8a89898989613e7f565b9050613d798186614cd1565b945082604052508080613d8b90614a67565b915050613d56565b506129d1848761411f565b60006602ed57011e0000601f1936013581161480613dcf576040516373bb264f60e11b815260040160405180910390fd5b60003660291115613df357604051632bcb7bc560e11b815260040160405180910390fd5b5060281936013560006009613e0e600362ffffff8516614cd1565b613e189190614cd1565b905036613e26600283614cd1565b111561134d5760405163c30a7bd760e01b815260040160405180910390fd5b600080613e53602084614cd1565b905036811115613e7657604051632bcb7bc560e11b815260040160405180910390fd5b36033592915050565b600080600080613e8e85614238565b909250905060008080606081600d613eb1613eaa602089614cd1565b8990613b7a565b613ebb9190614cd1565b90506000613ed4613ecd60688d614cd1565b3690613115565b90506000613ef183613ee760418f614cd1565b613ecd9190614cd1565b9050613efd8382613f10565b9350826020850120945081359650613f34565b60408051838152602081850181019092526000910183838237601f19019392505050565b613f458765ffffffffffff16612be3565b613f5985613f5460418f614cd1565b614288565b9550613f6486611548565b60ff1699505050505050505060008060005b848110156140ec57613f89888583614300565b909350915060005b8c518110156140d9578c8181518110613fac57613fac614a28565b602002602001015184036140c75760008b8281518110613fce57613fce614a28565b60200260200101519050613fe781896001901b16151590565b1580156140105750600360ff168d838151811061400657614006614a28565b6020026020010151105b156140c1578c828151811061402757614027614a28565b60200260200101805180919061403c90614a67565b81525050838b838151811061405357614053614a28565b602002602001015160018f858151811061406f5761406f614a28565b60200260200101516140819190614a54565b8151811061409157614091614a28565b60209081029190910101526001881b81178c83815181106140b4576140b4614a28565b6020026020010181815250505b506140d9565b806140d181614a67565b915050613f91565b50806140e481614a67565b915050613f76565b505050816020826140fd9190614cd1565b6141079190614cba565b61411290604e614cd1565b9998505050505050505050565b60606000835167ffffffffffffffff81111561413d5761413d6147e8565b604051908082528060200260200182016040528015614166578160200160208202803683370190505b509050600360005b855181101561422e578185828151811061418a5761418a614a28565b602002602001015110156141d7578481815181106141aa576141aa614a28565b602002602001015182604051632b13aef560e01b8152600401610c89929190918252602082015260400190565b60006141fb8783815181106141ee576141ee614a28565b6020026020010151612002565b90508084838151811061421057614210614a28565b6020908102919091010152508061422681614a67565b91505061416e565b5090949350505050565b600080808080614249604187614cd1565b9050600061425b613ecd602084614cd1565b80359450905061426c816003613115565b62ffffff9490941697933563ffffffff16965092945050505050565b60408051600080825260208083018085528690523685900380850135831a948401859052803560608501819052910135608084018190529193909260019060a0016020604051602081039080840390855afa1580156142eb573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6000808061430f604e87614cd1565b9050600061433c614335614324602089614cd1565b61432f886001614cd1565b90613b7a565b8390613109565b9050600061434a3683613115565b80359960209091013598509650505050505050565b6040518061014001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016143ab6040518060200160405280600081525090565b81526020016143c66040518060200160405280600081525090565b81526020016143e16040518060200160405280600081525090565b81526020016143fc6040518060200160405280600081525090565b905290565b60008083601f84011261441357600080fd5b50813567ffffffffffffffff81111561442b57600080fd5b6020830191508360208260051b850101111561444657600080fd5b9250929050565b6000806000806040858703121561446357600080fd5b843567ffffffffffffffff8082111561447b57600080fd5b61448788838901614401565b909650945060208701359150808211156144a057600080fd5b506144ad87828801614401565b95989497509550505050565b6001600160a01b038116811461118657600080fd5b801515811461118657600080fd5b600080604083850312156144ef57600080fd5b82356144fa816144b9565b9150602083013561450a816144ce565b809150509250929050565b60006020828403121561452757600080fd5b813561134d816144b9565b600080600080600060a0868803121561454a57600080fd5b8535614555816144b9565b94506020860135614565816144b9565b93506040860135614575816144b9565b94979396509394606081013594506080013592915050565b600080600080608085870312156145a357600080fd5b84356145ae816144b9565b935060208501356145be816144b9565b925060408501356145ce816144b9565b9396929550929360600135925050565b6000602082840312156145f057600080fd5b813561134d816144ce565b60006020828403121561460d57600080fd5b5035919050565b6000806000806080858703121561462a57600080fd5b8435614635816144b9565b93506020850135614645816144b9565b93969395505050506040820135916060013590565b60008060008060008060c0878903121561467357600080fd5b863561467e816144b9565b9550602087013561468e816144b9565b9450604087013561469e816144b9565b935060608701356146ae816144b9565b9598949750929560808101359460a0909101359350915050565b6000806000606084860312156146dd57600080fd5b83356146e8816144b9565b925060208401356146f8816144b9565b929592945050506040919091013590565b600080600080600060a0868803121561472157600080fd5b853561472c816144b9565b9450602086013561473c816144b9565b9350604086013561474c816144b9565b9250606086013561475c816144b9565b949793965091946080013592915050565b6000806040838503121561478057600080fd5b823561478b816144b9565b9150602083013561450a816144b9565b6020808252825182820181905260009190848201906040850190845b818110156147dc5783516001600160a01b0316835292840192918401916001016147b7565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614827576148276147e8565b604052919050565b600067ffffffffffffffff821115614849576148496147e8565b5060051b60200190565b6000602080838503121561486657600080fd5b823567ffffffffffffffff81111561487d57600080fd5b8301601f8101851361488e57600080fd5b80356148a161489c8261482f565b6147fe565b81815260059190911b820183019083810190878311156148c057600080fd5b928401925b82841015612855578335825292840192908401906148c5565b60005b838110156148f95781810151838201526020016148e1565b50506000910152565b60208152600082518060208401526149218160408501602087016148de565b601f01601f19169190910160400192915050565b6000602080838503121561494857600080fd5b823567ffffffffffffffff81111561495f57600080fd5b8301601f8101851361497057600080fd5b803561497e61489c8261482f565b81815260059190911b8201830190838101908783111561499d57600080fd5b928401925b828410156128555783356149b5816144b9565b825292840192908401906149a2565b6020808252825182820181905260009190848201906040850190845b818110156147dc578351835292840192918401916001016149e0565b60008060408385031215614a0f57600080fd5b8235614a1a816144b9565b946020939093013593505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8181038181111561100557611005614a3e565b600060018201614a7957614a79614a3e565b5060010190565b60208082526028908201527f63616e6e6f742070617573652061206d61726b65742074686174206973206e6f6040820152671d081b1a5cdd195960c21b606082015260800190565b60208082526027908201527f6f6e6c7920706175736520677561726469616e20616e642061646d696e2063616040820152666e20706175736560c81b606082015260800190565b6020808252601690820152756f6e6c792061646d696e2063616e20756e706175736560501b604082015260600190565b600060208284031215614b5157600080fd5b815161134d816144b9565b600060208284031215614b6e57600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215614b9d57600080fd5b815161134d816144ce565b634e487b7160e01b600052600160045260246000fd5b60008060008060808587031215614bd457600080fd5b505082516020840151604085015160609095015191969095509092509050565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614c1c57600080fd5b815167ffffffffffffffff80821115614c3457600080fd5b818401915084601f830112614c4857600080fd5b815181811115614c5a57614c5a6147e8565b614c6d601f8201601f19166020016147fe565b9150808252856020828501011115614c8457600080fd5b614c958160208401602086016148de565b50949350505050565b60008251614cb08184602087016148de565b9190910192915050565b808202811582820484141761100557611005614a3e565b8082018082111561100557611005614a3e565b634e487b7160e01b600052601260045260246000fd5b600082614d0957614d09614ce4565b500490565b600082614d1d57614d1d614ce4565b50069056fea2646970667358221220bafd5e6394cb5564fc079ac4bc62f2bead18ad908f73aa6a16a21b14bd82f29564736f6c63430008120033

Deployed Bytecode Sourcemap

89114:28162:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37584:41;;37621:4;37584:41;;;;;179:14:1;;172:22;154:41;;142:2;127:18;37584:41:0;;;;;;;;115200:1411;;;;;;:::i;:::-;;:::i;:::-;;113678:509;;;;;;:::i;:::-;;:::i;114958:234::-;;;;;;:::i;:::-;;:::i;80166:42::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;2718:25:1;;;2706:2;2691:18;80166:42:0;2572:177:1;99696:369:0;;;;;;:::i;:::-;;;;;;;80621:32;;;;;-1:-1:-1;;;;;80621:32:0;;;;;;-1:-1:-1;;;;;3614:32:1;;;3596:51;;3584:2;3569:18;80621:32:0;3450:203:1;99310:378:0;;;;;;:::i;:::-;;:::i;79642:28::-;;;;;-1:-1:-1;;;;;79642:28:0;;;78969:27;;;;;-1:-1:-1;;;;;78969:27:0;;;114581:369;;;;;;:::i;:::-;;:::i;107914:391::-;;;;;;:::i;:::-;;:::i;112371:355::-;;;;;;:::i;:::-;;:::i;113167:503::-;;;;;;:::i;:::-;;:::i;79677:31::-;;;;;-1:-1:-1;;;79677:31:0;;;;;;36801:662;;;;;;:::i;:::-;;:::i;:::-;;;4888:4:1;4876:17;;;4858:36;;4846:2;4831:18;36801:662:0;4716:184:1;94408:273:0;;;;;;:::i;:::-;;;;;;117174:99;117253:12;117174:99;;101290:457;;;;;;:::i;:::-;;;;;;;;80662:42;;;;;;:::i;:::-;;;;;;;;;;;;;;79214:40;;;;;;104330:408;;;;;;:::i;:::-;;:::i;:::-;;;;6499:25:1;;;6555:2;6540:18;;6533:34;;;;6583:18;;;6576:34;6487:2;6472:18;104330:408:0;6297:319:1;94036:364:0;;;;;;:::i;:::-;;:::i;109612:552::-;;;;;;:::i;:::-;;:::i;95714:267::-;;;;;;:::i;:::-;;:::i;80102:26::-;;;;;;:::i;:::-;;:::i;99069:233::-;;;;;;:::i;:::-;;;;;103841:277;;;;;;:::i;:::-;;:::i;112734:425::-;;;;;;:::i;:::-;;:::i;100073:1209::-;;;;;;:::i;:::-;;:::i;111760:603::-;;;;;;:::i;:::-;;:::i;103222:256::-;;;;;;:::i;81017:48::-;;;;;;:::i;:::-;;;;;;;;;;;;;;80217:58;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;80217:58:0;;;-1:-1:-1;;;80217:58:0;;;;;;;;;;-1:-1:-1;;;;;9081:32:1;;;9063:51;;9162:10;9150:23;;;9145:2;9130:18;;9123:51;9036:18;80217:58:0;8891:289:1;79891:52:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;102418:386;;;;;;:::i;79834:50::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;81178:46;;;;;;:::i;:::-;;;;;;;;;;;;;;79755:34;;;;;-1:-1:-1;;;79755:34:0;;;;;;80284:58;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;80284:58:0;;;-1:-1:-1;;;80284:58:0;;;;;;79592:41;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9400:14:1;;9393:22;9375:41;;9447:2;9432:18;;9425:34;;;;9502:14;9495:22;9475:18;;;9468:50;9363:2;9348:18;79592:41:0;9185:339:1;114195:378:0;;;;;;:::i;:::-;;:::i;91374:163::-;;;;;;:::i;:::-;-1:-1:-1;;;;;91478:24:0;;;91454:4;91478:24;;;:7;:24;;;;;;;;:51;;;;;:42;;;;:51;;;;;;91374:163;;;;;116882:284;;;;;;:::i;:::-;;:::i;79263:21::-;;;;;;80775:53;;;;;;:::i;:::-;;;;;;;;;;;;;;110172:745;;;;;;:::i;:::-;;:::i;90879:47::-;;90922:4;90879:47;;;;;-1:-1:-1;;;;;10392:32:1;;;10374:51;;10362:2;10347:18;90879:47:0;10228:203:1;80137:20:0;;;;;;91192:174;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;79796:31::-;;;;;-1:-1:-1;;;79796:31:0;;;;;;116775:99;;;:::i;80351:69::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;20964:151;;;;;;:::i;:::-;;:::i;79005:40::-;;;;;-1:-1:-1;;;;;79005:40:0;;;102812:402;;;;;;:::i;:::-;;:::i;80837:52::-;;;;;;:::i;:::-;;;;;;;;;;;;;;36562:124;36650:30;;;;;;;;;;;-1:-1:-1;;;36650:30:0;;;;36562:124;;;;36650:30;36562:124;:::i;91545:388::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;106831:1075::-;;;;;;:::i;:::-;;:::i;:::-;;;;15465:25:1;;;15521:2;15506:18;;15499:34;;;;15438:18;106831:1075:0;15291:248:1;80429:69:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;80507:43;;;;;;:::i;:::-;;;;;;;;;;;;;;101755:655;;;;;;:::i;:::-;;:::i;97618:1443::-;;;;;;:::i;:::-;;:::i;79293:49::-;;;;;;:::i;:::-;;:::i;79054:47::-;;;;;-1:-1:-1;;;;;79054:47:0;;;108313:1291;;;;;;:::i;:::-;;:::i;79715:33::-;;;;;-1:-1:-1;;;79715:33:0;;;;;;79174:31;;;;;;94689:324;;;;;;:::i;:::-;;:::i;92514:1514::-;;;;;;:::i;:::-;;:::i;81136:33::-;;;;;;;;;80960:48;;;;;;:::i;:::-;;;;;;;;;;;;;;20170:167;;;;;;:::i;:::-;;:::i;78940:20::-;;;;;-1:-1:-1;;;;;78940:20:0;;;36692:103;36788:1;36692:103;;95989:1621;;;;;;:::i;:::-;;:::i;115200:1411::-;115325:5;;-1:-1:-1;;;;;115325:5:0;115311:10;:19;115303:65;;;;-1:-1:-1;;;115303:65:0;;16417:2:1;115303:65:0;;;16399:21:1;16456:2;16436:18;;;16429:30;16495:34;16475:18;;;16468:62;-1:-1:-1;;;16546:18:1;;;16539:31;16587:19;;115303:65:0;;;;;;;;;115389:21;;;;115388:22;115380:73;;;;-1:-1:-1;;;115380:73:0;;16819:2:1;115380:73:0;;;16801:21:1;16858:2;16838:18;;;16831:30;16897:34;16877:18;;;16870:62;-1:-1:-1;;;16948:18:1;;;16941:36;16994:19;;115380:73:0;16617:402:1;115380:73:0;115473:38;;;115465:64;;;;-1:-1:-1;;;115465:64:0;;17226:2:1;115465:64:0;;;17208:21:1;17265:2;17245:18;;;17238:30;-1:-1:-1;;;17284:18:1;;;17277:43;17337:18;;115465:64:0;17024:337:1;115465:64:0;115542:12;115565:19;115595:21;115627:15;115660:6;115655:907;115672:24;;;115655:907;;;115725:13;;115739:1;115725:16;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;115773:17:0;;;;;;:11;:17;;;;;;115718:23;;-1:-1:-1;115773:17:0;-1:-1:-1;115826:7:0;;115834:1;115826:10;;;;;;;:::i;:::-;;;;;;;115807:29;;115876:14;115857:16;:33;115853:469;;;115913:22;115938:33;115957:14;115938:16;:33;:::i;:::-;-1:-1:-1;;;;;116014:20:0;;115993:18;116014:20;;;:14;:20;;;;;;115913:58;;-1:-1:-1;116074:38:0;116014:20;115913:58;116074:4;:38::i;:::-;-1:-1:-1;;;;;116133:20:0;;;;;;:14;:20;;;;;;;;;:36;;;116195:57;;15465:25:1;;;15506:18;;;15499:34;;;116133:36:0;;-1:-1:-1;116133:20:0;;116195:57;;15438:18:1;116195:57:0;;;;;;;116292:14;116273:33;;115892:430;;;115853:469;116342:20;;116338:213;;116418:38;116423:14;116439:16;116418:4;:38::i;:::-;-1:-1:-1;;;;;116385:17:0;;;;;;:11;:17;;;;;;;;;:71;;;116482:53;;15465:25:1;;;15506:18;;;15499:34;;;116385:71:0;;-1:-1:-1;116385:17:0;;116482:53;;15438:18:1;116482:53:0;;;;;;;116338:213;115698:3;;;:::i;:::-;;;115655:907;;;-1:-1:-1;;116574:21:0;:28;;-1:-1:-1;;116574:28:0;116598:4;116574:28;;;-1:-1:-1;;;;;;;115200:1411:0:o;113678:509::-;-1:-1:-1;;;;;113772:24:0;;113747:4;113772:24;;;:7;:24;;;;;:33;;;113764:86;;;;-1:-1:-1;;;113764:86:0;;;;;;;:::i;:::-;113883:13;;-1:-1:-1;;;;;113883:13:0;113869:10;:27;;:50;;-1:-1:-1;113914:5:0;;-1:-1:-1;;;;;113914:5:0;113900:10;:19;113869:50;113861:102;;;;-1:-1:-1;;;113861:102:0;;;;;;;:::i;:::-;113996:5;;-1:-1:-1;;;;;113996:5:0;113982:10;:19;;:36;;-1:-1:-1;114014:4:0;114005:13;;;;113982:36;113974:71;;;;-1:-1:-1;;;113974:71:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;114058:37:0;;;;;;:20;:37;;;;;;;;;:45;;-1:-1:-1;;114058:45:0;;;;;;;;;;114119:37;;19320:51:1;;;19407:2;19387:18;;;19380:30;;;19446:1;19426:18;;;19419:29;;;;-1:-1:-1;;;19479:3:1;19464:19;;19457:37;19546:18;;;19539:50;114119:37:0;;19358:3:1;19511:19;114119:37:0;;;;;;;;-1:-1:-1;114174:5:0;113678:509;;;;;:::o;114958:234::-;115038:10;-1:-1:-1;;;;;115038:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;115024:32:0;:10;-1:-1:-1;;;;;115024:32:0;;115016:84;;;;-1:-1:-1;;;115016:84:0;;20066:2:1;115016:84:0;;;20048:21:1;20105:2;20085:18;;;20078:30;20144:34;20124:18;;;20117:62;-1:-1:-1;;;20195:18:1;;;20188:37;20242:19;;115016:84:0;19864:403:1;115016:84:0;115119:10;-1:-1:-1;;;;;115119:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:39;115111:73;;;;-1:-1:-1;;;115111:73:0;;20663:2:1;115111:73:0;;;20645:21:1;20702:2;20682:18;;;20675:30;-1:-1:-1;;;20721:18:1;;;20714:51;20782:18;;115111:73:0;20461:345:1;115111:73:0;114958:234;:::o;99310:378::-;-1:-1:-1;;;;;99552:15:0;;99469:4;99552:15;;;:7;:15;;;;;:24;;;99547:94;;-1:-1:-1;99605:23:0;99593:36;;99547:94;-1:-1:-1;99665:14:0;99310:378;;;;;;;:::o;114581:369::-;114673:13;;114634:4;;-1:-1:-1;;;;;114673:13:0;114659:10;:27;;:50;;-1:-1:-1;114704:5:0;;-1:-1:-1;;;;;114704:5:0;114690:10;:19;114659:50;114651:102;;;;-1:-1:-1;;;114651:102:0;;;;;;;:::i;:::-;114786:5;;-1:-1:-1;;;;;114786:5:0;114772:10;:19;;:36;;-1:-1:-1;114804:4:0;114795:13;;;;114772:36;114764:71;;;;-1:-1:-1;;;114764:71:0;;;;;;;:::i;:::-;114848:19;:27;;;;;-1:-1:-1;;;114848:27:0;-1:-1:-1;;;;114848:27:0;;;;;;114891:28;;;;;;114870:5;;21167:2:1;21149:21;;;21206:1;21186:18;;;21179:29;-1:-1:-1;;;21239:2:1;21224:18;;21217:35;21333:14;;21326:22;21319:4;21304:20;;21297:52;21284:3;21269:19;;20943:412;114891:28:0;;;;;;;;-1:-1:-1;114937:5:0;114581:369::o;107914:391::-;107986:4;108024:5;;-1:-1:-1;;;;;108024:5:0;108010:10;:19;108002:63;;;;-1:-1:-1;;;108002:63:0;;21562:2:1;108002:63:0;;;21544:21:1;21601:2;21581:18;;;21574:30;21640:33;21620:18;;;21613:61;21691:18;;108002:63:0;21360:355:1;108002:63:0;108108:19;;;108138:44;;;;108198:59;;;15465:25:1;;;15521:2;15506:18;;15499:34;;;108198:59:0;;15438:18:1;108198:59:0;;;;;;;;108282:14;108277:20;108270:27;107914:391;-1:-1:-1;;;107914:391:0:o;112371:355::-;112474:5;;-1:-1:-1;;;;;112474:5:0;112460:10;:19;112452:70;;;;-1:-1:-1;;;112452:70:0;;21922:2:1;112452:70:0;;;21904:21:1;21961:2;21941:18;;;21934:30;22000:34;21980:18;;;21973:62;-1:-1:-1;;;22051:18:1;;;22044:36;22097:19;;112452:70:0;21720:402:1;112452:70:0;112566:17;;;-1:-1:-1;;;;;112596:40:0;;;-1:-1:-1;;;;;;112596:40:0;;;;;;;112654:64;;;112566:17;;;;22339:34:1;;;22404:2;22389:18;;22382:43;;;;112654:64:0;;22274:18:1;112654:64:0;;;;;;;112441:285;112371:355;:::o;113167:503::-;-1:-1:-1;;;;;113259:24:0;;113234:4;113259:24;;;:7;:24;;;;;:33;;;113251:86;;;;-1:-1:-1;;;113251:86:0;;;;;;;:::i;:::-;113370:13;;-1:-1:-1;;;;;113370:13:0;113356:10;:27;;:50;;-1:-1:-1;113401:5:0;;-1:-1:-1;;;;;113401:5:0;113387:10;:19;113356:50;113348:102;;;;-1:-1:-1;;;113348:102:0;;;;;;;:::i;:::-;113483:5;;-1:-1:-1;;;;;113483:5:0;113469:10;:19;;:36;;-1:-1:-1;113501:4:0;113492:13;;;;113469:36;113461:71;;;;-1:-1:-1;;;113461:71:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;113545:35:0;;;;;;:18;:35;;;;;;;;;:43;;-1:-1:-1;;113545:43:0;;;;;;;;;;113604:35;;22685:51:1;;;22772:2;22752:18;;;22745:30;;;22811:1;22791:18;;;22784:29;;;;-1:-1:-1;;;22844:3:1;22829:19;;22822:35;22909:18;;;22902:50;113604:35:0;;22723:3:1;22874:19;113604:35:0;22436:522:1;36801:662:0;36906:5;-1:-1:-1;;;;;36924:59:0;;36941:42;36924:59;36920:538;;-1:-1:-1;37001:1:0;;36801:662;-1:-1:-1;36801:662:0:o;36920:538::-;-1:-1:-1;;;;;37020:59:0;;37037:42;37020:59;37016:442;;-1:-1:-1;37097:1:0;;36801:662;-1:-1:-1;36801:662:0:o;37016:442::-;-1:-1:-1;;;;;37116:59:0;;37133:42;37116:59;37112:346;;-1:-1:-1;37193:1:0;;36801:662;-1:-1:-1;36801:662:0:o;37112:346::-;-1:-1:-1;;;;;37212:59:0;;37229:42;37212:59;37208:250;;-1:-1:-1;37289:1:0;;36801:662;-1:-1:-1;36801:662:0:o;37208:250::-;-1:-1:-1;;;;;37308:59:0;;37325:42;37308:59;37304:154;;-1:-1:-1;37385:1:0;;36801:662;-1:-1:-1;36801:662:0:o;37304:154::-;37416:34;;-1:-1:-1;;;37416:34:0;;-1:-1:-1;;;;;3614:32:1;;37416:34:0;;;3596:51:1;3569:18;;37416:34:0;3450:203:1;104330:408:0;104506:4;104512;104518;104536:9;104547:14;104563;104581:98;104621:7;104637:12;104652;104666;104581:39;:98::i;:::-;104535:144;;;;;;104703:3;104698:9;;;;;;;;:::i;:::-;104690:40;-1:-1:-1;104709:9:0;;-1:-1:-1;104720:9:0;-1:-1:-1;;104330:408:0;;;;;;;;;:::o;94036:364::-;-1:-1:-1;;;;;94161:26:0;;94133:4;94161:26;;;:18;:26;;;;;;;;94160:27;94152:54;;;;-1:-1:-1;;;94152:54:0;;23165:2:1;94152:54:0;;;23147:21:1;23204:2;23184:18;;;23177:30;-1:-1:-1;;;23223:18:1;;;23216:44;23277:18;;94152:54:0;22963:338:1;94152:54:0;-1:-1:-1;;;;;94264:15:0;;;;;;:7;:15;;;;;:24;;;94259:94;;94317:23;94312:29;94305:36;;;;94259:94;94377:14;94365:27;94036:364;-1:-1:-1;;;;94036:364:0:o;109612:552::-;109702:4;109739:5;;-1:-1:-1;;;;;109739:5:0;109725:10;:19;109721:134;;109768:75;109773:18;109793:49;109768:4;:75::i;109721:134::-;109906:28;;;109947:62;;;;110027:89;;;15465:25:1;;;15521:2;15506:18;;15499:34;;;110027:89:0;;15438:18:1;110027:89:0;15291:248:1;95714:267:0;95881:17;;:37;;;;;95917:1;95902:12;:16;95881:37;95877:97;;;95935:27;;-1:-1:-1;;;95935:27:0;;23508:2:1;95935:27:0;;;23490:21:1;23547:2;23527:18;;;23520:30;-1:-1:-1;;;23566:18:1;;;23559:47;23623:18;;95935:27:0;23306:341:1;80102:26:0;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;80102:26:0;;-1:-1:-1;80102:26:0;:::o;103841:277::-;103908:4;103914;103920;103938:9;103949:14;103965;103983:74;104023:7;104047:1;104052;104055;103983:39;:74::i;:::-;103937:120;;;;;;104083:3;104078:9;;;;;;;;:::i;:::-;104070:40;104089:9;;-1:-1:-1;104089:9:0;-1:-1:-1;103841:277:0;-1:-1:-1;;;103841:277:0:o;112734:425::-;112803:4;112838:5;;-1:-1:-1;;;;;112838:5:0;112824:10;:19;112820:127;;112867:68;112872:18;112892:42;112867:4;:68::i;112820:127::-;112986:13;;;-1:-1:-1;;;;;113012:32:0;;;-1:-1:-1;;;;;;113012:32:0;;;;;;;113062:49;;;112986:13;;;;22339:34:1;;;22404:2;22389:18;;22382:43;;;;113062:49:0;;22274:18:1;113062:49:0;22127:304:1;100073:1209:0;-1:-1:-1;;;;;100331:23:0;;100284:4;100331:23;;;:7;:23;;;;;:32;;;100330:33;;:72;;-1:-1:-1;;;;;;100368:25:0;;;;;;:7;:25;;;;;:34;;;100367:35;100330:72;100326:141;;;100431:23;100426:29;100419:36;;;;100326:141;100500:52;;-1:-1:-1;;;100500:52:0;;-1:-1:-1;;;;;3614:32:1;;;100500:52:0;;;3596:51:1;100479:18:0;;100500:42;;;;;;3569:18:1;;100500:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;100479:73;;100569:36;100589:14;100569:12;:36::i;:::-;100565:672;;;100647:11;100630:13;:28;;100622:81;;;;-1:-1:-1;;;100622:81:0;;23854:2:1;100622:81:0;;;23836:21:1;23893:2;23873:18;;;23866:30;23932:34;23912:18;;;23905:62;-1:-1:-1;;;23983:18:1;;;23976:38;24031:19;;100622:81:0;23652:404:1;100622:81:0;100565:672;;;100739:9;100752:14;100770:37;100798:8;100770:27;:37::i;:::-;100738:69;;-1:-1:-1;100738:69:0;;-1:-1:-1;100833:14:0;;-1:-1:-1;100826:3:0;:21;;;;;;;;:::i;:::-;;100822:78;;100880:3;100875:9;;;;;;;;:::i;:::-;100868:16;;;;;;;100822:78;100920:9;100933:1;100920:14;100916:96;;100967:28;100962:34;;100916:96;101028:13;101044:71;101063:36;;;;;;;;101078:19;;101063:36;;;101101:13;101044:18;:71::i;:::-;101028:87;;101148:8;101134:11;:22;101130:96;;;101189:20;101177:33;;;;;;;;101130:96;100721:516;;;100565:672;101259:14;101247:27;;;100073:1209;;;;;;;;:::o;111760:603::-;111887:5;;-1:-1:-1;;;;;111887:5:0;111873:10;:19;;:54;;-1:-1:-1;111910:17:0;;-1:-1:-1;;;;;111910:17:0;111896:10;:31;111873:54;111865:120;;;;-1:-1:-1;;;111865:120:0;;24263:2:1;111865:120:0;;;24245:21:1;24302:2;24282:18;;;24275:30;24341:34;24321:18;;;24314:62;-1:-1:-1;;;24392:18:1;;;24385:51;24453:19;;111865:120:0;24061:417:1;111865:120:0;112016:7;112062:13;112103:15;;;;;:46;;;112136:13;112122:10;:27;112103:46;112095:72;;;;-1:-1:-1;;;112095:72:0;;24685:2:1;112095:72:0;;;24667:21:1;24724:2;24704:18;;;24697:30;-1:-1:-1;;;24743:18:1;;;24736:43;24796:18;;112095:72:0;24483:337:1;112095:72:0;112184:6;112180:176;112200:10;112196:1;:14;112180:176;;;112266:13;;112280:1;112266:16;;;;;;;:::i;:::-;;;;;;;112232:10;:31;112251:7;;112259:1;112251:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;112232:31:0;;;;;;;;;;;;-1:-1:-1;112232:31:0;:50;112315:7;;112323:1;112315:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;112302:42:0;;112327:13;;112341:1;112327:16;;;;;;;:::i;:::-;;;;;;;112302:42;;;;2718:25:1;;2706:2;2691:18;;2572:177;112302:42:0;;;;;;;;112212:3;;;;:::i;:::-;;;;112180:176;;;;111857:506;;111760:603;;;;:::o;114195:378::-;114290:13;;114251:4;;-1:-1:-1;;;;;114290:13:0;114276:10;:27;;:50;;-1:-1:-1;114321:5:0;;-1:-1:-1;;;;;114321:5:0;114307:10;:19;114276:50;114268:102;;;;-1:-1:-1;;;114268:102:0;;;;;;;:::i;:::-;114403:5;;-1:-1:-1;;;;;114403:5:0;114389:10;:19;;:36;;-1:-1:-1;114421:4:0;114412:13;;;;114389:36;114381:71;;;;-1:-1:-1;;;114381:71:0;;;;;;;:::i;:::-;114465:22;:30;;;;;-1:-1:-1;;;114465:30:0;-1:-1:-1;;;;114465:30:0;;;;;;114511:31;;;;;;114490:5;;25049:2:1;25031:21;;;25088:1;25068:18;;;25061:29;-1:-1:-1;;;25121:2:1;25106:18;;25099:38;25218:14;;25211:22;25204:4;25189:20;;25182:52;25169:3;25154:19;;24825:415;116882:284:0;-1:-1:-1;;;;;116977:24:0;;116940:4;116977:24;;;:7;:24;;;;;:49;;;:54;:116;;;;-1:-1:-1;;;;;;117048:37:0;;;;;;:20;:37;;;;;;;;:45;;:37;:45;116977:116;:171;;;;;117110:6;-1:-1:-1;;;;;117110:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;117144:4;117110:38;116957:191;116882:284;-1:-1:-1;;116882:284:0:o;110172:745::-;110229:4;110264:5;;-1:-1:-1;;;;;110264:5:0;110250:10;:19;110246:123;;110293:64;110298:18;110318:38;110293:4;:64::i;110246:123::-;-1:-1:-1;;;;;110385:24:0;;;;;;:7;:24;;;;;:33;;;110381:141;;;110442:68;110447:27;110476:33;110442:4;:68::i;110381:141::-;110534:6;-1:-1:-1;;;;;110534:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;;110592:24:0;;110565;110592;;;:7;:24;;;;;110627:25;;110648:4;-1:-1:-1;;110627:25:0;;;;;;;110663:18;;;:26;;;;;;;;110700:34;;:38;;;;110751:35;110592:24;110751:18;:35::i;:::-;110797:34;110823:6;110797:17;:34::i;:::-;110849:20;;-1:-1:-1;;;;;3614:32:1;;3596:51;;110849:20:0;;3584:2:1;3569:18;110849:20:0;3450:203:1;91192:174:0;-1:-1:-1;;;;;91308:22:0;;91281:24;91308:22;;;:13;:22;;;;;;;;91281:49;;;;;;;;;;;;;;;;;91253:15;;91281:24;:49;;91308:22;91281:49;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;91281:49:0;;;;;;;;;;;;;;;;-1:-1:-1;91281:49:0;;91192:174;-1:-1:-1;;;;;;;91192:174:0:o;116775:99::-;116821:15;116856:10;116849:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;116849:17:0;;;;;;;;;;;;;;;;;;;;;;;116775:99;:::o;20964:151::-;21043:7;21066:43;21102:6;21066:35;:43::i;102812:402::-;102955:22;;102927:4;;-1:-1:-1;;;102955:22:0;;;;102954:23;102946:54;;;;-1:-1:-1;;;102946:54:0;;25697:2:1;102946:54:0;;;25679:21:1;25736:2;25716:18;;;25709:30;-1:-1:-1;;;25755:18:1;;;25748:48;25813:18;;102946:54:0;25495:342:1;102946:54:0;103013:12;103028:50;103050:6;103058:3;103063:14;103028:21;:50::i;:::-;103013:65;-1:-1:-1;103093:31:0;;103089:78;;103148:7;-1:-1:-1;103141:14:0;;103089:78;103191:14;103179:27;102812:402;-1:-1:-1;;;;;;102812:402:0:o;91545:388::-;91655:14;;91618:13;;91644:8;91655:14;91706:15;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;91706:15:0;;91682:39;;91737:6;91732:167;91753:3;91749:1;:7;91732:167;;;91778:13;91801:7;91809:1;91801:10;;;;;;;;:::i;:::-;;;;;;;91778:34;;91847:39;91867:6;91875:10;91847:19;:39::i;:::-;91842:45;;;;;;;;:::i;:::-;91829:7;91837:1;91829:10;;;;;;;;:::i;:::-;;;;;;;;;;:58;-1:-1:-1;91758:3:0;;;;:::i;:::-;;;;91732:167;;;-1:-1:-1;91918:7:0;91545:388;-1:-1:-1;;;91545:388:0:o;106831:1075::-;106976:4;106982;107001:26;107030:42;107056:14;107030:18;:42::i;:::-;107001:71;;107083:28;107114:44;107140:16;107114:18;:44::i;:::-;107083:75;-1:-1:-1;107173:26:0;;;:58;;-1:-1:-1;107203:28:0;;107173:58;107169:126;;;107261:17;107281:1;107248:35;;;;;;;;107169:126;107307:25;107342:16;-1:-1:-1;;;;;107335:43:0;;:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;107307:73;;107392:16;107419:20;-1:-1:-1;;;;;;;;;;;;;;107419:20:0;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;107529:45:0;;;;;;;107544:28;;107529:45;;107576:38;;;;;;;;;;;-1:-1:-1;;107524:91:0;;:4;:91::i;:::-;107512:103;;107640:85;107645:40;;;;;;;;107660:23;107645:40;;;107687:37;;;;;;;;107702:20;107687:37;;;107640:4;:85::i;:::-;107626:99;;107744:28;107749:9;107760:11;107744:4;:28::i;:::-;107736:36;;107799:44;107818:5;107825:17;107799:18;:44::i;:::-;107869:14;;-1:-1:-1;107785:58:0;-1:-1:-1;;;;;;;;106831:1075:0;;;;;;;:::o;101755:655::-;101984:19;;101956:4;;-1:-1:-1;;;101984:19:0;;;;101983:20;101975:48;;;;-1:-1:-1;;;101975:48:0;;26044:2:1;101975:48:0;;;26026:21:1;26083:2;26063:18;;;26056:30;-1:-1:-1;;;26102:18:1;;;26095:45;26157:18;;101975:48:0;25842:339:1;101975:48:0;-1:-1:-1;;;;;102065:25:0;;;;;;:7;:25;;;;;:34;;;102064:35;;:72;;-1:-1:-1;;;;;;102104:23:0;;;;;;:7;:23;;;;;:32;;;102103:33;102064:72;102060:141;;;102165:23;102160:29;;102060:141;102266:14;-1:-1:-1;;;;;102259:34:0;;:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;102217:78:0;102224:16;-1:-1:-1;;;;;102217:36:0;;:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;102217:78:0;;102213:150;;102324:26;102319:32;;97618:1443;-1:-1:-1;;;;;97749:28:0;;97721:4;97749:28;;;:20;:28;;;;;;;;97748:29;97740:58;;;;-1:-1:-1;;;97740:58:0;;26681:2:1;97740:58:0;;;26663:21:1;26720:2;26700:18;;;26693:30;-1:-1:-1;;;26739:18:1;;;26732:46;26795:18;;97740:58:0;26479:340:1;97740:58:0;-1:-1:-1;;;;;97816:15:0;;;;;;:7;:15;;;;;:24;;;97811:94;;97869:23;97864:29;;97811:94;-1:-1:-1;;;;;97922:15:0;;;;;;;:7;:15;;;;;;;;:43;;;;;:33;;;;:43;;;;;;97917:371;;97992:10;-1:-1:-1;;;;;97992:20:0;;;97984:54;;;;-1:-1:-1;;;97984:54:0;;27026:2:1;97984:54:0;;;27008:21:1;27065:2;27045:18;;;27038:30;-1:-1:-1;;;27084:18:1;;;27077:51;27145:18;;97984:54:0;26824:345:1;97984:54:0;98055:9;98067:49;98094:10;98107:8;98067:19;:49::i;:::-;98055:61;-1:-1:-1;98142:14:0;98135:3;:21;;;;;;;;:::i;:::-;;98131:78;;98189:3;98184:9;;;;;;;;:::i;:::-;98177:16;;;;;98131:78;-1:-1:-1;;;;;98232:15:0;;;;;;;:7;:15;;;;;;;;:43;;;;;:33;;;;:43;;;;;;98225:51;;;;:::i;:::-;97967:321;97917:371;98304:34;98330:6;98304:18;:34::i;:::-;98342:1;98304:39;98300:102;;98372:17;98367:23;;98300:102;-1:-1:-1;;;;;98431:18:0;;98414:14;98431:18;;;:10;:18;;;;;;98466:14;;98462:248;;98497:17;98524:6;-1:-1:-1;;;;;98517:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;98497:49;;98561:21;98585:32;98590:12;98604;98585:4;:32::i;:::-;98561:56;;98659:9;98640:16;:28;98632:66;;;;-1:-1:-1;;;98632:66:0;;27508:2:1;98632:66:0;;;27490:21:1;27547:2;27527:18;;;27520:30;27586:27;27566:18;;;27559:55;27631:18;;98632:66:0;27306:349:1;98632:66:0;98482:228;;98462:248;98723:9;98736:14;98754:82;98794:8;98811:6;98820:1;98823:12;98754:39;:82::i;:::-;98722:114;;-1:-1:-1;98722:114:0;;-1:-1:-1;98858:14:0;;-1:-1:-1;98851:3:0;:21;;;;;;;;:::i;:::-;;98847:70;;98901:3;98896:9;;;;;;;;:::i;:::-;98889:16;;;;;;;98847:70;98931:13;;98927:87;;98973:28;98968:34;;98927:87;99038:14;99026:27;97618:1443;-1:-1:-1;;;;;;;97618:1443:0:o;79293:49::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;79293:49:0;;-1:-1:-1;79293:49:0;;-1:-1:-1;79293:49:0:o;108313:1291::-;108410:4;108447:5;;-1:-1:-1;;;;;108447:5:0;108433:10;:19;108429:130;;108476:71;108481:18;108501:45;108476:4;:71::i;:::-;108469:78;;;;108429:130;-1:-1:-1;;;;;108595:24:0;;108571:21;108595:24;;;:7;:24;;;;;108635:15;;;;108630:130;;108674:74;108679:23;108704:43;108674:4;:74::i;:::-;108667:81;;;;;108630:130;108808:44;;;;;;;;;;;;108888;;;;;;;;91117:6;108888:44;;108808;108947:46;108888:44;108808;52722:14;52706:13;;:30;;52603:141;108947:46;108943:169;;;109017:83;109022:31;109055:44;109017:4;:83::i;:::-;109010:90;;;;;;;108943:169;109128:32;;;;;:67;;;109164:26;109183:6;109164:18;:26::i;:::-;:31;109128:67;109124:179;;;109219:72;109224:17;109243:47;109219:4;:72::i;109124:179::-;109350:31;;;;;109392:61;;;;109471:85;;;-1:-1:-1;;;;;27895:32:1;;27877:51;;27959:2;27944:18;;27937:34;;;27987:18;;;27980:34;;;109471:85:0;;27865:2:1;27850:18;109471:85:0;;;;;;;109581:14;109576:20;109569:27;108313:1291;-1:-1:-1;;;;;;;108313:1291:0:o;94689:324::-;94792:4;94809:12;94824:53;94846:6;94854:8;94864:12;94824:21;:53::i;:::-;94809:68;-1:-1:-1;94892:31:0;;94888:78;;94947:7;-1:-1:-1;94940:14:0;;94888:78;94990:14;94978:27;94689:324;-1:-1:-1;;;;;94689:324:0:o;92514:1514::-;92701:37;;-1:-1:-1;;;92701:37:0;;92727:10;92701:37;;;3596:51:1;92584:4:0;;92624:13;;92584:4;;;;;;-1:-1:-1;;;;;92701:25:0;;;;;3569:18:1;;92701:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;92651:87;;;;;;;92757:4;92765:1;92757:9;92749:59;;;;-1:-1:-1;;;92749:59:0;;28600:2:1;92749:59:0;;;28582:21:1;28639:2;28619:18;;;28612:30;28678:34;28658:18;;;28651:62;-1:-1:-1;;;28729:18:1;;;28722:35;28774:19;;92749:59:0;28398:401:1;92749:59:0;92826:15;;92822:127;;92865:72;92870:28;92900:36;92865:4;:72::i;:::-;92858:79;92514:1514;-1:-1:-1;;;;;;92514:1514:0:o;92822:127::-;92961:12;92976:60;92998:13;93013:10;93025;92976:21;:60::i;:::-;92961:75;-1:-1:-1;93051:12:0;;93047:123;;93087:71;93098:15;93115:33;93150:7;93087:10;:71::i;93047:123::-;-1:-1:-1;;;;;93212:24:0;;93182:27;93212:24;;;:7;:24;;;;;;;;93285:10;93254:42;;:30;;;:42;;;;;;;;;93249:103;;93325:14;93320:20;93313:27;92514:1514;-1:-1:-1;;;;;;;;92514:1514:0:o;93249:103::-;93402:10;93371:42;;;;:30;;;:42;;;;;;;;93364:49;;-1:-1:-1;;93364:49:0;;;93458:13;:25;;;;;93426:57;;;;;;;;;;;;;;;;;;;93458:25;;93426:57;;;93458:25;93426:57;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;93426:57:0;;;;;;;;;;;;;;;;-1:-1:-1;;93505:20:0;;93426:57;;-1:-1:-1;93505:20:0;;-1:-1:-1;93494:8:0;;-1:-1:-1;;93568:162:0;93589:3;93585:1;:7;93568:162;;;93638:6;-1:-1:-1;;;;;93618:26:0;:13;93632:1;93618:16;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;93618:26:0;;93614:105;;93678:1;93665:14;;93698:5;;93614:105;93594:3;;;;:::i;:::-;;;;93568:162;;;;93762:3;93749:10;:16;93742:24;;;;:::i;:::-;93823:10;93779:27;93809:25;;;:13;:25;;;;;93881:17;;93809:25;;93881:21;;93901:1;;93881:21;:::i;:::-;93870:33;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;93870:33:0;93845:10;93856;93845:22;;;;;;;;:::i;:::-;;;;;;;;;:58;;;;;-1:-1:-1;;;;;93845:58:0;;;;;-1:-1:-1;;;;;93845:58:0;;;;;;93914:10;:16;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;93914:16:0;;;;;-1:-1:-1;;;;;;93914:16:0;;;;;;93948:32;;;;;;93961:6;;93969:10;;-1:-1:-1;;;;;22357:15:1;;;22339:34;;22409:15;;22404:2;22389:18;;22382:43;22289:2;22274:18;;22127:304;93948:32:0;;;;;;;;94005:14;93993:27;92514:1514;-1:-1:-1;;;;;;;;;;;;92514:1514:0:o;20170:167::-;20263:68;20301:29;20263:37;:68::i;95989:1621::-;96053:4;96070:16;96099:13;96185:24;;;;;;-1:-1:-1;;;29462:19:1;;29506:1;29497:11;;29260:254;96185:24:0;;;;;;;;;;;;;96175:35;;;;;;96154:6;-1:-1:-1;;;;;96154:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;96154:15:0;;;;;;;;;;;;:::i;:::-;96137:33;;;;;;;;:::i;:::-;;;;;;;;;;;;;96127:44;;;;;;:83;96123:1454;;96238:46;-1:-1:-1;;;96238:30:0;:46::i;:::-;96227:57;;96123:1454;;;96364:25;;-1:-1:-1;;;96364:25:0;;;30739:20:1;30775:11;;96364:25:0;;;;;;;;;;;;96354:36;;;;;;96333:6;-1:-1:-1;;;;;96333:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;96333:15:0;;;;;;;;;;;;:::i;:::-;96316:33;;;;;;;;:::i;:::-;;;;;;;;;;;;;96306:44;;;;;;:84;96302:1275;;96418:46;-1:-1:-1;;;96418:30:0;:46::i;96302:1275::-;96544:25;;-1:-1:-1;;;96544:25:0;;;30999:20:1;31035:11;;96544:25:0;;;;;;;;;;;;96534:36;;;;;;96513:6;-1:-1:-1;;;;;96513:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;96513:15:0;;;;;;;;;;;;:::i;:::-;96496:33;;;;;;;;:::i;:::-;;;;;;;;;;;;;96486:44;;;;;;:84;96482:1095;;96598:47;-1:-1:-1;;;96598:30:0;:47::i;:::-;:54;;96648:4;96598:54;:::i;96482:1095::-;96732:25;;-1:-1:-1;;;96732:25:0;;;31432:20:1;31468:11;;96732:25:0;;;;;;;;;;;;96722:36;;;;;;96701:6;-1:-1:-1;;;;;96701:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;96701:15:0;;;;;;;;;;;;:::i;:::-;96684:33;;;;;;;;:::i;:::-;;;;;;;;;;;;;96674:44;;;;;;:84;96670:907;;96786:47;-1:-1:-1;;;96786:30:0;:47::i;96670:907::-;96920:25;;-1:-1:-1;;;96920:25:0;;;31692:20:1;31728:11;;96920:25:0;;;;;;;;;;;;96910:36;;;;;;96889:6;-1:-1:-1;;;;;96889:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;96889:15:0;;;;;;;;;;;;:::i;:::-;96872:33;;;;;;;;:::i;:::-;;;;;;;;;;;;;96862:44;;;;;;:84;96858:719;;96974:46;-1:-1:-1;;;96974:30:0;:46::i;:::-;:53;;97023:4;96974:53;:::i;96858:719::-;97060:30;97131:6;-1:-1:-1;;;;;97116:34:0;;:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;97093:68:0;;:70;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;97093:70:0;;;;;;;;;;;;:::i;:::-;97060:103;;97178:14;97207:32;97248:16;97207:58;;97284:19;:26;97314:1;97284:31;97280:84;;97345:3;;-1:-1:-1;97280:84:0;97444:2;97426:16;97422:25;97416:32;97406:42;;97493:6;97477:23;;97528:37;97559:5;97528:30;:37::i;96858:719::-;-1:-1:-1;97594:8:0;95989:1621;-1:-1:-1;;95989:1621:0:o;53846:90::-;53899:4;53923:5;53927:1;53923;:5;:::i;54268:90::-;54321:4;54345:5;54349:1;54345;:5;:::i;104746:2077::-;104931:5;104938:4;104944;104963:37;;:::i;:::-;-1:-1:-1;;;;;105059:22:0;;105012:9;105059:22;;;:13;:22;;;;;;;;105034:47;;;;;;;;;;;;;;;;;105012:9;;105034:47;;105059:22;105034:47;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;105034:47:0;;;;;;;;;;;;;;;;;;;;;;;105097:6;105092:1452;105113:6;:13;105109:1;:17;105092:1452;;;105148:12;105163:6;105170:1;105163:9;;;;;;;;:::i;:::-;;;;;;;;;;;105265:33;;-1:-1:-1;;;105265:33:0;;-1:-1:-1;;;;;3614:32:1;;;105265:33:0;;;3596:51:1;105163:9:0;;-1:-1:-1;105265:24:0;;;;;;3569:18:1;;105265:33:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;105236:25;;;105189:109;105216:18;;;105189:109;105196:18;;;105189:109;;-1:-1:-1;105317:9:0;;105313:86;;105356:20;105378:1;105381;105348:35;;;;;;;;;;;;;105313:86;105437:65;;;;;;;;;-1:-1:-1;;;;;105452:23:0;;-1:-1:-1;105452:23:0;;;:7;:23;;;;;:48;;;105437:65;;105413:21;;;:89;;;;105537:42;;;;;;;;-1:-1:-1;;;105552:25:0;105537:42;;105517:17;;;:62;105623:25;105468:5;105623:18;:25::i;:::-;105596:24;;;:52;;;105695:1;105667:29;105663:102;;105725:17;105744:1;105747;105717:32;;;;;;;;;;;;;105663:102;105798:41;;;;;;;;;105813:24;;;;105798:41;;105779:16;;;:60;105887:21;;;;105910:17;;;;105877:70;;105882:46;;:4;:46::i;:::-;105930:4;:16;;;105877:4;:70::i;:::-;105856:18;;;:91;;;106031:18;;;;106051;;105985:85;;105856:91;106031:18;105985:25;:85::i;:::-;105964:106;;106141:16;;;;106159:18;;;;106179:25;;;;106115:90;;106141:16;106159:18;106115:25;:90::i;:::-;106087:25;;;:118;-1:-1:-1;;;;;106226:21:0;;;;;;;106222:311;;106298:86;106324:4;:18;;;106344:12;106358:4;:25;;;106298;:86::i;:::-;106270:25;;;:114;;;106459:16;;;;106433:84;;106477:12;;106433:25;:84::i;:::-;106405:25;;;:112;106222:311;-1:-1:-1;105128:3:0;;;;:::i;:::-;;;;105092:1452;;;-1:-1:-1;106581:25:0;;;;106560:18;;:46;106556:260;;;106668:25;;;;106647:18;;106631:14;;106647:46;;;:::i;:::-;106695:1;106623:74;;;;;;;;;;;106556:260;106738:14;106754:1;106785:4;:18;;;106757:4;:25;;;:46;;;;:::i;:::-;106730:74;;;;;;;;;;;42657:153;42718:4;42740:33;42753:3;42748:9;;;;;;;;:::i;:::-;42764:4;42759:10;;;;;;;;:::i;:::-;42740:33;;;6499:25:1;;;6555:2;6540:18;;6533:34;;;;42771:1:0;6583:18:1;;;6576:34;6487:2;6472:18;42740:33:0;;;;;;;42798:3;42793:9;;;;;;;;:::i;104126:196::-;104203:5;104210:4;104216;104240:74;104280:7;104304:1;104309;104312;104240:39;:74::i;:::-;104233:81;;;;;;104126:196;;;;;:::o;52205:174::-;52283:4;52300:18;52321:15;52326:1;52329:6;52321:4;:15::i;:::-;52300:36;;52354:17;52363:7;52354:8;:17::i;110925:250::-;110994:6;110989:137;111010:10;:17;111006:21;;110989:137;;;111082:6;-1:-1:-1;;;;;111058:31:0;:10;111069:1;111058:13;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;111058:13:0;:31;111050:64;;;;-1:-1:-1;;;111050:64:0;;32414:2:1;111050:64:0;;;32396:21:1;32453:2;32433:18;;;32426:30;-1:-1:-1;;;32472:18:1;;;32465:50;32532:18;;111050:64:0;32212:344:1;111050:64:0;111029:4;;;;:::i;:::-;;;;110989:137;;;-1:-1:-1;111136:10:0;:31;;;;;;;-1:-1:-1;111136:31:0;;;;;;;;-1:-1:-1;;;;;;111136:31:0;-1:-1:-1;;;;;111136:31:0;;;;;;;;;;110925:250::o;111183:569::-;111246:18;111267:56;117253:12;111267:56;;;;;;;;;;;;;;;;;:6;:56::i;:::-;-1:-1:-1;;;;;111374:23:0;;111336:35;111374:23;;;:15;:23;;;;;;;;111446:15;:23;;;;;111486:17;;111246:77;;-1:-1:-1;111374:23:0;;111446;;-1:-1:-1;;;;;111486:17:0;;;:22;;111482:93;;111527:36;;-1:-1:-1;;;;;;111527:36:0;90922:4;111527:36;;;111482:93;111591:17;;-1:-1:-1;;;;;111591:17:0;;:22;111587:93;;111632:36;;-1:-1:-1;;;;;;111632:36:0;90922:4;111632:36;;;111587:93;111713:31;;;;;;-1:-1:-1;;;111713:31:0;-1:-1:-1;;;;;111713:31:0;;;;;;;;111693:51;;;;;;;;;;-1:-1:-1;111183:569:0:o;18663:136::-;18736:7;18759:34;18786:6;18759:26;:34::i;95021:685::-;-1:-1:-1;;;;;95150:15:0;;95128:4;95150:15;;;:7;:15;;;;;:24;;;95145:94;;95203:23;95198:29;;95145:94;-1:-1:-1;;;;;95256:15:0;;;;;;;:7;:15;;;;;;;;:43;;;;;:33;;;;:43;;;;;;95251:104;;95328:14;95323:20;;95251:104;95368:9;95381:14;95399:82;95439:8;95456:6;95465:12;95479:1;95399:39;:82::i;:::-;95367:114;;-1:-1:-1;95367:114:0;;-1:-1:-1;95503:14:0;;-1:-1:-1;95496:3:0;:21;;;;;;;;:::i;:::-;;95492:70;;95546:3;95541:9;;;;;;;;:::i;:::-;95534:16;;;;;;95492:70;95576:13;;95572:87;;95618:28;95613:34;;91941:565;-1:-1:-1;;;;;92069:24:0;;92021:5;92069:24;;;:7;:24;;;;;92111:21;;;;92106:87;;92158:23;92151:30;;;;;92106:87;-1:-1:-1;;;;;92209:40:0;;;;;;:30;;;:40;;;;;;;;:48;;:40;:48;92205:104;;92283:14;92276:21;;;;;92205:104;-1:-1:-1;;;;;92321:40:0;;;;;;;:30;;;:40;;;;;;;;:47;;92364:4;-1:-1:-1;;92321:47:0;;;;;;;;92379:13;:23;;;;;:36;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;92379:36:0;;;;;;;;;92433:31;;22339:34:1;;;22389:18;;22382:43;;;;92433:31:0;;22274:18:1;92433:31:0;;;;;;;-1:-1:-1;92484:14:0;;91941:565;-1:-1:-1;;;91941:565:0:o;54366:159::-;-1:-1:-1;;;;;;;;;;;;54461:56:0;;;;;;;;51837:4;54476:28;54481:1;:10;;;54493:1;:10;;;54476:4;:28::i;:::-;:39;;;;:::i;:::-;54461:56;;54454:63;54366:159;-1:-1:-1;;;54366:159:0:o;55368:164::-;-1:-1:-1;;;;;;;;;;;;55463:61:0;;;;;;;;55478:44;55483:26;55488:1;:10;;;51837:4;55483;:26::i;:::-;55511:10;;55478:4;:44::i;42818:187::-;42903:4;42925:43;42938:3;42933:9;;;;;;;;:::i;:::-;42949:4;42944:10;;;;;;;;:::i;:::-;42925:43;;;6499:25:1;;;6555:2;6540:18;;6533:34;;;;6583:18;;6576:34;;;6487:2;6472:18;42925:43:0;;;;;;;42993:3;42988:9;;;;;;;;:::i;17682:975::-;18135:32;18170:36;18202:4;18170:29;:36;:::i;:::-;18135:71;;18237:24;18219:15;:42;18215:437;;;17483:9;18277:42;18304:15;18277:24;:42;:::i;:::-;18276:87;18272:190;;;18383:69;;-1:-1:-1;;;18383:69:0;;;;;15465:25:1;;;18436:15:0;15506:18:1;;;15499:34;15438:18;;18383:69:0;15291:248:1;18272:190:0;17762:895;17682:975;:::o;18215:437::-;17409:9;18480:42;18498:24;18480:15;:42;:::i;:::-;18479:87;18475:177;;;18584:60;;-1:-1:-1;;;18584:60:0;;;;;15465:25:1;;;18628:15:0;15506:18:1;;;15499:34;15438:18;;18584:60:0;15291:248:1;32370:278:0;32531:16;;;32545:1;32531:16;;;;;;;;;32481:7;;;;32531:16;;;;;;;;;;;;-1:-1:-1;32531:16:0;32500:47;;32571:10;32554:11;32566:1;32554:14;;;;;;;;:::i;:::-;;;;;;:27;;;;;32595:44;32627:11;32595:31;:44::i;:::-;32640:1;32595:47;;;;;;;;:::i;:::-;;;;;;;32588:54;;;32370:278;;;:::o;52387:208::-;52485:4;52502:18;52523:15;52528:1;52531:6;52523:4;:15::i;:::-;52502:36;;52556:31;52561:17;52570:7;52561:8;:17::i;:::-;52580:6;52556:4;:31::i;54533:133::-;-1:-1:-1;;;;;;;;;;;;54622:36:0;;;;;;;;54637:19;54642:1;:10;;;54654:1;54637:4;:19::i;52083:114::-;52166:12;;52140:4;;52166:23;;51837:4;;52166:23;:::i;53353:161::-;53428:6;53466:12;53459:5;53455:9;;53447:32;;;;-1:-1:-1;;;53447:32:0;;;;;;;;:::i;:::-;-1:-1:-1;53504:1:0;;53353:161;-1:-1:-1;;53353:161:0:o;15883:403::-;15948:7;15968:3;:10;15982:1;15968:15;15964:75;;16001:30;;-1:-1:-1;;;16001:30:0;;;;;;;;;;;15964:75;16045:9;16050:3;16045:4;:9::i;:::-;16061:19;16096:1;16083:3;:10;:14;;;;:::i;:::-;16061:36;;16121:1;16108:3;:10;:14;;;;:::i;:::-;16126:1;16108:19;16104:177;;16138:11;16152:52;16165:3;16169:15;16183:1;16169:11;:15;:::i;:::-;16165:20;;;;;;;;:::i;:::-;;;;;;;16187:3;16191:11;16187:16;;;;;;;;:::i;:::-;;;;;;;16152:12;:52::i;:::-;16138:66;-1:-1:-1;16220:7:0;16226:1;16138:66;16220:7;:::i;16104:177::-;16257:3;16261:11;16257:16;;;;;;;;:::i;55270:90::-;55323:4;55347:5;55351:1;55347;:5;:::i;56292:90::-;56345:4;56369:5;56373:1;56369;:5;:::i;33509:213::-;33631:16;33666:50;33704:11;33666:37;:50::i;16292:774::-;16390:3;16384:10;16428:20;16423:3;16419:30;16501:16;16490:9;16486:32;16475:9;16471:48;16457:62;;16557:9;16527:527;16588:6;16579:7;16576:19;16527:527;;;16718:9;16686:359;16751:7;16742;16739:20;16686:359;;;16874:7;16868:14;16912:7;16906:14;16944:4;16938;16935:14;16932:102;;;16981:4;16972:7;16965:21;17016:4;17007:7;17000:21;16932:102;-1:-1:-1;;16797:16:0;16784:30;16686:359;;;-1:-1:-1;16631:16:0;16618:30;16527:527;;22032:2070;22147:16;22236:48;22301:11;:18;22287:33;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;22287:33:0;;22236:84;;22327:44;22388:11;:18;22374:33;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;22374:33:0;;22327:80;;22414:37;22470:11;:18;22454:35;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22414:75;;22501:9;22496:350;22520:11;:18;22516:1;:22;22496:350;;;22796:42;;;36788:1;22796:42;;;;;;;;;;;;;;;;;;;;-1:-1:-1;22796:42:0;22772:18;22791:1;22772:21;;;;;;;;:::i;:::-;;;;;;:66;;;;22540:3;;;;;:::i;:::-;;;;22496:350;;;;22915:30;22948:36;:34;:36::i;:::-;22915:69;;22991:25;23019:61;23057:22;23019:37;:61::i;:::-;22991:89;;;-1:-1:-1;23087:48:0;2638:1;23087:48;;:::i;:::-;23250:15;23244:22;23087:48;;-1:-1:-1;23187:18:0;23324:585;23378:17;23359:16;:36;23324:585;;;23492:27;23522:192;23552:11;23574:31;23616:27;23654:18;23683:22;23522:19;:192::i;:::-;23492:222;-1:-1:-1;23723:45:0;23492:222;23723:45;;:::i;:::-;;;23882:10;23865:15;23858:35;23847:55;23397:18;;;;;:::i;:::-;;;;23324:585;;;;24023:73;24044:18;24064:31;24023:20;:73::i;11718:1200::-;11787:7;12099:20;-1:-1:-1;;11962:14:0;11958:37;11945:51;12074:46;;12030:99;;12142:83;;12187:30;;-1:-1:-1;;;12187:30:0;;;;;;;;;;;12142:83;12310:31;12395:8;3752:2;12352:58;12348:113;;;12428:25;;-1:-1:-1;;;12428:25:0;;;;;;;;;;;12348:113;-1:-1:-1;;;12540:14:0;12536:61;12513:93;12619:30;2994:1;12652:64;2941:1;12652:64;;;;:::i;:::-;:92;;;;:::i;:::-;12619:125;-1:-1:-1;12805:8:0;12755:47;2638:1;12619:125;12755:47;:::i;:::-;:65;12751:126;;;12838:31;;-1:-1:-1;;;12838:31:0;;;;;;;;;;;13003:540;13120:24;;13205:41;2023:2;13205:22;:41;:::i;:::-;13156:90;-1:-1:-1;13298:8:0;13257:56;;13253:111;;;13331:25;;-1:-1:-1;;;13331:25:0;;;;;;;;;;;13253:111;13436:14;13432:59;13409:91;;13003:540;-1:-1:-1;;13003:540:0:o;24917:4605::-;25195:7;25211:19;25248:23;25280:34;25324:63;25364:22;25324:39;:63::i;:::-;25239:148;;-1:-1:-1;25239:148:0;-1:-1:-1;25466:25:0;;;25557:26;25466:25;3605:2;25660:70;25680:49;2812:2;25239:148;25680:49;:::i;:::-;25660:15;;:19;:70::i;:::-;:125;;;;:::i;:::-;25634:151;-1:-1:-1;25866:31:0;25900:119;25930:88;3290:3;25930:22;:88;:::i;:::-;25900:8;;:19;:119::i;:::-;25866:153;-1:-1:-1;26030:35:0;26068:88;26132:23;26098:31;2533:2;26098:22;:31;:::i;:::-;:57;;;;:::i;26068:88::-;26030:126;;26246:111;26323:23;26283:27;26246:111;:::i;:::-;26229:128;;26474:23;26451:20;26436:13;26432:40;26422:76;26408:90;;26578:23;26565:37;26543:59;;26614:236;;26862:350;26682:15;26676:22;;26710:23;;;26761:20;26818;;;;;26794:45;;;26919:14;;26752:30;27099:10;27078:6;27041:22;27014:108;-1:-1:-1;;27152:49:0;;26862:350;-1:-1:-1;;;26862:350:0:o;:::-;27262:37;27280:18;27262:37;;:17;:37::i;:::-;27399:105;27443:10;27464:31;2533:2;27464:22;:31;:::i;:::-;27399:33;:105::i;:::-;27383:121;;27527:39;27552:13;27527:24;:39::i;:::-;27513:53;;;;25457:2117;;;;;;;27623:27;27659:22;27695;27690:1632;27740:15;27723:14;:32;27690:1632;;;27899:147;27947:22;27982:26;28021:14;27899:35;:147::i;:::-;27859:187;;-1:-1:-1;27859:187:0;-1:-1:-1;28076:23:0;28059:1254;28134:11;:18;28116:15;:36;28059:1254;;;28234:11;28246:15;28234:28;;;;;;;;:::i;:::-;;;;;;;28211:19;:51;28207:1095;;28279:34;28316:27;28344:15;28316:44;;;;;;;;:::i;:::-;;;;;;;28279:81;;28398:67;28425:26;28453:11;1382:1;:13;;1372:24;1410:14;;;1255:175;28398:67;28397:68;:225;;;;-1:-1:-1;36788:1:0;28544:78;;:31;28576:15;28544:48;;;;;;;;:::i;:::-;;;;;;;:78;28397:225;28377:806;;;28704:31;28736:15;28704:48;;;;;;;;:::i;:::-;;;;;;:50;;;;;;;;:::i;:::-;;;;;28931:14;28805:18;28824:15;28805:35;;;;;;;;:::i;:::-;;;;;;;28910:1;28859:31;28891:15;28859:48;;;;;;;;:::i;:::-;;;;;;;:52;;;;:::i;:::-;28805:123;;;;;;;;:::i;:::-;;;;;;;;;;:140;1229:1;:13;;1219:24;;29004:27;29032:15;29004:44;;;;;;;;:::i;:::-;;;;;;:163;;;;;28377:806;29283:5;;;28207:1095;28165:17;;;;:::i;:::-;;;;28059:1254;;;-1:-1:-1;27757:16:0;;;;:::i;:::-;;;;27690:1632;;;;27614:1715;;29501:15;2812:2;29441:26;:49;;;;:::i;:::-;29440:76;;;;:::i;:::-;29395:121;;3446:2;29395:121;:::i;:::-;29381:135;24917:4605;-1:-1:-1;;;;;;;;;24917:4605:0:o;30004:880::-;30160:16;30185:33;30235:18;:25;30221:40;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;30221:40:0;-1:-1:-1;30185:76:0;-1:-1:-1;36788:1:0;30268:30;30337:510;30385:18;:25;30369:13;:41;30337:510;;;30491:22;30442:31;30474:13;30442:46;;;;;;;;:::i;:::-;;;;;;;:71;30438:233;;;30579:31;30611:13;30579:46;;;;;;;;:::i;:::-;;;;;;;30638:22;30533:128;;-1:-1:-1;;;30533:128:0;;;;;;;;15465:25:1;;;15521:2;15506:18;;15499:34;15453:2;15438:18;;15291:248;30438:233:0;30679:36;30718:50;30734:18;30753:13;30734:33;;;;;;;;:::i;:::-;;;;;;;30718:15;:50::i;:::-;30679:89;;30811:28;30777:16;30794:13;30777:31;;;;;;;;:::i;:::-;;;;;;;;;;:62;-1:-1:-1;30412:15:0;;;;:::i;:::-;;;;30337:510;;;-1:-1:-1;30862:16:0;;30004:880;-1:-1:-1;;;;30004:880:0:o;14370:1053::-;14503:23;;;;;14862:45;2533:2;14862:36;:45;:::i;:::-;14829:78;-1:-1:-1;14914:22:0;14939:62;14959:41;2023:2;14829:78;14959:41;:::i;14939:62::-;15046:28;;;-1:-1:-1;14914:87:0;-1:-1:-1;15149:40:0;14914:87;2693:1;15149:18;:40::i;:::-;15320:34;;;;;;15245:28;;15361:56;;;-1:-1:-1;15320:34:0;;-1:-1:-1;;;;;14370:1053:0:o;254:727::-;775:46;945:30;;383:7;945:30;;;671:14;945:30;;;;;;33162:25:1;;;503:14:0;499:52;;;775:46;;;842:39;834:48;;33203:18:1;;;33196:45;;;564:39:0;;33257:18:1;;;33250:34;;;640:46:0;;699:39;33300:18:1;;;33293:34;;;383:7:0;;564:39;;945:30;;33134:19:1;;945:30:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;945:30:0;;-1:-1:-1;;945:30:0;;;254:727;-1:-1:-1;;;;;;;254:727:0:o;13549:815::-;13754:27;;;13851:74;3446:2;13851:36;:74;:::i;:::-;13814:111;-1:-1:-1;13932:31:0;13966:126;14005:80;14031:52;2812:2;14031:29;:52;:::i;:::-;14006:18;14010:14;14006:1;:18;:::i;:::-;14005:24;;:80::i;:::-;13966:26;;:30;:126::i;:::-;13932:160;-1:-1:-1;14099:31:0;14133:44;:8;13932:160;14133:19;:44::i;:::-;14225:37;;;14330:20;14301:50;;;14288:64;;-1:-1:-1;13549:815:0;-1:-1:-1;;;;;;;13549:815:0:o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;206:367:1:-;269:8;279:6;333:3;326:4;318:6;314:17;310:27;300:55;;351:1;348;341:12;300:55;-1:-1:-1;374:20:1;;417:18;406:30;;403:50;;;449:1;446;439:12;403:50;486:4;478:6;474:17;462:29;;546:3;539:4;529:6;526:1;522:14;514:6;510:27;506:38;503:47;500:67;;;563:1;560;553:12;500:67;206:367;;;;;:::o;578:773::-;700:6;708;716;724;777:2;765:9;756:7;752:23;748:32;745:52;;;793:1;790;783:12;745:52;833:9;820:23;862:18;903:2;895:6;892:14;889:34;;;919:1;916;909:12;889:34;958:70;1020:7;1011:6;1000:9;996:22;958:70;:::i;:::-;1047:8;;-1:-1:-1;932:96:1;-1:-1:-1;1135:2:1;1120:18;;1107:32;;-1:-1:-1;1151:16:1;;;1148:36;;;1180:1;1177;1170:12;1148:36;;1219:72;1283:7;1272:8;1261:9;1257:24;1219:72;:::i;:::-;578:773;;;;-1:-1:-1;1310:8:1;-1:-1:-1;;;;578:773:1:o;1356:139::-;-1:-1:-1;;;;;1439:31:1;;1429:42;;1419:70;;1485:1;1482;1475:12;1500:118;1586:5;1579:13;1572:21;1565:5;1562:32;1552:60;;1608:1;1605;1598:12;1623:405;1703:6;1711;1764:2;1752:9;1743:7;1739:23;1735:32;1732:52;;;1780:1;1777;1770:12;1732:52;1819:9;1806:23;1838:39;1871:5;1838:39;:::i;:::-;1896:5;-1:-1:-1;1953:2:1;1938:18;;1925:32;1966:30;1925:32;1966:30;:::i;:::-;2015:7;2005:17;;;1623:405;;;;;:::o;2033:274::-;2111:6;2164:2;2152:9;2143:7;2139:23;2135:32;2132:52;;;2180:1;2177;2170:12;2132:52;2219:9;2206:23;2238:39;2271:5;2238:39;:::i;2754:691::-;2849:6;2857;2865;2873;2881;2934:3;2922:9;2913:7;2909:23;2905:33;2902:53;;;2951:1;2948;2941:12;2902:53;2990:9;2977:23;3009:39;3042:5;3009:39;:::i;:::-;3067:5;-1:-1:-1;3124:2:1;3109:18;;3096:32;3137:41;3096:32;3137:41;:::i;:::-;3197:7;-1:-1:-1;3256:2:1;3241:18;;3228:32;3269:41;3228:32;3269:41;:::i;:::-;2754:691;;;;-1:-1:-1;3329:7:1;;3383:2;3368:18;;3355:32;;-1:-1:-1;3434:3:1;3419:19;3406:33;;2754:691;-1:-1:-1;;2754:691:1:o;3658:622::-;3744:6;3752;3760;3768;3821:3;3809:9;3800:7;3796:23;3792:33;3789:53;;;3838:1;3835;3828:12;3789:53;3877:9;3864:23;3896:39;3929:5;3896:39;:::i;:::-;3954:5;-1:-1:-1;4011:2:1;3996:18;;3983:32;4024:41;3983:32;4024:41;:::i;:::-;4084:7;-1:-1:-1;4143:2:1;4128:18;;4115:32;4156:41;4115:32;4156:41;:::i;:::-;3658:622;;;;-1:-1:-1;4216:7:1;;4270:2;4255:18;4242:32;;-1:-1:-1;;3658:622:1:o;4285:241::-;4341:6;4394:2;4382:9;4373:7;4369:23;4365:32;4362:52;;;4410:1;4407;4400:12;4362:52;4449:9;4436:23;4468:28;4490:5;4468:28;:::i;4531:180::-;4590:6;4643:2;4631:9;4622:7;4618:23;4614:32;4611:52;;;4659:1;4656;4649:12;4611:52;-1:-1:-1;4682:23:1;;4531:180;-1:-1:-1;4531:180:1:o;4905:541::-;4991:6;4999;5007;5015;5068:3;5056:9;5047:7;5043:23;5039:33;5036:53;;;5085:1;5082;5075:12;5036:53;5124:9;5111:23;5143:39;5176:5;5143:39;:::i;:::-;5201:5;-1:-1:-1;5258:2:1;5243:18;;5230:32;5271:41;5230:32;5271:41;:::i;:::-;4905:541;;5331:7;;-1:-1:-1;;;;5385:2:1;5370:18;;5357:32;;5436:2;5421:18;5408:32;;4905:541::o;5451:841::-;5555:6;5563;5571;5579;5587;5595;5648:3;5636:9;5627:7;5623:23;5619:33;5616:53;;;5665:1;5662;5655:12;5616:53;5704:9;5691:23;5723:39;5756:5;5723:39;:::i;:::-;5781:5;-1:-1:-1;5838:2:1;5823:18;;5810:32;5851:41;5810:32;5851:41;:::i;:::-;5911:7;-1:-1:-1;5970:2:1;5955:18;;5942:32;5983:41;5942:32;5983:41;:::i;:::-;6043:7;-1:-1:-1;6102:2:1;6087:18;;6074:32;6115:41;6074:32;6115:41;:::i;:::-;5451:841;;;;-1:-1:-1;5451:841:1;;6229:3;6214:19;;6201:33;;6281:3;6266:19;;;6253:33;;-1:-1:-1;5451:841:1;-1:-1:-1;;5451:841:1:o;6621:472::-;6698:6;6706;6714;6767:2;6755:9;6746:7;6742:23;6738:32;6735:52;;;6783:1;6780;6773:12;6735:52;6822:9;6809:23;6841:39;6874:5;6841:39;:::i;:::-;6899:5;-1:-1:-1;6956:2:1;6941:18;;6928:32;6969:41;6928:32;6969:41;:::i;:::-;6621:472;;7029:7;;-1:-1:-1;;;7083:2:1;7068:18;;;;7055:32;;6621:472::o;7321:772::-;7416:6;7424;7432;7440;7448;7501:3;7489:9;7480:7;7476:23;7472:33;7469:53;;;7518:1;7515;7508:12;7469:53;7557:9;7544:23;7576:39;7609:5;7576:39;:::i;:::-;7634:5;-1:-1:-1;7691:2:1;7676:18;;7663:32;7704:41;7663:32;7704:41;:::i;:::-;7764:7;-1:-1:-1;7823:2:1;7808:18;;7795:32;7836:41;7795:32;7836:41;:::i;:::-;7896:7;-1:-1:-1;7955:2:1;7940:18;;7927:32;7968:41;7927:32;7968:41;:::i;:::-;7321:772;;;;-1:-1:-1;7321:772:1;;8082:3;8067:19;8054:33;;7321:772;-1:-1:-1;;7321:772:1:o;9529:419::-;9612:6;9620;9673:2;9661:9;9652:7;9648:23;9644:32;9641:52;;;9689:1;9686;9679:12;9641:52;9728:9;9715:23;9747:39;9780:5;9747:39;:::i;:::-;9805:5;-1:-1:-1;9862:2:1;9847:18;;9834:32;9875:41;9834:32;9875:41;:::i;10436:673::-;10622:2;10674:21;;;10744:13;;10647:18;;;10766:22;;;10593:4;;10622:2;10845:15;;;;10819:2;10804:18;;;10593:4;10888:195;10902:6;10899:1;10896:13;10888:195;;;10967:13;;-1:-1:-1;;;;;10963:39:1;10951:52;;11058:15;;;;11023:12;;;;10999:1;10917:9;10888:195;;;-1:-1:-1;11100:3:1;;10436:673;-1:-1:-1;;;;;;10436:673:1:o;11523:127::-;11584:10;11579:3;11575:20;11572:1;11565:31;11615:4;11612:1;11605:15;11639:4;11636:1;11629:15;11655:275;11726:2;11720:9;11791:2;11772:13;;-1:-1:-1;;11768:27:1;11756:40;;11826:18;11811:34;;11847:22;;;11808:62;11805:88;;;11873:18;;:::i;:::-;11909:2;11902:22;11655:275;;-1:-1:-1;11655:275:1:o;11935:183::-;11995:4;12028:18;12020:6;12017:30;12014:56;;;12050:18;;:::i;:::-;-1:-1:-1;12095:1:1;12091:14;12107:4;12087:25;;11935:183::o;12123:891::-;12207:6;12238:2;12281;12269:9;12260:7;12256:23;12252:32;12249:52;;;12297:1;12294;12287:12;12249:52;12337:9;12324:23;12370:18;12362:6;12359:30;12356:50;;;12402:1;12399;12392:12;12356:50;12425:22;;12478:4;12470:13;;12466:27;-1:-1:-1;12456:55:1;;12507:1;12504;12497:12;12456:55;12543:2;12530:16;12566:60;12582:43;12622:2;12582:43;:::i;:::-;12566:60;:::i;:::-;12660:15;;;12742:1;12738:10;;;;12730:19;;12726:28;;;12691:12;;;;12766:19;;;12763:39;;;12798:1;12795;12788:12;12763:39;12822:11;;;;12842:142;12858:6;12853:3;12850:15;12842:142;;;12924:17;;12912:30;;12875:12;;;;12962;;;;12842:142;;13019:250;13104:1;13114:113;13128:6;13125:1;13122:13;13114:113;;;13204:11;;;13198:18;13185:11;;;13178:39;13150:2;13143:10;13114:113;;;-1:-1:-1;;13261:1:1;13243:16;;13236:27;13019:250::o;13274:396::-;13423:2;13412:9;13405:21;13386:4;13455:6;13449:13;13498:6;13493:2;13482:9;13478:18;13471:34;13514:79;13586:6;13581:2;13570:9;13566:18;13561:2;13553:6;13549:15;13514:79;:::i;:::-;13654:2;13633:15;-1:-1:-1;;13629:29:1;13614:45;;;;13661:2;13610:54;;13274:396;-1:-1:-1;;13274:396:1:o;13675:974::-;13759:6;13790:2;13833;13821:9;13812:7;13808:23;13804:32;13801:52;;;13849:1;13846;13839:12;13801:52;13889:9;13876:23;13922:18;13914:6;13911:30;13908:50;;;13954:1;13951;13944:12;13908:50;13977:22;;14030:4;14022:13;;14018:27;-1:-1:-1;14008:55:1;;14059:1;14056;14049:12;14008:55;14095:2;14082:16;14118:60;14134:43;14174:2;14134:43;:::i;14118:60::-;14212:15;;;14294:1;14290:10;;;;14282:19;;14278:28;;;14243:12;;;;14318:19;;;14315:39;;;14350:1;14347;14340:12;14315:39;14374:11;;;;14394:225;14410:6;14405:3;14402:15;14394:225;;;14490:3;14477:17;14507:39;14540:5;14507:39;:::i;:::-;14559:18;;14427:12;;;;14597;;;;14394:225;;14654:632;14825:2;14877:21;;;14947:13;;14850:18;;;14969:22;;;14796:4;;14825:2;15048:15;;;;15022:2;15007:18;;;14796:4;15091:169;15105:6;15102:1;15099:13;15091:169;;;15166:13;;15154:26;;15235:15;;;;15200:12;;;;15127:1;15120:9;15091:169;;15544:323;15612:6;15620;15673:2;15661:9;15652:7;15648:23;15644:32;15641:52;;;15689:1;15686;15679:12;15641:52;15728:9;15715:23;15747:39;15780:5;15747:39;:::i;:::-;15805:5;15857:2;15842:18;;;;15829:32;;-1:-1:-1;;;15544:323:1:o;17366:127::-;17427:10;17422:3;17418:20;17415:1;17408:31;17458:4;17455:1;17448:15;17482:4;17479:1;17472:15;17498:127;17559:10;17554:3;17550:20;17547:1;17540:31;17590:4;17587:1;17580:15;17614:4;17611:1;17604:15;17630:128;17697:9;;;17718:11;;;17715:37;;;17732:18;;:::i;17763:135::-;17802:3;17823:17;;;17820:43;;17843:18;;:::i;:::-;-1:-1:-1;17890:1:1;17879:13;;17763:135::o;17903:404::-;18105:2;18087:21;;;18144:2;18124:18;;;18117:30;18183:34;18178:2;18163:18;;18156:62;-1:-1:-1;;;18249:2:1;18234:18;;18227:38;18297:3;18282:19;;17903:404::o;18312:403::-;18514:2;18496:21;;;18553:2;18533:18;;;18526:30;18592:34;18587:2;18572:18;;18565:62;-1:-1:-1;;;18658:2:1;18643:18;;18636:37;18705:3;18690:19;;18312:403::o;18720:346::-;18922:2;18904:21;;;18961:2;18941:18;;;18934:30;-1:-1:-1;;;18995:2:1;18980:18;;18973:52;19057:2;19042:18;;18720:346::o;19600:259::-;19670:6;19723:2;19711:9;19702:7;19698:23;19694:32;19691:52;;;19739:1;19736;19729:12;19691:52;19771:9;19765:16;19790:39;19823:5;19790:39;:::i;20272:184::-;20342:6;20395:2;20383:9;20374:7;20370:23;20366:32;20363:52;;;20411:1;20408;20401:12;20363:52;-1:-1:-1;20434:16:1;;20272:184;-1:-1:-1;20272:184:1:o;20811:127::-;20872:10;20867:3;20863:20;20860:1;20853:31;20903:4;20900:1;20893:15;20927:4;20924:1;20917:15;25245:245;25312:6;25365:2;25353:9;25344:7;25340:23;25336:32;25333:52;;;25381:1;25378;25371:12;25333:52;25413:9;25407:16;25432:28;25454:5;25432:28;:::i;27174:127::-;27235:10;27230:3;27226:20;27223:1;27216:31;27266:4;27263:1;27256:15;27290:4;27287:1;27280:15;28025:368;28122:6;28130;28138;28146;28199:3;28187:9;28178:7;28174:23;28170:33;28167:53;;;28216:1;28213;28206:12;28167:53;-1:-1:-1;;28239:16:1;;28295:2;28280:18;;28274:25;28339:2;28324:18;;28318:25;28383:2;28368:18;;;28362:25;28239:16;;28274:25;;-1:-1:-1;28362:25:1;;-1:-1:-1;28025:368:1;-1:-1:-1;28025:368:1:o;28804:127::-;28865:10;28860:3;28856:20;28853:1;28846:31;28896:4;28893:1;28886:15;28920:4;28917:1;28910:15;29519:719;29599:6;29652:2;29640:9;29631:7;29627:23;29623:32;29620:52;;;29668:1;29665;29658:12;29620:52;29701:9;29695:16;29730:18;29771:2;29763:6;29760:14;29757:34;;;29787:1;29784;29777:12;29757:34;29825:6;29814:9;29810:22;29800:32;;29870:7;29863:4;29859:2;29855:13;29851:27;29841:55;;29892:1;29889;29882:12;29841:55;29921:2;29915:9;29943:2;29939;29936:10;29933:36;;;29949:18;;:::i;:::-;29991:53;30034:2;30015:13;;-1:-1:-1;;30011:27:1;30040:2;30007:36;29991:53;:::i;:::-;29978:66;;30067:2;30060:5;30053:17;30107:7;30102:2;30097;30093;30089:11;30085:20;30082:33;30079:53;;;30128:1;30125;30118:12;30079:53;30141:67;30205:2;30200;30193:5;30189:14;30184:2;30180;30176:11;30141:67;:::i;:::-;-1:-1:-1;30227:5:1;29519:719;-1:-1:-1;;;;29519:719:1:o;30243:289::-;30374:3;30412:6;30406:13;30428:66;30487:6;30482:3;30475:4;30467:6;30463:17;30428:66;:::i;:::-;30510:16;;;;;30243:289;-1:-1:-1;;30243:289:1:o;31057:168::-;31130:9;;;31161;;31178:15;;;31172:22;;31158:37;31148:71;;31199:18;;:::i;31750:125::-;31815:9;;;31836:10;;;31833:36;;;31849:18;;:::i;32561:127::-;32622:10;32617:3;32613:20;32610:1;32603:31;32653:4;32650:1;32643:15;32677:4;32674:1;32667:15;32693:120;32733:1;32759;32749:35;;32764:18;;:::i;:::-;-1:-1:-1;32798:9:1;;32693:120::o;32818:112::-;32850:1;32876;32866:35;;32881:18;;:::i;:::-;-1:-1:-1;32915:9:1;;32818:112::o

Swarm Source

ipfs://bafd5e6394cb5564fc079ac4bc62f2bead18ad908f73aa6a16a21b14bd82f295

Block Transaction Gas Used Reward
view all blocks sequenced

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
[ 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.