Contract Address Details
0x206949295503c4FC5C9757099db479dD5383A5dC
- Contract Name
- MultiPools
- Creator
- 0x1e9d5f–779a29 at 0x98b21d–5b6fb4
- Balance
- 0 Doge
- Tokens
-
Fetching tokens...
- Transactions
- 26,900 Transactions
- Transfers
- 28,332 Transfers
- Gas Used
- 2,485,055,133
- Last Balance Update
- 25345155
Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
- Contract name:
- MultiPools
- Optimization enabled
- false
- Compiler version
- v0.8.16+commit.07a7930e
- EVM Version
- default
- Verified at
- 2022-08-23T04:15:00.043236Z
Contract source code
// SPDX-License-Identifier: RYOSHI pragma solidity ^0.8.0; // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with 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; } } /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } } // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } } // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount ) external returns (bool); } // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } contract MultiPools is Ownable, ReentrancyGuard, Pausable { /* ========== STATE VARIABLES ========== */ struct Pool { address stakingToken; address rewardsToken; // Duration of rewards to be paid out (in seconds) uint256 duration; // Timestamp of when the rewards finish uint256 finishAt; // Minimum of last updated time and reward finish time uint256 updatedAt; // Reward to be paid out per second uint256 rewardRate; // Sum of (reward rate * dt * 1e18 / total supply) uint256 rewardPerTokenStored; // Total staked uint256 totalSupply; } uint256 public poolCounter = 0; // Index => pool info mapping(uint256 => Pool) public pools; // User address => rewardPerTokenStored mapping(uint256 => mapping(address => uint256)) public userRewardPerTokenPaid; // User address => rewards to be claimed mapping(uint256 => mapping(address => uint256)) public rewards; // User address => staked amount mapping(uint256 => mapping(address => uint256)) public balanceOf; /* ========== VIEWS ========== */ function lastTimeRewardApplicable(uint256 _poolId) public view returns (uint256) { Pool storage pool = pools[_poolId]; return block.timestamp < pool.finishAt ? block.timestamp : pool.finishAt; } function rewardPerToken(uint256 _poolId) public view returns (uint256) { Pool storage pool = pools[_poolId]; if (pool.totalSupply == 0) { return pool.rewardPerTokenStored; } return pool.rewardPerTokenStored + (pool.rewardRate * (lastTimeRewardApplicable(_poolId) - pool.updatedAt) * 1e18) / pool.totalSupply; } function earned(uint256 _poolId, address _account) public view returns (uint256) { return ((balanceOf[_poolId][_account] * (rewardPerToken(_poolId) - userRewardPerTokenPaid[_poolId][_account])) / 1e18) + rewards[_poolId][_account]; } function getRewardForDuration(uint256 _poolId) external view returns (uint256) { Pool storage pool = pools[_poolId]; return pool.rewardRate * pool.duration; } /* ========== MUTATIVE FUNCTIONS ========== */ function createPool(address _stakingToken, address _rewardsToken) public onlyOwner { poolCounter++; Pool storage pool = pools[poolCounter]; pool.stakingToken = _stakingToken; pool.rewardsToken = _rewardsToken; emit PoolCreated(poolCounter, _stakingToken, _rewardsToken); } function stake(uint256 _poolId, uint256 _amount) external nonReentrant whenNotPaused updateReward(_poolId, msg.sender) { require(_amount > 0, "Cannot stake 0"); Pool storage pool = pools[_poolId]; pool.totalSupply = pool.totalSupply + _amount; balanceOf[_poolId][msg.sender] = balanceOf[_poolId][msg.sender] + _amount; IERC20((pool.stakingToken)).transferFrom( msg.sender, address(this), _amount ); emit Staked(_poolId, msg.sender, _amount); } function withdraw(uint256 _poolId, uint256 _amount) public nonReentrant updateReward(_poolId, msg.sender) { require(_amount > 0, "Cannot withdraw 0"); Pool storage pool = pools[_poolId]; pool.totalSupply = pool.totalSupply - _amount; balanceOf[_poolId][msg.sender] = balanceOf[_poolId][msg.sender] - _amount; IERC20(pool.stakingToken).transfer(msg.sender, _amount); emit Withdrawn(_poolId, msg.sender, _amount); } function getReward(uint256 _poolId) public nonReentrant updateReward(_poolId, msg.sender) { Pool storage pool = pools[_poolId]; uint256 reward = rewards[_poolId][msg.sender]; if (reward > 0) { rewards[_poolId][msg.sender] = 0; IERC20(pool.rewardsToken).transfer(msg.sender, reward); emit RewardPaid(_poolId, msg.sender, reward); } } function exit(uint256 _poolId) external { withdraw(_poolId, balanceOf[_poolId][msg.sender]); getReward(_poolId); } /* ========== RESTRICTED FUNCTIONS ========== */ function notifyRewardAmount(uint256 _poolId, uint256 _reward) external onlyOwner updateReward(_poolId, address(0)) { Pool storage pool = pools[_poolId]; if (block.timestamp >= pool.finishAt) { pool.rewardRate = _reward / pool.duration; } else { uint256 remaining = pool.finishAt - block.timestamp; uint256 leftover = remaining * pool.rewardRate; pool.rewardRate = (_reward + leftover) / pool.duration; } // Ensure the provided reward amount is not more than the balance in the contract. // This keeps the reward rate in the right range, preventing overflows due to // very high values of rewardRate in the earned and rewardsPerToken functions; // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow. uint256 balance = IERC20(pool.rewardsToken).balanceOf(address(this)); require( pool.rewardRate <= balance / pool.duration, "Provided reward too high" ); pool.updatedAt = block.timestamp; pool.finishAt = block.timestamp + pool.duration; emit RewardAdded(_poolId, _reward); } // Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders function recoverERC20( uint256 _poolId, address _tokenAddress, uint256 _tokenAmount ) external onlyOwner { Pool storage pool = pools[_poolId]; require( _tokenAddress != address(pool.stakingToken), "Cannot withdraw the staking token" ); IERC20(_tokenAddress).transfer(owner(), _tokenAmount); emit Recovered(_poolId, _tokenAddress, _tokenAmount); } function setRewardsDuration(uint256 _poolId, uint256 _rewardsDuration) external onlyOwner { Pool storage pool = pools[_poolId]; require( block.timestamp > pool.finishAt, "Previous rewards period must be complete before changing the duration for the new period" ); pool.duration = _rewardsDuration; emit RewardsDurationUpdated(_poolId, pool.duration); } /* ========== MODIFIERS ========== */ modifier updateReward(uint256 _poolId, address _account) { Pool storage pool = pools[_poolId]; pool.rewardPerTokenStored = rewardPerToken(_poolId); pool.updatedAt = lastTimeRewardApplicable(_poolId); if (_account != address(0)) { rewards[_poolId][_account] = earned(_poolId, _account); userRewardPerTokenPaid[_poolId][_account] = pool .rewardPerTokenStored; } _; } /* ========== EVENTS ========== */ event PoolCreated( uint256 indexed poolId, address stakingToken, address rewardsToken ); event RewardAdded(uint256 indexed poolId, uint256 reward); event Staked(uint256 indexed poolId, address indexed user, uint256 amount); event Withdrawn( uint256 indexed poolId, address indexed user, uint256 amount ); event RewardPaid( uint256 indexed poolId, address indexed user, uint256 reward ); event RewardsDurationUpdated(uint256 indexed poolId, uint256 newDuration); event Recovered(uint256 indexed poolId, address token, uint256 amount); }
Contract ABI
[{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"PoolCreated","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256","indexed":true},{"type":"address","name":"stakingToken","internalType":"address","indexed":false},{"type":"address","name":"rewardsToken","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Recovered","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256","indexed":true},{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardAdded","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256","indexed":true},{"type":"uint256","name":"reward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardPaid","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256","indexed":true},{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"reward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardsDurationUpdated","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256","indexed":true},{"type":"uint256","name":"newDuration","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Staked","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256","indexed":true},{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Withdrawn","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256","indexed":true},{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createPool","inputs":[{"type":"address","name":"_stakingToken","internalType":"address"},{"type":"address","name":"_rewardsToken","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"earned","inputs":[{"type":"uint256","name":"_poolId","internalType":"uint256"},{"type":"address","name":"_account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"exit","inputs":[{"type":"uint256","name":"_poolId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"getReward","inputs":[{"type":"uint256","name":"_poolId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRewardForDuration","inputs":[{"type":"uint256","name":"_poolId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastTimeRewardApplicable","inputs":[{"type":"uint256","name":"_poolId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"notifyRewardAmount","inputs":[{"type":"uint256","name":"_poolId","internalType":"uint256"},{"type":"uint256","name":"_reward","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"poolCounter","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"stakingToken","internalType":"address"},{"type":"address","name":"rewardsToken","internalType":"address"},{"type":"uint256","name":"duration","internalType":"uint256"},{"type":"uint256","name":"finishAt","internalType":"uint256"},{"type":"uint256","name":"updatedAt","internalType":"uint256"},{"type":"uint256","name":"rewardRate","internalType":"uint256"},{"type":"uint256","name":"rewardPerTokenStored","internalType":"uint256"},{"type":"uint256","name":"totalSupply","internalType":"uint256"}],"name":"pools","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recoverERC20","inputs":[{"type":"uint256","name":"_poolId","internalType":"uint256"},{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_tokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardPerToken","inputs":[{"type":"uint256","name":"_poolId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewards","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRewardsDuration","inputs":[{"type":"uint256","name":"_poolId","internalType":"uint256"},{"type":"uint256","name":"_rewardsDuration","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stake","inputs":[{"type":"uint256","name":"_poolId","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"userRewardPerTokenPaid","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"uint256","name":"_poolId","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]}]
Contract Creation Code
0x608060405260006003553480156200001657600080fd5b50620000376200002b6200005f60201b60201c565b6200006760201b60201c565b600180819055506000600260006101000a81548160ff0219169083151502179055506200012b565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6124db806200013b6000396000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c8063874c120b116100b8578063ac4afa381161007c578063ac4afa3814610323578063e34336151461035a578063e39c08fc14610376578063eeca1562146103a6578063f2db11af146103d6578063f2fde38b1461040657610136565b8063874c120b1461027f5780638ca43f91146102af5780638da5cb5b146102cb5780639e3079cb146102e95780639efb70371461030757610136565b8063441a3e70116100ff578063441a3e70146102035780635c975abb1461021f578063715018a61461023d5780637b0472f0146102475780637f8661a11461026357610136565b8062a47ddd1461013b5780630e213a3d1461016b5780631c4b774b1461019b578063246132f9146101b75780633656eec2146101d3575b600080fd5b61015560048036038101906101509190611afe565b610422565b6040516101629190611b4d565b60405180910390f35b61018560048036038101906101809190611b68565b610447565b6040516101929190611b4d565b60405180910390f35b6101b560048036038101906101b09190611b68565b61047b565b005b6101d160048036038101906101cc9190611b95565b610778565b005b6101ed60048036038101906101e89190611afe565b610a8e565b6040516101fa9190611b4d565b60405180910390f35b61021d60048036038101906102189190611b95565b610ab3565b005b610227610e06565b6040516102349190611bf0565b60405180910390f35b610245610e1d565b005b610261600480360381019061025c9190611b95565b610e31565b005b61027d60048036038101906102789190611b68565b61118e565b005b61029960048036038101906102949190611b68565b6111f4565b6040516102a69190611b4d565b60405180910390f35b6102c960048036038101906102c49190611c0b565b611286565b005b6102d36113fd565b6040516102e09190611c6d565b60405180910390f35b6102f1611426565b6040516102fe9190611b4d565b60405180910390f35b610321600480360381019061031c9190611b95565b61142c565b005b61033d60048036038101906103389190611b68565b6114db565b604051610351989796959493929190611c88565b60405180910390f35b610374600480360381019061036f9190611d06565b611563565b005b610390600480360381019061038b9190611afe565b611663565b60405161039d9190611b4d565b60405180910390f35b6103c060048036038101906103bb9190611b68565b61179a565b6040516103cd9190611b4d565b60405180910390f35b6103f060048036038101906103eb9190611afe565b6117d1565b6040516103fd9190611b4d565b60405180910390f35b610420600480360381019061041b9190611d46565b6117f6565b005b6005602052816000526040600020602052806000526040600020600091509150505481565b600080600460008481526020019081526020016000209050806002015481600501546104739190611da2565b915050919050565b610483611879565b803360006004600084815260200190815260200160002090506104a5836111f4565b81600601819055506104b68361179a565b8160040181905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146105aa576104fc8383611663565b6006600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080600601546005600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b600060046000868152602001908152602001600020905060006006600087815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060008111156107685760006006600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33836040518363ffffffff1660e01b81526004016106d4929190611dfc565b6020604051808303816000875af11580156106f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107179190611e51565b503373ffffffffffffffffffffffffffffffffffffffff16867f04492fab062412e7e4e5f46c9e919f1640652946a5e163ad6e6c1c03d87954d28360405161075f9190611b4d565b60405180910390a35b50505050506107756118c8565b50565b6107806118d1565b816000806004600084815260200190815260200160002090506107a2836111f4565b81600601819055506107b38361179a565b8160040181905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146108a7576107f98383611663565b6006600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080600601546005600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b6000600460008781526020019081526020016000209050806003015442106108e6578060020154856108d99190611ead565b8160050181905550610934565b60004282600301546108f89190611ede565b9050600082600501548261090c9190611da2565b90508260020154818861091f9190611f12565b6109299190611ead565b836005018190555050505b60008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016109939190611c6d565b602060405180830381865afa1580156109b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d49190611f5b565b90508160020154816109e69190611ead565b82600501541115610a2c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a2390611fe5565b60405180910390fd5b428260040181905550816002015442610a459190611f12565b8260030181905550867f6c07ee05dcf262f13abf9d87b846ee789d2f90fe991d495acd7d7fc109ee1f5587604051610a7d9190611b4d565b60405180910390a250505050505050565b6007602052816000526040600020602052806000526040600020600091509150505481565b610abb611879565b81336000600460008481526020019081526020016000209050610add836111f4565b8160060181905550610aee8361179a565b8160040181905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610be257610b348383611663565b6006600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080600601546005600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b60008411610c25576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1c90612051565b60405180910390fd5b6000600460008781526020019081526020016000209050848160070154610c4c9190611ede565b8160070181905550846007600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610cb09190611ede565b6007600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33876040518363ffffffff1660e01b8152600401610d63929190611dfc565b6020604051808303816000875af1158015610d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da69190611e51565b503373ffffffffffffffffffffffffffffffffffffffff16867fcf7d23a3cbe4e8b36ff82fd1b05b1b17373dc7804b4ebbd6e2356716ef20237287604051610dee9190611b4d565b60405180910390a350505050610e026118c8565b5050565b6000600260009054906101000a900460ff16905090565b610e256118d1565b610e2f600061194f565b565b610e39611879565b610e41611a13565b81336000600460008481526020019081526020016000209050610e63836111f4565b8160060181905550610e748361179a565b8160040181905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610f6857610eba8383611663565b6006600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080600601546005600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b60008411610fab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fa2906120bd565b60405180910390fd5b6000600460008781526020019081526020016000209050848160070154610fd29190611f12565b8160070181905550846007600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546110369190611f12565b6007600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b81526004016110eb939291906120dd565b6020604051808303816000875af115801561110a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112e9190611e51565b503373ffffffffffffffffffffffffffffffffffffffff16867f18dcd430020e4d4899772fd94a8b40451dc5044dfb70bc46b532eeae431c864f876040516111769190611b4d565b60405180910390a35050505061118a6118c8565b5050565b6111e8816007600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ab3565b6111f18161047b565b50565b6000806004600084815260200190815260200160002090506000816007015403611225578060060154915050611281565b8060070154670de0b6b3a764000082600401546112418661179a565b61124b9190611ede565b836005015461125a9190611da2565b6112649190611da2565b61126e9190611ead565b816006015461127d9190611f12565b9150505b919050565b61128e6118d1565b60006004600085815260200190815260200160002090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611337576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161132e90612186565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61135b6113fd565b846040518363ffffffff1660e01b8152600401611379929190611dfc565b6020604051808303816000875af1158015611398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bc9190611e51565b50837f986159ceffdc791f0b3a91a14e4141b9e6f9b1cf6130751c819dd646f616b81084846040516113ef929190611dfc565b60405180910390a250505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60035481565b6114346118d1565b600060046000848152602001908152602001600020905080600301544211611491576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114889061223e565b60405180910390fd5b818160020181905550827fd20a04eb2807bde8cbdf16ef27a46d94a3162d81818f1781c0fe4ed9194ca39182600201546040516114ce9190611b4d565b60405180910390a2505050565b60046020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020154908060030154908060040154908060050154908060060154908060070154905088565b61156b6118d1565b6003600081548092919061157e9061225e565b919050555060006004600060035481526020019081526020016000209050828160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506003547f1a7a1d16c3ec9167827a7be3534be26288720a0bdd3de56d290f415db3d3e0a684846040516116569291906122a6565b60405180910390a2505050565b60006006600084815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054670de0b6b3a76400006005600086815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611719866111f4565b6117239190611ede565b6007600087815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461177e9190611da2565b6117889190611ead565b6117929190611f12565b905092915050565b600080600460008481526020019081526020016000209050806003015442106117c75780600301546117c9565b425b915050919050565b6006602052816000526040600020602052806000526040600020600091509150505481565b6117fe6118d1565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361186d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161186490612341565b60405180910390fd5b6118768161194f565b50565b6002600154036118be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118b5906123ad565b60405180910390fd5b6002600181905550565b60018081905550565b6118d9611a5d565b73ffffffffffffffffffffffffffffffffffffffff166118f76113fd565b73ffffffffffffffffffffffffffffffffffffffff161461194d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161194490612419565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b611a1b610e06565b15611a5b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a5290612485565b60405180910390fd5b565b600033905090565b600080fd5b6000819050919050565b611a7d81611a6a565b8114611a8857600080fd5b50565b600081359050611a9a81611a74565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611acb82611aa0565b9050919050565b611adb81611ac0565b8114611ae657600080fd5b50565b600081359050611af881611ad2565b92915050565b60008060408385031215611b1557611b14611a65565b5b6000611b2385828601611a8b565b9250506020611b3485828601611ae9565b9150509250929050565b611b4781611a6a565b82525050565b6000602082019050611b626000830184611b3e565b92915050565b600060208284031215611b7e57611b7d611a65565b5b6000611b8c84828501611a8b565b91505092915050565b60008060408385031215611bac57611bab611a65565b5b6000611bba85828601611a8b565b9250506020611bcb85828601611a8b565b9150509250929050565b60008115159050919050565b611bea81611bd5565b82525050565b6000602082019050611c056000830184611be1565b92915050565b600080600060608486031215611c2457611c23611a65565b5b6000611c3286828701611a8b565b9350506020611c4386828701611ae9565b9250506040611c5486828701611a8b565b9150509250925092565b611c6781611ac0565b82525050565b6000602082019050611c826000830184611c5e565b92915050565b600061010082019050611c9e600083018b611c5e565b611cab602083018a611c5e565b611cb86040830189611b3e565b611cc56060830188611b3e565b611cd26080830187611b3e565b611cdf60a0830186611b3e565b611cec60c0830185611b3e565b611cf960e0830184611b3e565b9998505050505050505050565b60008060408385031215611d1d57611d1c611a65565b5b6000611d2b85828601611ae9565b9250506020611d3c85828601611ae9565b9150509250929050565b600060208284031215611d5c57611d5b611a65565b5b6000611d6a84828501611ae9565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611dad82611a6a565b9150611db883611a6a565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611df157611df0611d73565b5b828202905092915050565b6000604082019050611e116000830185611c5e565b611e1e6020830184611b3e565b9392505050565b611e2e81611bd5565b8114611e3957600080fd5b50565b600081519050611e4b81611e25565b92915050565b600060208284031215611e6757611e66611a65565b5b6000611e7584828501611e3c565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000611eb882611a6a565b9150611ec383611a6a565b925082611ed357611ed2611e7e565b5b828204905092915050565b6000611ee982611a6a565b9150611ef483611a6a565b9250828203905081811115611f0c57611f0b611d73565b5b92915050565b6000611f1d82611a6a565b9150611f2883611a6a565b9250828201905080821115611f4057611f3f611d73565b5b92915050565b600081519050611f5581611a74565b92915050565b600060208284031215611f7157611f70611a65565b5b6000611f7f84828501611f46565b91505092915050565b600082825260208201905092915050565b7f50726f76696465642072657761726420746f6f20686967680000000000000000600082015250565b6000611fcf601883611f88565b9150611fda82611f99565b602082019050919050565b60006020820190508181036000830152611ffe81611fc2565b9050919050565b7f43616e6e6f742077697468647261772030000000000000000000000000000000600082015250565b600061203b601183611f88565b915061204682612005565b602082019050919050565b6000602082019050818103600083015261206a8161202e565b9050919050565b7f43616e6e6f74207374616b652030000000000000000000000000000000000000600082015250565b60006120a7600e83611f88565b91506120b282612071565b602082019050919050565b600060208201905081810360008301526120d68161209a565b9050919050565b60006060820190506120f26000830186611c5e565b6120ff6020830185611c5e565b61210c6040830184611b3e565b949350505050565b7f43616e6e6f7420776974686472617720746865207374616b696e6720746f6b6560008201527f6e00000000000000000000000000000000000000000000000000000000000000602082015250565b6000612170602183611f88565b915061217b82612114565b604082019050919050565b6000602082019050818103600083015261219f81612163565b9050919050565b7f50726576696f7573207265776172647320706572696f64206d7573742062652060008201527f636f6d706c657465206265666f7265206368616e67696e67207468652064757260208201527f6174696f6e20666f7220746865206e657720706572696f640000000000000000604082015250565b6000612228605883611f88565b9150612233826121a6565b606082019050919050565b600060208201905081810360008301526122578161221b565b9050919050565b600061226982611a6a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361229b5761229a611d73565b5b600182019050919050565b60006040820190506122bb6000830185611c5e565b6122c86020830184611c5e565b9392505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b600061232b602683611f88565b9150612336826122cf565b604082019050919050565b6000602082019050818103600083015261235a8161231e565b9050919050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000612397601f83611f88565b91506123a282612361565b602082019050919050565b600060208201905081810360008301526123c68161238a565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000612403602083611f88565b915061240e826123cd565b602082019050919050565b60006020820190508181036000830152612432816123f6565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b600061246f601083611f88565b915061247a82612439565b602082019050919050565b6000602082019050818103600083015261249e81612462565b905091905056fea264697066735822122079eecfcac730e6c0140814361f99e0e866919857497d33cd0ba323f2df65fd2f64736f6c63430008100033
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106101365760003560e01c8063874c120b116100b8578063ac4afa381161007c578063ac4afa3814610323578063e34336151461035a578063e39c08fc14610376578063eeca1562146103a6578063f2db11af146103d6578063f2fde38b1461040657610136565b8063874c120b1461027f5780638ca43f91146102af5780638da5cb5b146102cb5780639e3079cb146102e95780639efb70371461030757610136565b8063441a3e70116100ff578063441a3e70146102035780635c975abb1461021f578063715018a61461023d5780637b0472f0146102475780637f8661a11461026357610136565b8062a47ddd1461013b5780630e213a3d1461016b5780631c4b774b1461019b578063246132f9146101b75780633656eec2146101d3575b600080fd5b61015560048036038101906101509190611afe565b610422565b6040516101629190611b4d565b60405180910390f35b61018560048036038101906101809190611b68565b610447565b6040516101929190611b4d565b60405180910390f35b6101b560048036038101906101b09190611b68565b61047b565b005b6101d160048036038101906101cc9190611b95565b610778565b005b6101ed60048036038101906101e89190611afe565b610a8e565b6040516101fa9190611b4d565b60405180910390f35b61021d60048036038101906102189190611b95565b610ab3565b005b610227610e06565b6040516102349190611bf0565b60405180910390f35b610245610e1d565b005b610261600480360381019061025c9190611b95565b610e31565b005b61027d60048036038101906102789190611b68565b61118e565b005b61029960048036038101906102949190611b68565b6111f4565b6040516102a69190611b4d565b60405180910390f35b6102c960048036038101906102c49190611c0b565b611286565b005b6102d36113fd565b6040516102e09190611c6d565b60405180910390f35b6102f1611426565b6040516102fe9190611b4d565b60405180910390f35b610321600480360381019061031c9190611b95565b61142c565b005b61033d60048036038101906103389190611b68565b6114db565b604051610351989796959493929190611c88565b60405180910390f35b610374600480360381019061036f9190611d06565b611563565b005b610390600480360381019061038b9190611afe565b611663565b60405161039d9190611b4d565b60405180910390f35b6103c060048036038101906103bb9190611b68565b61179a565b6040516103cd9190611b4d565b60405180910390f35b6103f060048036038101906103eb9190611afe565b6117d1565b6040516103fd9190611b4d565b60405180910390f35b610420600480360381019061041b9190611d46565b6117f6565b005b6005602052816000526040600020602052806000526040600020600091509150505481565b600080600460008481526020019081526020016000209050806002015481600501546104739190611da2565b915050919050565b610483611879565b803360006004600084815260200190815260200160002090506104a5836111f4565b81600601819055506104b68361179a565b8160040181905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146105aa576104fc8383611663565b6006600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080600601546005600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b600060046000868152602001908152602001600020905060006006600087815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060008111156107685760006006600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33836040518363ffffffff1660e01b81526004016106d4929190611dfc565b6020604051808303816000875af11580156106f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107179190611e51565b503373ffffffffffffffffffffffffffffffffffffffff16867f04492fab062412e7e4e5f46c9e919f1640652946a5e163ad6e6c1c03d87954d28360405161075f9190611b4d565b60405180910390a35b50505050506107756118c8565b50565b6107806118d1565b816000806004600084815260200190815260200160002090506107a2836111f4565b81600601819055506107b38361179a565b8160040181905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146108a7576107f98383611663565b6006600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080600601546005600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b6000600460008781526020019081526020016000209050806003015442106108e6578060020154856108d99190611ead565b8160050181905550610934565b60004282600301546108f89190611ede565b9050600082600501548261090c9190611da2565b90508260020154818861091f9190611f12565b6109299190611ead565b836005018190555050505b60008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016109939190611c6d565b602060405180830381865afa1580156109b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d49190611f5b565b90508160020154816109e69190611ead565b82600501541115610a2c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a2390611fe5565b60405180910390fd5b428260040181905550816002015442610a459190611f12565b8260030181905550867f6c07ee05dcf262f13abf9d87b846ee789d2f90fe991d495acd7d7fc109ee1f5587604051610a7d9190611b4d565b60405180910390a250505050505050565b6007602052816000526040600020602052806000526040600020600091509150505481565b610abb611879565b81336000600460008481526020019081526020016000209050610add836111f4565b8160060181905550610aee8361179a565b8160040181905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610be257610b348383611663565b6006600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080600601546005600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b60008411610c25576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1c90612051565b60405180910390fd5b6000600460008781526020019081526020016000209050848160070154610c4c9190611ede565b8160070181905550846007600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610cb09190611ede565b6007600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33876040518363ffffffff1660e01b8152600401610d63929190611dfc565b6020604051808303816000875af1158015610d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da69190611e51565b503373ffffffffffffffffffffffffffffffffffffffff16867fcf7d23a3cbe4e8b36ff82fd1b05b1b17373dc7804b4ebbd6e2356716ef20237287604051610dee9190611b4d565b60405180910390a350505050610e026118c8565b5050565b6000600260009054906101000a900460ff16905090565b610e256118d1565b610e2f600061194f565b565b610e39611879565b610e41611a13565b81336000600460008481526020019081526020016000209050610e63836111f4565b8160060181905550610e748361179a565b8160040181905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610f6857610eba8383611663565b6006600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080600601546005600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b60008411610fab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fa2906120bd565b60405180910390fd5b6000600460008781526020019081526020016000209050848160070154610fd29190611f12565b8160070181905550846007600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546110369190611f12565b6007600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b81526004016110eb939291906120dd565b6020604051808303816000875af115801561110a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112e9190611e51565b503373ffffffffffffffffffffffffffffffffffffffff16867f18dcd430020e4d4899772fd94a8b40451dc5044dfb70bc46b532eeae431c864f876040516111769190611b4d565b60405180910390a35050505061118a6118c8565b5050565b6111e8816007600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ab3565b6111f18161047b565b50565b6000806004600084815260200190815260200160002090506000816007015403611225578060060154915050611281565b8060070154670de0b6b3a764000082600401546112418661179a565b61124b9190611ede565b836005015461125a9190611da2565b6112649190611da2565b61126e9190611ead565b816006015461127d9190611f12565b9150505b919050565b61128e6118d1565b60006004600085815260200190815260200160002090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611337576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161132e90612186565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61135b6113fd565b846040518363ffffffff1660e01b8152600401611379929190611dfc565b6020604051808303816000875af1158015611398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bc9190611e51565b50837f986159ceffdc791f0b3a91a14e4141b9e6f9b1cf6130751c819dd646f616b81084846040516113ef929190611dfc565b60405180910390a250505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60035481565b6114346118d1565b600060046000848152602001908152602001600020905080600301544211611491576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114889061223e565b60405180910390fd5b818160020181905550827fd20a04eb2807bde8cbdf16ef27a46d94a3162d81818f1781c0fe4ed9194ca39182600201546040516114ce9190611b4d565b60405180910390a2505050565b60046020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020154908060030154908060040154908060050154908060060154908060070154905088565b61156b6118d1565b6003600081548092919061157e9061225e565b919050555060006004600060035481526020019081526020016000209050828160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506003547f1a7a1d16c3ec9167827a7be3534be26288720a0bdd3de56d290f415db3d3e0a684846040516116569291906122a6565b60405180910390a2505050565b60006006600084815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054670de0b6b3a76400006005600086815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611719866111f4565b6117239190611ede565b6007600087815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461177e9190611da2565b6117889190611ead565b6117929190611f12565b905092915050565b600080600460008481526020019081526020016000209050806003015442106117c75780600301546117c9565b425b915050919050565b6006602052816000526040600020602052806000526040600020600091509150505481565b6117fe6118d1565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361186d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161186490612341565b60405180910390fd5b6118768161194f565b50565b6002600154036118be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118b5906123ad565b60405180910390fd5b6002600181905550565b60018081905550565b6118d9611a5d565b73ffffffffffffffffffffffffffffffffffffffff166118f76113fd565b73ffffffffffffffffffffffffffffffffffffffff161461194d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161194490612419565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b611a1b610e06565b15611a5b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a5290612485565b60405180910390fd5b565b600033905090565b600080fd5b6000819050919050565b611a7d81611a6a565b8114611a8857600080fd5b50565b600081359050611a9a81611a74565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611acb82611aa0565b9050919050565b611adb81611ac0565b8114611ae657600080fd5b50565b600081359050611af881611ad2565b92915050565b60008060408385031215611b1557611b14611a65565b5b6000611b2385828601611a8b565b9250506020611b3485828601611ae9565b9150509250929050565b611b4781611a6a565b82525050565b6000602082019050611b626000830184611b3e565b92915050565b600060208284031215611b7e57611b7d611a65565b5b6000611b8c84828501611a8b565b91505092915050565b60008060408385031215611bac57611bab611a65565b5b6000611bba85828601611a8b565b9250506020611bcb85828601611a8b565b9150509250929050565b60008115159050919050565b611bea81611bd5565b82525050565b6000602082019050611c056000830184611be1565b92915050565b600080600060608486031215611c2457611c23611a65565b5b6000611c3286828701611a8b565b9350506020611c4386828701611ae9565b9250506040611c5486828701611a8b565b9150509250925092565b611c6781611ac0565b82525050565b6000602082019050611c826000830184611c5e565b92915050565b600061010082019050611c9e600083018b611c5e565b611cab602083018a611c5e565b611cb86040830189611b3e565b611cc56060830188611b3e565b611cd26080830187611b3e565b611cdf60a0830186611b3e565b611cec60c0830185611b3e565b611cf960e0830184611b3e565b9998505050505050505050565b60008060408385031215611d1d57611d1c611a65565b5b6000611d2b85828601611ae9565b9250506020611d3c85828601611ae9565b9150509250929050565b600060208284031215611d5c57611d5b611a65565b5b6000611d6a84828501611ae9565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611dad82611a6a565b9150611db883611a6a565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611df157611df0611d73565b5b828202905092915050565b6000604082019050611e116000830185611c5e565b611e1e6020830184611b3e565b9392505050565b611e2e81611bd5565b8114611e3957600080fd5b50565b600081519050611e4b81611e25565b92915050565b600060208284031215611e6757611e66611a65565b5b6000611e7584828501611e3c565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000611eb882611a6a565b9150611ec383611a6a565b925082611ed357611ed2611e7e565b5b828204905092915050565b6000611ee982611a6a565b9150611ef483611a6a565b9250828203905081811115611f0c57611f0b611d73565b5b92915050565b6000611f1d82611a6a565b9150611f2883611a6a565b9250828201905080821115611f4057611f3f611d73565b5b92915050565b600081519050611f5581611a74565b92915050565b600060208284031215611f7157611f70611a65565b5b6000611f7f84828501611f46565b91505092915050565b600082825260208201905092915050565b7f50726f76696465642072657761726420746f6f20686967680000000000000000600082015250565b6000611fcf601883611f88565b9150611fda82611f99565b602082019050919050565b60006020820190508181036000830152611ffe81611fc2565b9050919050565b7f43616e6e6f742077697468647261772030000000000000000000000000000000600082015250565b600061203b601183611f88565b915061204682612005565b602082019050919050565b6000602082019050818103600083015261206a8161202e565b9050919050565b7f43616e6e6f74207374616b652030000000000000000000000000000000000000600082015250565b60006120a7600e83611f88565b91506120b282612071565b602082019050919050565b600060208201905081810360008301526120d68161209a565b9050919050565b60006060820190506120f26000830186611c5e565b6120ff6020830185611c5e565b61210c6040830184611b3e565b949350505050565b7f43616e6e6f7420776974686472617720746865207374616b696e6720746f6b6560008201527f6e00000000000000000000000000000000000000000000000000000000000000602082015250565b6000612170602183611f88565b915061217b82612114565b604082019050919050565b6000602082019050818103600083015261219f81612163565b9050919050565b7f50726576696f7573207265776172647320706572696f64206d7573742062652060008201527f636f6d706c657465206265666f7265206368616e67696e67207468652064757260208201527f6174696f6e20666f7220746865206e657720706572696f640000000000000000604082015250565b6000612228605883611f88565b9150612233826121a6565b606082019050919050565b600060208201905081810360008301526122578161221b565b9050919050565b600061226982611a6a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361229b5761229a611d73565b5b600182019050919050565b60006040820190506122bb6000830185611c5e565b6122c86020830184611c5e565b9392505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b600061232b602683611f88565b9150612336826122cf565b604082019050919050565b6000602082019050818103600083015261235a8161231e565b9050919050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000612397601f83611f88565b91506123a282612361565b602082019050919050565b600060208201905081810360008301526123c68161238a565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000612403602083611f88565b915061240e826123cd565b602082019050919050565b60006020820190508181036000830152612432816123f6565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b600061246f601083611f88565b915061247a82612439565b602082019050919050565b6000602082019050818103600083015261249e81612462565b905091905056fea264697066735822122079eecfcac730e6c0140814361f99e0e866919857497d33cd0ba323f2df65fd2f64736f6c63430008100033