Address Details
contract
token
0xC2cCCd430E27C7890Be19e7B1475F186d10612c8
- Token
- Continous Token (TOK)
- Creator
- 0xe91286–9209d6 at 0xa3e60c–20bee6
- Balance
- 0 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- 0 Transactions
- Transfers
- 0 Transfers
- Gas Used
- Fetching gas used...
- Last Balance Update
- 7808190
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- ReputationToken
- Optimization enabled
- true
- Compiler version
- v0.8.0+commit.c7dfd78e
- Optimization runs
- 200
- EVM Version
- istanbul
- Verified at
- 2023-02-06T10:30:14.926230Z
contracts/reputation.sol
// SPDX-License-Identifier: MIT //Deployed on Ethereum Goerli testnet: 0x97DB500303C219FB11fFded8EADaA8945663D2A5 //Deployed on Near testner: 97db500303c219fb11ffded8eadaa8945663d2a5.factory.goerli.testnet //Deployed on Aurora testnet: 0x7fc383a117f64b29ab012231ae91dab6dfb95043 pragma solidity ^0.8.0; import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import "https://github.com/slim12kg/protofire-continous-token-task/blob/master/contracts/curves/BancorFormula.sol"; contract ReputationToken is BancorFormula, ERC20 { using SafeMath for uint256; uint256 public scale = 10**18; uint256 public reserveBalance = 10 * scale; uint256 public reserveRatio; address public reserveTokenAddress; /** * @dev Fired when TOK is exchanged for Dai */ event ContinuousBurn( address _address, uint256 continuousTokenAmount, uint256 reserveTokenAmount ); /** * @dev Fired when Dai us exchanged for TOK */ event ContinuousMint( address _address, uint256 reserveTokenAmount, uint256 continuousTokenAmount ); /** * @param _reserveRatio(RR) to determine the bonding curve to be used. 50% RR = Linear Bonding Curve, 10% RR = Exponential Bonding Curve * @param _reserveTokenAddress Contract address of ERC20 Token to use as reserve/exchange of value e.g DAI */ constructor(uint256 _reserveRatio, address _reserveTokenAddress) ERC20("Continous Token", "TOK") { reserveRatio = _reserveRatio; reserveTokenAddress = _reserveTokenAddress; _mint(msg.sender, 1 * scale); } /** * @dev Mint some TOK token by allowing contract to spend an amount of caller reserve tokens * @param _amount Number of reserve token approved for this contract to convert to TOK tokens */ function mint(uint256 _amount) public returns (uint256 _amountMinted) { uint256 allowance = IERC20(reserveTokenAddress).allowance( msg.sender, address(this) ); require(allowance > 0, "Must approve DAI to buy tokens."); require(allowance >= _amount, "Must approve enough DAI."); bool success = IERC20(reserveTokenAddress).transferFrom( msg.sender, address(this), allowance ); if (success) { return _continuousMint(allowance); } else { require(allowance > 0, "Failed to transfer Dai tokens"); } } /** * @dev Burn some TOK token and return reserve token based on current curve price * @param _amount Number of TOK token to convert to reserve tokens */ function burn(uint256 _amount) public { uint256 returnAmount = _continuousBurn(_amount); IERC20(reserveTokenAddress).transfer(msg.sender, returnAmount); } function calculateContinuousMintReturn(uint256 _amount) public view returns (uint256 mintAmount) { return purchaseTargetAmount( totalSupply(), reserveBalance, uint32(reserveRatio), _amount ); } function calculateContinuousBurnReturn(uint256 _amount) public view returns (uint256 burnAmount) { return saleTargetAmount( totalSupply(), reserveBalance, uint32(reserveRatio), _amount ); } function _continuousMint(uint256 _deposit) internal returns (uint256) { require(_deposit > 0, "Deposit must be non-zero."); uint256 amount = calculateContinuousMintReturn(_deposit); _mint(msg.sender, amount); reserveBalance = reserveBalance.add(_deposit); emit ContinuousMint(msg.sender, _deposit, amount); return amount; } function _continuousBurn(uint256 _amount) internal returns (uint256) { require(_amount > 0, "Amount must be non-zero."); require( balanceOf(msg.sender) >= _amount, "Insufficient tokens to burn." ); uint256 reimburseAmount = calculateContinuousBurnReturn(_amount); _burn(msg.sender, _amount); reserveBalance = reserveBalance.sub(reimburseAmount); emit ContinuousBurn(msg.sender, _amount, reimburseAmount); return reimburseAmount; } }
/_openzeppelin/contracts/utils/math/SafeMath.sol
// SPDX-License-Identifier: MIT 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 no longer needed starting with Solidity 0.8. 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 substraction 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; } } }
/https_/github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); unchecked { _approve(sender, _msgSender(), currentAllowance - amount); } return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(_msgSender(), spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `sender` to `recipient`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); uint256 senderBalance = _balances[sender]; require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[sender] = senderBalance - amount; } _balances[recipient] += amount; emit Transfer(sender, recipient, amount); _afterTokenTransfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
/https_/github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
/https_/github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
/https_/github.com/OpenZeppelin/openzeppelin-contracts/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
/https_/github.com/slim12kg/protofire-continous-token-task/blob/master/contracts/curves/BancorFormula.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../interfaces/IBancorFormula.sol"; import "../utils/Power.sol"; contract BancorFormula is IBancorFormula, Power { using SafeMath for uint256; uint256 private constant ONE = 1; uint32 private constant MAX_WEIGHT = 1000000; uint8 private constant MIN_PRECISION = 32; uint8 private constant MAX_PRECISION = 127; // Auto-generated via 'PrintMaxExpArray.py' uint256[128] private maxExpArray; /** * @dev should be executed after construction (too large for the constructor) */ function init() public { initMaxExpArray(); initLambertArray(); } /** * @dev given a token supply, reserve balance, weight and a deposit amount (in the reserve token), * calculates the target amount for a given conversion (in the main token) * * Formula: * return = _supply * ((1 + _amount / _reserveBalance) ^ (_reserveWeight / 1000000) - 1) * * @param _supply liquid token supply * @param _reserveBalance reserve balance * @param _reserveWeight reserve weight, represented in ppm (1-1000000) * @param _amount amount of reserve tokens to get the target amount for * * @return target */ function purchaseTargetAmount( uint256 _supply, uint256 _reserveBalance, uint32 _reserveWeight, uint256 _amount ) public view override returns (uint256) { // validate input require(_supply > 0, "ERR_INVALID_SUPPLY"); require(_reserveBalance > 0, "ERR_INVALID_RESERVE_BALANCE"); require( _reserveWeight > 0 && _reserveWeight <= MAX_WEIGHT, "ERR_INVALID_RESERVE_WEIGHT" ); // special case for 0 deposit amount if (_amount == 0) return 0; // special case if the weight = 100% if (_reserveWeight == MAX_WEIGHT) return _supply.mul(_amount) / _reserveBalance; uint256 result; uint8 precision; uint256 baseN = _amount.add(_reserveBalance); (result, precision) = power( baseN, _reserveBalance, _reserveWeight, MAX_WEIGHT ); uint256 temp = _supply.mul(result) >> precision; return temp - _supply; } /** * @dev given a token supply, reserve balance, weight and a sell amount (in the main token), * calculates the target amount for a given conversion (in the reserve token) * * Formula: * return = _reserveBalance * (1 - (1 - _amount / _supply) ^ (1000000 / _reserveWeight)) * * @param _supply liquid token supply * @param _reserveBalance reserve balance * @param _reserveWeight reserve weight, represented in ppm (1-1000000) * @param _amount amount of liquid tokens to get the target amount for * * @return reserve token amount */ function saleTargetAmount( uint256 _supply, uint256 _reserveBalance, uint32 _reserveWeight, uint256 _amount ) public view override returns (uint256) { // validate input require(_supply > 0, "ERR_INVALID_SUPPLY"); require(_reserveBalance > 0, "ERR_INVALID_RESERVE_BALANCE"); require( _reserveWeight > 0 && _reserveWeight <= MAX_WEIGHT, "ERR_INVALID_RESERVE_WEIGHT" ); require(_amount <= _supply, "ERR_INVALID_AMOUNT"); // special case for 0 sell amount if (_amount == 0) return 0; // special case for selling the entire supply if (_amount == _supply) return _reserveBalance; // special case if the weight = 100% if (_reserveWeight == MAX_WEIGHT) return _reserveBalance.mul(_amount) / _supply; uint256 result; uint8 precision; uint256 baseD = _supply - _amount; (result, precision) = power(_supply, baseD, MAX_WEIGHT, _reserveWeight); uint256 temp1 = _reserveBalance.mul(result); uint256 temp2 = _reserveBalance << precision; return (temp1 - temp2) / result; } /** * @dev given two reserve balances/weights and a sell amount (in the first reserve token), * calculates the target amount for a conversion from the source reserve token to the target reserve token * * Formula: * return = _targetReserveBalance * (1 - (_sourceReserveBalance / (_sourceReserveBalance + _amount)) ^ (_sourceReserveWeight / _targetReserveWeight)) * * @param _sourceReserveBalance source reserve balance * @param _sourceReserveWeight source reserve weight, represented in ppm (1-1000000) * @param _targetReserveBalance target reserve balance * @param _targetReserveWeight target reserve weight, represented in ppm (1-1000000) * @param _amount source reserve amount * * @return target reserve amount */ function crossReserveTargetAmount( uint256 _sourceReserveBalance, uint32 _sourceReserveWeight, uint256 _targetReserveBalance, uint32 _targetReserveWeight, uint256 _amount ) public view override returns (uint256) { // validate input require( _sourceReserveBalance > 0 && _targetReserveBalance > 0, "ERR_INVALID_RESERVE_BALANCE" ); require( _sourceReserveWeight > 0 && _sourceReserveWeight <= MAX_WEIGHT && _targetReserveWeight > 0 && _targetReserveWeight <= MAX_WEIGHT, "ERR_INVALID_RESERVE_WEIGHT" ); // special case for equal weights if (_sourceReserveWeight == _targetReserveWeight) return _targetReserveBalance.mul(_amount) / _sourceReserveBalance.add(_amount); uint256 result; uint8 precision; uint256 baseN = _sourceReserveBalance.add(_amount); (result, precision) = power( baseN, _sourceReserveBalance, _sourceReserveWeight, _targetReserveWeight ); uint256 temp1 = _targetReserveBalance.mul(result); uint256 temp2 = _targetReserveBalance << precision; return (temp1 - temp2) / result; } /** * @dev given a pool token supply, reserve balance, reserve ratio and an amount of requested pool tokens, * calculates the amount of reserve tokens required for purchasing the given amount of pool tokens * * Formula: * return = _reserveBalance * (((_supply + _amount) / _supply) ^ (MAX_WEIGHT / _reserveRatio) - 1) * * @param _supply pool token supply * @param _reserveBalance reserve balance * @param _reserveRatio reserve ratio, represented in ppm (2-2000000) * @param _amount requested amount of pool tokens * * @return reserve token amount */ function fundCost( uint256 _supply, uint256 _reserveBalance, uint32 _reserveRatio, uint256 _amount ) public view override returns (uint256) { // validate input require(_supply > 0, "ERR_INVALID_SUPPLY"); require(_reserveBalance > 0, "ERR_INVALID_RESERVE_BALANCE"); require( _reserveRatio > 1 && _reserveRatio <= MAX_WEIGHT * 2, "ERR_INVALID_RESERVE_RATIO" ); // special case for 0 amount if (_amount == 0) return 0; // special case if the reserve ratio = 100% if (_reserveRatio == MAX_WEIGHT) return (_amount.mul(_reserveBalance) - 1) / _supply + 1; uint256 result; uint8 precision; uint256 baseN = _supply.add(_amount); (result, precision) = power(baseN, _supply, MAX_WEIGHT, _reserveRatio); uint256 temp = ((_reserveBalance.mul(result) - 1) >> precision) + 1; return temp - _reserveBalance; } /** * @dev given a pool token supply, reserve balance, reserve ratio and an amount of reserve tokens to fund with, * calculates the amount of pool tokens received for purchasing with the given amount of reserve tokens * * Formula: * return = _supply * ((_amount / _reserveBalance + 1) ^ (_reserveRatio / MAX_WEIGHT) - 1) * * @param _supply pool token supply * @param _reserveBalance reserve balance * @param _reserveRatio reserve ratio, represented in ppm (2-2000000) * @param _amount amount of reserve tokens to fund with * * @return pool token amount */ function fundSupplyAmount( uint256 _supply, uint256 _reserveBalance, uint32 _reserveRatio, uint256 _amount ) public view override returns (uint256) { // validate input require(_supply > 0, "ERR_INVALID_SUPPLY"); require(_reserveBalance > 0, "ERR_INVALID_RESERVE_BALANCE"); require( _reserveRatio > 1 && _reserveRatio <= MAX_WEIGHT * 2, "ERR_INVALID_RESERVE_RATIO" ); // special case for 0 amount if (_amount == 0) return 0; // special case if the reserve ratio = 100% if (_reserveRatio == MAX_WEIGHT) return _amount.mul(_supply) / _reserveBalance; uint256 result; uint8 precision; uint256 baseN = _reserveBalance.add(_amount); (result, precision) = power( baseN, _reserveBalance, _reserveRatio, MAX_WEIGHT ); uint256 temp = _supply.mul(result) >> precision; return temp - _supply; } /** * @dev given a pool token supply, reserve balance, reserve ratio and an amount of pool tokens to liquidate, * calculates the amount of reserve tokens received for selling the given amount of pool tokens * * Formula: * return = _reserveBalance * (1 - ((_supply - _amount) / _supply) ^ (MAX_WEIGHT / _reserveRatio)) * * @param _supply pool token supply * @param _reserveBalance reserve balance * @param _reserveRatio reserve ratio, represented in ppm (2-2000000) * @param _amount amount of pool tokens to liquidate * * @return reserve token amount */ function liquidateReserveAmount( uint256 _supply, uint256 _reserveBalance, uint32 _reserveRatio, uint256 _amount ) public view override returns (uint256) { // validate input require(_supply > 0, "ERR_INVALID_SUPPLY"); require(_reserveBalance > 0, "ERR_INVALID_RESERVE_BALANCE"); require( _reserveRatio > 1 && _reserveRatio <= MAX_WEIGHT * 2, "ERR_INVALID_RESERVE_RATIO" ); require(_amount <= _supply, "ERR_INVALID_AMOUNT"); // special case for 0 amount if (_amount == 0) return 0; // special case for liquidating the entire supply if (_amount == _supply) return _reserveBalance; // special case if the reserve ratio = 100% if (_reserveRatio == MAX_WEIGHT) return _amount.mul(_reserveBalance) / _supply; uint256 result; uint8 precision; uint256 baseD = _supply - _amount; (result, precision) = power(_supply, baseD, MAX_WEIGHT, _reserveRatio); uint256 temp1 = _reserveBalance.mul(result); uint256 temp2 = _reserveBalance << precision; return (temp1 - temp2) / result; } /** * @dev The arbitrage incentive is to convert to the point where the on-chain price is equal to the off-chain price. * We want this operation to also impact the primary reserve balance becoming equal to the primary reserve staked balance. * In other words, we want the arbitrager to convert the difference between the reserve balance and the reserve staked balance. * * Formula input: * - let t denote the primary reserve token staked balance * - let s denote the primary reserve token balance * - let r denote the secondary reserve token balance * - let q denote the numerator of the rate between the tokens * - let p denote the denominator of the rate between the tokens * Where p primary tokens are equal to q secondary tokens * * Formula output: * - compute x = W(t / r * q / p * log(s / t)) / log(s / t) * - return x / (1 + x) as the weight of the primary reserve token * - return 1 / (1 + x) as the weight of the secondary reserve token * Where W is the Lambert W Function * * If the rate-provider provides the rates for a common unit, for example: * - P = 2 ==> 2 primary reserve tokens = 1 ether * - Q = 3 ==> 3 secondary reserve tokens = 1 ether * Then you can simply use p = P and q = Q * * If the rate-provider provides the rates for a single unit, for example: * - P = 2 ==> 1 primary reserve token = 2 ethers * - Q = 3 ==> 1 secondary reserve token = 3 ethers * Then you can simply use p = Q and q = P * * @param _primaryReserveStakedBalance the primary reserve token staked balance * @param _primaryReserveBalance the primary reserve token balance * @param _secondaryReserveBalance the secondary reserve token balance * @param _reserveRateNumerator the numerator of the rate between the tokens * @param _reserveRateDenominator the denominator of the rate between the tokens * * Note that `numerator / denominator` should represent the amount of secondary tokens equal to one primary token * * @return the weight of the primary reserve token and the weight of the secondary reserve token, both in ppm (0-1000000) */ function balancedWeights( uint256 _primaryReserveStakedBalance, uint256 _primaryReserveBalance, uint256 _secondaryReserveBalance, uint256 _reserveRateNumerator, uint256 _reserveRateDenominator ) public view override returns (uint32, uint32) { if (_primaryReserveStakedBalance == _primaryReserveBalance) require( _primaryReserveStakedBalance > 0 || _secondaryReserveBalance > 0, "ERR_INVALID_RESERVE_BALANCE" ); else require( _primaryReserveStakedBalance > 0 && _primaryReserveBalance > 0 && _secondaryReserveBalance > 0, "ERR_INVALID_RESERVE_BALANCE" ); require( _reserveRateNumerator > 0 && _reserveRateDenominator > 0, "ERR_INVALID_RESERVE_RATE" ); uint256 tq = _primaryReserveStakedBalance.mul(_reserveRateNumerator); uint256 rp = _secondaryReserveBalance.mul(_reserveRateDenominator); if (_primaryReserveStakedBalance < _primaryReserveBalance) return balancedWeightsByStake( _primaryReserveBalance, _primaryReserveStakedBalance, tq, rp, true ); if (_primaryReserveStakedBalance > _primaryReserveBalance) return balancedWeightsByStake( _primaryReserveStakedBalance, _primaryReserveBalance, tq, rp, false ); return normalizedWeights(tq, rp); } }
/https_/github.com/slim12kg/protofire-continous-token-task/blob/master/contracts/interfaces/IBancorFormula.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /* Bancor Formula interface */ interface IBancorFormula { function purchaseTargetAmount( uint256 _supply, uint256 _reserveBalance, uint32 _reserveWeight, uint256 _amount ) external view returns (uint256); function saleTargetAmount( uint256 _supply, uint256 _reserveBalance, uint32 _reserveWeight, uint256 _amount ) external view returns (uint256); function crossReserveTargetAmount( uint256 _sourceReserveBalance, uint32 _sourceReserveWeight, uint256 _targetReserveBalance, uint32 _targetReserveWeight, uint256 _amount ) external view returns (uint256); function fundCost( uint256 _supply, uint256 _reserveBalance, uint32 _reserveRatio, uint256 _amount ) external view returns (uint256); function fundSupplyAmount( uint256 _supply, uint256 _reserveBalance, uint32 _reserveRatio, uint256 _amount ) external view returns (uint256); function liquidateReserveAmount( uint256 _supply, uint256 _reserveBalance, uint32 _reserveRatio, uint256 _amount ) external view returns (uint256); function balancedWeights( uint256 _primaryReserveStakedBalance, uint256 _primaryReserveBalance, uint256 _secondaryReserveBalance, uint256 _reserveRateNumerator, uint256 _reserveRateDenominator ) external view returns (uint32, uint32); }
/https_/github.com/slim12kg/protofire-continous-token-task/blob/master/contracts/utils/Power.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; contract Power{ using SafeMath for uint256; uint256 private constant ONE = 1; uint32 private constant MAX_WEIGHT = 1000000; uint8 private constant MIN_PRECISION = 32; uint8 private constant MAX_PRECISION = 127; // Auto-generated via 'PrintIntScalingFactors.py' uint256 private constant FIXED_1 = 0x080000000000000000000000000000000; uint256 private constant FIXED_2 = 0x100000000000000000000000000000000; uint256 private constant MAX_NUM = 0x200000000000000000000000000000000; // Auto-generated via 'PrintLn2ScalingFactors.py' uint256 private constant LN2_NUMERATOR = 0x3f80fe03f80fe03f80fe03f80fe03f8; uint256 private constant LN2_DENOMINATOR = 0x5b9de1d10bf4103d647b0955897ba80; // Auto-generated via 'PrintFunctionOptimalLog.py' and 'PrintFunctionOptimalExp.py' uint256 private constant OPT_LOG_MAX_VAL = 0x15bf0a8b1457695355fb8ac404e7a79e3; uint256 private constant OPT_EXP_MAX_VAL = 0x800000000000000000000000000000000; // Auto-generated via 'PrintLambertFactors.py' uint256 private constant LAMBERT_CONV_RADIUS = 0x002f16ac6c59de6f8d5d6f63c1482a7c86; uint256 private constant LAMBERT_POS2_SAMPLE = 0x0003060c183060c183060c183060c18306; uint256 private constant LAMBERT_POS2_MAXVAL = 0x01af16ac6c59de6f8d5d6f63c1482a7c80; uint256 private constant LAMBERT_POS3_MAXVAL = 0x6b22d43e72c326539cceeef8bb48f255ff; // Auto-generated via 'PrintWeightFactors.py' uint256 private constant MAX_UNF_WEIGHT = 0x10c6f7a0b5ed8d36b4c7f34938583621fafc8b0079a2834d26fa3fcc9ea9; // Auto-generated via 'PrintMaxExpArray.py' uint256[128] private maxExpArray; function initMaxExpArray() public { maxExpArray[32] = 0x1c35fedd14ffffffffffffffffffffffff; maxExpArray[33] = 0x1b0ce43b323fffffffffffffffffffffff; maxExpArray[34] = 0x19f0028ec1ffffffffffffffffffffffff; maxExpArray[35] = 0x18ded91f0e7fffffffffffffffffffffff; maxExpArray[36] = 0x17d8ec7f0417ffffffffffffffffffffff; maxExpArray[37] = 0x16ddc6556cdbffffffffffffffffffffff; maxExpArray[38] = 0x15ecf52776a1ffffffffffffffffffffff; maxExpArray[39] = 0x15060c256cb2ffffffffffffffffffffff; maxExpArray[40] = 0x1428a2f98d72ffffffffffffffffffffff; maxExpArray[41] = 0x13545598e5c23fffffffffffffffffffff; maxExpArray[42] = 0x1288c4161ce1dfffffffffffffffffffff; maxExpArray[43] = 0x11c592761c666fffffffffffffffffffff; maxExpArray[44] = 0x110a688680a757ffffffffffffffffffff; maxExpArray[45] = 0x1056f1b5bedf77ffffffffffffffffffff; maxExpArray[46] = 0x0faadceceeff8bffffffffffffffffffff; maxExpArray[47] = 0x0f05dc6b27edadffffffffffffffffffff; maxExpArray[48] = 0x0e67a5a25da4107fffffffffffffffffff; maxExpArray[49] = 0x0dcff115b14eedffffffffffffffffffff; maxExpArray[50] = 0x0d3e7a392431239fffffffffffffffffff; maxExpArray[51] = 0x0cb2ff529eb71e4fffffffffffffffffff; maxExpArray[52] = 0x0c2d415c3db974afffffffffffffffffff; maxExpArray[53] = 0x0bad03e7d883f69bffffffffffffffffff; maxExpArray[54] = 0x0b320d03b2c343d5ffffffffffffffffff; maxExpArray[55] = 0x0abc25204e02828dffffffffffffffffff; maxExpArray[56] = 0x0a4b16f74ee4bb207fffffffffffffffff; maxExpArray[57] = 0x09deaf736ac1f569ffffffffffffffffff; maxExpArray[58] = 0x0976bd9952c7aa957fffffffffffffffff; maxExpArray[59] = 0x09131271922eaa606fffffffffffffffff; maxExpArray[60] = 0x08b380f3558668c46fffffffffffffffff; maxExpArray[61] = 0x0857ddf0117efa215bffffffffffffffff; maxExpArray[62] = 0x07ffffffffffffffffffffffffffffffff; maxExpArray[63] = 0x07abbf6f6abb9d087fffffffffffffffff; maxExpArray[64] = 0x075af62cbac95f7dfa7fffffffffffffff; maxExpArray[65] = 0x070d7fb7452e187ac13fffffffffffffff; maxExpArray[66] = 0x06c3390ecc8af379295fffffffffffffff; maxExpArray[67] = 0x067c00a3b07ffc01fd6fffffffffffffff; maxExpArray[68] = 0x0637b647c39cbb9d3d27ffffffffffffff; maxExpArray[69] = 0x05f63b1fc104dbd39587ffffffffffffff; maxExpArray[70] = 0x05b771955b36e12f7235ffffffffffffff; maxExpArray[71] = 0x057b3d49dda84556d6f6ffffffffffffff; maxExpArray[72] = 0x054183095b2c8ececf30ffffffffffffff; maxExpArray[73] = 0x050a28be635ca2b888f77fffffffffffff; maxExpArray[74] = 0x04d5156639708c9db33c3fffffffffffff; maxExpArray[75] = 0x04a23105873875bd52dfdfffffffffffff; maxExpArray[76] = 0x0471649d87199aa990756fffffffffffff; maxExpArray[77] = 0x04429a21a029d4c1457cfbffffffffffff; maxExpArray[78] = 0x0415bc6d6fb7dd71af2cb3ffffffffffff; maxExpArray[79] = 0x03eab73b3bbfe282243ce1ffffffffffff; maxExpArray[80] = 0x03c1771ac9fb6b4c18e229ffffffffffff; maxExpArray[81] = 0x0399e96897690418f785257fffffffffff; maxExpArray[82] = 0x0373fc456c53bb779bf0ea9fffffffffff; maxExpArray[83] = 0x034f9e8e490c48e67e6ab8bfffffffffff; maxExpArray[84] = 0x032cbfd4a7adc790560b3337ffffffffff; maxExpArray[85] = 0x030b50570f6e5d2acca94613ffffffffff; maxExpArray[86] = 0x02eb40f9f620fda6b56c2861ffffffffff; maxExpArray[87] = 0x02cc8340ecb0d0f520a6af58ffffffffff; maxExpArray[88] = 0x02af09481380a0a35cf1ba02ffffffffff; maxExpArray[89] = 0x0292c5bdd3b92ec810287b1b3fffffffff; maxExpArray[90] = 0x0277abdcdab07d5a77ac6d6b9fffffffff; maxExpArray[91] = 0x025daf6654b1eaa55fd64df5efffffffff; maxExpArray[92] = 0x0244c49c648baa98192dce88b7ffffffff; maxExpArray[93] = 0x022ce03cd5619a311b2471268bffffffff; maxExpArray[94] = 0x0215f77c045fbe885654a44a0fffffffff; maxExpArray[95] = 0x01ffffffffffffffffffffffffffffffff; maxExpArray[96] = 0x01eaefdbdaaee7421fc4d3ede5ffffffff; maxExpArray[97] = 0x01d6bd8b2eb257df7e8ca57b09bfffffff; maxExpArray[98] = 0x01c35fedd14b861eb0443f7f133fffffff; maxExpArray[99] = 0x01b0ce43b322bcde4a56e8ada5afffffff; maxExpArray[100] = 0x019f0028ec1fff007f5a195a39dfffffff; maxExpArray[101] = 0x018ded91f0e72ee74f49b15ba527ffffff; maxExpArray[102] = 0x017d8ec7f04136f4e5615fd41a63ffffff; maxExpArray[103] = 0x016ddc6556cdb84bdc8d12d22e6fffffff; maxExpArray[104] = 0x015ecf52776a1155b5bd8395814f7fffff; maxExpArray[105] = 0x015060c256cb23b3b3cc3754cf40ffffff; maxExpArray[106] = 0x01428a2f98d728ae223ddab715be3fffff; maxExpArray[107] = 0x013545598e5c23276ccf0ede68034fffff; maxExpArray[108] = 0x01288c4161ce1d6f54b7f61081194fffff; maxExpArray[109] = 0x011c592761c666aa641d5a01a40f17ffff; maxExpArray[110] = 0x0110a688680a7530515f3e6e6cfdcdffff; maxExpArray[111] = 0x01056f1b5bedf75c6bcb2ce8aed428ffff; maxExpArray[112] = 0x00faadceceeff8a0890f3875f008277fff; maxExpArray[113] = 0x00f05dc6b27edad306388a600f6ba0bfff; maxExpArray[114] = 0x00e67a5a25da41063de1495d5b18cdbfff; maxExpArray[115] = 0x00dcff115b14eedde6fc3aa5353f2e4fff; maxExpArray[116] = 0x00d3e7a3924312399f9aae2e0f868f8fff; maxExpArray[117] = 0x00cb2ff529eb71e41582cccd5a1ee26fff; maxExpArray[118] = 0x00c2d415c3db974ab32a51840c0b67edff; maxExpArray[119] = 0x00bad03e7d883f69ad5b0a186184e06bff; maxExpArray[120] = 0x00b320d03b2c343d4829abd6075f0cc5ff; maxExpArray[121] = 0x00abc25204e02828d73c6e80bcdb1a95bf; maxExpArray[122] = 0x00a4b16f74ee4bb2040a1ec6c15fbbf2df; maxExpArray[123] = 0x009deaf736ac1f569deb1b5ae3f36c130f; maxExpArray[124] = 0x00976bd9952c7aa957f5937d790ef65037; maxExpArray[125] = 0x009131271922eaa6064b73a22d0bd4f2bf; maxExpArray[126] = 0x008b380f3558668c46c91c49a2f8e967b9; maxExpArray[127] = 0x00857ddf0117efa215952912839f6473e6; } // Auto-generated via 'PrintLambertArray.py' uint256[128] private lambertArray; function initLambertArray() public { lambertArray[0] = 0x60e393c68d20b1bd09deaabc0373b9c5; lambertArray[1] = 0x5f8f46e4854120989ed94719fb4c2011; lambertArray[2] = 0x5e479ebb9129fb1b7e72a648f992b606; lambertArray[3] = 0x5d0bd23fe42dfedde2e9586be12b85fe; lambertArray[4] = 0x5bdb29ddee979308ddfca81aeeb8095a; lambertArray[5] = 0x5ab4fd8a260d2c7e2c0d2afcf0009dad; lambertArray[6] = 0x5998b31359a55d48724c65cf09001221; lambertArray[7] = 0x5885bcad2b322dfc43e8860f9c018cf5; lambertArray[8] = 0x577b97aa1fe222bb452fdf111b1f0be2; lambertArray[9] = 0x5679cb5e3575632e5baa27e2b949f704; lambertArray[10] = 0x557fe8241b3a31c83c732f1cdff4a1c5; lambertArray[11] = 0x548d868026504875d6e59bbe95fc2a6b; lambertArray[12] = 0x53a2465ce347cf34d05a867c17dd3088; lambertArray[13] = 0x52bdce5dcd4faed59c7f5511cf8f8acc; lambertArray[14] = 0x51dfcb453c07f8da817606e7885f7c3e; lambertArray[15] = 0x5107ef6b0a5a2be8f8ff15590daa3cce; lambertArray[16] = 0x5035f241d6eae0cd7bacba119993de7b; lambertArray[17] = 0x4f698fe90d5b53d532171e1210164c66; lambertArray[18] = 0x4ea288ca297a0e6a09a0eee240e16c85; lambertArray[19] = 0x4de0a13fdcf5d4213fc398ba6e3becde; lambertArray[20] = 0x4d23a145eef91fec06b06140804c4808; lambertArray[21] = 0x4c6b5430d4c1ee5526473db4ae0f11de; lambertArray[22] = 0x4bb7886c240562eba11f4963a53b4240; lambertArray[23] = 0x4b080f3f1cb491d2d521e0ea4583521e; lambertArray[24] = 0x4a5cbc96a05589cb4d86be1db3168364; lambertArray[25] = 0x49b566d40243517658d78c33162d6ece; lambertArray[26] = 0x4911e6a02e5507a30f947383fd9a3276; lambertArray[27] = 0x487216c2b31be4adc41db8a8d5cc0c88; lambertArray[28] = 0x47d5d3fc4a7a1b188cd3d788b5c5e9fc; lambertArray[29] = 0x473cfce4871a2c40bc4f9e1c32b955d0; lambertArray[30] = 0x46a771ca578ab878485810e285e31c67; lambertArray[31] = 0x4615149718aed4c258c373dc676aa72d; lambertArray[32] = 0x4585c8b3f8fe489c6e1833ca47871384; lambertArray[33] = 0x44f972f174e41e5efb7e9d63c29ce735; lambertArray[34] = 0x446ff970ba86d8b00beb05ecebf3c4dc; lambertArray[35] = 0x43e9438ec88971812d6f198b5ccaad96; lambertArray[36] = 0x436539d11ff7bea657aeddb394e809ef; lambertArray[37] = 0x42e3c5d3e5a913401d86f66db5d81c2c; lambertArray[38] = 0x4264d2395303070ea726cbe98df62174; lambertArray[39] = 0x41e84a9a593bb7194c3a6349ecae4eea; lambertArray[40] = 0x416e1b785d13eba07a08f3f18876a5ab; lambertArray[41] = 0x40f6322ff389d423ba9dd7e7e7b7e809; lambertArray[42] = 0x40807cec8a466880ecf4184545d240a4; lambertArray[43] = 0x400cea9ce88a8d3ae668e8ea0d9bf07f; lambertArray[44] = 0x3f9b6ae8772d4c55091e0ed7dfea0ac1; lambertArray[45] = 0x3f2bee253fd84594f54bcaafac383a13; lambertArray[46] = 0x3ebe654e95208bb9210c575c081c5958; lambertArray[47] = 0x3e52c1fc5665635b78ce1f05ad53c086; lambertArray[48] = 0x3de8f65ac388101ddf718a6f5c1eff65; lambertArray[49] = 0x3d80f522d59bd0b328ca012df4cd2d49; lambertArray[50] = 0x3d1ab193129ea72b23648a161163a85a; lambertArray[51] = 0x3cb61f68d32576c135b95cfb53f76d75; lambertArray[52] = 0x3c5332d9f1aae851a3619e77e4cc8473; lambertArray[53] = 0x3bf1e08edbe2aa109e1525f65759ef73; lambertArray[54] = 0x3b921d9cff13fa2c197746a3dfc4918f; lambertArray[55] = 0x3b33df818910bfc1a5aefb8f63ae2ac4; lambertArray[56] = 0x3ad71c1c77e34fa32a9f184967eccbf6; lambertArray[57] = 0x3a7bc9abf2c5bb53e2f7384a8a16521a; lambertArray[58] = 0x3a21dec7e76369783a68a0c6385a1c57; lambertArray[59] = 0x39c9525de6c9cdf7c1c157ca4a7a6ee3; lambertArray[60] = 0x39721bad3dc85d1240ff0190e0adaac3; lambertArray[61] = 0x391c324344d3248f0469eb28dd3d77e0; lambertArray[62] = 0x38c78df7e3c796279fb4ff84394ab3da; lambertArray[63] = 0x387426ea4638ae9aae08049d3554c20a; lambertArray[64] = 0x3821f57dbd2763256c1a99bbd2051378; lambertArray[65] = 0x37d0f256cb46a8c92ff62fbbef289698; lambertArray[66] = 0x37811658591ffc7abdd1feaf3cef9b73; lambertArray[67] = 0x37325aa10e9e82f7df0f380f7997154b; lambertArray[68] = 0x36e4b888cfb408d873b9a80d439311c6; lambertArray[69] = 0x3698299e59f4bb9de645fc9b08c64cca; lambertArray[70] = 0x364ca7a5012cb603023b57dd3ebfd50d; lambertArray[71] = 0x36022c928915b778ab1b06aaee7e61d4; lambertArray[72] = 0x35b8b28d1a73dc27500ffe35559cc028; lambertArray[73] = 0x357033e951fe250ec5eb4e60955132d7; lambertArray[74] = 0x3528ab2867934e3a21b5412e4c4f8881; lambertArray[75] = 0x34e212f66c55057f9676c80094a61d59; lambertArray[76] = 0x349c66289e5b3c4b540c24f42fa4b9bb; lambertArray[77] = 0x34579fbbd0c733a9c8d6af6b0f7d00f7; lambertArray[78] = 0x3413bad2e712288b924b5882b5b369bf; lambertArray[79] = 0x33d0b2b56286510ef730e213f71f12e9; lambertArray[80] = 0x338e82ce00e2496262c64457535ba1a1; lambertArray[81] = 0x334d26a96b373bb7c2f8ea1827f27a92; lambertArray[82] = 0x330c99f4f4211469e00b3e18c31475ea; lambertArray[83] = 0x32ccd87d6486094999c7d5e6f33237d8; lambertArray[84] = 0x328dde2dd617b6665a2e8556f250c1af; lambertArray[85] = 0x324fa70e9adc270f8262755af5a99af9; lambertArray[86] = 0x32122f443110611ca51040f41fa6e1e3; lambertArray[87] = 0x31d5730e42c0831482f0f1485c4263d8; lambertArray[88] = 0x31996ec6b07b4a83421b5ebc4ab4e1f1; lambertArray[89] = 0x315e1ee0a68ff46bb43ec2b85032e876; lambertArray[90] = 0x31237fe7bc4deacf6775b9efa1a145f8; lambertArray[91] = 0x30e98e7f1cc5a356e44627a6972ea2ff; lambertArray[92] = 0x30b04760b8917ec74205a3002650ec05; lambertArray[93] = 0x3077a75c803468e9132ce0cf3224241d; lambertArray[94] = 0x303fab57a6a275c36f19cda9bace667a; lambertArray[95] = 0x3008504beb8dcbd2cf3bc1f6d5a064f0; lambertArray[96] = 0x2fd19346ed17dac61219ce0c2c5ac4b0; lambertArray[97] = 0x2f9b7169808c324b5852fd3d54ba9714; lambertArray[98] = 0x2f65e7e711cf4b064eea9c08cbdad574; lambertArray[99] = 0x2f30f405093042ddff8a251b6bf6d103; lambertArray[100] = 0x2efc931a3750f2e8bfe323edfe037574; lambertArray[101] = 0x2ec8c28e46dbe56d98685278339400cb; lambertArray[102] = 0x2e957fd933c3926d8a599b602379b851; lambertArray[103] = 0x2e62c882c7c9ed4473412702f08ba0e5; lambertArray[104] = 0x2e309a221c12ba361e3ed695167feee2; lambertArray[105] = 0x2dfef25d1f865ae18dd07cfea4bcea10; lambertArray[106] = 0x2dcdcee821cdc80decc02c44344aeb31; lambertArray[107] = 0x2d9d2d8562b34944d0b201bb87260c83; lambertArray[108] = 0x2d6d0c04a5b62a2c42636308669b729a; lambertArray[109] = 0x2d3d6842c9a235517fc5a0332691528f; lambertArray[110] = 0x2d0e402963fe1ea2834abc408c437c10; lambertArray[111] = 0x2cdf91ae602647908aff975e4d6a2a8c; lambertArray[112] = 0x2cb15ad3a1eb65f6d74a75da09a1b6c5; lambertArray[113] = 0x2c8399a6ab8e9774d6fcff373d210727; lambertArray[114] = 0x2c564c4046f64edba6883ca06bbc4535; lambertArray[115] = 0x2c2970c431f952641e05cb493e23eed3; lambertArray[116] = 0x2bfd0560cd9eb14563bc7c0732856c18; lambertArray[117] = 0x2bd1084ed0332f7ff4150f9d0ef41a2c; lambertArray[118] = 0x2ba577d0fa1628b76d040b12a82492fb; lambertArray[119] = 0x2b7a5233cd21581e855e89dc2f1e8a92; lambertArray[120] = 0x2b4f95cd46904d05d72bdcde337d9cc7; lambertArray[121] = 0x2b2540fc9b4d9abba3faca6691914675; lambertArray[122] = 0x2afb5229f68d0830d8be8adb0a0db70f; lambertArray[123] = 0x2ad1c7c63a9b294c5bc73a3ba3ab7a2b; lambertArray[124] = 0x2aa8a04ac3cbe1ee1c9c86361465dbb8; lambertArray[125] = 0x2a7fda392d725a44a2c8aeb9ab35430d; lambertArray[126] = 0x2a57741b18cde618717792b4faa216db; lambertArray[127] = 0x2a2f6c81f5d84dd950a35626d6d5503a; } /** * @dev General Description: * Determine a value of precision. * Calculate an integer approximation of (_baseN / _baseD) ^ (_expN / _expD) * 2 ^ precision. * Return the result along with the precision used. * * Detailed Description: * Instead of calculating "base ^ exp", we calculate "e ^ (log(base) * exp)". * The value of "log(base)" is represented with an integer slightly smaller than "log(base) * 2 ^ precision". * The larger "precision" is, the more accurately this value represents the real value. * However, the larger "precision" is, the more bits are required in order to store this value. * And the exponentiation function, which takes "x" and calculates "e ^ x", is limited to a maximum exponent (maximum value of "x"). * This maximum exponent depends on the "precision" used, and it is given by "maxExpArray[precision] >> (MAX_PRECISION - precision)". * Hence we need to determine the highest precision which can be used for the given input, before calling the exponentiation function. * This allows us to compute "base ^ exp" with maximum accuracy and without exceeding 256 bits in any of the intermediate computations. * This functions assumes that "_expN < 2 ^ 256 / log(MAX_NUM - 1)", otherwise the multiplication should be replaced with a "safeMul". * Since we rely on unsigned-integer arithmetic and "base < 1" ==> "log(base) < 0", this function does not support "_baseN < _baseD". */ function power( uint256 _baseN, uint256 _baseD, uint32 _expN, uint32 _expD ) public view returns (uint256, uint8) { require(_baseN < MAX_NUM); uint256 baseLog; uint256 base = (_baseN * FIXED_1) / _baseD; if (base < OPT_LOG_MAX_VAL) { baseLog = optimalLog(base); } else { baseLog = generalLog(base); } uint256 baseLogTimesExp = (baseLog * _expN) / _expD; if (baseLogTimesExp < OPT_EXP_MAX_VAL) { return (optimalExp(baseLogTimesExp), MAX_PRECISION); } else { uint8 precision = findPositionInMaxExpArray(baseLogTimesExp); return ( generalExp( baseLogTimesExp >> (MAX_PRECISION - precision), precision ), precision ); } } /** * @dev computes log(x / FIXED_1) * FIXED_1. * This functions assumes that "x >= FIXED_1", because the output would be negative otherwise. */ function generalLog(uint256 x) internal pure returns (uint256) { uint256 res = 0; // If x >= 2, then we compute the integer part of log2(x), which is larger than 0. if (x >= FIXED_2) { uint8 count = floorLog2(x / FIXED_1); x >>= count; // now x < 2 res = count * FIXED_1; } // If x > 1, then we compute the fraction part of log2(x), which is larger than 0. if (x > FIXED_1) { for (uint8 i = MAX_PRECISION; i > 0; --i) { x = (x * x) / FIXED_1; // now 1 < x < 4 if (x >= FIXED_2) { x >>= 1; // now 1 < x < 2 res += ONE << (i - 1); } } } return (res * LN2_NUMERATOR) / LN2_DENOMINATOR; } /** * @dev computes the largest integer smaller than or equal to the binary logarithm of the input. */ function floorLog2(uint256 _n) internal pure returns (uint8) { uint8 res = 0; if (_n < 256) { // At most 8 iterations while (_n > 1) { _n >>= 1; res += 1; } } else { // Exactly 8 iterations for (uint8 s = 128; s > 0; s >>= 1) { if (_n >= (ONE << s)) { _n >>= s; res |= s; } } } return res; } /** * @dev the global "maxExpArray" is sorted in descending order, and therefore the following statements are equivalent: * - This function finds the position of [the smallest value in "maxExpArray" larger than or equal to "x"] * - This function finds the highest position of [a value in "maxExpArray" larger than or equal to "x"] */ function findPositionInMaxExpArray(uint256 _x) internal view returns (uint8 pos) { uint8 lo = MIN_PRECISION; uint8 hi = MAX_PRECISION; while (lo + 1 < hi) { uint8 mid = (lo + hi) / 2; if (maxExpArray[mid] >= _x) lo = mid; else hi = mid; } if (maxExpArray[hi] >= _x) return pos = hi; if (maxExpArray[lo] >= _x) return pos = lo; require(false); } /** * @dev this function can be auto-generated by the script 'PrintFunctionGeneralExp.py'. * it approximates "e ^ x" via maclaurin summation: "(x^0)/0! + (x^1)/1! + ... + (x^n)/n!". * it returns "e ^ (x / 2 ^ precision) * 2 ^ precision", that is, the result is upshifted for accuracy. * the global "maxExpArray" maps each "precision" to "((maximumExponent + 1) << (MAX_PRECISION - precision)) - 1". * the maximum permitted value for "x" is therefore given by "maxExpArray[precision] >> (MAX_PRECISION - precision)". */ function generalExp(uint256 _x, uint8 _precision) internal pure returns (uint256) { uint256 xi = _x; uint256 res = 0; xi = (xi * _x) >> _precision; res += xi * 0x3442c4e6074a82f1797f72ac0000000; // add x^02 * (33! / 02!) xi = (xi * _x) >> _precision; res += xi * 0x116b96f757c380fb287fd0e40000000; // add x^03 * (33! / 03!) xi = (xi * _x) >> _precision; res += xi * 0x045ae5bdd5f0e03eca1ff4390000000; // add x^04 * (33! / 04!) xi = (xi * _x) >> _precision; res += xi * 0x00defabf91302cd95b9ffda50000000; // add x^05 * (33! / 05!) xi = (xi * _x) >> _precision; res += xi * 0x002529ca9832b22439efff9b8000000; // add x^06 * (33! / 06!) xi = (xi * _x) >> _precision; res += xi * 0x00054f1cf12bd04e516b6da88000000; // add x^07 * (33! / 07!) xi = (xi * _x) >> _precision; res += xi * 0x0000a9e39e257a09ca2d6db51000000; // add x^08 * (33! / 08!) xi = (xi * _x) >> _precision; res += xi * 0x000012e066e7b839fa050c309000000; // add x^09 * (33! / 09!) xi = (xi * _x) >> _precision; res += xi * 0x000001e33d7d926c329a1ad1a800000; // add x^10 * (33! / 10!) xi = (xi * _x) >> _precision; res += xi * 0x0000002bee513bdb4a6b19b5f800000; // add x^11 * (33! / 11!) xi = (xi * _x) >> _precision; res += xi * 0x00000003a9316fa79b88eccf2a00000; // add x^12 * (33! / 12!) xi = (xi * _x) >> _precision; res += xi * 0x0000000048177ebe1fa812375200000; // add x^13 * (33! / 13!) xi = (xi * _x) >> _precision; res += xi * 0x0000000005263fe90242dcbacf00000; // add x^14 * (33! / 14!) xi = (xi * _x) >> _precision; res += xi * 0x000000000057e22099c030d94100000; // add x^15 * (33! / 15!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000057e22099c030d9410000; // add x^16 * (33! / 16!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000052b6b54569976310000; // add x^17 * (33! / 17!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000004985f67696bf748000; // add x^18 * (33! / 18!) xi = (xi * _x) >> _precision; res += xi * 0x000000000000003dea12ea99e498000; // add x^19 * (33! / 19!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000000031880f2214b6e000; // add x^20 * (33! / 20!) xi = (xi * _x) >> _precision; res += xi * 0x000000000000000025bcff56eb36000; // add x^21 * (33! / 21!) xi = (xi * _x) >> _precision; res += xi * 0x000000000000000001b722e10ab1000; // add x^22 * (33! / 22!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000001317c70077000; // add x^23 * (33! / 23!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000000000000cba84aafa00; // add x^24 * (33! / 24!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000000000000082573a0a00; // add x^25 * (33! / 25!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000000000000005035ad900; // add x^26 * (33! / 26!) xi = (xi * _x) >> _precision; res += xi * 0x000000000000000000000002f881b00; // add x^27 * (33! / 27!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000000000001b29340; // add x^28 * (33! / 28!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000000000000000000efc40; // add x^29 * (33! / 29!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000000000000007fe0; // add x^30 * (33! / 30!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000000000000000420; // add x^31 * (33! / 31!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000000000000000021; // add x^32 * (33! / 32!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000000000000000001; // add x^33 * (33! / 33!) return res / 0x688589cc0e9505e2f2fee5580000000 + _x + (ONE << _precision); // divide by 33! and then add x^1 / 1! + x^0 / 0! } /** * @dev computes log(x / FIXED_1) * FIXED_1 * Input range: FIXED_1 <= x <= OPT_LOG_MAX_VAL - 1 * Auto-generated via 'PrintFunctionOptimalLog.py' * Detailed description: * - Rewrite the input as a product of natural exponents and a single residual r, such that 1 < r < 2 * - The natural logarithm of each (pre-calculated) exponent is the degree of the exponent * - The natural logarithm of r is calculated via Taylor series for log(1 + x), where x = r - 1 * - The natural logarithm of the input is calculated by summing up the intermediate results above * - For example: log(250) = log(e^4 * e^1 * e^0.5 * 1.021692859) = 4 + 1 + 0.5 + log(1 + 0.021692859) */ function optimalLog(uint256 x) internal pure returns (uint256) { uint256 res = 0; uint256 y; uint256 z; uint256 w; if (x >= 0xd3094c70f034de4b96ff7d5b6f99fcd8) { res += 0x40000000000000000000000000000000; x = (x * FIXED_1) / 0xd3094c70f034de4b96ff7d5b6f99fcd8; } // add 1 / 2^1 if (x >= 0xa45af1e1f40c333b3de1db4dd55f29a7) { res += 0x20000000000000000000000000000000; x = (x * FIXED_1) / 0xa45af1e1f40c333b3de1db4dd55f29a7; } // add 1 / 2^2 if (x >= 0x910b022db7ae67ce76b441c27035c6a1) { res += 0x10000000000000000000000000000000; x = (x * FIXED_1) / 0x910b022db7ae67ce76b441c27035c6a1; } // add 1 / 2^3 if (x >= 0x88415abbe9a76bead8d00cf112e4d4a8) { res += 0x08000000000000000000000000000000; x = (x * FIXED_1) / 0x88415abbe9a76bead8d00cf112e4d4a8; } // add 1 / 2^4 if (x >= 0x84102b00893f64c705e841d5d4064bd3) { res += 0x04000000000000000000000000000000; x = (x * FIXED_1) / 0x84102b00893f64c705e841d5d4064bd3; } // add 1 / 2^5 if (x >= 0x8204055aaef1c8bd5c3259f4822735a2) { res += 0x02000000000000000000000000000000; x = (x * FIXED_1) / 0x8204055aaef1c8bd5c3259f4822735a2; } // add 1 / 2^6 if (x >= 0x810100ab00222d861931c15e39b44e99) { res += 0x01000000000000000000000000000000; x = (x * FIXED_1) / 0x810100ab00222d861931c15e39b44e99; } // add 1 / 2^7 if (x >= 0x808040155aabbbe9451521693554f733) { res += 0x00800000000000000000000000000000; x = (x * FIXED_1) / 0x808040155aabbbe9451521693554f733; } // add 1 / 2^8 z = y = x - FIXED_1; w = (y * y) / FIXED_1; res += (z * (0x100000000000000000000000000000000 - y)) / 0x100000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^01 / 01 - y^02 / 02 res += (z * (0x0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - y)) / 0x200000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^03 / 03 - y^04 / 04 res += (z * (0x099999999999999999999999999999999 - y)) / 0x300000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^05 / 05 - y^06 / 06 res += (z * (0x092492492492492492492492492492492 - y)) / 0x400000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^07 / 07 - y^08 / 08 res += (z * (0x08e38e38e38e38e38e38e38e38e38e38e - y)) / 0x500000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^09 / 09 - y^10 / 10 res += (z * (0x08ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8b - y)) / 0x600000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^11 / 11 - y^12 / 12 res += (z * (0x089d89d89d89d89d89d89d89d89d89d89 - y)) / 0x700000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^13 / 13 - y^14 / 14 res += (z * (0x088888888888888888888888888888888 - y)) / 0x800000000000000000000000000000000; // add y^15 / 15 - y^16 / 16 return res; } /** * @dev computes e ^ (x / FIXED_1) * FIXED_1 * input range: 0 <= x <= OPT_EXP_MAX_VAL - 1 * auto-generated via 'PrintFunctionOptimalExp.py' * Detailed description: * - Rewrite the input as a sum of binary exponents and a single residual r, as small as possible * - The exponentiation of each binary exponent is given (pre-calculated) * - The exponentiation of r is calculated via Taylor series for e^x, where x = r * - The exponentiation of the input is calculated by multiplying the intermediate results above * - For example: e^5.521692859 = e^(4 + 1 + 0.5 + 0.021692859) = e^4 * e^1 * e^0.5 * e^0.021692859 */ function optimalExp(uint256 x) internal pure returns (uint256) { uint256 res = 0; uint256 y; uint256 z; z = y = x % 0x10000000000000000000000000000000; // get the input modulo 2^(-3) z = (z * y) / FIXED_1; res += z * 0x10e1b3be415a0000; // add y^02 * (20! / 02!) z = (z * y) / FIXED_1; res += z * 0x05a0913f6b1e0000; // add y^03 * (20! / 03!) z = (z * y) / FIXED_1; res += z * 0x0168244fdac78000; // add y^04 * (20! / 04!) z = (z * y) / FIXED_1; res += z * 0x004807432bc18000; // add y^05 * (20! / 05!) z = (z * y) / FIXED_1; res += z * 0x000c0135dca04000; // add y^06 * (20! / 06!) z = (z * y) / FIXED_1; res += z * 0x0001b707b1cdc000; // add y^07 * (20! / 07!) z = (z * y) / FIXED_1; res += z * 0x000036e0f639b800; // add y^08 * (20! / 08!) z = (z * y) / FIXED_1; res += z * 0x00000618fee9f800; // add y^09 * (20! / 09!) z = (z * y) / FIXED_1; res += z * 0x0000009c197dcc00; // add y^10 * (20! / 10!) z = (z * y) / FIXED_1; res += z * 0x0000000e30dce400; // add y^11 * (20! / 11!) z = (z * y) / FIXED_1; res += z * 0x000000012ebd1300; // add y^12 * (20! / 12!) z = (z * y) / FIXED_1; res += z * 0x0000000017499f00; // add y^13 * (20! / 13!) z = (z * y) / FIXED_1; res += z * 0x0000000001a9d480; // add y^14 * (20! / 14!) z = (z * y) / FIXED_1; res += z * 0x00000000001c6380; // add y^15 * (20! / 15!) z = (z * y) / FIXED_1; res += z * 0x000000000001c638; // add y^16 * (20! / 16!) z = (z * y) / FIXED_1; res += z * 0x0000000000001ab8; // add y^17 * (20! / 17!) z = (z * y) / FIXED_1; res += z * 0x000000000000017c; // add y^18 * (20! / 18!) z = (z * y) / FIXED_1; res += z * 0x0000000000000014; // add y^19 * (20! / 19!) z = (z * y) / FIXED_1; res += z * 0x0000000000000001; // add y^20 * (20! / 20!) res = res / 0x21c3677c82b40000 + y + FIXED_1; // divide by 20! and then add y^1 / 1! + y^0 / 0! if ((x & 0x010000000000000000000000000000000) != 0) res = (res * 0x1c3d6a24ed82218787d624d3e5eba95f9) / 0x18ebef9eac820ae8682b9793ac6d1e776; // multiply by e^2^(-3) if ((x & 0x020000000000000000000000000000000) != 0) res = (res * 0x18ebef9eac820ae8682b9793ac6d1e778) / 0x1368b2fc6f9609fe7aceb46aa619baed4; // multiply by e^2^(-2) if ((x & 0x040000000000000000000000000000000) != 0) res = (res * 0x1368b2fc6f9609fe7aceb46aa619baed5) / 0x0bc5ab1b16779be3575bd8f0520a9f21f; // multiply by e^2^(-1) if ((x & 0x080000000000000000000000000000000) != 0) res = (res * 0x0bc5ab1b16779be3575bd8f0520a9f21e) / 0x0454aaa8efe072e7f6ddbab84b40a55c9; // multiply by e^2^(+0) if ((x & 0x100000000000000000000000000000000) != 0) res = (res * 0x0454aaa8efe072e7f6ddbab84b40a55c5) / 0x00960aadc109e7a3bf4578099615711ea; // multiply by e^2^(+1) if ((x & 0x200000000000000000000000000000000) != 0) res = (res * 0x00960aadc109e7a3bf4578099615711d7) / 0x0002bf84208204f5977f9a8cf01fdce3d; // multiply by e^2^(+2) if ((x & 0x400000000000000000000000000000000) != 0) res = (res * 0x0002bf84208204f5977f9a8cf01fdc307) / 0x0000003c6ab775dd0b95b4cbee7e65d11; // multiply by e^2^(+3) return res; } /** * @dev computes W(x / FIXED_1) / (x / FIXED_1) * FIXED_1 */ function lowerStake(uint256 _x) internal view returns (uint256 pos) { if (_x <= LAMBERT_CONV_RADIUS) return pos = lambertPos1(_x); if (_x <= LAMBERT_POS2_MAXVAL) return pos = lambertPos2(_x); if (_x <= LAMBERT_POS3_MAXVAL) return pos = lambertPos3(_x); require(false); } /** * @dev computes W(-x / FIXED_1) / (-x / FIXED_1) * FIXED_1 */ function higherStake(uint256 _x) internal pure returns (uint256) { if (_x <= LAMBERT_CONV_RADIUS) return lambertNeg1(_x); return (FIXED_1 * FIXED_1) / _x; } /** * @dev computes W(x / FIXED_1) / (x / FIXED_1) * FIXED_1 * input range: 1 <= x <= 1 / e * FIXED_1 * auto-generated via 'PrintFunctionLambertPos1.py' */ function lambertPos1(uint256 _x) internal pure returns (uint256) { uint256 xi = _x; uint256 res = (FIXED_1 - _x) * 0xde1bc4d19efcac82445da75b00000000; // x^(1-1) * (34! * 1^(1-1) / 1!) - x^(2-1) * (34! * 2^(2-1) / 2!) xi = (xi * _x) / FIXED_1; res += xi * 0x00000000014d29a73a6e7b02c3668c7b0880000000; // add x^(03-1) * (34! * 03^(03-1) / 03!) xi = (xi * _x) / FIXED_1; res -= xi * 0x0000000002504a0cd9a7f7215b60f9be4800000000; // sub x^(04-1) * (34! * 04^(04-1) / 04!) xi = (xi * _x) / FIXED_1; res += xi * 0x000000000484d0a1191c0ead267967c7a4a0000000; // add x^(05-1) * (34! * 05^(05-1) / 05!) xi = (xi * _x) / FIXED_1; res -= xi * 0x00000000095ec580d7e8427a4baf26a90a00000000; // sub x^(06-1) * (34! * 06^(06-1) / 06!) xi = (xi * _x) / FIXED_1; res += xi * 0x000000001440b0be1615a47dba6e5b3b1f10000000; // add x^(07-1) * (34! * 07^(07-1) / 07!) xi = (xi * _x) / FIXED_1; res -= xi * 0x000000002d207601f46a99b4112418400000000000; // sub x^(08-1) * (34! * 08^(08-1) / 08!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000000066ebaac4c37c622dd8288a7eb1b2000000; // add x^(09-1) * (34! * 09^(09-1) / 09!) xi = (xi * _x) / FIXED_1; res -= xi * 0x00000000ef17240135f7dbd43a1ba10cf200000000; // sub x^(10-1) * (34! * 10^(10-1) / 10!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000000233c33c676a5eb2416094a87b3657000000; // add x^(11-1) * (34! * 11^(11-1) / 11!) xi = (xi * _x) / FIXED_1; res -= xi * 0x0000000541cde48bc0254bed49a9f8700000000000; // sub x^(12-1) * (34! * 12^(12-1) / 12!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000000cae1fad2cdd4d4cb8d73abca0d19a400000; // add x^(13-1) * (34! * 13^(13-1) / 13!) xi = (xi * _x) / FIXED_1; res -= xi * 0x0000001edb2aa2f760d15c41ceedba956400000000; // sub x^(14-1) * (34! * 14^(14-1) / 14!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000004ba8d20d2dabd386c9529659841a2e200000; // add x^(15-1) * (34! * 15^(15-1) / 15!) xi = (xi * _x) / FIXED_1; res -= xi * 0x000000bac08546b867cdaa20000000000000000000; // sub x^(16-1) * (34! * 16^(16-1) / 16!) xi = (xi * _x) / FIXED_1; res += xi * 0x000001cfa8e70c03625b9db76c8ebf5bbf24820000; // add x^(17-1) * (34! * 17^(17-1) / 17!) xi = (xi * _x) / FIXED_1; res -= xi * 0x000004851d99f82060df265f3309b26f8200000000; // sub x^(18-1) * (34! * 18^(18-1) / 18!) xi = (xi * _x) / FIXED_1; res += xi * 0x00000b550d19b129d270c44f6f55f027723cbb0000; // add x^(19-1) * (34! * 19^(19-1) / 19!) xi = (xi * _x) / FIXED_1; res -= xi * 0x00001c877dadc761dc272deb65d4b0000000000000; // sub x^(20-1) * (34! * 20^(20-1) / 20!) xi = (xi * _x) / FIXED_1; res += xi * 0x000048178ece97479f33a77f2ad22a81b64406c000; // add x^(21-1) * (34! * 21^(21-1) / 21!) xi = (xi * _x) / FIXED_1; res -= xi * 0x0000b6ca8268b9d810fedf6695ef2f8a6c00000000; // sub x^(22-1) * (34! * 22^(22-1) / 22!) xi = (xi * _x) / FIXED_1; res += xi * 0x0001d0e76631a5b05d007b8cb72a7c7f11ec36e000; // add x^(23-1) * (34! * 23^(23-1) / 23!) xi = (xi * _x) / FIXED_1; res -= xi * 0x0004a1c37bd9f85fd9c6c780000000000000000000; // sub x^(24-1) * (34! * 24^(24-1) / 24!) xi = (xi * _x) / FIXED_1; res += xi * 0x000bd8369f1b702bf491e2ebfcee08250313b65400; // add x^(25-1) * (34! * 25^(25-1) / 25!) xi = (xi * _x) / FIXED_1; res -= xi * 0x001e5c7c32a9f6c70ab2cb59d9225764d400000000; // sub x^(26-1) * (34! * 26^(26-1) / 26!) xi = (xi * _x) / FIXED_1; res += xi * 0x004dff5820e165e910f95120a708e742496221e600; // add x^(27-1) * (34! * 27^(27-1) / 27!) xi = (xi * _x) / FIXED_1; res -= xi * 0x00c8c8f66db1fced378ee50e536000000000000000; // sub x^(28-1) * (34! * 28^(28-1) / 28!) xi = (xi * _x) / FIXED_1; res += xi * 0x0205db8dffff45bfa2938f128f599dbf16eb11d880; // add x^(29-1) * (34! * 29^(29-1) / 29!) xi = (xi * _x) / FIXED_1; res -= xi * 0x053a044ebd984351493e1786af38d39a0800000000; // sub x^(30-1) * (34! * 30^(30-1) / 30!) xi = (xi * _x) / FIXED_1; res += xi * 0x0d86dae2a4cc0f47633a544479735869b487b59c40; // add x^(31-1) * (34! * 31^(31-1) / 31!) xi = (xi * _x) / FIXED_1; res -= xi * 0x231000000000000000000000000000000000000000; // sub x^(32-1) * (34! * 32^(32-1) / 32!) xi = (xi * _x) / FIXED_1; res += xi * 0x5b0485a76f6646c2039db1507cdd51b08649680822; // add x^(33-1) * (34! * 33^(33-1) / 33!) xi = (xi * _x) / FIXED_1; res -= xi * 0xec983c46c49545bc17efa6b5b0055e242200000000; // sub x^(34-1) * (34! * 34^(34-1) / 34!) return res / 0xde1bc4d19efcac82445da75b00000000; // divide by 34! } /** * @dev computes W(x / FIXED_1) / (x / FIXED_1) * FIXED_1 * input range: LAMBERT_CONV_RADIUS + 1 <= x <= LAMBERT_POS2_MAXVAL */ function lambertPos2(uint256 _x) internal view returns (uint256) { uint256 x = _x - LAMBERT_CONV_RADIUS - 1; uint256 i = x / LAMBERT_POS2_SAMPLE; uint256 a = LAMBERT_POS2_SAMPLE * i; uint256 b = LAMBERT_POS2_SAMPLE * (i + 1); uint256 c = lambertArray[i]; uint256 d = lambertArray[i + 1]; return (c * (b - x) + d * (x - a)) / LAMBERT_POS2_SAMPLE; } /** * @dev computes W(x / FIXED_1) / (x / FIXED_1) * FIXED_1 * input range: LAMBERT_POS2_MAXVAL + 1 <= x <= LAMBERT_POS3_MAXVAL */ function lambertPos3(uint256 _x) internal pure returns (uint256) { uint256 l1 = _x < OPT_LOG_MAX_VAL ? optimalLog(_x) : generalLog(_x); uint256 l2 = l1 < OPT_LOG_MAX_VAL ? optimalLog(l1) : generalLog(l1); return ((l1 - l2 + (l2 * FIXED_1) / l1) * FIXED_1) / _x; } /** * @dev computes W(-x / FIXED_1) / (-x / FIXED_1) * FIXED_1 * input range: 1 <= x <= 1 / e * FIXED_1 * auto-generated via 'PrintFunctionLambertNeg1.py' */ function lambertNeg1(uint256 _x) internal pure returns (uint256) { uint256 xi = _x; uint256 res = 0; xi = (xi * _x) / FIXED_1; res += xi * 0x00000000014d29a73a6e7b02c3668c7b0880000000; // add x^(03-1) * (34! * 03^(03-1) / 03!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000000002504a0cd9a7f7215b60f9be4800000000; // add x^(04-1) * (34! * 04^(04-1) / 04!) xi = (xi * _x) / FIXED_1; res += xi * 0x000000000484d0a1191c0ead267967c7a4a0000000; // add x^(05-1) * (34! * 05^(05-1) / 05!) xi = (xi * _x) / FIXED_1; res += xi * 0x00000000095ec580d7e8427a4baf26a90a00000000; // add x^(06-1) * (34! * 06^(06-1) / 06!) xi = (xi * _x) / FIXED_1; res += xi * 0x000000001440b0be1615a47dba6e5b3b1f10000000; // add x^(07-1) * (34! * 07^(07-1) / 07!) xi = (xi * _x) / FIXED_1; res += xi * 0x000000002d207601f46a99b4112418400000000000; // add x^(08-1) * (34! * 08^(08-1) / 08!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000000066ebaac4c37c622dd8288a7eb1b2000000; // add x^(09-1) * (34! * 09^(09-1) / 09!) xi = (xi * _x) / FIXED_1; res += xi * 0x00000000ef17240135f7dbd43a1ba10cf200000000; // add x^(10-1) * (34! * 10^(10-1) / 10!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000000233c33c676a5eb2416094a87b3657000000; // add x^(11-1) * (34! * 11^(11-1) / 11!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000000541cde48bc0254bed49a9f8700000000000; // add x^(12-1) * (34! * 12^(12-1) / 12!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000000cae1fad2cdd4d4cb8d73abca0d19a400000; // add x^(13-1) * (34! * 13^(13-1) / 13!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000001edb2aa2f760d15c41ceedba956400000000; // add x^(14-1) * (34! * 14^(14-1) / 14!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000004ba8d20d2dabd386c9529659841a2e200000; // add x^(15-1) * (34! * 15^(15-1) / 15!) xi = (xi * _x) / FIXED_1; res += xi * 0x000000bac08546b867cdaa20000000000000000000; // add x^(16-1) * (34! * 16^(16-1) / 16!) xi = (xi * _x) / FIXED_1; res += xi * 0x000001cfa8e70c03625b9db76c8ebf5bbf24820000; // add x^(17-1) * (34! * 17^(17-1) / 17!) xi = (xi * _x) / FIXED_1; res += xi * 0x000004851d99f82060df265f3309b26f8200000000; // add x^(18-1) * (34! * 18^(18-1) / 18!) xi = (xi * _x) / FIXED_1; res += xi * 0x00000b550d19b129d270c44f6f55f027723cbb0000; // add x^(19-1) * (34! * 19^(19-1) / 19!) xi = (xi * _x) / FIXED_1; res += xi * 0x00001c877dadc761dc272deb65d4b0000000000000; // add x^(20-1) * (34! * 20^(20-1) / 20!) xi = (xi * _x) / FIXED_1; res += xi * 0x000048178ece97479f33a77f2ad22a81b64406c000; // add x^(21-1) * (34! * 21^(21-1) / 21!) xi = (xi * _x) / FIXED_1; res += xi * 0x0000b6ca8268b9d810fedf6695ef2f8a6c00000000; // add x^(22-1) * (34! * 22^(22-1) / 22!) xi = (xi * _x) / FIXED_1; res += xi * 0x0001d0e76631a5b05d007b8cb72a7c7f11ec36e000; // add x^(23-1) * (34! * 23^(23-1) / 23!) xi = (xi * _x) / FIXED_1; res += xi * 0x0004a1c37bd9f85fd9c6c780000000000000000000; // add x^(24-1) * (34! * 24^(24-1) / 24!) xi = (xi * _x) / FIXED_1; res += xi * 0x000bd8369f1b702bf491e2ebfcee08250313b65400; // add x^(25-1) * (34! * 25^(25-1) / 25!) xi = (xi * _x) / FIXED_1; res += xi * 0x001e5c7c32a9f6c70ab2cb59d9225764d400000000; // add x^(26-1) * (34! * 26^(26-1) / 26!) xi = (xi * _x) / FIXED_1; res += xi * 0x004dff5820e165e910f95120a708e742496221e600; // add x^(27-1) * (34! * 27^(27-1) / 27!) xi = (xi * _x) / FIXED_1; res += xi * 0x00c8c8f66db1fced378ee50e536000000000000000; // add x^(28-1) * (34! * 28^(28-1) / 28!) xi = (xi * _x) / FIXED_1; res += xi * 0x0205db8dffff45bfa2938f128f599dbf16eb11d880; // add x^(29-1) * (34! * 29^(29-1) / 29!) xi = (xi * _x) / FIXED_1; res += xi * 0x053a044ebd984351493e1786af38d39a0800000000; // add x^(30-1) * (34! * 30^(30-1) / 30!) xi = (xi * _x) / FIXED_1; res += xi * 0x0d86dae2a4cc0f47633a544479735869b487b59c40; // add x^(31-1) * (34! * 31^(31-1) / 31!) xi = (xi * _x) / FIXED_1; res += xi * 0x231000000000000000000000000000000000000000; // add x^(32-1) * (34! * 32^(32-1) / 32!) xi = (xi * _x) / FIXED_1; res += xi * 0x5b0485a76f6646c2039db1507cdd51b08649680822; // add x^(33-1) * (34! * 33^(33-1) / 33!) xi = (xi * _x) / FIXED_1; res += xi * 0xec983c46c49545bc17efa6b5b0055e242200000000; // add x^(34-1) * (34! * 34^(34-1) / 34!) return res / 0xde1bc4d19efcac82445da75b00000000 + _x + FIXED_1; // divide by 34! and then add x^(2-1) * (34! * 2^(2-1) / 2!) + x^(1-1) * (34! * 1^(1-1) / 1!) } /** * @dev computes the weights based on "W(log(hi / lo) * tq / rp) * tq / rp", where "W" is a variation of the Lambert W function. */ function balancedWeightsByStake( uint256 _hi, uint256 _lo, uint256 _tq, uint256 _rp, bool _lowerStake ) public view returns (uint32, uint32) { (_tq, _rp) = safeFactors(_tq, _rp); uint256 f = _hi.mul(FIXED_1) / _lo; uint256 g = f < OPT_LOG_MAX_VAL ? optimalLog(f) : generalLog(f); uint256 x = g.mul(_tq) / _rp; uint256 y = _lowerStake ? lowerStake(x) : higherStake(x); return normalizedWeights(y.mul(_tq), _rp.mul(FIXED_1)); } /** * @dev reduces "a" and "b" while maintaining their ratio. */ function safeFactors(uint256 _a, uint256 _b) public pure returns (uint256, uint256) { if (_a <= FIXED_2 && _b <= FIXED_2) return (_a, _b); if (_a < FIXED_2) return ((_a * FIXED_2) / _b, FIXED_2); if (_b < FIXED_2) return (FIXED_2, (_b * FIXED_2) / _a); uint256 c = _a > _b ? _a : _b; uint256 n = floorLog2(c / FIXED_1); return (_a >> n, _b >> n); } /** * @dev computes "MAX_WEIGHT * a / (a + b)" and "MAX_WEIGHT * b / (a + b)". */ function normalizedWeights(uint256 _a, uint256 _b) public pure returns (uint32, uint32) { if (_a <= _b) return accurateWeights(_a, _b); (uint32 y, uint32 x) = accurateWeights(_b, _a); return (x, y); } /** * @dev computes "MAX_WEIGHT * a / (a + b)" and "MAX_WEIGHT * b / (a + b)", assuming that "a <= b". */ function accurateWeights(uint256 _a, uint256 _b) public pure returns (uint32, uint32) { if (_a > MAX_UNF_WEIGHT) { uint256 c = _a / (MAX_UNF_WEIGHT + 1) + 1; _a /= c; _b /= c; } uint256 x = roundDiv(_a * MAX_WEIGHT, _a.add(_b)); uint256 y = MAX_WEIGHT - x; return (uint32(x), uint32(y)); } /** * @dev computes the nearest integer to a given quotient without overflowing or underflowing. */ function roundDiv(uint256 _n, uint256 _d) internal pure returns (uint256) { return _n / _d + (_n % _d) / (_d - _d / 2); } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"uint256","name":"_reserveRatio","internalType":"uint256"},{"type":"address","name":"_reserveTokenAddress","internalType":"address"}]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ContinuousBurn","inputs":[{"type":"address","name":"_address","internalType":"address","indexed":false},{"type":"uint256","name":"continuousTokenAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"reserveTokenAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ContinuousMint","inputs":[{"type":"address","name":"_address","internalType":"address","indexed":false},{"type":"uint256","name":"reserveTokenAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"continuousTokenAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint32","name":"","internalType":"uint32"},{"type":"uint32","name":"","internalType":"uint32"}],"name":"accurateWeights","inputs":[{"type":"uint256","name":"_a","internalType":"uint256"},{"type":"uint256","name":"_b","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"},{"type":"uint32","name":"","internalType":"uint32"}],"name":"balancedWeights","inputs":[{"type":"uint256","name":"_primaryReserveStakedBalance","internalType":"uint256"},{"type":"uint256","name":"_primaryReserveBalance","internalType":"uint256"},{"type":"uint256","name":"_secondaryReserveBalance","internalType":"uint256"},{"type":"uint256","name":"_reserveRateNumerator","internalType":"uint256"},{"type":"uint256","name":"_reserveRateDenominator","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"},{"type":"uint32","name":"","internalType":"uint32"}],"name":"balancedWeightsByStake","inputs":[{"type":"uint256","name":"_hi","internalType":"uint256"},{"type":"uint256","name":"_lo","internalType":"uint256"},{"type":"uint256","name":"_tq","internalType":"uint256"},{"type":"uint256","name":"_rp","internalType":"uint256"},{"type":"bool","name":"_lowerStake","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"burn","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"burnAmount","internalType":"uint256"}],"name":"calculateContinuousBurnReturn","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"mintAmount","internalType":"uint256"}],"name":"calculateContinuousMintReturn","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"crossReserveTargetAmount","inputs":[{"type":"uint256","name":"_sourceReserveBalance","internalType":"uint256"},{"type":"uint32","name":"_sourceReserveWeight","internalType":"uint32"},{"type":"uint256","name":"_targetReserveBalance","internalType":"uint256"},{"type":"uint32","name":"_targetReserveWeight","internalType":"uint32"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"decreaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"subtractedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"fundCost","inputs":[{"type":"uint256","name":"_supply","internalType":"uint256"},{"type":"uint256","name":"_reserveBalance","internalType":"uint256"},{"type":"uint32","name":"_reserveRatio","internalType":"uint32"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"fundSupplyAmount","inputs":[{"type":"uint256","name":"_supply","internalType":"uint256"},{"type":"uint256","name":"_reserveBalance","internalType":"uint256"},{"type":"uint32","name":"_reserveRatio","internalType":"uint32"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"increaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"addedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"init","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initLambertArray","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initMaxExpArray","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"liquidateReserveAmount","inputs":[{"type":"uint256","name":"_supply","internalType":"uint256"},{"type":"uint256","name":"_reserveBalance","internalType":"uint256"},{"type":"uint32","name":"_reserveRatio","internalType":"uint32"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"_amountMinted","internalType":"uint256"}],"name":"mint","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint32","name":"","internalType":"uint32"},{"type":"uint32","name":"","internalType":"uint32"}],"name":"normalizedWeights","inputs":[{"type":"uint256","name":"_a","internalType":"uint256"},{"type":"uint256","name":"_b","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint8","name":"","internalType":"uint8"}],"name":"power","inputs":[{"type":"uint256","name":"_baseN","internalType":"uint256"},{"type":"uint256","name":"_baseD","internalType":"uint256"},{"type":"uint32","name":"_expN","internalType":"uint32"},{"type":"uint32","name":"_expD","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"purchaseTargetAmount","inputs":[{"type":"uint256","name":"_supply","internalType":"uint256"},{"type":"uint256","name":"_reserveBalance","internalType":"uint256"},{"type":"uint32","name":"_reserveWeight","internalType":"uint32"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"reserveBalance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"reserveRatio","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"reserveTokenAddress","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"safeFactors","inputs":[{"type":"uint256","name":"_a","internalType":"uint256"},{"type":"uint256","name":"_b","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"saleTargetAmount","inputs":[{"type":"uint256","name":"_supply","internalType":"uint256"},{"type":"uint256","name":"_reserveBalance","internalType":"uint256"},{"type":"uint32","name":"_reserveWeight","internalType":"uint32"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"scale","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]}]
Contract Creation Code
0x6080604052670de0b6b3a76400006101858190556200002090600a62000330565b610186553480156200003157600080fd5b506040516200620138038062006201833981016040819052620000549162000298565b604080518082018252600f81526e21b7b73a34b737bab9902a37b5b2b760891b602080830191825283518085019094526003845262544f4b60e81b908401528151919291620000a79161018391620001f2565b508051620000be90610184906020840190620001f2565b50505061018782905561018880546001600160a01b0319166001600160a01b0383161790556101855462000101903390620000fb90600162000330565b62000109565b5050620003a5565b6001600160a01b0382166200013b5760405162461bcd60e51b81526004016200013290620002d5565b60405180910390fd5b6200014960008383620001ed565b8061018260008282546200015e919062000315565b90915550506001600160a01b03821660009081526101806020526040812080548392906200018e90849062000315565b90915550506040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90620001d39085906200030c565b60405180910390a3620001e960008383620001ed565b5050565b505050565b828054620002009062000352565b90600052602060002090601f0160209004810192826200022457600085556200026f565b82601f106200023f57805160ff19168380011785556200026f565b828001600101855582156200026f579182015b828111156200026f57825182559160200191906001019062000252565b506200027d92915062000281565b5090565b5b808211156200027d576000815560010162000282565b60008060408385031215620002ab578182fd5b825160208401519092506001600160a01b0381168114620002ca578182fd5b809150509250929050565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b90815260200190565b600082198211156200032b576200032b6200038f565b500190565b60008160001904831182151516156200034d576200034d6200038f565b500290565b6002810460018216806200036757607f821691505b602082108114156200038957634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b615e4c80620003b56000396000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c806394491fab1161011a578063a67453b0116100ad578063e1c7392a1161007c578063e1c7392a14610443578063ebbb21581461044b578063ee1ea4ff1461045e578063f3250fe214610473578063f51e181a1461048657610206565b8063a67453b0146103f4578063a9059cbb14610415578063aa248a4614610428578063dd62ed3e1461043057610206565b8063a11aa1b4116100e9578063a11aa1b4146103b3578063a179dd93146103c6578063a3882291146103ce578063a457c2d7146103e157610206565b806394491fab1461037d57806395d89b4114610390578063a0712d6814610398578063a10954fe146103ab57610206565b8063313ce5671161019d57806370a082311161016c57806370a082311461031e57806376c2d5101461033157806376cf0b56146103445780638074590a1461035757806390f0c2ea1461036a57610206565b8063313ce567146102c057806332833d51146102d557806339509351146102f657806342966c681461030957610206565b806323b872dd116101d957806323b872dd1461026657806328c3d701146102795780632f55bdb51461028c57806330c7d6371461029f57610206565b806306fdde031461020b578063095ea7b3146102295780630c7d5cd81461024957806318160ddd1461025e575b600080fd5b61021361048e565b60405161022091906156bc565b60405180910390f35b61023c61023736600461543b565b610521565b60405161022091906156b1565b61025161053e565b6040516102209190615c28565b610251610545565b61023c610274366004615400565b61054c565b610251610287366004615480565b6105e6565b61025161029a366004615557565b610609565b6102b26102ad3660046154b0565b610720565b604051610220929190615c50565b6102c86107e6565b6040516102209190615c67565b6102e86102e3366004615593565b6107eb565b604051610220929190615c3f565b61023c61030436600461543b565b6108d8565b61031c610317366004615480565b61092d565b005b61025161032c3660046153b4565b6109c3565b6102b261033f3660046154b0565b6109df565b610251610352366004615557565b610a15565b610251610365366004615557565b610b45565b610251610378366004615480565b610c29565b61025161038b3660046155d8565b610c44565b610213610d68565b6102516103a6366004615480565b610d78565b610251610f0b565b6102b26103c136600461551d565b610f12565b61031c61101f565b6102b26103dc3660046154d1565b611a26565b61023c6103ef36600461543b565b611aee565b6104076104023660046154b0565b611b68565b604051610220929190615c31565b61023c61042336600461543b565b611c28565b61031c611c3c565b61025161043e3660046153ce565b612412565b61031c61243e565b610251610459366004615557565b612450565b61046661257e565b6040516102209190615625565b610251610481366004615557565b61258e565b610251612641565b6060610183805461049e90615d8a565b80601f01602080910402602001604051908101604052809291908181526020018280546104ca90615d8a565b80156105175780601f106104ec57610100808354040283529160200191610517565b820191906000526020600020905b8154815290600101906020018083116104fa57829003601f168201915b5050505050905090565b600061053561052e612648565b848461264c565b50600192915050565b6101875481565b6101825490565b6000610559848484612701565b6001600160a01b0384166000908152610181602052604081208161057b612648565b6001600160a01b03166001600160a01b03168152602001908152602001600020549050828110156105c75760405162461bcd60e51b81526004016105be9061595b565b60405180910390fd5b6105db856105d3612648565b85840361264c565b506001949350505050565b60006106016105f3610545565b61018654610187548561258e565b90505b919050565b600080851161062a5760405162461bcd60e51b81526004016105be906158f8565b6000841161064a5760405162461bcd60e51b81526004016105be9061588a565b60018363ffffffff161180156106795750610669620f42406002615d07565b63ffffffff168363ffffffff1611155b6106955760405162461bcd60e51b81526004016105be90615924565b816106a257506000610718565b63ffffffff8316620f424014156106cf57836106be838761282d565b6106c89190615cb2565b9050610718565b600080806106dd8786612840565b90506106ee818888620f42406107eb565b9093509150600060ff83166107038a8661282d565b901c90506107118982615d33565b9450505050505b949350505050565b6000807d10c6f7a0b5ed8d36b4c7f34938583621fafc8b0079a2834d26fa3fcc9ea98411156107a55760006107747d10c6f7a0b5ed8d36b4c7f34938583621fafc8b0079a2834d26fa3fcc9ea96001615c75565b61077e9086615cb2565b610789906001615c75565b90506107958186615cb2565b94506107a18185615cb2565b9350505b60006107c66107b7620f424087615ce8565b6107c18787612840565b61284c565b905060006107d782620f4240615d33565b919350909150505b9250929050565b601290565b600080600160811b86106107fe57600080fd5b600080866108106001607f1b8a615ce8565b61081a9190615cb2565b905070015bf0a8b1457695355fb8ac404e7a79e38110156108455761083e8161288b565b9150610851565b61084e81612e04565b91505b60008563ffffffff168763ffffffff168461086c9190615ce8565b6108769190615cb2565b9050600160831b81101561089b5761088d81612eed565b607f945094505050506108cf565b60006108a682613518565b90506108c26108b682607f615d4a565b60ff1683901c826135f8565b955093506108cf92505050565b94509492505050565b60006105356108e5612648565b848461018160006108f4612648565b6001600160a01b03908116825260208083019390935260409182016000908120918b16815292529020546109289190615c75565b61264c565b600061093882613c56565b6101885460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb9061096c9033908590600401615677565b602060405180830381600087803b15801561098657600080fd5b505af115801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be9190615464565b505050565b6001600160a01b03166000908152610180602052604090205490565b6000808284116109fc576109f38484610720565b915091506107df565b600080610a098587610720565b97909650945050505050565b6000808511610a365760405162461bcd60e51b81526004016105be906158f8565b60008411610a565760405162461bcd60e51b81526004016105be9061588a565b60008363ffffffff16118015610a755750620f424063ffffffff841611155b610a915760405162461bcd60e51b81526004016105be90615b3e565b84821115610ab15760405162461bcd60e51b81526004016105be90615a97565b81610abe57506000610718565b84821415610acd575082610718565b63ffffffff8316620f42401415610ae957846106be858461282d565b60008080610af78589615d33565b9050610b088882620f4240896107eb565b90935091506000610b19888561282d565b905060ff831688901b84610b2d8284615d33565b610b379190615cb2565b9a9950505050505050505050565b6000808511610b665760405162461bcd60e51b81526004016105be906158f8565b60008411610b865760405162461bcd60e51b81526004016105be9061588a565b60018363ffffffff16118015610bb55750610ba5620f42406002615d07565b63ffffffff168363ffffffff1611155b610bd15760405162461bcd60e51b81526004016105be90615924565b84821115610bf15760405162461bcd60e51b81526004016105be90615a97565b81610bfe57506000610718565b84821415610c0d575082610718565b63ffffffff8316620f42401415610ae957846106be838661282d565b6000610601610c36610545565b610186546101875485610a15565b60008086118015610c555750600084115b610c715760405162461bcd60e51b81526004016105be9061588a565b60008563ffffffff16118015610c905750620f424063ffffffff861611155b8015610ca2575060008363ffffffff16115b8015610cb75750620f424063ffffffff841611155b610cd35760405162461bcd60e51b81526004016105be90615b3e565b8263ffffffff168563ffffffff161415610d0c57610cf18683612840565b610cfb858461282d565b610d059190615cb2565b9050610d5f565b60008080610d1a8986612840565b9050610d28818a8a896107eb565b90935091506000610d39888561282d565b905060ff831688901b84610d4d8284615d33565b610d579190615cb2565b955050505050505b95945050505050565b6060610184805461049e90615d8a565b61018854604051636eb1769f60e11b815260009182916001600160a01b039091169063dd62ed3e90610db09033903090600401615639565b60206040518083038186803b158015610dc857600080fd5b505afa158015610ddc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e009190615498565b905060008111610e225760405162461bcd60e51b81526004016105be906158c1565b82811015610e425760405162461bcd60e51b81526004016105be906159a3565b610188546040516323b872dd60e01b81526000916001600160a01b0316906323b872dd90610e7890339030908790600401615653565b602060405180830381600087803b158015610e9257600080fd5b505af1158015610ea6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eca9190615464565b90508015610ee457610edb82613d0a565b92505050610604565b60008211610f045760405162461bcd60e51b81526004016105be90615794565b5050919050565b6101865481565b60008085871415610f4d576000871180610f2c5750600085115b610f485760405162461bcd60e51b81526004016105be9061588a565b610f85565b600087118015610f5d5750600086115b8015610f695750600085115b610f855760405162461bcd60e51b81526004016105be9061588a565b600084118015610f955750600083115b610fb15760405162461bcd60e51b81526004016105be90615b75565b6000610fbd888661282d565b90506000610fcb878661282d565b905087891015610fee57610fe3888a84846001611a26565b935093505050611015565b8789111561100457610fe3898984846000611a26565b61100e82826109df565b9350935050505b9550959350505050565b6f60e393c68d20b1bd09deaabc0373b9c560809081556f5f8f46e4854120989ed94719fb4c20116081556f5e479ebb9129fb1b7e72a648f992b6066082556f5d0bd23fe42dfedde2e9586be12b85fe6083556f5bdb29ddee979308ddfca81aeeb8095a6084556f5ab4fd8a260d2c7e2c0d2afcf0009dad6085556f5998b31359a55d48724c65cf090012216086556f5885bcad2b322dfc43e8860f9c018cf56087556f577b97aa1fe222bb452fdf111b1f0be26088556f5679cb5e3575632e5baa27e2b949f7046089556f557fe8241b3a31c83c732f1cdff4a1c5608a556f548d868026504875d6e59bbe95fc2a6b608b556f53a2465ce347cf34d05a867c17dd3088608c556f52bdce5dcd4faed59c7f5511cf8f8acc608d556f51dfcb453c07f8da817606e7885f7c3e608e556f5107ef6b0a5a2be8f8ff15590daa3cce608f556f5035f241d6eae0cd7bacba119993de7b6090556f4f698fe90d5b53d532171e1210164c666091556f4ea288ca297a0e6a09a0eee240e16c856092556f4de0a13fdcf5d4213fc398ba6e3becde6093556f4d23a145eef91fec06b06140804c48086094556f4c6b5430d4c1ee5526473db4ae0f11de6095556f4bb7886c240562eba11f4963a53b42406096556f4b080f3f1cb491d2d521e0ea4583521e6097556f4a5cbc96a05589cb4d86be1db31683646098556f49b566d40243517658d78c33162d6ece6099556f4911e6a02e5507a30f947383fd9a3276609a556f487216c2b31be4adc41db8a8d5cc0c88609b556f47d5d3fc4a7a1b188cd3d788b5c5e9fc609c556f473cfce4871a2c40bc4f9e1c32b955d0609d556f46a771ca578ab878485810e285e31c67609e556f4615149718aed4c258c373dc676aa72d609f556f4585c8b3f8fe489c6e1833ca4787138460a0556f44f972f174e41e5efb7e9d63c29ce73560a1556f446ff970ba86d8b00beb05ecebf3c4dc60a2556f43e9438ec88971812d6f198b5ccaad9660a3556f436539d11ff7bea657aeddb394e809ef60a4556f42e3c5d3e5a913401d86f66db5d81c2c60a5556f4264d2395303070ea726cbe98df6217460a6556f41e84a9a593bb7194c3a6349ecae4eea60a7556f416e1b785d13eba07a08f3f18876a5ab60a8556f40f6322ff389d423ba9dd7e7e7b7e80960a9556f40807cec8a466880ecf4184545d240a460aa556f400cea9ce88a8d3ae668e8ea0d9bf07f60ab556f3f9b6ae8772d4c55091e0ed7dfea0ac160ac556f3f2bee253fd84594f54bcaafac383a1360ad556f3ebe654e95208bb9210c575c081c595860ae556f3e52c1fc5665635b78ce1f05ad53c08660af556f3de8f65ac388101ddf718a6f5c1eff6560b0556f3d80f522d59bd0b328ca012df4cd2d4960b1556f3d1ab193129ea72b23648a161163a85a60b2556f3cb61f68d32576c135b95cfb53f76d7560b3556f3c5332d9f1aae851a3619e77e4cc847360b4556f3bf1e08edbe2aa109e1525f65759ef7360b5556f3b921d9cff13fa2c197746a3dfc4918f60b6556f3b33df818910bfc1a5aefb8f63ae2ac460b7556f3ad71c1c77e34fa32a9f184967eccbf660b8556f3a7bc9abf2c5bb53e2f7384a8a16521a60b9556f3a21dec7e76369783a68a0c6385a1c5760ba556f39c9525de6c9cdf7c1c157ca4a7a6ee360bb556f39721bad3dc85d1240ff0190e0adaac360bc556f391c324344d3248f0469eb28dd3d77e060bd556f38c78df7e3c796279fb4ff84394ab3da60be556f387426ea4638ae9aae08049d3554c20a60bf556f3821f57dbd2763256c1a99bbd205137860c0556f37d0f256cb46a8c92ff62fbbef28969860c1556f37811658591ffc7abdd1feaf3cef9b7360c2556f37325aa10e9e82f7df0f380f7997154b60c3556f36e4b888cfb408d873b9a80d439311c660c4556f3698299e59f4bb9de645fc9b08c64cca60c5556f364ca7a5012cb603023b57dd3ebfd50d60c6556f36022c928915b778ab1b06aaee7e61d460c7556f35b8b28d1a73dc27500ffe35559cc02860c8556f357033e951fe250ec5eb4e60955132d760c9556f3528ab2867934e3a21b5412e4c4f888160ca556f34e212f66c55057f9676c80094a61d5960cb556f349c66289e5b3c4b540c24f42fa4b9bb60cc556f34579fbbd0c733a9c8d6af6b0f7d00f760cd556f3413bad2e712288b924b5882b5b369bf60ce556f33d0b2b56286510ef730e213f71f12e960cf556f338e82ce00e2496262c64457535ba1a160d0556f334d26a96b373bb7c2f8ea1827f27a9260d1556f330c99f4f4211469e00b3e18c31475ea60d2556f32ccd87d6486094999c7d5e6f33237d860d3556f328dde2dd617b6665a2e8556f250c1af60d4556f324fa70e9adc270f8262755af5a99af960d5556f32122f443110611ca51040f41fa6e1e360d6556f31d5730e42c0831482f0f1485c4263d860d7556f31996ec6b07b4a83421b5ebc4ab4e1f160d8556f315e1ee0a68ff46bb43ec2b85032e87660d9556f31237fe7bc4deacf6775b9efa1a145f860da556f30e98e7f1cc5a356e44627a6972ea2ff60db556f30b04760b8917ec74205a3002650ec0560dc556f3077a75c803468e9132ce0cf3224241d60dd556f303fab57a6a275c36f19cda9bace667a60de556f3008504beb8dcbd2cf3bc1f6d5a064f060df556f2fd19346ed17dac61219ce0c2c5ac4b060e0556f2f9b7169808c324b5852fd3d54ba971460e1556f2f65e7e711cf4b064eea9c08cbdad57460e2556f2f30f405093042ddff8a251b6bf6d10360e3556f2efc931a3750f2e8bfe323edfe03757460e4556f2ec8c28e46dbe56d98685278339400cb60e5556f2e957fd933c3926d8a599b602379b85160e6556f2e62c882c7c9ed4473412702f08ba0e560e7556f2e309a221c12ba361e3ed695167feee260e8556f2dfef25d1f865ae18dd07cfea4bcea1060e9556f2dcdcee821cdc80decc02c44344aeb3160ea556f2d9d2d8562b34944d0b201bb87260c8360eb556f2d6d0c04a5b62a2c42636308669b729a60ec556f2d3d6842c9a235517fc5a0332691528f60ed556f2d0e402963fe1ea2834abc408c437c1060ee556f2cdf91ae602647908aff975e4d6a2a8c60ef556f2cb15ad3a1eb65f6d74a75da09a1b6c560f0556f2c8399a6ab8e9774d6fcff373d21072760f1556f2c564c4046f64edba6883ca06bbc453560f2556f2c2970c431f952641e05cb493e23eed360f3556f2bfd0560cd9eb14563bc7c0732856c1860f4556f2bd1084ed0332f7ff4150f9d0ef41a2c60f5556f2ba577d0fa1628b76d040b12a82492fb60f6556f2b7a5233cd21581e855e89dc2f1e8a9260f7556f2b4f95cd46904d05d72bdcde337d9cc760f8556f2b2540fc9b4d9abba3faca669191467560f9556f2afb5229f68d0830d8be8adb0a0db70f60fa556f2ad1c7c63a9b294c5bc73a3ba3ab7a2b60fb556f2aa8a04ac3cbe1ee1c9c86361465dbb860fc556f2a7fda392d725a44a2c8aeb9ab35430d60fd556f2a57741b18cde618717792b4faa216db60fe556f2a2f6c81f5d84dd950a35626d6d5503a90607f5b0155565b600080611a338585611b68565b9095509350600086611a49896001607f1b61282d565b611a539190615cb2565b9050600070015bf0a8b1457695355fb8ac404e7a79e38210611a7d57611a7882612e04565b611a86565b611a868261288b565b9050600086611a95838a61282d565b611a9f9190615cb2565b9050600086611ab657611ab182613d88565b611abf565b611abf82613dca565b9050611adc611ace828b61282d565b61033f8a6001607f1b61282d565b95509550505050509550959350505050565b6000806101816000611afe612648565b6001600160a01b0390811682526020808301939093526040918201600090812091881681529252902054905082811015611b4a5760405162461bcd60e51b81526004016105be90615bac565b611b5e611b55612648565b8585840361264c565b5060019392505050565b600080600160801b8411158015611b835750600160801b8311155b15611b925750829050816107df565b600160801b841015611bc55782611bad600160801b86615ce8565b611bb79190615cb2565b600160801b915091506107df565b600160801b831015611beb57600160801b84611be18286615ce8565b6109f39190615cb2565b6000838511611bfa5783611bfc565b845b90506000611c16611c116001607f1b84615cb2565b613e2e565b60ff1695861c969490951c9450505050565b6000610535611c35612648565b8484612701565b701c35fedd14ffffffffffffffffffffffff602055701b0ce43b323fffffffffffffffffffffff6021557019f0028ec1ffffffffffffffffffffffff6022557018ded91f0e7fffffffffffffffffffffff6023557017d8ec7f0417ffffffffffffffffffffff6024557016ddc6556cdbffffffffffffffffffffff6025557015ecf52776a1ffffffffffffffffffffff6026557015060c256cb2ffffffffffffffffffffff602755701428a2f98d72ffffffffffffffffffffff6028557013545598e5c23fffffffffffffffffffff602955701288c4161ce1dfffffffffffffffffffff602a557011c592761c666fffffffffffffffffffff602b5570110a688680a757ffffffffffffffffffff602c55701056f1b5bedf77ffffffffffffffffffff602d55700faadceceeff8bffffffffffffffffffff602e55700f05dc6b27edadffffffffffffffffffff602f55700e67a5a25da4107fffffffffffffffffff603055700dcff115b14eedffffffffffffffffffff603155700d3e7a392431239fffffffffffffffffff603255700cb2ff529eb71e4fffffffffffffffffff603355700c2d415c3db974afffffffffffffffffff603455700bad03e7d883f69bffffffffffffffffff603555700b320d03b2c343d5ffffffffffffffffff603655700abc25204e02828dffffffffffffffffff603755700a4b16f74ee4bb207fffffffffffffffff6038557009deaf736ac1f569ffffffffffffffffff603955700976bd9952c7aa957fffffffffffffffff603a557009131271922eaa606fffffffffffffffff603b557008b380f3558668c46fffffffffffffffff603c55700857ddf0117efa215bffffffffffffffff603d557007ffffffffffffffffffffffffffffffff603e557007abbf6f6abb9d087fffffffffffffffff603f5570075af62cbac95f7dfa7fffffffffffffff60405570070d7fb7452e187ac13fffffffffffffff6041557006c3390ecc8af379295fffffffffffffff60425570067c00a3b07ffc01fd6fffffffffffffff604355700637b647c39cbb9d3d27ffffffffffffff6044557005f63b1fc104dbd39587ffffffffffffff6045557005b771955b36e12f7235ffffffffffffff60465570057b3d49dda84556d6f6ffffffffffffff60475570054183095b2c8ececf30ffffffffffffff60485570050a28be635ca2b888f77fffffffffffff6049557004d5156639708c9db33c3fffffffffffff604a557004a23105873875bd52dfdfffffffffffff604b55700471649d87199aa990756fffffffffffff604c557004429a21a029d4c1457cfbffffffffffff604d55700415bc6d6fb7dd71af2cb3ffffffffffff604e557003eab73b3bbfe282243ce1ffffffffffff604f557003c1771ac9fb6b4c18e229ffffffffffff605055700399e96897690418f785257fffffffffff605155700373fc456c53bb779bf0ea9fffffffffff60525570034f9e8e490c48e67e6ab8bfffffffffff60535570032cbfd4a7adc790560b3337ffffffffff60545570030b50570f6e5d2acca94613ffffffffff6055557002eb40f9f620fda6b56c2861ffffffffff6056557002cc8340ecb0d0f520a6af58ffffffffff6057557002af09481380a0a35cf1ba02ffffffffff605855700292c5bdd3b92ec810287b1b3fffffffff605955700277abdcdab07d5a77ac6d6b9fffffffff605a5570025daf6654b1eaa55fd64df5efffffffff605b55700244c49c648baa98192dce88b7ffffffff605c5570022ce03cd5619a311b2471268bffffffff605d55700215f77c045fbe885654a44a0fffffffff605e557001ffffffffffffffffffffffffffffffff605f557001eaefdbdaaee7421fc4d3ede5ffffffff6060557001d6bd8b2eb257df7e8ca57b09bfffffff6061557001c35fedd14b861eb0443f7f133fffffff6062557001b0ce43b322bcde4a56e8ada5afffffff60635570019f0028ec1fff007f5a195a39dfffffff60645570018ded91f0e72ee74f49b15ba527ffffff60655570017d8ec7f04136f4e5615fd41a63ffffff60665570016ddc6556cdb84bdc8d12d22e6fffffff60675570015ecf52776a1155b5bd8395814f7fffff60685570015060c256cb23b3b3cc3754cf40ffffff6069557001428a2f98d728ae223ddab715be3fffff606a5570013545598e5c23276ccf0ede68034fffff606b557001288c4161ce1d6f54b7f61081194fffff606c5570011c592761c666aa641d5a01a40f17ffff606d55700110a688680a7530515f3e6e6cfdcdffff606e557001056f1b5bedf75c6bcb2ce8aed428ffff606f556ffaadceceeff8a0890f3875f008277fff6070556ff05dc6b27edad306388a600f6ba0bfff6071556fe67a5a25da41063de1495d5b18cdbfff6072556fdcff115b14eedde6fc3aa5353f2e4fff6073556fd3e7a3924312399f9aae2e0f868f8fff6074556fcb2ff529eb71e41582cccd5a1ee26fff6075556fc2d415c3db974ab32a51840c0b67edff6076556fbad03e7d883f69ad5b0a186184e06bff6077556fb320d03b2c343d4829abd6075f0cc5ff6078556fabc25204e02828d73c6e80bcdb1a95bf6079556fa4b16f74ee4bb2040a1ec6c15fbbf2df607a556f9deaf736ac1f569deb1b5ae3f36c130f607b556f976bd9952c7aa957f5937d790ef65037607c556f9131271922eaa6064b73a22d0bd4f2bf607d556f8b380f3558668c46c91c49a2f8e967b9607e556f857ddf0117efa215952912839f6473e66000607f611a22565b6001600160a01b0391821660009081526101816020908152604080832093909416825291909152205490565b612446611c3c565b61244e61101f565b565b60008085116124715760405162461bcd60e51b81526004016105be906158f8565b600084116124915760405162461bcd60e51b81526004016105be9061588a565b60018363ffffffff161180156124c057506124b0620f42406002615d07565b63ffffffff168363ffffffff1611155b6124dc5760405162461bcd60e51b81526004016105be90615924565b816124e957506000610718565b63ffffffff8316620f4240141561252657846001612507848761282d565b6125119190615d33565b61251b9190615cb2565b6106c8906001615c75565b600080806125348886612840565b90506125458189620f4240896107eb565b9093509150600060ff8316600161255c8a8761282d565b6125669190615d33565b612572911c6001615c75565b90506107118882615d33565b610188546001600160a01b031681565b60008085116125af5760405162461bcd60e51b81526004016105be906158f8565b600084116125cf5760405162461bcd60e51b81526004016105be9061588a565b60008363ffffffff161180156125ee5750620f424063ffffffff841611155b61260a5760405162461bcd60e51b81526004016105be90615b3e565b8161261757506000610718565b63ffffffff8316620f4240141561263357836106be868461282d565b600080806106dd8588612840565b6101855481565b3390565b6001600160a01b0383166126725760405162461bcd60e51b81526004016105be90615ac3565b6001600160a01b0382166126985760405162461bcd60e51b81526004016105be906157cb565b6001600160a01b038084166000818152610181602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906126f4908590615c28565b60405180910390a3505050565b6001600160a01b0383166127275760405162461bcd60e51b81526004016105be90615a52565b6001600160a01b03821661274d5760405162461bcd60e51b81526004016105be9061570f565b6127588383836109be565b6001600160a01b03831660009081526101806020526040902054818110156127925760405162461bcd60e51b81526004016105be90615844565b6001600160a01b03808516600090815261018060205260408082208585039055918516815290812080548492906127ca908490615c75565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516128149190615c28565b60405180910390a36128278484846109be565b50505050565b60006128398284615ce8565b9392505050565b60006128398284615c75565b6000612859600283615cb2565b6128639083615d33565b61286d8385615dc5565b6128779190615cb2565b6128818385615cb2565b6128399190615c75565b6000808080806fd3094c70f034de4b96ff7d5b6f99fcd886106128e4576128b66001607e1b85615c75565b93506fd3094c70f034de4b96ff7d5b6f99fcd86128d76001607f1b88615ce8565b6128e19190615cb2565b95505b6fa45af1e1f40c333b3de1db4dd55f29a78610612937576129096001607d1b85615c75565b93506fa45af1e1f40c333b3de1db4dd55f29a761292a6001607f1b88615ce8565b6129349190615cb2565b95505b6f910b022db7ae67ce76b441c27035c6a1861061298a5761295c6001607c1b85615c75565b93506f910b022db7ae67ce76b441c27035c6a161297d6001607f1b88615ce8565b6129879190615cb2565b95505b6f88415abbe9a76bead8d00cf112e4d4a886106129dd576129af6001607b1b85615c75565b93506f88415abbe9a76bead8d00cf112e4d4a86129d06001607f1b88615ce8565b6129da9190615cb2565b95505b6f84102b00893f64c705e841d5d4064bd38610612a3057612a026001607a1b85615c75565b93506f84102b00893f64c705e841d5d4064bd3612a236001607f1b88615ce8565b612a2d9190615cb2565b95505b6f8204055aaef1c8bd5c3259f4822735a28610612a8357612a55600160791b85615c75565b93506f8204055aaef1c8bd5c3259f4822735a2612a766001607f1b88615ce8565b612a809190615cb2565b95505b6f810100ab00222d861931c15e39b44e998610612ad657612aa8600160781b85615c75565b93506f810100ab00222d861931c15e39b44e99612ac96001607f1b88615ce8565b612ad39190615cb2565b95505b6f808040155aabbbe9451521693554f7338610612b2957612afb600160771b85615c75565b93506f808040155aabbbe9451521693554f733612b1c6001607f1b88615ce8565b612b269190615cb2565b95505b612b376001607f1b87615d33565b92508291506001607f1b612b4b8380615ce8565b612b559190615cb2565b9050600160801b612b668482615d33565b612b709084615ce8565b612b7a9190615cb2565b612b849085615c75565b93506001607f1b612b958284615ce8565b612b9f9190615cb2565b9150600160811b612bc0846faaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa615d33565b612bca9084615ce8565b612bd49190615cb2565b612bde9085615c75565b93506001607f1b612bef8284615ce8565b612bf99190615cb2565b9150600360801b612c1a846f99999999999999999999999999999999615d33565b612c249084615ce8565b612c2e9190615cb2565b612c389085615c75565b93506001607f1b612c498284615ce8565b612c539190615cb2565b9150600160821b612c74846f92492492492492492492492492492492615d33565b612c7e9084615ce8565b612c889190615cb2565b612c929085615c75565b93506001607f1b612ca38284615ce8565b612cad9190615cb2565b9150600560801b612cce846f8e38e38e38e38e38e38e38e38e38e38e615d33565b612cd89084615ce8565b612ce29190615cb2565b612cec9085615c75565b93506001607f1b612cfd8284615ce8565b612d079190615cb2565b9150600360811b612d28846f8ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8b615d33565b612d329084615ce8565b612d3c9190615cb2565b612d469085615c75565b93506001607f1b612d578284615ce8565b612d619190615cb2565b9150600760801b612d82846f89d89d89d89d89d89d89d89d89d89d89615d33565b612d8c9084615ce8565b612d969190615cb2565b612da09085615c75565b93506001607f1b612db18284615ce8565b612dbb9190615cb2565b9150600160831b612ddc846f88888888888888888888888888888888615d33565b612de69084615ce8565b612df09190615cb2565b612dfa9085615c75565b9695505050505050565b600080600160801b8310612e43576000612e25611c116001607f1b86615cb2565b60ff811694851c94909150612e3f906001607f1b90615ce8565b9150505b6001607f1b831115612eb857607f5b60ff811615612eb6576001607f1b612e6a8580615ce8565b612e749190615cb2565b9350600160801b8410612ea657600193841c93612e919082615d4a565b60ff166001901b82612ea39190615c75565b91505b612eaf81615d6d565b9050612e52565b505b6f05b9de1d10bf4103d647b0955897ba80612ee36f03f80fe03f80fe03f80fe03f80fe03f883615ce8565b6128399190615cb2565b6000808080612f006001607c1b86615dc5565b91508190506001607f1b612f148280615ce8565b612f1e9190615cb2565b9050612f32816710e1b3be415a0000615ce8565b612f3c9084615c75565b92506001607f1b612f4d8383615ce8565b612f579190615cb2565b9050612f6b816705a0913f6b1e0000615ce8565b612f759084615c75565b92506001607f1b612f868383615ce8565b612f909190615cb2565b9050612fa481670168244fdac78000615ce8565b612fae9084615c75565b92506001607f1b612fbf8383615ce8565b612fc99190615cb2565b9050612fdc81664807432bc18000615ce8565b612fe69084615c75565b92506001607f1b612ff78383615ce8565b6130019190615cb2565b905061301481660c0135dca04000615ce8565b61301e9084615c75565b92506001607f1b61302f8383615ce8565b6130399190615cb2565b905061304c816601b707b1cdc000615ce8565b6130569084615c75565b92506001607f1b6130678383615ce8565b6130719190615cb2565b9050613083816536e0f639b800615ce8565b61308d9084615c75565b92506001607f1b61309e8383615ce8565b6130a89190615cb2565b90506130ba81650618fee9f800615ce8565b6130c49084615c75565b92506001607f1b6130d58383615ce8565b6130df9190615cb2565b90506130f081649c197dcc00615ce8565b6130fa9084615c75565b92506001607f1b61310b8383615ce8565b6131159190615cb2565b905061312681640e30dce400615ce8565b6131309084615c75565b92506001607f1b6131418383615ce8565b61314b9190615cb2565b905061315c8164012ebd1300615ce8565b6131669084615c75565b92506001607f1b6131778383615ce8565b6131819190615cb2565b9050613191816317499f00615ce8565b61319b9084615c75565b92506001607f1b6131ac8383615ce8565b6131b69190615cb2565b90506131c6816301a9d480615ce8565b6131d09084615c75565b92506001607f1b6131e18383615ce8565b6131eb9190615cb2565b90506131fa81621c6380615ce8565b6132049084615c75565b92506001607f1b6132158383615ce8565b61321f9190615cb2565b905061322e816201c638615ce8565b6132389084615c75565b92506001607f1b6132498383615ce8565b6132539190615cb2565b905061326181611ab8615ce8565b61326b9084615c75565b92506001607f1b61327c8383615ce8565b6132869190615cb2565b90506132948161017c615ce8565b61329e9084615c75565b92506001607f1b6132af8383615ce8565b6132b99190615cb2565b90506132c6816014615ce8565b6132d09084615c75565b92506001607f1b6132e18383615ce8565b6132eb9190615cb2565b90506132f8816001615ce8565b6133029084615c75565b92506001607f1b8261331c6721c3677c82b4000086615cb2565b6133269190615c75565b6133309190615c75565b92506001607c1b8516156133785770018ebef9eac820ae8682b9793ac6d1e77661336b847001c3d6a24ed82218787d624d3e5eba95f9615ce8565b6133759190615cb2565b92505b6001607d1b8516156133be577001368b2fc6f9609fe7aceb46aa619baed46133b18470018ebef9eac820ae8682b9793ac6d1e778615ce8565b6133bb9190615cb2565b92505b6001607e1b851615613403576fbc5ab1b16779be3575bd8f0520a9f21f6133f6847001368b2fc6f9609fe7aceb46aa619baed5615ce8565b6134009190615cb2565b92505b6001607f1b851615613447576f454aaa8efe072e7f6ddbab84b40a55c961343a846fbc5ab1b16779be3575bd8f0520a9f21e615ce8565b6134449190615cb2565b92505b600160801b85161561348b576f0960aadc109e7a3bf4578099615711ea61347e846f454aaa8efe072e7f6ddbab84b40a55c5615ce8565b6134889190615cb2565b92505b600160811b8516156134ce576e2bf84208204f5977f9a8cf01fdce3d6134c1846f0960aadc109e7a3bf4578099615711d7615ce8565b6134cb9190615cb2565b92505b600160821b85161561350f576d03c6ab775dd0b95b4cbee7e65d11613502846e2bf84208204f5977f9a8cf01fdc307615ce8565b61350c9190615cb2565b92505b50909392505050565b60006020607f5b60ff811661352e836001615c8d565b60ff16101561358f57600060026135458385615c8d565b61354f9190615cc6565b90508460008260ff166080811061357657634e487b7160e01b600052603260045260246000fd5b01541061358557809250613589565b8091505b5061351f565b8360008260ff16608081106135b457634e487b7160e01b600052603260045260246000fd5b0154106135c45791506106049050565b8360008360ff16608081106135e957634e487b7160e01b600052603260045260246000fd5b01541061020657509050610604565b6000828160ff841661360a8380615ce8565b901c9150613628826f03442c4e6074a82f1797f72ac0000000615ce8565b6136329082615c75565b905060ff84166136428684615ce8565b901c9150613660826f0116b96f757c380fb287fd0e40000000615ce8565b61366a9082615c75565b905060ff841661367a8684615ce8565b901c9150613697826e45ae5bdd5f0e03eca1ff4390000000615ce8565b6136a19082615c75565b905060ff84166136b18684615ce8565b901c91506136ce826e0defabf91302cd95b9ffda50000000615ce8565b6136d89082615c75565b905060ff84166136e88684615ce8565b901c9150613705826e02529ca9832b22439efff9b8000000615ce8565b61370f9082615c75565b905060ff841661371f8684615ce8565b901c915061373b826d54f1cf12bd04e516b6da88000000615ce8565b6137459082615c75565b905060ff84166137558684615ce8565b901c9150613771826d0a9e39e257a09ca2d6db51000000615ce8565b61377b9082615c75565b905060ff841661378b8684615ce8565b901c91506137a7826d012e066e7b839fa050c309000000615ce8565b6137b19082615c75565b905060ff84166137c18684615ce8565b901c91506137dc826c1e33d7d926c329a1ad1a800000615ce8565b6137e69082615c75565b905060ff84166137f68684615ce8565b901c9150613811826c02bee513bdb4a6b19b5f800000615ce8565b61381b9082615c75565b905060ff841661382b8684615ce8565b901c9150613845826b3a9316fa79b88eccf2a00000615ce8565b61384f9082615c75565b905060ff841661385f8684615ce8565b901c9150613879826b048177ebe1fa812375200000615ce8565b6138839082615c75565b905060ff84166138938684615ce8565b901c91506138ac826a5263fe90242dcbacf00000615ce8565b6138b69082615c75565b905060ff84166138c68684615ce8565b901c91506138df826a057e22099c030d94100000615ce8565b6138e99082615c75565b905060ff84166138f98684615ce8565b901c9150613911826957e22099c030d9410000615ce8565b61391b9082615c75565b905060ff841661392b8684615ce8565b901c91506139438269052b6b54569976310000615ce8565b61394d9082615c75565b905060ff841661395d8684615ce8565b901c915061397482684985f67696bf748000615ce8565b61397e9082615c75565b905060ff841661398e8684615ce8565b901c91506139a5826803dea12ea99e498000615ce8565b6139af9082615c75565b905060ff84166139bf8684615ce8565b901c91506139d5826731880f2214b6e000615ce8565b6139df9082615c75565b905060ff84166139ef8684615ce8565b901c9150613a058267025bcff56eb36000615ce8565b613a0f9082615c75565b905060ff8416613a1f8684615ce8565b901c9150613a3482661b722e10ab1000615ce8565b613a3e9082615c75565b905060ff8416613a4e8684615ce8565b901c9150613a63826601317c70077000615ce8565b613a6d9082615c75565b905060ff8416613a7d8684615ce8565b901c9150613a9182650cba84aafa00615ce8565b613a9b9082615c75565b905060ff8416613aab8684615ce8565b901c9150613abe826482573a0a00615ce8565b613ac89082615c75565b905060ff8416613ad88684615ce8565b901c9150613aeb826405035ad900615ce8565b613af59082615c75565b905060ff8416613b058684615ce8565b901c9150613b1782632f881b00615ce8565b613b219082615c75565b905060ff8416613b318684615ce8565b901c9150613b43826301b29340615ce8565b613b4d9082615c75565b905060ff8416613b5d8684615ce8565b901c9150613b6e82620efc40615ce8565b613b789082615c75565b905060ff8416613b888684615ce8565b901c9150613b9882617fe0615ce8565b613ba29082615c75565b905060ff8416613bb28684615ce8565b901c9150613bc282610420615ce8565b613bcc9082615c75565b905060ff8416613bdc8684615ce8565b901c9150613beb826021615ce8565b613bf59082615c75565b905060ff8416613c058684615ce8565b901c9150613c14826001615ce8565b613c1e9082615c75565b9050600160ff85161b85613c426f0688589cc0e9505e2f2fee558000000084615cb2565b613c4c9190615c75565b610d5f9190615c75565b6000808211613c775760405162461bcd60e51b81526004016105be90615b07565b81613c81336109c3565b1015613c9f5760405162461bcd60e51b81526004016105be906159da565b6000613caa83610c29565b9050613cb63384613e9a565b61018654613cc49082613f8e565b610186556040517f42cdee5ad59c78ee53adb50e8d3f4b66918ce660505ab55abb44035e4c79ad1d90613cfc90339086908590615690565b60405180910390a192915050565b6000808211613d2b5760405162461bcd60e51b81526004016105be9061580d565b6000613d36836105e6565b9050613d423382613f9a565b61018654613d509084612840565b610186556040517fa9b5c37908cbe11fc228c10af0ce98bf944b069510207388ac875a3d2a314bbe90613cfc90339086908590615690565b60006f2f16ac6c59de6f8d5d6f63c1482a7c868211613db157613daa82614068565b9050610604565b81613dc06001607f1b80615ce8565b6106019190615cb2565b60006f2f16ac6c59de6f8d5d6f63c1482a7c868211613dec57613daa826148fb565b7001af16ac6c59de6f8d5d6f63c1482a7c808211613e0d57613daa8261519e565b706b22d43e72c326539cceeef8bb48f255ff821161020657613daa826152df565b600080610100831015613e61575b6001831115613e5c57600192831c92613e559082615c8d565b9050613e3c565b610601565b60805b60ff811615613e9357600160ff82161b8410613e885760ff81169390931c92908117905b60011c607f16613e64565b5092915050565b6001600160a01b038216613ec05760405162461bcd60e51b81526004016105be90615a11565b613ecc826000836109be565b6001600160a01b0382166000908152610180602052604090205481811015613f065760405162461bcd60e51b81526004016105be90615752565b6001600160a01b03831660009081526101806020526040812083830390556101828054849290613f37908490615d33565b90915550506040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613f7a908690615c28565b60405180910390a36109be836000846109be565b60006128398284615d33565b6001600160a01b038216613fc05760405162461bcd60e51b81526004016105be90615bf1565b613fcc600083836109be565b806101826000828254613fdf9190615c75565b90915550506001600160a01b038216600090815261018060205260408120805483929061400d908490615c75565b90915550506040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90614050908590615c28565b60405180910390a3614064600083836109be565b5050565b600081816001607f1b61407b8380615ce8565b6140859190615cb2565b91506140a28270014d29a73a6e7b02c3668c7b0880000000615ce8565b6140ac9082615c75565b90506001607f1b6140bd8584615ce8565b6140c79190615cb2565b91506140e4827002504a0cd9a7f7215b60f9be4800000000615ce8565b6140ee9082615c75565b90506001607f1b6140ff8584615ce8565b6141099190615cb2565b915061412682700484d0a1191c0ead267967c7a4a0000000615ce8565b6141309082615c75565b90506001607f1b6141418584615ce8565b61414b9190615cb2565b91506141688270095ec580d7e8427a4baf26a90a00000000615ce8565b6141729082615c75565b90506001607f1b6141838584615ce8565b61418d9190615cb2565b91506141aa82701440b0be1615a47dba6e5b3b1f10000000615ce8565b6141b49082615c75565b90506001607f1b6141c58584615ce8565b6141cf9190615cb2565b91506141ec82702d207601f46a99b4112418400000000000615ce8565b6141f69082615c75565b90506001607f1b6142078584615ce8565b6142119190615cb2565b915061422e827066ebaac4c37c622dd8288a7eb1b2000000615ce8565b6142389082615c75565b90506001607f1b6142498584615ce8565b6142539190615cb2565b91506142708270ef17240135f7dbd43a1ba10cf200000000615ce8565b61427a9082615c75565b90506001607f1b61428b8584615ce8565b6142959190615cb2565b91506142b382710233c33c676a5eb2416094a87b3657000000615ce8565b6142bd9082615c75565b90506001607f1b6142ce8584615ce8565b6142d89190615cb2565b91506142f682710541cde48bc0254bed49a9f8700000000000615ce8565b6143009082615c75565b90506001607f1b6143118584615ce8565b61431b9190615cb2565b915061433982710cae1fad2cdd4d4cb8d73abca0d19a400000615ce8565b6143439082615c75565b90506001607f1b6143548584615ce8565b61435e9190615cb2565b915061437c82711edb2aa2f760d15c41ceedba956400000000615ce8565b6143869082615c75565b90506001607f1b6143978584615ce8565b6143a19190615cb2565b91506143bf82714ba8d20d2dabd386c9529659841a2e200000615ce8565b6143c99082615c75565b90506001607f1b6143da8584615ce8565b6143e49190615cb2565b91506143fc826805d6042a35c33e6d51604d1b615ce8565b6144069082615c75565b90506001607f1b6144178584615ce8565b6144219190615cb2565b9150614440827201cfa8e70c03625b9db76c8ebf5bbf24820000615ce8565b61444a9082615c75565b90506001607f1b61445b8584615ce8565b6144659190615cb2565b9150614484827204851d99f82060df265f3309b26f8200000000615ce8565b61448e9082615c75565b90506001607f1b61449f8584615ce8565b6144a99190615cb2565b91506144c882720b550d19b129d270c44f6f55f027723cbb0000615ce8565b6144d29082615c75565b90506001607f1b6144e38584615ce8565b6144ed9190615cb2565b915061450c82721c877dadc761dc272deb65d4b0000000000000615ce8565b6145169082615c75565b90506001607f1b6145278584615ce8565b6145319190615cb2565b9150614550827248178ece97479f33a77f2ad22a81b64406c000615ce8565b61455a9082615c75565b90506001607f1b61456b8584615ce8565b6145759190615cb2565b91506145948272b6ca8268b9d810fedf6695ef2f8a6c00000000615ce8565b61459e9082615c75565b90506001607f1b6145af8584615ce8565b6145b99190615cb2565b91506145d9827301d0e76631a5b05d007b8cb72a7c7f11ec36e000615ce8565b6145e39082615c75565b90506001607f1b6145f48584615ce8565b6145fe9190615cb2565b91506146178269094386f7b3f0bfb38d8f604f1b615ce8565b6146219082615c75565b90506001607f1b6146328584615ce8565b61463c9190615cb2565b915061465c82730bd8369f1b702bf491e2ebfcee08250313b65400615ce8565b6146669082615c75565b90506001607f1b6146778584615ce8565b6146819190615cb2565b91506146a182731e5c7c32a9f6c70ab2cb59d9225764d400000000615ce8565b6146ab9082615c75565b90506001607f1b6146bc8584615ce8565b6146c69190615cb2565b91506146e682734dff5820e165e910f95120a708e742496221e600615ce8565b6146f09082615c75565b90506001607f1b6147018584615ce8565b61470b9190615cb2565b9150614727826c064647b36d8fe769bc7728729b603d1b615ce8565b6147319082615c75565b90506001607f1b6147428584615ce8565b61474c9190615cb2565b915061476d82740205db8dffff45bfa2938f128f599dbf16eb11d880615ce8565b6147779082615c75565b90506001607f1b6147888584615ce8565b6147929190615cb2565b91506147b38274053a044ebd984351493e1786af38d39a0800000000615ce8565b6147bd9082615c75565b90506001607f1b6147ce8584615ce8565b6147d89190615cb2565b91506147f982740d86dae2a4cc0f47633a544479735869b487b59c40615ce8565b6148039082615c75565b90506001607f1b6148148584615ce8565b61481e9190615cb2565b915061482f82610231609c1b615ce8565b6148399082615c75565b90506001607f1b61484a8584615ce8565b6148549190615cb2565b915061487582745b0485a76f6646c2039db1507cdd51b08649680822615ce8565b61487f9082615c75565b90506001607f1b6148908584615ce8565b61489a9190615cb2565b91506148bb8274ec983c46c49545bc17efa6b5b0055e242200000000615ce8565b6148c59082615c75565b90506001607f1b846148e76fde1bc4d19efcac82445da75b0000000084615cb2565b6148f19190615c75565b6107189190615c75565b6000818161490d826001607f1b615d33565b614927906fde1bc4d19efcac82445da75b00000000615ce8565b90506001607f1b6149388584615ce8565b6149429190615cb2565b915061495f8270014d29a73a6e7b02c3668c7b0880000000615ce8565b6149699082615c75565b90506001607f1b61497a8584615ce8565b6149849190615cb2565b91506149a1827002504a0cd9a7f7215b60f9be4800000000615ce8565b6149ab9082615d33565b90506001607f1b6149bc8584615ce8565b6149c69190615cb2565b91506149e382700484d0a1191c0ead267967c7a4a0000000615ce8565b6149ed9082615c75565b90506001607f1b6149fe8584615ce8565b614a089190615cb2565b9150614a258270095ec580d7e8427a4baf26a90a00000000615ce8565b614a2f9082615d33565b90506001607f1b614a408584615ce8565b614a4a9190615cb2565b9150614a6782701440b0be1615a47dba6e5b3b1f10000000615ce8565b614a719082615c75565b90506001607f1b614a828584615ce8565b614a8c9190615cb2565b9150614aa982702d207601f46a99b4112418400000000000615ce8565b614ab39082615d33565b90506001607f1b614ac48584615ce8565b614ace9190615cb2565b9150614aeb827066ebaac4c37c622dd8288a7eb1b2000000615ce8565b614af59082615c75565b90506001607f1b614b068584615ce8565b614b109190615cb2565b9150614b2d8270ef17240135f7dbd43a1ba10cf200000000615ce8565b614b379082615d33565b90506001607f1b614b488584615ce8565b614b529190615cb2565b9150614b7082710233c33c676a5eb2416094a87b3657000000615ce8565b614b7a9082615c75565b90506001607f1b614b8b8584615ce8565b614b959190615cb2565b9150614bb382710541cde48bc0254bed49a9f8700000000000615ce8565b614bbd9082615d33565b90506001607f1b614bce8584615ce8565b614bd89190615cb2565b9150614bf682710cae1fad2cdd4d4cb8d73abca0d19a400000615ce8565b614c009082615c75565b90506001607f1b614c118584615ce8565b614c1b9190615cb2565b9150614c3982711edb2aa2f760d15c41ceedba956400000000615ce8565b614c439082615d33565b90506001607f1b614c548584615ce8565b614c5e9190615cb2565b9150614c7c82714ba8d20d2dabd386c9529659841a2e200000615ce8565b614c869082615c75565b90506001607f1b614c978584615ce8565b614ca19190615cb2565b9150614cb9826805d6042a35c33e6d51604d1b615ce8565b614cc39082615d33565b90506001607f1b614cd48584615ce8565b614cde9190615cb2565b9150614cfd827201cfa8e70c03625b9db76c8ebf5bbf24820000615ce8565b614d079082615c75565b90506001607f1b614d188584615ce8565b614d229190615cb2565b9150614d41827204851d99f82060df265f3309b26f8200000000615ce8565b614d4b9082615d33565b90506001607f1b614d5c8584615ce8565b614d669190615cb2565b9150614d8582720b550d19b129d270c44f6f55f027723cbb0000615ce8565b614d8f9082615c75565b90506001607f1b614da08584615ce8565b614daa9190615cb2565b9150614dc982721c877dadc761dc272deb65d4b0000000000000615ce8565b614dd39082615d33565b90506001607f1b614de48584615ce8565b614dee9190615cb2565b9150614e0d827248178ece97479f33a77f2ad22a81b64406c000615ce8565b614e179082615c75565b90506001607f1b614e288584615ce8565b614e329190615cb2565b9150614e518272b6ca8268b9d810fedf6695ef2f8a6c00000000615ce8565b614e5b9082615d33565b90506001607f1b614e6c8584615ce8565b614e769190615cb2565b9150614e96827301d0e76631a5b05d007b8cb72a7c7f11ec36e000615ce8565b614ea09082615c75565b90506001607f1b614eb18584615ce8565b614ebb9190615cb2565b9150614ed48269094386f7b3f0bfb38d8f604f1b615ce8565b614ede9082615d33565b90506001607f1b614eef8584615ce8565b614ef99190615cb2565b9150614f1982730bd8369f1b702bf491e2ebfcee08250313b65400615ce8565b614f239082615c75565b90506001607f1b614f348584615ce8565b614f3e9190615cb2565b9150614f5e82731e5c7c32a9f6c70ab2cb59d9225764d400000000615ce8565b614f689082615d33565b90506001607f1b614f798584615ce8565b614f839190615cb2565b9150614fa382734dff5820e165e910f95120a708e742496221e600615ce8565b614fad9082615c75565b90506001607f1b614fbe8584615ce8565b614fc89190615cb2565b9150614fe4826c064647b36d8fe769bc7728729b603d1b615ce8565b614fee9082615d33565b90506001607f1b614fff8584615ce8565b6150099190615cb2565b915061502a82740205db8dffff45bfa2938f128f599dbf16eb11d880615ce8565b6150349082615c75565b90506001607f1b6150458584615ce8565b61504f9190615cb2565b91506150708274053a044ebd984351493e1786af38d39a0800000000615ce8565b61507a9082615d33565b90506001607f1b61508b8584615ce8565b6150959190615cb2565b91506150b682740d86dae2a4cc0f47633a544479735869b487b59c40615ce8565b6150c09082615c75565b90506001607f1b6150d18584615ce8565b6150db9190615cb2565b91506150ec82610231609c1b615ce8565b6150f69082615d33565b90506001607f1b6151078584615ce8565b6151119190615cb2565b915061513282745b0485a76f6646c2039db1507cdd51b08649680822615ce8565b61513c9082615c75565b90506001607f1b61514d8584615ce8565b6151579190615cb2565b91506151788274ec983c46c49545bc17efa6b5b0055e242200000000615ce8565b6151829082615d33565b90506107186fde1bc4d19efcac82445da75b0000000082615cb2565b60008060016151bd6f2f16ac6c59de6f8d5d6f63c1482a7c8685615d33565b6151c79190615d33565b905060006151e56f03060c183060c183060c183060c1830683615cb2565b90506000615203826f03060c183060c183060c183060c18306615ce8565b90506000615212836001615c75565b61522c906f03060c183060c183060c183060c18306615ce8565b905060006080846080811061525157634e487b7160e01b600052603260045260246000fd5b0154905060006080615264866001615c75565b6080811061528257634e487b7160e01b600052603260045260246000fd5b015490506f03060c183060c183060c183060c183066152a18588615d33565b6152ab9083615ce8565b6152b58886615d33565b6152bf9085615ce8565b6152c99190615c75565b6152d39190615cb2565b98975050505050505050565b60008070015bf0a8b1457695355fb8ac404e7a79e383106153085761530383612e04565b615311565b6153118361288b565b9050600070015bf0a8b1457695355fb8ac404e7a79e3821061533b5761533682612e04565b615344565b6153448261288b565b9050836001607f1b836153578285615ce8565b6153619190615cb2565b61536b8486615d33565b6153759190615c75565b61537f9190615ce8565b6107189190615cb2565b80356001600160a01b038116811461060457600080fd5b803563ffffffff8116811461060457600080fd5b6000602082840312156153c5578081fd5b61283982615389565b600080604083850312156153e0578081fd5b6153e983615389565b91506153f760208401615389565b90509250929050565b600080600060608486031215615414578081fd5b61541d84615389565b925061542b60208501615389565b9150604084013590509250925092565b6000806040838503121561544d578182fd5b61545683615389565b946020939093013593505050565b600060208284031215615475578081fd5b815161283981615e05565b600060208284031215615491578081fd5b5035919050565b6000602082840312156154a9578081fd5b5051919050565b600080604083850312156154c2578182fd5b50508035926020909101359150565b600080600080600060a086880312156154e8578081fd5b85359450602086013593506040860135925060608601359150608086013561550f81615e05565b809150509295509295909350565b600080600080600060a08688031215615534578081fd5b505083359560208501359550604085013594606081013594506080013592509050565b6000806000806080858703121561556c578384fd5b8435935060208501359250615583604086016153a0565b9396929550929360600135925050565b600080600080608085870312156155a8578384fd5b84359350602085013592506155bf604086016153a0565b91506155cd606086016153a0565b905092959194509250565b600080600080600060a086880312156155ef578081fd5b853594506155ff602087016153a0565b935060408601359250615614606087016153a0565b949793965091946080013592915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b901515815260200190565b6000602080835283518082850152825b818110156156e8578581018301518582016040015282016156cc565b818111156156f95783604083870101525b50601f01601f1916929092016040019392505050565b60208082526023908201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526022908201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604082015261636560f01b606082015260800190565b6020808252601d908201527f4661696c656420746f207472616e736665722044616920746f6b656e73000000604082015260600190565b60208082526022908201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604082015261737360f01b606082015260800190565b60208082526019908201527f4465706f736974206d757374206265206e6f6e2d7a65726f2e00000000000000604082015260600190565b60208082526026908201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604082015265616c616e636560d01b606082015260800190565b6020808252601b908201527f4552525f494e56414c49445f524553455256455f42414c414e43450000000000604082015260600190565b6020808252601f908201527f4d75737420617070726f76652044414920746f2062757920746f6b656e732e00604082015260600190565b6020808252601290820152714552525f494e56414c49445f535550504c5960701b604082015260600190565b60208082526019908201527f4552525f494e56414c49445f524553455256455f524154494f00000000000000604082015260600190565b60208082526028908201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616040820152676c6c6f77616e636560c01b606082015260800190565b60208082526018908201527f4d75737420617070726f766520656e6f756768204441492e0000000000000000604082015260600190565b6020808252601c908201527f496e73756666696369656e7420746f6b656e7320746f206275726e2e00000000604082015260600190565b60208082526021908201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736040820152607360f81b606082015260800190565b60208082526025908201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604082015264647265737360d81b606082015260800190565b60208082526012908201527111549497d253959053125117d05353d5539560721b604082015260600190565b60208082526024908201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60208082526018908201527f416d6f756e74206d757374206265206e6f6e2d7a65726f2e0000000000000000604082015260600190565b6020808252601a908201527f4552525f494e56414c49445f524553455256455f574549474854000000000000604082015260600190565b60208082526018908201527f4552525f494e56414c49445f524553455256455f524154450000000000000000604082015260600190565b60208082526025908201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604082015264207a65726f60d81b606082015260800190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b90815260200190565b918252602082015260400190565b91825260ff16602082015260400190565b63ffffffff92831681529116602082015260400190565b60ff91909116815260200190565b60008219821115615c8857615c88615dd9565b500190565b600060ff821660ff84168060ff03821115615caa57615caa615dd9565b019392505050565b600082615cc157615cc1615def565b500490565b600060ff831680615cd957615cd9615def565b8060ff84160491505092915050565b6000816000190483118215151615615d0257615d02615dd9565b500290565b600063ffffffff80831681851681830481118215151615615d2a57615d2a615dd9565b02949350505050565b600082821015615d4557615d45615dd9565b500390565b600060ff821660ff841680821015615d6457615d64615dd9565b90039392505050565b600060ff821680615d8057615d80615dd9565b6000190192915050565b600281046001821680615d9e57607f821691505b60208210811415615dbf57634e487b7160e01b600052602260045260246000fd5b50919050565b600082615dd457615dd4615def565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b8015158114615e1357600080fd5b5056fea2646970667358221220ef5825b993891458b48a0f8873f3a2659e644e8dd9ceae4df4d96b2d60fe043b64736f6c634300080000330000000000000000000000000000000000000000000000000000000000000014000000000000000000000000e91286d05c1c93d300abf9f4ebdb8e25749209d6
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106102065760003560e01c806394491fab1161011a578063a67453b0116100ad578063e1c7392a1161007c578063e1c7392a14610443578063ebbb21581461044b578063ee1ea4ff1461045e578063f3250fe214610473578063f51e181a1461048657610206565b8063a67453b0146103f4578063a9059cbb14610415578063aa248a4614610428578063dd62ed3e1461043057610206565b8063a11aa1b4116100e9578063a11aa1b4146103b3578063a179dd93146103c6578063a3882291146103ce578063a457c2d7146103e157610206565b806394491fab1461037d57806395d89b4114610390578063a0712d6814610398578063a10954fe146103ab57610206565b8063313ce5671161019d57806370a082311161016c57806370a082311461031e57806376c2d5101461033157806376cf0b56146103445780638074590a1461035757806390f0c2ea1461036a57610206565b8063313ce567146102c057806332833d51146102d557806339509351146102f657806342966c681461030957610206565b806323b872dd116101d957806323b872dd1461026657806328c3d701146102795780632f55bdb51461028c57806330c7d6371461029f57610206565b806306fdde031461020b578063095ea7b3146102295780630c7d5cd81461024957806318160ddd1461025e575b600080fd5b61021361048e565b60405161022091906156bc565b60405180910390f35b61023c61023736600461543b565b610521565b60405161022091906156b1565b61025161053e565b6040516102209190615c28565b610251610545565b61023c610274366004615400565b61054c565b610251610287366004615480565b6105e6565b61025161029a366004615557565b610609565b6102b26102ad3660046154b0565b610720565b604051610220929190615c50565b6102c86107e6565b6040516102209190615c67565b6102e86102e3366004615593565b6107eb565b604051610220929190615c3f565b61023c61030436600461543b565b6108d8565b61031c610317366004615480565b61092d565b005b61025161032c3660046153b4565b6109c3565b6102b261033f3660046154b0565b6109df565b610251610352366004615557565b610a15565b610251610365366004615557565b610b45565b610251610378366004615480565b610c29565b61025161038b3660046155d8565b610c44565b610213610d68565b6102516103a6366004615480565b610d78565b610251610f0b565b6102b26103c136600461551d565b610f12565b61031c61101f565b6102b26103dc3660046154d1565b611a26565b61023c6103ef36600461543b565b611aee565b6104076104023660046154b0565b611b68565b604051610220929190615c31565b61023c61042336600461543b565b611c28565b61031c611c3c565b61025161043e3660046153ce565b612412565b61031c61243e565b610251610459366004615557565b612450565b61046661257e565b6040516102209190615625565b610251610481366004615557565b61258e565b610251612641565b6060610183805461049e90615d8a565b80601f01602080910402602001604051908101604052809291908181526020018280546104ca90615d8a565b80156105175780601f106104ec57610100808354040283529160200191610517565b820191906000526020600020905b8154815290600101906020018083116104fa57829003601f168201915b5050505050905090565b600061053561052e612648565b848461264c565b50600192915050565b6101875481565b6101825490565b6000610559848484612701565b6001600160a01b0384166000908152610181602052604081208161057b612648565b6001600160a01b03166001600160a01b03168152602001908152602001600020549050828110156105c75760405162461bcd60e51b81526004016105be9061595b565b60405180910390fd5b6105db856105d3612648565b85840361264c565b506001949350505050565b60006106016105f3610545565b61018654610187548561258e565b90505b919050565b600080851161062a5760405162461bcd60e51b81526004016105be906158f8565b6000841161064a5760405162461bcd60e51b81526004016105be9061588a565b60018363ffffffff161180156106795750610669620f42406002615d07565b63ffffffff168363ffffffff1611155b6106955760405162461bcd60e51b81526004016105be90615924565b816106a257506000610718565b63ffffffff8316620f424014156106cf57836106be838761282d565b6106c89190615cb2565b9050610718565b600080806106dd8786612840565b90506106ee818888620f42406107eb565b9093509150600060ff83166107038a8661282d565b901c90506107118982615d33565b9450505050505b949350505050565b6000807d10c6f7a0b5ed8d36b4c7f34938583621fafc8b0079a2834d26fa3fcc9ea98411156107a55760006107747d10c6f7a0b5ed8d36b4c7f34938583621fafc8b0079a2834d26fa3fcc9ea96001615c75565b61077e9086615cb2565b610789906001615c75565b90506107958186615cb2565b94506107a18185615cb2565b9350505b60006107c66107b7620f424087615ce8565b6107c18787612840565b61284c565b905060006107d782620f4240615d33565b919350909150505b9250929050565b601290565b600080600160811b86106107fe57600080fd5b600080866108106001607f1b8a615ce8565b61081a9190615cb2565b905070015bf0a8b1457695355fb8ac404e7a79e38110156108455761083e8161288b565b9150610851565b61084e81612e04565b91505b60008563ffffffff168763ffffffff168461086c9190615ce8565b6108769190615cb2565b9050600160831b81101561089b5761088d81612eed565b607f945094505050506108cf565b60006108a682613518565b90506108c26108b682607f615d4a565b60ff1683901c826135f8565b955093506108cf92505050565b94509492505050565b60006105356108e5612648565b848461018160006108f4612648565b6001600160a01b03908116825260208083019390935260409182016000908120918b16815292529020546109289190615c75565b61264c565b600061093882613c56565b6101885460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb9061096c9033908590600401615677565b602060405180830381600087803b15801561098657600080fd5b505af115801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be9190615464565b505050565b6001600160a01b03166000908152610180602052604090205490565b6000808284116109fc576109f38484610720565b915091506107df565b600080610a098587610720565b97909650945050505050565b6000808511610a365760405162461bcd60e51b81526004016105be906158f8565b60008411610a565760405162461bcd60e51b81526004016105be9061588a565b60008363ffffffff16118015610a755750620f424063ffffffff841611155b610a915760405162461bcd60e51b81526004016105be90615b3e565b84821115610ab15760405162461bcd60e51b81526004016105be90615a97565b81610abe57506000610718565b84821415610acd575082610718565b63ffffffff8316620f42401415610ae957846106be858461282d565b60008080610af78589615d33565b9050610b088882620f4240896107eb565b90935091506000610b19888561282d565b905060ff831688901b84610b2d8284615d33565b610b379190615cb2565b9a9950505050505050505050565b6000808511610b665760405162461bcd60e51b81526004016105be906158f8565b60008411610b865760405162461bcd60e51b81526004016105be9061588a565b60018363ffffffff16118015610bb55750610ba5620f42406002615d07565b63ffffffff168363ffffffff1611155b610bd15760405162461bcd60e51b81526004016105be90615924565b84821115610bf15760405162461bcd60e51b81526004016105be90615a97565b81610bfe57506000610718565b84821415610c0d575082610718565b63ffffffff8316620f42401415610ae957846106be838661282d565b6000610601610c36610545565b610186546101875485610a15565b60008086118015610c555750600084115b610c715760405162461bcd60e51b81526004016105be9061588a565b60008563ffffffff16118015610c905750620f424063ffffffff861611155b8015610ca2575060008363ffffffff16115b8015610cb75750620f424063ffffffff841611155b610cd35760405162461bcd60e51b81526004016105be90615b3e565b8263ffffffff168563ffffffff161415610d0c57610cf18683612840565b610cfb858461282d565b610d059190615cb2565b9050610d5f565b60008080610d1a8986612840565b9050610d28818a8a896107eb565b90935091506000610d39888561282d565b905060ff831688901b84610d4d8284615d33565b610d579190615cb2565b955050505050505b95945050505050565b6060610184805461049e90615d8a565b61018854604051636eb1769f60e11b815260009182916001600160a01b039091169063dd62ed3e90610db09033903090600401615639565b60206040518083038186803b158015610dc857600080fd5b505afa158015610ddc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e009190615498565b905060008111610e225760405162461bcd60e51b81526004016105be906158c1565b82811015610e425760405162461bcd60e51b81526004016105be906159a3565b610188546040516323b872dd60e01b81526000916001600160a01b0316906323b872dd90610e7890339030908790600401615653565b602060405180830381600087803b158015610e9257600080fd5b505af1158015610ea6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eca9190615464565b90508015610ee457610edb82613d0a565b92505050610604565b60008211610f045760405162461bcd60e51b81526004016105be90615794565b5050919050565b6101865481565b60008085871415610f4d576000871180610f2c5750600085115b610f485760405162461bcd60e51b81526004016105be9061588a565b610f85565b600087118015610f5d5750600086115b8015610f695750600085115b610f855760405162461bcd60e51b81526004016105be9061588a565b600084118015610f955750600083115b610fb15760405162461bcd60e51b81526004016105be90615b75565b6000610fbd888661282d565b90506000610fcb878661282d565b905087891015610fee57610fe3888a84846001611a26565b935093505050611015565b8789111561100457610fe3898984846000611a26565b61100e82826109df565b9350935050505b9550959350505050565b6f60e393c68d20b1bd09deaabc0373b9c560809081556f5f8f46e4854120989ed94719fb4c20116081556f5e479ebb9129fb1b7e72a648f992b6066082556f5d0bd23fe42dfedde2e9586be12b85fe6083556f5bdb29ddee979308ddfca81aeeb8095a6084556f5ab4fd8a260d2c7e2c0d2afcf0009dad6085556f5998b31359a55d48724c65cf090012216086556f5885bcad2b322dfc43e8860f9c018cf56087556f577b97aa1fe222bb452fdf111b1f0be26088556f5679cb5e3575632e5baa27e2b949f7046089556f557fe8241b3a31c83c732f1cdff4a1c5608a556f548d868026504875d6e59bbe95fc2a6b608b556f53a2465ce347cf34d05a867c17dd3088608c556f52bdce5dcd4faed59c7f5511cf8f8acc608d556f51dfcb453c07f8da817606e7885f7c3e608e556f5107ef6b0a5a2be8f8ff15590daa3cce608f556f5035f241d6eae0cd7bacba119993de7b6090556f4f698fe90d5b53d532171e1210164c666091556f4ea288ca297a0e6a09a0eee240e16c856092556f4de0a13fdcf5d4213fc398ba6e3becde6093556f4d23a145eef91fec06b06140804c48086094556f4c6b5430d4c1ee5526473db4ae0f11de6095556f4bb7886c240562eba11f4963a53b42406096556f4b080f3f1cb491d2d521e0ea4583521e6097556f4a5cbc96a05589cb4d86be1db31683646098556f49b566d40243517658d78c33162d6ece6099556f4911e6a02e5507a30f947383fd9a3276609a556f487216c2b31be4adc41db8a8d5cc0c88609b556f47d5d3fc4a7a1b188cd3d788b5c5e9fc609c556f473cfce4871a2c40bc4f9e1c32b955d0609d556f46a771ca578ab878485810e285e31c67609e556f4615149718aed4c258c373dc676aa72d609f556f4585c8b3f8fe489c6e1833ca4787138460a0556f44f972f174e41e5efb7e9d63c29ce73560a1556f446ff970ba86d8b00beb05ecebf3c4dc60a2556f43e9438ec88971812d6f198b5ccaad9660a3556f436539d11ff7bea657aeddb394e809ef60a4556f42e3c5d3e5a913401d86f66db5d81c2c60a5556f4264d2395303070ea726cbe98df6217460a6556f41e84a9a593bb7194c3a6349ecae4eea60a7556f416e1b785d13eba07a08f3f18876a5ab60a8556f40f6322ff389d423ba9dd7e7e7b7e80960a9556f40807cec8a466880ecf4184545d240a460aa556f400cea9ce88a8d3ae668e8ea0d9bf07f60ab556f3f9b6ae8772d4c55091e0ed7dfea0ac160ac556f3f2bee253fd84594f54bcaafac383a1360ad556f3ebe654e95208bb9210c575c081c595860ae556f3e52c1fc5665635b78ce1f05ad53c08660af556f3de8f65ac388101ddf718a6f5c1eff6560b0556f3d80f522d59bd0b328ca012df4cd2d4960b1556f3d1ab193129ea72b23648a161163a85a60b2556f3cb61f68d32576c135b95cfb53f76d7560b3556f3c5332d9f1aae851a3619e77e4cc847360b4556f3bf1e08edbe2aa109e1525f65759ef7360b5556f3b921d9cff13fa2c197746a3dfc4918f60b6556f3b33df818910bfc1a5aefb8f63ae2ac460b7556f3ad71c1c77e34fa32a9f184967eccbf660b8556f3a7bc9abf2c5bb53e2f7384a8a16521a60b9556f3a21dec7e76369783a68a0c6385a1c5760ba556f39c9525de6c9cdf7c1c157ca4a7a6ee360bb556f39721bad3dc85d1240ff0190e0adaac360bc556f391c324344d3248f0469eb28dd3d77e060bd556f38c78df7e3c796279fb4ff84394ab3da60be556f387426ea4638ae9aae08049d3554c20a60bf556f3821f57dbd2763256c1a99bbd205137860c0556f37d0f256cb46a8c92ff62fbbef28969860c1556f37811658591ffc7abdd1feaf3cef9b7360c2556f37325aa10e9e82f7df0f380f7997154b60c3556f36e4b888cfb408d873b9a80d439311c660c4556f3698299e59f4bb9de645fc9b08c64cca60c5556f364ca7a5012cb603023b57dd3ebfd50d60c6556f36022c928915b778ab1b06aaee7e61d460c7556f35b8b28d1a73dc27500ffe35559cc02860c8556f357033e951fe250ec5eb4e60955132d760c9556f3528ab2867934e3a21b5412e4c4f888160ca556f34e212f66c55057f9676c80094a61d5960cb556f349c66289e5b3c4b540c24f42fa4b9bb60cc556f34579fbbd0c733a9c8d6af6b0f7d00f760cd556f3413bad2e712288b924b5882b5b369bf60ce556f33d0b2b56286510ef730e213f71f12e960cf556f338e82ce00e2496262c64457535ba1a160d0556f334d26a96b373bb7c2f8ea1827f27a9260d1556f330c99f4f4211469e00b3e18c31475ea60d2556f32ccd87d6486094999c7d5e6f33237d860d3556f328dde2dd617b6665a2e8556f250c1af60d4556f324fa70e9adc270f8262755af5a99af960d5556f32122f443110611ca51040f41fa6e1e360d6556f31d5730e42c0831482f0f1485c4263d860d7556f31996ec6b07b4a83421b5ebc4ab4e1f160d8556f315e1ee0a68ff46bb43ec2b85032e87660d9556f31237fe7bc4deacf6775b9efa1a145f860da556f30e98e7f1cc5a356e44627a6972ea2ff60db556f30b04760b8917ec74205a3002650ec0560dc556f3077a75c803468e9132ce0cf3224241d60dd556f303fab57a6a275c36f19cda9bace667a60de556f3008504beb8dcbd2cf3bc1f6d5a064f060df556f2fd19346ed17dac61219ce0c2c5ac4b060e0556f2f9b7169808c324b5852fd3d54ba971460e1556f2f65e7e711cf4b064eea9c08cbdad57460e2556f2f30f405093042ddff8a251b6bf6d10360e3556f2efc931a3750f2e8bfe323edfe03757460e4556f2ec8c28e46dbe56d98685278339400cb60e5556f2e957fd933c3926d8a599b602379b85160e6556f2e62c882c7c9ed4473412702f08ba0e560e7556f2e309a221c12ba361e3ed695167feee260e8556f2dfef25d1f865ae18dd07cfea4bcea1060e9556f2dcdcee821cdc80decc02c44344aeb3160ea556f2d9d2d8562b34944d0b201bb87260c8360eb556f2d6d0c04a5b62a2c42636308669b729a60ec556f2d3d6842c9a235517fc5a0332691528f60ed556f2d0e402963fe1ea2834abc408c437c1060ee556f2cdf91ae602647908aff975e4d6a2a8c60ef556f2cb15ad3a1eb65f6d74a75da09a1b6c560f0556f2c8399a6ab8e9774d6fcff373d21072760f1556f2c564c4046f64edba6883ca06bbc453560f2556f2c2970c431f952641e05cb493e23eed360f3556f2bfd0560cd9eb14563bc7c0732856c1860f4556f2bd1084ed0332f7ff4150f9d0ef41a2c60f5556f2ba577d0fa1628b76d040b12a82492fb60f6556f2b7a5233cd21581e855e89dc2f1e8a9260f7556f2b4f95cd46904d05d72bdcde337d9cc760f8556f2b2540fc9b4d9abba3faca669191467560f9556f2afb5229f68d0830d8be8adb0a0db70f60fa556f2ad1c7c63a9b294c5bc73a3ba3ab7a2b60fb556f2aa8a04ac3cbe1ee1c9c86361465dbb860fc556f2a7fda392d725a44a2c8aeb9ab35430d60fd556f2a57741b18cde618717792b4faa216db60fe556f2a2f6c81f5d84dd950a35626d6d5503a90607f5b0155565b600080611a338585611b68565b9095509350600086611a49896001607f1b61282d565b611a539190615cb2565b9050600070015bf0a8b1457695355fb8ac404e7a79e38210611a7d57611a7882612e04565b611a86565b611a868261288b565b9050600086611a95838a61282d565b611a9f9190615cb2565b9050600086611ab657611ab182613d88565b611abf565b611abf82613dca565b9050611adc611ace828b61282d565b61033f8a6001607f1b61282d565b95509550505050509550959350505050565b6000806101816000611afe612648565b6001600160a01b0390811682526020808301939093526040918201600090812091881681529252902054905082811015611b4a5760405162461bcd60e51b81526004016105be90615bac565b611b5e611b55612648565b8585840361264c565b5060019392505050565b600080600160801b8411158015611b835750600160801b8311155b15611b925750829050816107df565b600160801b841015611bc55782611bad600160801b86615ce8565b611bb79190615cb2565b600160801b915091506107df565b600160801b831015611beb57600160801b84611be18286615ce8565b6109f39190615cb2565b6000838511611bfa5783611bfc565b845b90506000611c16611c116001607f1b84615cb2565b613e2e565b60ff1695861c969490951c9450505050565b6000610535611c35612648565b8484612701565b701c35fedd14ffffffffffffffffffffffff602055701b0ce43b323fffffffffffffffffffffff6021557019f0028ec1ffffffffffffffffffffffff6022557018ded91f0e7fffffffffffffffffffffff6023557017d8ec7f0417ffffffffffffffffffffff6024557016ddc6556cdbffffffffffffffffffffff6025557015ecf52776a1ffffffffffffffffffffff6026557015060c256cb2ffffffffffffffffffffff602755701428a2f98d72ffffffffffffffffffffff6028557013545598e5c23fffffffffffffffffffff602955701288c4161ce1dfffffffffffffffffffff602a557011c592761c666fffffffffffffffffffff602b5570110a688680a757ffffffffffffffffffff602c55701056f1b5bedf77ffffffffffffffffffff602d55700faadceceeff8bffffffffffffffffffff602e55700f05dc6b27edadffffffffffffffffffff602f55700e67a5a25da4107fffffffffffffffffff603055700dcff115b14eedffffffffffffffffffff603155700d3e7a392431239fffffffffffffffffff603255700cb2ff529eb71e4fffffffffffffffffff603355700c2d415c3db974afffffffffffffffffff603455700bad03e7d883f69bffffffffffffffffff603555700b320d03b2c343d5ffffffffffffffffff603655700abc25204e02828dffffffffffffffffff603755700a4b16f74ee4bb207fffffffffffffffff6038557009deaf736ac1f569ffffffffffffffffff603955700976bd9952c7aa957fffffffffffffffff603a557009131271922eaa606fffffffffffffffff603b557008b380f3558668c46fffffffffffffffff603c55700857ddf0117efa215bffffffffffffffff603d557007ffffffffffffffffffffffffffffffff603e557007abbf6f6abb9d087fffffffffffffffff603f5570075af62cbac95f7dfa7fffffffffffffff60405570070d7fb7452e187ac13fffffffffffffff6041557006c3390ecc8af379295fffffffffffffff60425570067c00a3b07ffc01fd6fffffffffffffff604355700637b647c39cbb9d3d27ffffffffffffff6044557005f63b1fc104dbd39587ffffffffffffff6045557005b771955b36e12f7235ffffffffffffff60465570057b3d49dda84556d6f6ffffffffffffff60475570054183095b2c8ececf30ffffffffffffff60485570050a28be635ca2b888f77fffffffffffff6049557004d5156639708c9db33c3fffffffffffff604a557004a23105873875bd52dfdfffffffffffff604b55700471649d87199aa990756fffffffffffff604c557004429a21a029d4c1457cfbffffffffffff604d55700415bc6d6fb7dd71af2cb3ffffffffffff604e557003eab73b3bbfe282243ce1ffffffffffff604f557003c1771ac9fb6b4c18e229ffffffffffff605055700399e96897690418f785257fffffffffff605155700373fc456c53bb779bf0ea9fffffffffff60525570034f9e8e490c48e67e6ab8bfffffffffff60535570032cbfd4a7adc790560b3337ffffffffff60545570030b50570f6e5d2acca94613ffffffffff6055557002eb40f9f620fda6b56c2861ffffffffff6056557002cc8340ecb0d0f520a6af58ffffffffff6057557002af09481380a0a35cf1ba02ffffffffff605855700292c5bdd3b92ec810287b1b3fffffffff605955700277abdcdab07d5a77ac6d6b9fffffffff605a5570025daf6654b1eaa55fd64df5efffffffff605b55700244c49c648baa98192dce88b7ffffffff605c5570022ce03cd5619a311b2471268bffffffff605d55700215f77c045fbe885654a44a0fffffffff605e557001ffffffffffffffffffffffffffffffff605f557001eaefdbdaaee7421fc4d3ede5ffffffff6060557001d6bd8b2eb257df7e8ca57b09bfffffff6061557001c35fedd14b861eb0443f7f133fffffff6062557001b0ce43b322bcde4a56e8ada5afffffff60635570019f0028ec1fff007f5a195a39dfffffff60645570018ded91f0e72ee74f49b15ba527ffffff60655570017d8ec7f04136f4e5615fd41a63ffffff60665570016ddc6556cdb84bdc8d12d22e6fffffff60675570015ecf52776a1155b5bd8395814f7fffff60685570015060c256cb23b3b3cc3754cf40ffffff6069557001428a2f98d728ae223ddab715be3fffff606a5570013545598e5c23276ccf0ede68034fffff606b557001288c4161ce1d6f54b7f61081194fffff606c5570011c592761c666aa641d5a01a40f17ffff606d55700110a688680a7530515f3e6e6cfdcdffff606e557001056f1b5bedf75c6bcb2ce8aed428ffff606f556ffaadceceeff8a0890f3875f008277fff6070556ff05dc6b27edad306388a600f6ba0bfff6071556fe67a5a25da41063de1495d5b18cdbfff6072556fdcff115b14eedde6fc3aa5353f2e4fff6073556fd3e7a3924312399f9aae2e0f868f8fff6074556fcb2ff529eb71e41582cccd5a1ee26fff6075556fc2d415c3db974ab32a51840c0b67edff6076556fbad03e7d883f69ad5b0a186184e06bff6077556fb320d03b2c343d4829abd6075f0cc5ff6078556fabc25204e02828d73c6e80bcdb1a95bf6079556fa4b16f74ee4bb2040a1ec6c15fbbf2df607a556f9deaf736ac1f569deb1b5ae3f36c130f607b556f976bd9952c7aa957f5937d790ef65037607c556f9131271922eaa6064b73a22d0bd4f2bf607d556f8b380f3558668c46c91c49a2f8e967b9607e556f857ddf0117efa215952912839f6473e66000607f611a22565b6001600160a01b0391821660009081526101816020908152604080832093909416825291909152205490565b612446611c3c565b61244e61101f565b565b60008085116124715760405162461bcd60e51b81526004016105be906158f8565b600084116124915760405162461bcd60e51b81526004016105be9061588a565b60018363ffffffff161180156124c057506124b0620f42406002615d07565b63ffffffff168363ffffffff1611155b6124dc5760405162461bcd60e51b81526004016105be90615924565b816124e957506000610718565b63ffffffff8316620f4240141561252657846001612507848761282d565b6125119190615d33565b61251b9190615cb2565b6106c8906001615c75565b600080806125348886612840565b90506125458189620f4240896107eb565b9093509150600060ff8316600161255c8a8761282d565b6125669190615d33565b612572911c6001615c75565b90506107118882615d33565b610188546001600160a01b031681565b60008085116125af5760405162461bcd60e51b81526004016105be906158f8565b600084116125cf5760405162461bcd60e51b81526004016105be9061588a565b60008363ffffffff161180156125ee5750620f424063ffffffff841611155b61260a5760405162461bcd60e51b81526004016105be90615b3e565b8161261757506000610718565b63ffffffff8316620f4240141561263357836106be868461282d565b600080806106dd8588612840565b6101855481565b3390565b6001600160a01b0383166126725760405162461bcd60e51b81526004016105be90615ac3565b6001600160a01b0382166126985760405162461bcd60e51b81526004016105be906157cb565b6001600160a01b038084166000818152610181602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906126f4908590615c28565b60405180910390a3505050565b6001600160a01b0383166127275760405162461bcd60e51b81526004016105be90615a52565b6001600160a01b03821661274d5760405162461bcd60e51b81526004016105be9061570f565b6127588383836109be565b6001600160a01b03831660009081526101806020526040902054818110156127925760405162461bcd60e51b81526004016105be90615844565b6001600160a01b03808516600090815261018060205260408082208585039055918516815290812080548492906127ca908490615c75565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516128149190615c28565b60405180910390a36128278484846109be565b50505050565b60006128398284615ce8565b9392505050565b60006128398284615c75565b6000612859600283615cb2565b6128639083615d33565b61286d8385615dc5565b6128779190615cb2565b6128818385615cb2565b6128399190615c75565b6000808080806fd3094c70f034de4b96ff7d5b6f99fcd886106128e4576128b66001607e1b85615c75565b93506fd3094c70f034de4b96ff7d5b6f99fcd86128d76001607f1b88615ce8565b6128e19190615cb2565b95505b6fa45af1e1f40c333b3de1db4dd55f29a78610612937576129096001607d1b85615c75565b93506fa45af1e1f40c333b3de1db4dd55f29a761292a6001607f1b88615ce8565b6129349190615cb2565b95505b6f910b022db7ae67ce76b441c27035c6a1861061298a5761295c6001607c1b85615c75565b93506f910b022db7ae67ce76b441c27035c6a161297d6001607f1b88615ce8565b6129879190615cb2565b95505b6f88415abbe9a76bead8d00cf112e4d4a886106129dd576129af6001607b1b85615c75565b93506f88415abbe9a76bead8d00cf112e4d4a86129d06001607f1b88615ce8565b6129da9190615cb2565b95505b6f84102b00893f64c705e841d5d4064bd38610612a3057612a026001607a1b85615c75565b93506f84102b00893f64c705e841d5d4064bd3612a236001607f1b88615ce8565b612a2d9190615cb2565b95505b6f8204055aaef1c8bd5c3259f4822735a28610612a8357612a55600160791b85615c75565b93506f8204055aaef1c8bd5c3259f4822735a2612a766001607f1b88615ce8565b612a809190615cb2565b95505b6f810100ab00222d861931c15e39b44e998610612ad657612aa8600160781b85615c75565b93506f810100ab00222d861931c15e39b44e99612ac96001607f1b88615ce8565b612ad39190615cb2565b95505b6f808040155aabbbe9451521693554f7338610612b2957612afb600160771b85615c75565b93506f808040155aabbbe9451521693554f733612b1c6001607f1b88615ce8565b612b269190615cb2565b95505b612b376001607f1b87615d33565b92508291506001607f1b612b4b8380615ce8565b612b559190615cb2565b9050600160801b612b668482615d33565b612b709084615ce8565b612b7a9190615cb2565b612b849085615c75565b93506001607f1b612b958284615ce8565b612b9f9190615cb2565b9150600160811b612bc0846faaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa615d33565b612bca9084615ce8565b612bd49190615cb2565b612bde9085615c75565b93506001607f1b612bef8284615ce8565b612bf99190615cb2565b9150600360801b612c1a846f99999999999999999999999999999999615d33565b612c249084615ce8565b612c2e9190615cb2565b612c389085615c75565b93506001607f1b612c498284615ce8565b612c539190615cb2565b9150600160821b612c74846f92492492492492492492492492492492615d33565b612c7e9084615ce8565b612c889190615cb2565b612c929085615c75565b93506001607f1b612ca38284615ce8565b612cad9190615cb2565b9150600560801b612cce846f8e38e38e38e38e38e38e38e38e38e38e615d33565b612cd89084615ce8565b612ce29190615cb2565b612cec9085615c75565b93506001607f1b612cfd8284615ce8565b612d079190615cb2565b9150600360811b612d28846f8ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8b615d33565b612d329084615ce8565b612d3c9190615cb2565b612d469085615c75565b93506001607f1b612d578284615ce8565b612d619190615cb2565b9150600760801b612d82846f89d89d89d89d89d89d89d89d89d89d89615d33565b612d8c9084615ce8565b612d969190615cb2565b612da09085615c75565b93506001607f1b612db18284615ce8565b612dbb9190615cb2565b9150600160831b612ddc846f88888888888888888888888888888888615d33565b612de69084615ce8565b612df09190615cb2565b612dfa9085615c75565b9695505050505050565b600080600160801b8310612e43576000612e25611c116001607f1b86615cb2565b60ff811694851c94909150612e3f906001607f1b90615ce8565b9150505b6001607f1b831115612eb857607f5b60ff811615612eb6576001607f1b612e6a8580615ce8565b612e749190615cb2565b9350600160801b8410612ea657600193841c93612e919082615d4a565b60ff166001901b82612ea39190615c75565b91505b612eaf81615d6d565b9050612e52565b505b6f05b9de1d10bf4103d647b0955897ba80612ee36f03f80fe03f80fe03f80fe03f80fe03f883615ce8565b6128399190615cb2565b6000808080612f006001607c1b86615dc5565b91508190506001607f1b612f148280615ce8565b612f1e9190615cb2565b9050612f32816710e1b3be415a0000615ce8565b612f3c9084615c75565b92506001607f1b612f4d8383615ce8565b612f579190615cb2565b9050612f6b816705a0913f6b1e0000615ce8565b612f759084615c75565b92506001607f1b612f868383615ce8565b612f909190615cb2565b9050612fa481670168244fdac78000615ce8565b612fae9084615c75565b92506001607f1b612fbf8383615ce8565b612fc99190615cb2565b9050612fdc81664807432bc18000615ce8565b612fe69084615c75565b92506001607f1b612ff78383615ce8565b6130019190615cb2565b905061301481660c0135dca04000615ce8565b61301e9084615c75565b92506001607f1b61302f8383615ce8565b6130399190615cb2565b905061304c816601b707b1cdc000615ce8565b6130569084615c75565b92506001607f1b6130678383615ce8565b6130719190615cb2565b9050613083816536e0f639b800615ce8565b61308d9084615c75565b92506001607f1b61309e8383615ce8565b6130a89190615cb2565b90506130ba81650618fee9f800615ce8565b6130c49084615c75565b92506001607f1b6130d58383615ce8565b6130df9190615cb2565b90506130f081649c197dcc00615ce8565b6130fa9084615c75565b92506001607f1b61310b8383615ce8565b6131159190615cb2565b905061312681640e30dce400615ce8565b6131309084615c75565b92506001607f1b6131418383615ce8565b61314b9190615cb2565b905061315c8164012ebd1300615ce8565b6131669084615c75565b92506001607f1b6131778383615ce8565b6131819190615cb2565b9050613191816317499f00615ce8565b61319b9084615c75565b92506001607f1b6131ac8383615ce8565b6131b69190615cb2565b90506131c6816301a9d480615ce8565b6131d09084615c75565b92506001607f1b6131e18383615ce8565b6131eb9190615cb2565b90506131fa81621c6380615ce8565b6132049084615c75565b92506001607f1b6132158383615ce8565b61321f9190615cb2565b905061322e816201c638615ce8565b6132389084615c75565b92506001607f1b6132498383615ce8565b6132539190615cb2565b905061326181611ab8615ce8565b61326b9084615c75565b92506001607f1b61327c8383615ce8565b6132869190615cb2565b90506132948161017c615ce8565b61329e9084615c75565b92506001607f1b6132af8383615ce8565b6132b99190615cb2565b90506132c6816014615ce8565b6132d09084615c75565b92506001607f1b6132e18383615ce8565b6132eb9190615cb2565b90506132f8816001615ce8565b6133029084615c75565b92506001607f1b8261331c6721c3677c82b4000086615cb2565b6133269190615c75565b6133309190615c75565b92506001607c1b8516156133785770018ebef9eac820ae8682b9793ac6d1e77661336b847001c3d6a24ed82218787d624d3e5eba95f9615ce8565b6133759190615cb2565b92505b6001607d1b8516156133be577001368b2fc6f9609fe7aceb46aa619baed46133b18470018ebef9eac820ae8682b9793ac6d1e778615ce8565b6133bb9190615cb2565b92505b6001607e1b851615613403576fbc5ab1b16779be3575bd8f0520a9f21f6133f6847001368b2fc6f9609fe7aceb46aa619baed5615ce8565b6134009190615cb2565b92505b6001607f1b851615613447576f454aaa8efe072e7f6ddbab84b40a55c961343a846fbc5ab1b16779be3575bd8f0520a9f21e615ce8565b6134449190615cb2565b92505b600160801b85161561348b576f0960aadc109e7a3bf4578099615711ea61347e846f454aaa8efe072e7f6ddbab84b40a55c5615ce8565b6134889190615cb2565b92505b600160811b8516156134ce576e2bf84208204f5977f9a8cf01fdce3d6134c1846f0960aadc109e7a3bf4578099615711d7615ce8565b6134cb9190615cb2565b92505b600160821b85161561350f576d03c6ab775dd0b95b4cbee7e65d11613502846e2bf84208204f5977f9a8cf01fdc307615ce8565b61350c9190615cb2565b92505b50909392505050565b60006020607f5b60ff811661352e836001615c8d565b60ff16101561358f57600060026135458385615c8d565b61354f9190615cc6565b90508460008260ff166080811061357657634e487b7160e01b600052603260045260246000fd5b01541061358557809250613589565b8091505b5061351f565b8360008260ff16608081106135b457634e487b7160e01b600052603260045260246000fd5b0154106135c45791506106049050565b8360008360ff16608081106135e957634e487b7160e01b600052603260045260246000fd5b01541061020657509050610604565b6000828160ff841661360a8380615ce8565b901c9150613628826f03442c4e6074a82f1797f72ac0000000615ce8565b6136329082615c75565b905060ff84166136428684615ce8565b901c9150613660826f0116b96f757c380fb287fd0e40000000615ce8565b61366a9082615c75565b905060ff841661367a8684615ce8565b901c9150613697826e45ae5bdd5f0e03eca1ff4390000000615ce8565b6136a19082615c75565b905060ff84166136b18684615ce8565b901c91506136ce826e0defabf91302cd95b9ffda50000000615ce8565b6136d89082615c75565b905060ff84166136e88684615ce8565b901c9150613705826e02529ca9832b22439efff9b8000000615ce8565b61370f9082615c75565b905060ff841661371f8684615ce8565b901c915061373b826d54f1cf12bd04e516b6da88000000615ce8565b6137459082615c75565b905060ff84166137558684615ce8565b901c9150613771826d0a9e39e257a09ca2d6db51000000615ce8565b61377b9082615c75565b905060ff841661378b8684615ce8565b901c91506137a7826d012e066e7b839fa050c309000000615ce8565b6137b19082615c75565b905060ff84166137c18684615ce8565b901c91506137dc826c1e33d7d926c329a1ad1a800000615ce8565b6137e69082615c75565b905060ff84166137f68684615ce8565b901c9150613811826c02bee513bdb4a6b19b5f800000615ce8565b61381b9082615c75565b905060ff841661382b8684615ce8565b901c9150613845826b3a9316fa79b88eccf2a00000615ce8565b61384f9082615c75565b905060ff841661385f8684615ce8565b901c9150613879826b048177ebe1fa812375200000615ce8565b6138839082615c75565b905060ff84166138938684615ce8565b901c91506138ac826a5263fe90242dcbacf00000615ce8565b6138b69082615c75565b905060ff84166138c68684615ce8565b901c91506138df826a057e22099c030d94100000615ce8565b6138e99082615c75565b905060ff84166138f98684615ce8565b901c9150613911826957e22099c030d9410000615ce8565b61391b9082615c75565b905060ff841661392b8684615ce8565b901c91506139438269052b6b54569976310000615ce8565b61394d9082615c75565b905060ff841661395d8684615ce8565b901c915061397482684985f67696bf748000615ce8565b61397e9082615c75565b905060ff841661398e8684615ce8565b901c91506139a5826803dea12ea99e498000615ce8565b6139af9082615c75565b905060ff84166139bf8684615ce8565b901c91506139d5826731880f2214b6e000615ce8565b6139df9082615c75565b905060ff84166139ef8684615ce8565b901c9150613a058267025bcff56eb36000615ce8565b613a0f9082615c75565b905060ff8416613a1f8684615ce8565b901c9150613a3482661b722e10ab1000615ce8565b613a3e9082615c75565b905060ff8416613a4e8684615ce8565b901c9150613a63826601317c70077000615ce8565b613a6d9082615c75565b905060ff8416613a7d8684615ce8565b901c9150613a9182650cba84aafa00615ce8565b613a9b9082615c75565b905060ff8416613aab8684615ce8565b901c9150613abe826482573a0a00615ce8565b613ac89082615c75565b905060ff8416613ad88684615ce8565b901c9150613aeb826405035ad900615ce8565b613af59082615c75565b905060ff8416613b058684615ce8565b901c9150613b1782632f881b00615ce8565b613b219082615c75565b905060ff8416613b318684615ce8565b901c9150613b43826301b29340615ce8565b613b4d9082615c75565b905060ff8416613b5d8684615ce8565b901c9150613b6e82620efc40615ce8565b613b789082615c75565b905060ff8416613b888684615ce8565b901c9150613b9882617fe0615ce8565b613ba29082615c75565b905060ff8416613bb28684615ce8565b901c9150613bc282610420615ce8565b613bcc9082615c75565b905060ff8416613bdc8684615ce8565b901c9150613beb826021615ce8565b613bf59082615c75565b905060ff8416613c058684615ce8565b901c9150613c14826001615ce8565b613c1e9082615c75565b9050600160ff85161b85613c426f0688589cc0e9505e2f2fee558000000084615cb2565b613c4c9190615c75565b610d5f9190615c75565b6000808211613c775760405162461bcd60e51b81526004016105be90615b07565b81613c81336109c3565b1015613c9f5760405162461bcd60e51b81526004016105be906159da565b6000613caa83610c29565b9050613cb63384613e9a565b61018654613cc49082613f8e565b610186556040517f42cdee5ad59c78ee53adb50e8d3f4b66918ce660505ab55abb44035e4c79ad1d90613cfc90339086908590615690565b60405180910390a192915050565b6000808211613d2b5760405162461bcd60e51b81526004016105be9061580d565b6000613d36836105e6565b9050613d423382613f9a565b61018654613d509084612840565b610186556040517fa9b5c37908cbe11fc228c10af0ce98bf944b069510207388ac875a3d2a314bbe90613cfc90339086908590615690565b60006f2f16ac6c59de6f8d5d6f63c1482a7c868211613db157613daa82614068565b9050610604565b81613dc06001607f1b80615ce8565b6106019190615cb2565b60006f2f16ac6c59de6f8d5d6f63c1482a7c868211613dec57613daa826148fb565b7001af16ac6c59de6f8d5d6f63c1482a7c808211613e0d57613daa8261519e565b706b22d43e72c326539cceeef8bb48f255ff821161020657613daa826152df565b600080610100831015613e61575b6001831115613e5c57600192831c92613e559082615c8d565b9050613e3c565b610601565b60805b60ff811615613e9357600160ff82161b8410613e885760ff81169390931c92908117905b60011c607f16613e64565b5092915050565b6001600160a01b038216613ec05760405162461bcd60e51b81526004016105be90615a11565b613ecc826000836109be565b6001600160a01b0382166000908152610180602052604090205481811015613f065760405162461bcd60e51b81526004016105be90615752565b6001600160a01b03831660009081526101806020526040812083830390556101828054849290613f37908490615d33565b90915550506040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613f7a908690615c28565b60405180910390a36109be836000846109be565b60006128398284615d33565b6001600160a01b038216613fc05760405162461bcd60e51b81526004016105be90615bf1565b613fcc600083836109be565b806101826000828254613fdf9190615c75565b90915550506001600160a01b038216600090815261018060205260408120805483929061400d908490615c75565b90915550506040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90614050908590615c28565b60405180910390a3614064600083836109be565b5050565b600081816001607f1b61407b8380615ce8565b6140859190615cb2565b91506140a28270014d29a73a6e7b02c3668c7b0880000000615ce8565b6140ac9082615c75565b90506001607f1b6140bd8584615ce8565b6140c79190615cb2565b91506140e4827002504a0cd9a7f7215b60f9be4800000000615ce8565b6140ee9082615c75565b90506001607f1b6140ff8584615ce8565b6141099190615cb2565b915061412682700484d0a1191c0ead267967c7a4a0000000615ce8565b6141309082615c75565b90506001607f1b6141418584615ce8565b61414b9190615cb2565b91506141688270095ec580d7e8427a4baf26a90a00000000615ce8565b6141729082615c75565b90506001607f1b6141838584615ce8565b61418d9190615cb2565b91506141aa82701440b0be1615a47dba6e5b3b1f10000000615ce8565b6141b49082615c75565b90506001607f1b6141c58584615ce8565b6141cf9190615cb2565b91506141ec82702d207601f46a99b4112418400000000000615ce8565b6141f69082615c75565b90506001607f1b6142078584615ce8565b6142119190615cb2565b915061422e827066ebaac4c37c622dd8288a7eb1b2000000615ce8565b6142389082615c75565b90506001607f1b6142498584615ce8565b6142539190615cb2565b91506142708270ef17240135f7dbd43a1ba10cf200000000615ce8565b61427a9082615c75565b90506001607f1b61428b8584615ce8565b6142959190615cb2565b91506142b382710233c33c676a5eb2416094a87b3657000000615ce8565b6142bd9082615c75565b90506001607f1b6142ce8584615ce8565b6142d89190615cb2565b91506142f682710541cde48bc0254bed49a9f8700000000000615ce8565b6143009082615c75565b90506001607f1b6143118584615ce8565b61431b9190615cb2565b915061433982710cae1fad2cdd4d4cb8d73abca0d19a400000615ce8565b6143439082615c75565b90506001607f1b6143548584615ce8565b61435e9190615cb2565b915061437c82711edb2aa2f760d15c41ceedba956400000000615ce8565b6143869082615c75565b90506001607f1b6143978584615ce8565b6143a19190615cb2565b91506143bf82714ba8d20d2dabd386c9529659841a2e200000615ce8565b6143c99082615c75565b90506001607f1b6143da8584615ce8565b6143e49190615cb2565b91506143fc826805d6042a35c33e6d51604d1b615ce8565b6144069082615c75565b90506001607f1b6144178584615ce8565b6144219190615cb2565b9150614440827201cfa8e70c03625b9db76c8ebf5bbf24820000615ce8565b61444a9082615c75565b90506001607f1b61445b8584615ce8565b6144659190615cb2565b9150614484827204851d99f82060df265f3309b26f8200000000615ce8565b61448e9082615c75565b90506001607f1b61449f8584615ce8565b6144a99190615cb2565b91506144c882720b550d19b129d270c44f6f55f027723cbb0000615ce8565b6144d29082615c75565b90506001607f1b6144e38584615ce8565b6144ed9190615cb2565b915061450c82721c877dadc761dc272deb65d4b0000000000000615ce8565b6145169082615c75565b90506001607f1b6145278584615ce8565b6145319190615cb2565b9150614550827248178ece97479f33a77f2ad22a81b64406c000615ce8565b61455a9082615c75565b90506001607f1b61456b8584615ce8565b6145759190615cb2565b91506145948272b6ca8268b9d810fedf6695ef2f8a6c00000000615ce8565b61459e9082615c75565b90506001607f1b6145af8584615ce8565b6145b99190615cb2565b91506145d9827301d0e76631a5b05d007b8cb72a7c7f11ec36e000615ce8565b6145e39082615c75565b90506001607f1b6145f48584615ce8565b6145fe9190615cb2565b91506146178269094386f7b3f0bfb38d8f604f1b615ce8565b6146219082615c75565b90506001607f1b6146328584615ce8565b61463c9190615cb2565b915061465c82730bd8369f1b702bf491e2ebfcee08250313b65400615ce8565b6146669082615c75565b90506001607f1b6146778584615ce8565b6146819190615cb2565b91506146a182731e5c7c32a9f6c70ab2cb59d9225764d400000000615ce8565b6146ab9082615c75565b90506001607f1b6146bc8584615ce8565b6146c69190615cb2565b91506146e682734dff5820e165e910f95120a708e742496221e600615ce8565b6146f09082615c75565b90506001607f1b6147018584615ce8565b61470b9190615cb2565b9150614727826c064647b36d8fe769bc7728729b603d1b615ce8565b6147319082615c75565b90506001607f1b6147428584615ce8565b61474c9190615cb2565b915061476d82740205db8dffff45bfa2938f128f599dbf16eb11d880615ce8565b6147779082615c75565b90506001607f1b6147888584615ce8565b6147929190615cb2565b91506147b38274053a044ebd984351493e1786af38d39a0800000000615ce8565b6147bd9082615c75565b90506001607f1b6147ce8584615ce8565b6147d89190615cb2565b91506147f982740d86dae2a4cc0f47633a544479735869b487b59c40615ce8565b6148039082615c75565b90506001607f1b6148148584615ce8565b61481e9190615cb2565b915061482f82610231609c1b615ce8565b6148399082615c75565b90506001607f1b61484a8584615ce8565b6148549190615cb2565b915061487582745b0485a76f6646c2039db1507cdd51b08649680822615ce8565b61487f9082615c75565b90506001607f1b6148908584615ce8565b61489a9190615cb2565b91506148bb8274ec983c46c49545bc17efa6b5b0055e242200000000615ce8565b6148c59082615c75565b90506001607f1b846148e76fde1bc4d19efcac82445da75b0000000084615cb2565b6148f19190615c75565b6107189190615c75565b6000818161490d826001607f1b615d33565b614927906fde1bc4d19efcac82445da75b00000000615ce8565b90506001607f1b6149388584615ce8565b6149429190615cb2565b915061495f8270014d29a73a6e7b02c3668c7b0880000000615ce8565b6149699082615c75565b90506001607f1b61497a8584615ce8565b6149849190615cb2565b91506149a1827002504a0cd9a7f7215b60f9be4800000000615ce8565b6149ab9082615d33565b90506001607f1b6149bc8584615ce8565b6149c69190615cb2565b91506149e382700484d0a1191c0ead267967c7a4a0000000615ce8565b6149ed9082615c75565b90506001607f1b6149fe8584615ce8565b614a089190615cb2565b9150614a258270095ec580d7e8427a4baf26a90a00000000615ce8565b614a2f9082615d33565b90506001607f1b614a408584615ce8565b614a4a9190615cb2565b9150614a6782701440b0be1615a47dba6e5b3b1f10000000615ce8565b614a719082615c75565b90506001607f1b614a828584615ce8565b614a8c9190615cb2565b9150614aa982702d207601f46a99b4112418400000000000615ce8565b614ab39082615d33565b90506001607f1b614ac48584615ce8565b614ace9190615cb2565b9150614aeb827066ebaac4c37c622dd8288a7eb1b2000000615ce8565b614af59082615c75565b90506001607f1b614b068584615ce8565b614b109190615cb2565b9150614b2d8270ef17240135f7dbd43a1ba10cf200000000615ce8565b614b379082615d33565b90506001607f1b614b488584615ce8565b614b529190615cb2565b9150614b7082710233c33c676a5eb2416094a87b3657000000615ce8565b614b7a9082615c75565b90506001607f1b614b8b8584615ce8565b614b959190615cb2565b9150614bb382710541cde48bc0254bed49a9f8700000000000615ce8565b614bbd9082615d33565b90506001607f1b614bce8584615ce8565b614bd89190615cb2565b9150614bf682710cae1fad2cdd4d4cb8d73abca0d19a400000615ce8565b614c009082615c75565b90506001607f1b614c118584615ce8565b614c1b9190615cb2565b9150614c3982711edb2aa2f760d15c41ceedba956400000000615ce8565b614c439082615d33565b90506001607f1b614c548584615ce8565b614c5e9190615cb2565b9150614c7c82714ba8d20d2dabd386c9529659841a2e200000615ce8565b614c869082615c75565b90506001607f1b614c978584615ce8565b614ca19190615cb2565b9150614cb9826805d6042a35c33e6d51604d1b615ce8565b614cc39082615d33565b90506001607f1b614cd48584615ce8565b614cde9190615cb2565b9150614cfd827201cfa8e70c03625b9db76c8ebf5bbf24820000615ce8565b614d079082615c75565b90506001607f1b614d188584615ce8565b614d229190615cb2565b9150614d41827204851d99f82060df265f3309b26f8200000000615ce8565b614d4b9082615d33565b90506001607f1b614d5c8584615ce8565b614d669190615cb2565b9150614d8582720b550d19b129d270c44f6f55f027723cbb0000615ce8565b614d8f9082615c75565b90506001607f1b614da08584615ce8565b614daa9190615cb2565b9150614dc982721c877dadc761dc272deb65d4b0000000000000615ce8565b614dd39082615d33565b90506001607f1b614de48584615ce8565b614dee9190615cb2565b9150614e0d827248178ece97479f33a77f2ad22a81b64406c000615ce8565b614e179082615c75565b90506001607f1b614e288584615ce8565b614e329190615cb2565b9150614e518272b6ca8268b9d810fedf6695ef2f8a6c00000000615ce8565b614e5b9082615d33565b90506001607f1b614e6c8584615ce8565b614e769190615cb2565b9150614e96827301d0e76631a5b05d007b8cb72a7c7f11ec36e000615ce8565b614ea09082615c75565b90506001607f1b614eb18584615ce8565b614ebb9190615cb2565b9150614ed48269094386f7b3f0bfb38d8f604f1b615ce8565b614ede9082615d33565b90506001607f1b614eef8584615ce8565b614ef99190615cb2565b9150614f1982730bd8369f1b702bf491e2ebfcee08250313b65400615ce8565b614f239082615c75565b90506001607f1b614f348584615ce8565b614f3e9190615cb2565b9150614f5e82731e5c7c32a9f6c70ab2cb59d9225764d400000000615ce8565b614f689082615d33565b90506001607f1b614f798584615ce8565b614f839190615cb2565b9150614fa382734dff5820e165e910f95120a708e742496221e600615ce8565b614fad9082615c75565b90506001607f1b614fbe8584615ce8565b614fc89190615cb2565b9150614fe4826c064647b36d8fe769bc7728729b603d1b615ce8565b614fee9082615d33565b90506001607f1b614fff8584615ce8565b6150099190615cb2565b915061502a82740205db8dffff45bfa2938f128f599dbf16eb11d880615ce8565b6150349082615c75565b90506001607f1b6150458584615ce8565b61504f9190615cb2565b91506150708274053a044ebd984351493e1786af38d39a0800000000615ce8565b61507a9082615d33565b90506001607f1b61508b8584615ce8565b6150959190615cb2565b91506150b682740d86dae2a4cc0f47633a544479735869b487b59c40615ce8565b6150c09082615c75565b90506001607f1b6150d18584615ce8565b6150db9190615cb2565b91506150ec82610231609c1b615ce8565b6150f69082615d33565b90506001607f1b6151078584615ce8565b6151119190615cb2565b915061513282745b0485a76f6646c2039db1507cdd51b08649680822615ce8565b61513c9082615c75565b90506001607f1b61514d8584615ce8565b6151579190615cb2565b91506151788274ec983c46c49545bc17efa6b5b0055e242200000000615ce8565b6151829082615d33565b90506107186fde1bc4d19efcac82445da75b0000000082615cb2565b60008060016151bd6f2f16ac6c59de6f8d5d6f63c1482a7c8685615d33565b6151c79190615d33565b905060006151e56f03060c183060c183060c183060c1830683615cb2565b90506000615203826f03060c183060c183060c183060c18306615ce8565b90506000615212836001615c75565b61522c906f03060c183060c183060c183060c18306615ce8565b905060006080846080811061525157634e487b7160e01b600052603260045260246000fd5b0154905060006080615264866001615c75565b6080811061528257634e487b7160e01b600052603260045260246000fd5b015490506f03060c183060c183060c183060c183066152a18588615d33565b6152ab9083615ce8565b6152b58886615d33565b6152bf9085615ce8565b6152c99190615c75565b6152d39190615cb2565b98975050505050505050565b60008070015bf0a8b1457695355fb8ac404e7a79e383106153085761530383612e04565b615311565b6153118361288b565b9050600070015bf0a8b1457695355fb8ac404e7a79e3821061533b5761533682612e04565b615344565b6153448261288b565b9050836001607f1b836153578285615ce8565b6153619190615cb2565b61536b8486615d33565b6153759190615c75565b61537f9190615ce8565b6107189190615cb2565b80356001600160a01b038116811461060457600080fd5b803563ffffffff8116811461060457600080fd5b6000602082840312156153c5578081fd5b61283982615389565b600080604083850312156153e0578081fd5b6153e983615389565b91506153f760208401615389565b90509250929050565b600080600060608486031215615414578081fd5b61541d84615389565b925061542b60208501615389565b9150604084013590509250925092565b6000806040838503121561544d578182fd5b61545683615389565b946020939093013593505050565b600060208284031215615475578081fd5b815161283981615e05565b600060208284031215615491578081fd5b5035919050565b6000602082840312156154a9578081fd5b5051919050565b600080604083850312156154c2578182fd5b50508035926020909101359150565b600080600080600060a086880312156154e8578081fd5b85359450602086013593506040860135925060608601359150608086013561550f81615e05565b809150509295509295909350565b600080600080600060a08688031215615534578081fd5b505083359560208501359550604085013594606081013594506080013592509050565b6000806000806080858703121561556c578384fd5b8435935060208501359250615583604086016153a0565b9396929550929360600135925050565b600080600080608085870312156155a8578384fd5b84359350602085013592506155bf604086016153a0565b91506155cd606086016153a0565b905092959194509250565b600080600080600060a086880312156155ef578081fd5b853594506155ff602087016153a0565b935060408601359250615614606087016153a0565b949793965091946080013592915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b901515815260200190565b6000602080835283518082850152825b818110156156e8578581018301518582016040015282016156cc565b818111156156f95783604083870101525b50601f01601f1916929092016040019392505050565b60208082526023908201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526022908201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604082015261636560f01b606082015260800190565b6020808252601d908201527f4661696c656420746f207472616e736665722044616920746f6b656e73000000604082015260600190565b60208082526022908201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604082015261737360f01b606082015260800190565b60208082526019908201527f4465706f736974206d757374206265206e6f6e2d7a65726f2e00000000000000604082015260600190565b60208082526026908201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604082015265616c616e636560d01b606082015260800190565b6020808252601b908201527f4552525f494e56414c49445f524553455256455f42414c414e43450000000000604082015260600190565b6020808252601f908201527f4d75737420617070726f76652044414920746f2062757920746f6b656e732e00604082015260600190565b6020808252601290820152714552525f494e56414c49445f535550504c5960701b604082015260600190565b60208082526019908201527f4552525f494e56414c49445f524553455256455f524154494f00000000000000604082015260600190565b60208082526028908201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616040820152676c6c6f77616e636560c01b606082015260800190565b60208082526018908201527f4d75737420617070726f766520656e6f756768204441492e0000000000000000604082015260600190565b6020808252601c908201527f496e73756666696369656e7420746f6b656e7320746f206275726e2e00000000604082015260600190565b60208082526021908201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736040820152607360f81b606082015260800190565b60208082526025908201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604082015264647265737360d81b606082015260800190565b60208082526012908201527111549497d253959053125117d05353d5539560721b604082015260600190565b60208082526024908201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60208082526018908201527f416d6f756e74206d757374206265206e6f6e2d7a65726f2e0000000000000000604082015260600190565b6020808252601a908201527f4552525f494e56414c49445f524553455256455f574549474854000000000000604082015260600190565b60208082526018908201527f4552525f494e56414c49445f524553455256455f524154450000000000000000604082015260600190565b60208082526025908201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604082015264207a65726f60d81b606082015260800190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b90815260200190565b918252602082015260400190565b91825260ff16602082015260400190565b63ffffffff92831681529116602082015260400190565b60ff91909116815260200190565b60008219821115615c8857615c88615dd9565b500190565b600060ff821660ff84168060ff03821115615caa57615caa615dd9565b019392505050565b600082615cc157615cc1615def565b500490565b600060ff831680615cd957615cd9615def565b8060ff84160491505092915050565b6000816000190483118215151615615d0257615d02615dd9565b500290565b600063ffffffff80831681851681830481118215151615615d2a57615d2a615dd9565b02949350505050565b600082821015615d4557615d45615dd9565b500390565b600060ff821660ff841680821015615d6457615d64615dd9565b90039392505050565b600060ff821680615d8057615d80615dd9565b6000190192915050565b600281046001821680615d9e57607f821691505b60208210811415615dbf57634e487b7160e01b600052602260045260246000fd5b50919050565b600082615dd457615dd4615def565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b8015158114615e1357600080fd5b5056fea2646970667358221220ef5825b993891458b48a0f8873f3a2659e644e8dd9ceae4df4d96b2d60fe043b64736f6c63430008000033