Address Details
contract
0xbc518666F0827F4736220aC11c9a2cF37B1DE5aD
- Contract Name
- LockedGold
- Creator
- 0xf3eb91–a79239 at 0xdc6cdc–6a2e16
- 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
- 25504567
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- LockedGold
- Optimization enabled
- false
- Compiler version
- v0.5.13+commit.5b0b510c
- EVM Version
- istanbul
- Verified at
- 2024-05-08T18:57:31.203333Z
project:/contracts/governance/LockedGold.sol
pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/math/Math.sol"; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/utils/Address.sol"; import "openzeppelin-solidity/contracts/utils/EnumerableSet.sol"; import "./interfaces/ILockedGold.sol"; import "../common/FixidityLib.sol"; import "../common/Initializable.sol"; import "../common/Signatures.sol"; import "../common/UsingRegistry.sol"; import "../common/interfaces/ICeloVersionedContract.sol"; import "../common/libraries/ReentrancyGuard.sol"; contract LockedGold is ILockedGold, ICeloVersionedContract, ReentrancyGuard, Initializable, UsingRegistry { using SafeMath for uint256; using Address for address payable; // prettier-ignore using FixidityLib for FixidityLib.Fraction; using EnumerableSet for EnumerableSet.AddressSet; struct PendingWithdrawal { // The value of the pending withdrawal. uint256 value; // The timestamp at which the pending withdrawal becomes available. uint256 timestamp; } // NOTE: This contract does not store an account's locked gold that is being used in electing // validators. struct Balances { // The amount of locked gold that this account has that is not currently participating in // validator elections. uint256 nonvoting; // Gold that has been unlocked and will become available for withdrawal. PendingWithdrawal[] pendingWithdrawals; } struct DelegatedInfo { FixidityLib.Fraction percentage; uint256 currentAmount; } struct Delegated { EnumerableSet.AddressSet delegatees; // delegatees with how much percent delegatees are getting // Celo at the time of delegation/latest update mapping(address => DelegatedInfo) delegateesWithPercentagesAndAmount; FixidityLib.Fraction totalDelegatedCeloFraction; } mapping(address => Balances) internal balances; // Iterable map to store whitelisted identifiers. // Necessary to allow iterating over whitelisted IDs to check ID's address at runtime. mapping(bytes32 => bool) internal slashingMap; bytes32[] public slashingWhitelist; modifier onlySlasher { require( registry.isOneOf(slashingWhitelist, msg.sender), "Caller is not a whitelisted slasher." ); _; } function isSlasher(address slasher) external view returns (bool) { return (registry.isOneOf(slashingWhitelist, slasher)); } uint256 public totalNonvoting; uint256 public unlockingPeriod; // Info about delegator mapping(address => Delegated) delegatorInfo; // Celo that was delegated to this particular address mapping(address => uint256) public totalDelegatedCelo; // maximum amount of allowed delegatees uint256 maxDelegateesCount; event UnlockingPeriodSet(uint256 period); event GoldLocked(address indexed account, uint256 value); event GoldUnlocked(address indexed account, uint256 value, uint256 available); event GoldRelocked(address indexed account, uint256 value); event GoldWithdrawn(address indexed account, uint256 value); event SlasherWhitelistAdded(string indexed slasherIdentifier); event SlasherWhitelistRemoved(string indexed slasherIdentifier); event AccountSlashed( address indexed slashed, uint256 penalty, address indexed reporter, uint256 reward ); event CeloDelegated( address indexed delegator, address indexed delegatee, uint256 percent, uint256 amount ); event DelegatedCeloRevoked( address indexed delegator, address indexed delegatee, uint256 percent, uint256 amount ); event MaxDelegateesCountSet(uint256 value); /** * @notice Returns the storage, major, minor, and patch version of the contract. * @return Storage version of the contract. * @return Major version of the contract. * @return Minor version of the contract. * @return Patch version of the contract. */ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) { return (1, 1, 4, 0); } /** * @notice Sets initialized == true on implementation contracts * @param test Set to true to skip implementation initialization */ constructor(bool test) public Initializable(test) {} /** * @notice Used in place of the constructor to allow the contract to be upgradable via proxy. * @param registryAddress The address of the registry core smart contract. * @param _unlockingPeriod The unlocking period in seconds. */ function initialize(address registryAddress, uint256 _unlockingPeriod) external initializer { _transferOwnership(msg.sender); setRegistry(registryAddress); setUnlockingPeriod(_unlockingPeriod); maxDelegateesCount = 10; } /** * @notice Sets the duration in seconds users must wait before withdrawing gold after unlocking. * @param value The unlocking period in seconds. */ function setUnlockingPeriod(uint256 value) public onlyOwner { require(value != unlockingPeriod, "Unlocking period not changed"); unlockingPeriod = value; emit UnlockingPeriodSet(value); } /** * @notice Sets max delegatees count. * @param value The max delegatees count. */ function setMaxDelegateesCount(uint256 value) public onlyOwner { maxDelegateesCount = value; emit MaxDelegateesCountSet(value); } /** * @notice Locks gold to be used for voting. */ function lock() external payable nonReentrant { require( getAccounts().isAccount(msg.sender), "Must first register address with Account.createAccount" ); _incrementNonvotingAccountBalance(msg.sender, msg.value); _updateDelegatedAmount(msg.sender); emit GoldLocked(msg.sender, msg.value); } /** * @notice Increments the non-voting balance for an account. * @param account The account whose non-voting balance should be incremented. * @param value The amount by which to increment. * @dev Can only be called by the registered Election smart contract. */ function incrementNonvotingAccountBalance(address account, uint256 value) external onlyRegisteredContract(ELECTION_REGISTRY_ID) { _incrementNonvotingAccountBalance(account, value); } /** * @notice Decrements the non-voting balance for an account. * @param account The account whose non-voting balance should be decremented. * @param value The amount by which to decrement. * @dev Can only be called by the registered "Election" smart contract. */ function decrementNonvotingAccountBalance(address account, uint256 value) external onlyRegisteredContract(ELECTION_REGISTRY_ID) { _decrementNonvotingAccountBalance(account, value); } /** * @notice Increments the non-voting balance for an account. * @param account The account whose non-voting balance should be incremented. * @param value The amount by which to increment. */ function _incrementNonvotingAccountBalance(address account, uint256 value) private { balances[account].nonvoting = balances[account].nonvoting.add(value); totalNonvoting = totalNonvoting.add(value); } /** * @notice Decrements the non-voting balance for an account. * @param account The account whose non-voting balance should be decremented. * @param value The amount by which to decrement. */ function _decrementNonvotingAccountBalance(address account, uint256 value) private { balances[account].nonvoting = balances[account].nonvoting.sub(value); totalNonvoting = totalNonvoting.sub(value); } /** * @notice Unlocks gold that becomes withdrawable after the unlocking period. * @param value The amount of gold to unlock. */ function unlock(uint256 value) external nonReentrant { require( getAccounts().isAccount(msg.sender), "Sender must be registered with Account.createAccount to lock or unlock" ); Balances storage account = balances[msg.sender]; uint256 totalLockedGold = getAccountTotalLockedGold(msg.sender); // Prevent unlocking gold when voting on governance proposals so that the gold cannot be // used to vote more than once. uint256 remainingLockedGold = totalLockedGold.sub(value); uint256 totalReferendumVotes = getGovernance().getAmountOfGoldUsedForVoting(msg.sender); require( remainingLockedGold >= totalReferendumVotes, "Not enough unlockable celo. Celo is locked in voting." ); FixidityLib.Fraction memory delegatedPercentage = delegatorInfo[msg.sender] .totalDelegatedCeloFraction; if (FixidityLib.gt(delegatedPercentage, FixidityLib.newFixed(0))) { revokeFromDelegatedWhenUnlocking(msg.sender, value); } uint256 balanceRequirement = getValidators().getAccountLockedGoldRequirement(msg.sender); require( balanceRequirement == 0 || balanceRequirement <= remainingLockedGold, "Either account doesn't have enough locked Celo or locked Celo is being used for voting." ); _decrementNonvotingAccountBalance(msg.sender, value); uint256 available = now.add(unlockingPeriod); // CERTORA: the slot containing the length could be MAX_UINT account.pendingWithdrawals.push(PendingWithdrawal(value, available)); emit GoldUnlocked(msg.sender, value, available); } /** * @notice Relocks gold that has been unlocked but not withdrawn. * @param index The index of the pending withdrawal to relock from. * @param value The value to relock from the specified pending withdrawal. */ function relock(uint256 index, uint256 value) external nonReentrant { require( getAccounts().isAccount(msg.sender), "Sender must be registered with Account.createAccount to lock or relock" ); Balances storage account = balances[msg.sender]; require(index < account.pendingWithdrawals.length, "Bad pending withdrawal index"); PendingWithdrawal storage pendingWithdrawal = account.pendingWithdrawals[index]; require(value <= pendingWithdrawal.value, "Requested value larger than pending value"); if (value == pendingWithdrawal.value) { deletePendingWithdrawal(account.pendingWithdrawals, index); } else { pendingWithdrawal.value = pendingWithdrawal.value.sub(value); } _incrementNonvotingAccountBalance(msg.sender, value); _updateDelegatedAmount(msg.sender); emit GoldRelocked(msg.sender, value); } /** * @notice Withdraws gold that has been unlocked after the unlocking period has passed. * @param index The index of the pending withdrawal to withdraw. */ function withdraw(uint256 index) external nonReentrant { require( getAccounts().isAccount(msg.sender), "Sender must be registered with Account.createAccount to withdraw" ); Balances storage account = balances[msg.sender]; require(index < account.pendingWithdrawals.length, "Bad pending withdrawal index"); PendingWithdrawal storage pendingWithdrawal = account.pendingWithdrawals[index]; require(now >= pendingWithdrawal.timestamp, "Pending withdrawal not available"); uint256 value = pendingWithdrawal.value; deletePendingWithdrawal(account.pendingWithdrawals, index); require(value <= address(this).balance, "Inconsistent balance"); msg.sender.sendValue(value); emit GoldWithdrawn(msg.sender, value); } /** * @notice Returns the total amount of locked gold in the system. Note that this does not include * gold that has been unlocked but not yet withdrawn. * @return The total amount of locked gold in the system. */ function getTotalLockedGold() external view returns (uint256) { return totalNonvoting.add(getElection().getTotalVotes()); } /** * @notice Returns the total amount of locked gold not being used to vote in elections. * @return The total amount of locked gold not being used to vote in elections. */ function getNonvotingLockedGold() external view returns (uint256) { return totalNonvoting; } /** * Delegates CELO to delegatee. * @param delegatee The delegatee account. * @param delegateFraction Fraction of total CELO that will be delegated from delegatee. Fixidity fraction */ function delegateGovernanceVotes(address delegatee, uint256 delegateFraction) external { FixidityLib.Fraction memory percentageToDelegate = FixidityLib.wrap(delegateFraction); require( FixidityLib.lte(percentageToDelegate, FixidityLib.fixed1()), "Delegate fraction must be less than or equal to 1" ); address delegatorAccount = getAccounts().voteSignerToAccount(msg.sender); address delegateeAccount = getAccounts().voteSignerToAccount(delegatee); IValidators validators = getValidators(); require(!validators.isValidator(delegatorAccount), "Validators cannot delegate votes."); require( !validators.isValidatorGroup(delegatorAccount), "Validator groups cannot delegate votes." ); Delegated storage delegated = delegatorInfo[delegatorAccount]; delegated.delegatees.add(delegateeAccount); require(delegated.delegatees.length() <= maxDelegateesCount, "Too many delegatees"); DelegatedInfo storage currentDelegateeInfo = delegated .delegateesWithPercentagesAndAmount[delegateeAccount]; require( FixidityLib.gte(percentageToDelegate, currentDelegateeInfo.percentage), "Cannot decrease delegated amount - use revokeDelegatedGovernanceVotes." ); FixidityLib.Fraction memory requestedToDelegate = delegated .totalDelegatedCeloFraction .subtract(currentDelegateeInfo.percentage) .add(percentageToDelegate); require( FixidityLib.lte(requestedToDelegate, FixidityLib.fixed1()), "Cannot delegate more than 100%" ); uint256 totalLockedGold = getAccountTotalLockedGold(delegatorAccount); if (totalLockedGold == 0) { delegated.totalDelegatedCeloFraction = delegated .totalDelegatedCeloFraction .subtract(currentDelegateeInfo.percentage) .add(percentageToDelegate); currentDelegateeInfo.percentage = percentageToDelegate; emit CeloDelegated( delegatorAccount, delegateeAccount, FixidityLib.unwrap(percentageToDelegate), currentDelegateeInfo.currentAmount ); return; } uint256 totalReferendumVotes = getGovernance().getAmountOfGoldUsedForVoting(delegatorAccount); if (totalReferendumVotes != 0) { FixidityLib.Fraction memory referendumVotesInPercents = FixidityLib.newFixedFraction( totalReferendumVotes, totalLockedGold ); require( FixidityLib.lte(referendumVotesInPercents.add(requestedToDelegate), FixidityLib.fixed1()), "Cannot delegate votes that are voting in referendum" ); } // amount that will really be delegated - whatever is already // delegated to this particular delagatee is already subracted from this uint256 amountToDelegate = FixidityLib .newFixed(totalLockedGold) .multiply(percentageToDelegate) .subtract(FixidityLib.newFixed(currentDelegateeInfo.currentAmount)) .fromFixed(); delegated.totalDelegatedCeloFraction = delegated .totalDelegatedCeloFraction .subtract(currentDelegateeInfo.percentage) .add(percentageToDelegate); currentDelegateeInfo.percentage = percentageToDelegate; currentDelegateeInfo.currentAmount = currentDelegateeInfo.currentAmount.add(amountToDelegate); totalDelegatedCelo[delegateeAccount] = totalDelegatedCelo[delegateeAccount].add( amountToDelegate ); emit CeloDelegated( delegatorAccount, delegateeAccount, FixidityLib.unwrap(percentageToDelegate), currentDelegateeInfo.currentAmount ); } /** * Revokes delegated CELO. * @param delegatee The delegatee acount. * @param revokeFraction Fraction of total CELO that will be revoked from delegatee. Fixidity fraction */ function revokeDelegatedGovernanceVotes(address delegatee, uint256 revokeFraction) external { FixidityLib.Fraction memory percentageToRevoke = FixidityLib.wrap(revokeFraction); require( FixidityLib.lte(percentageToRevoke, FixidityLib.fixed1()), "Revoke fraction must be less than or equal to 1" ); address delegatorAccount = getAccounts().voteSignerToAccount(msg.sender); Delegated storage delegated = delegatorInfo[delegatorAccount]; require( FixidityLib.gte(delegated.totalDelegatedCeloFraction, percentageToRevoke), "Not enough total delegated percents" ); address delegateeAccount = getAccounts().voteSignerToAccount(delegatee); _updateDelegatedAmount(delegatorAccount, delegateeAccount); DelegatedInfo storage currentDelegateeInfo = delegated .delegateesWithPercentagesAndAmount[delegateeAccount]; require( FixidityLib.gte(currentDelegateeInfo.percentage, percentageToRevoke), "Not enough delegated percents" ); currentDelegateeInfo.percentage = currentDelegateeInfo.percentage.subtract(percentageToRevoke); uint256 totalLockedGold = getAccountTotalLockedGold(delegatorAccount); uint256 amountToRevoke = FixidityLib.unwrap(currentDelegateeInfo.percentage) == 0 ? currentDelegateeInfo.currentAmount : Math.min( FixidityLib.newFixed(totalLockedGold).multiply(percentageToRevoke).fromFixed(), currentDelegateeInfo.currentAmount ); _decreaseDelegateeVotingPower(delegateeAccount, amountToRevoke, currentDelegateeInfo); delegated.totalDelegatedCeloFraction = delegated.totalDelegatedCeloFraction.subtract( percentageToRevoke ); if (FixidityLib.unwrap(currentDelegateeInfo.percentage) == 0) { delegated.delegatees.remove(delegateeAccount); } emit DelegatedCeloRevoked( delegatorAccount, delegateeAccount, FixidityLib.unwrap(percentageToRevoke), amountToRevoke ); } /** * Revokes amount during unlocking. It will revoke votes from voted proposals if necessary. * @param delegator The delegator account. * @param amountToRevoke The amount to revoke. */ function revokeFromDelegatedWhenUnlocking(address delegator, uint256 amountToRevoke) private { address[] memory delegatees = getDelegateesOfDelegator(delegator); Delegated storage delegated = delegatorInfo[delegator]; for (uint256 i = 0; i < delegatees.length; i = i.add(1)) { DelegatedInfo storage currentDelegateeInfo = delegated .delegateesWithPercentagesAndAmount[delegatees[i]]; (uint256 expected, uint256 real) = _getDelegatorDelegateeExpectedAndRealAmount( delegator, delegatees[i] ); uint256 delegateeAmountToRevoke = FixidityLib .newFixed(amountToRevoke) .multiply(currentDelegateeInfo.percentage) .fromFixed(); delegateeAmountToRevoke = delegateeAmountToRevoke.sub(expected.sub(real)); _decreaseDelegateeVotingPower(delegatees[i], delegateeAmountToRevoke, currentDelegateeInfo); emit DelegatedCeloRevoked(delegator, delegatees[i], 0, delegateeAmountToRevoke); } } /** * Decreases delegatee voting power when removing or unlocking delegated votes. * @param delegatee The delegatee. * @param amountToRevoke Amount to revoke. * @param delegateeInfo Delegatee info. */ function _decreaseDelegateeVotingPower( address delegatee, uint256 amountToRevoke, DelegatedInfo storage delegateeInfo ) private { uint256 delegateeTotalVotingPower = getAccountTotalGovernanceVotingPower(delegatee); uint256 totalReferendumVotes = getGovernance().getAmountOfGoldUsedForVoting(delegatee); uint256 unusedReferendumVotes = delegateeTotalVotingPower.sub(totalReferendumVotes); if (unusedReferendumVotes < amountToRevoke) { getGovernance().removeVotesWhenRevokingDelegatedVotes( delegatee, delegateeTotalVotingPower.sub(amountToRevoke) ); } delegateeInfo.currentAmount = delegateeInfo.currentAmount.sub(amountToRevoke); totalDelegatedCelo[delegatee] = totalDelegatedCelo[delegatee].sub(amountToRevoke); } /** * Updates real delegated amount to all delegator's delegatees. * There might be discrepancy because of validator rewards or extra locked gold. * @param delegator The delegator address. */ function updateDelegatedAmount(address delegator) public { address delegatorAccount = getAccounts().voteSignerToAccount(delegator); _updateDelegatedAmount(delegatorAccount); } function _updateDelegatedAmount(address delegator) private { address delegatorAccount = getAccounts().voteSignerToAccount(delegator); EnumerableSet.AddressSet storage delegatees = delegatorInfo[delegatorAccount].delegatees; for (uint256 i = 0; i < delegatees.length(); i = i.add(1)) { _updateDelegatedAmount(delegatorAccount, delegatees.get(i)); } } /** * Updates real delegated amount to delegatee. * There might be discrepancy because of validator rewards or extra locked gold. * Voting power will always be smaller or equal to what it is supposed to be. * @param delegator The delegator address. * @param delegatee The delegatee address. */ function updateDelegatedAmount(address delegator, address delegatee) public returns (uint256) { address delegatorAccount = getAccounts().voteSignerToAccount(delegator); address delegateeAccount = getAccounts().voteSignerToAccount(delegatee); return _updateDelegatedAmount(delegatorAccount, delegateeAccount); } /** * Updates real delegated amount to delegatee. * There might be discrepancy because of validator rewards or extra locked gold. * Voting power will always be smaller or equal to what it is supposed to be. * @param delegator The delegator address. * @param delegatee The delegatee address. */ function _updateDelegatedAmount(address delegator, address delegatee) internal returns (uint256) { Delegated storage delegated = delegatorInfo[delegator]; require( FixidityLib.unwrap(delegated.totalDelegatedCeloFraction) != 0, "delegator is not delegating" ); DelegatedInfo storage currentDelegateeInfo = delegated .delegateesWithPercentagesAndAmount[delegatee]; require( FixidityLib.unwrap(currentDelegateeInfo.percentage) != 0, "delegator is not delegating for delegatee" ); (uint256 expected, uint256 real) = getDelegatorDelegateeExpectedAndRealAmount( delegator, delegatee ); currentDelegateeInfo.currentAmount = expected; totalDelegatedCelo[delegatee] = totalDelegatedCelo[delegatee].sub(real).add(expected); return expected; } /** * Returns how many percents of CELO is account delegating. * @param account The account address. */ function getAccountTotalDelegatedFraction(address account) public view returns (uint256) { Delegated storage delegated = delegatorInfo[account]; return FixidityLib.unwrap(delegated.totalDelegatedCeloFraction); } /** * @notice Returns the total amount of locked gold for an account. * @param account The account. * @return The total amount of locked gold for an account. */ function getAccountTotalLockedGold(address account) public view returns (uint256) { uint256 total = balances[account].nonvoting; return total.add(getElection().getTotalVotesByAccount(account)); } /** * @notice Returns the total amount of locked gold + delegated gold for an account. * @param account The account. * @return The total amount of locked gold + delegated gold for an account. */ function getAccountTotalGovernanceVotingPower(address account) public view returns (uint256) { FixidityLib.Fraction memory availableUndelegatedPercents = FixidityLib.fixed1().subtract( FixidityLib.wrap(getAccountTotalDelegatedFraction(account)) ); uint256 totalLockedGold = getAccountTotalLockedGold(account); uint256 availableForVoting = FixidityLib .newFixed(totalLockedGold) .multiply(availableUndelegatedPercents) .fromFixed(); return availableForVoting.add(totalDelegatedCelo[account]); } /** * Return percentage and amount that delegator assigned to delegateee. * Please note that amount doesn't have to be up to date. * In such case please use `updateDelegatedBalance`. * @param delegator The delegator address. * @param delegatee The delegatee address. * @return fraction The fraction that is delegator asigning to delegatee. * @return currentAmount The current actual Celo amount that is assigned to delegatee. */ function getDelegatorDelegateeInfo(address delegator, address delegatee) external view returns (uint256 fraction, uint256 currentAmount) { DelegatedInfo storage currentDelegateeInfo = delegatorInfo[delegator] .delegateesWithPercentagesAndAmount[delegatee]; fraction = FixidityLib.unwrap(currentDelegateeInfo.percentage); currentAmount = currentDelegateeInfo.currentAmount; } /** * Returns expected vs real delegated amount. * If there is a discrepancy it can be fixed by calling `updateDelegatedAmount` function. * @param delegator The delegator address. * @param delegatee The delegatee address. * @return expected The expected amount. * @return real The real amount. */ function getDelegatorDelegateeExpectedAndRealAmount(address delegator, address delegatee) public view returns (uint256 expected, uint256 real) { address delegatorAccount = getAccounts().voteSignerToAccount(delegator); address delegateeAccount = getAccounts().voteSignerToAccount(delegatee); (expected, real) = _getDelegatorDelegateeExpectedAndRealAmount( delegatorAccount, delegateeAccount ); } /** * Returns expected vs real delegated amount. * If there is a discrepancy it can be fixed by calling `updateDelegatedAmount` function. * @param delegator The delegator address. * @param delegatee The delegatee address. * @return expected The expected amount. * @return real The real amount. */ function _getDelegatorDelegateeExpectedAndRealAmount(address delegator, address delegatee) private view returns (uint256 expected, uint256 real) { DelegatedInfo storage currentDelegateeInfo = delegatorInfo[delegator] .delegateesWithPercentagesAndAmount[delegatee]; uint256 amountToDelegate = FixidityLib .newFixed(getAccountTotalLockedGold(delegator)) .multiply(currentDelegateeInfo.percentage) .fromFixed(); expected = amountToDelegate; real = currentDelegateeInfo.currentAmount; } /** * Retuns all delegatees of delegator * @param delegator The delegator address. */ function getDelegateesOfDelegator(address delegator) public view returns (address[] memory) { address[] memory values = delegatorInfo[delegator].delegatees.enumerate(); return values; } /** * @notice Returns the total amount of non-voting locked gold for an account. * @param account The account. * @return The total amount of non-voting locked gold for an account. */ function getAccountNonvotingLockedGold(address account) external view returns (uint256) { return balances[account].nonvoting; } /** * @notice Returns the pending withdrawals from unlocked gold for an account. * @param account The address of the account. * @return The value for each pending withdrawal. * @return The timestamp for each pending withdrawal. */ function getPendingWithdrawals(address account) external view returns (uint256[] memory, uint256[] memory) { require( getAccounts().isAccount(account), "Unknown account: only registered accounts have pending withdrawals" ); uint256 length = balances[account].pendingWithdrawals.length; uint256[] memory values = new uint256[](length); uint256[] memory timestamps = new uint256[](length); for (uint256 i = 0; i < length; i = i.add(1)) { PendingWithdrawal memory pendingWithdrawal = (balances[account].pendingWithdrawals[i]); values[i] = pendingWithdrawal.value; timestamps[i] = pendingWithdrawal.timestamp; } return (values, timestamps); } /** * @notice Returns the pending withdrawal at a given index for a given account. * @param account The address of the account. * @param index The index of the pending withdrawal. * @return The value of the pending withdrawal. * @return The timestamp of the pending withdrawal. */ function getPendingWithdrawal(address account, uint256 index) external view returns (uint256, uint256) { require( getAccounts().isAccount(account), "Unknown account: only registered accounts have pending withdrawals" ); require(index < balances[account].pendingWithdrawals.length, "Bad pending withdrawal index"); PendingWithdrawal memory pendingWithdrawal = (balances[account].pendingWithdrawals[index]); return (pendingWithdrawal.value, pendingWithdrawal.timestamp); } /** * @notice Returns the number of pending withdrawals for the specified account. * @param account The address of the account. * @return The count of pending withdrawals. */ function getTotalPendingWithdrawalsCount(address account) external view returns (uint256) { return balances[account].pendingWithdrawals.length; } /** * @notice Returns the total amount to withdraw from unlocked gold for an account. * @param account The address of the account. * @return Total amount to withdraw. */ function getTotalPendingWithdrawals(address account) external view returns (uint256) { uint256 pendingWithdrawalSum = 0; PendingWithdrawal[] memory withdrawals = balances[account].pendingWithdrawals; for (uint256 i = 0; i < withdrawals.length; i = i.add(1)) { pendingWithdrawalSum = pendingWithdrawalSum.add(withdrawals[i].value); } return pendingWithdrawalSum; } function getSlashingWhitelist() external view returns (bytes32[] memory) { return slashingWhitelist; } /** * @notice Deletes a pending withdrawal. * @param list The list of pending withdrawals from which to delete. * @param index The index of the pending withdrawal to delete. */ function deletePendingWithdrawal(PendingWithdrawal[] storage list, uint256 index) private { uint256 lastIndex = list.length.sub(1); list[index] = list[lastIndex]; list.length = lastIndex; } /** * @notice Adds `slasher` to whitelist of approved slashing addresses. * @param slasherIdentifier Identifier to whitelist. */ function addSlasher(string calldata slasherIdentifier) external onlyOwner { bytes32 keyBytes = keccak256(abi.encodePacked(slasherIdentifier)); require(registry.getAddressFor(keyBytes) != address(0), "Identifier is not registered"); require(!slashingMap[keyBytes], "Cannot add slasher ID twice."); slashingWhitelist.push(keyBytes); slashingMap[keyBytes] = true; emit SlasherWhitelistAdded(slasherIdentifier); } /** * @notice Removes `slasher` from whitelist of approved slashing addresses. * @param slasherIdentifier Identifier to remove from whitelist. * @param index Index of the provided identifier in slashingWhiteList array. */ function removeSlasher(string calldata slasherIdentifier, uint256 index) external onlyOwner { bytes32 keyBytes = keccak256(abi.encodePacked(slasherIdentifier)); require(slashingMap[keyBytes], "Cannot remove slasher ID not yet added."); require(index < slashingWhitelist.length, "Provided index exceeds whitelist bounds."); require(slashingWhitelist[index] == keyBytes, "Index doesn't match identifier"); slashingWhitelist[index] = slashingWhitelist[slashingWhitelist.length - 1]; slashingWhitelist.pop(); slashingMap[keyBytes] = false; emit SlasherWhitelistRemoved(slasherIdentifier); } /** * @notice Slashes `account` by reducing its nonvoting locked gold by `penalty`. * If there is not enough nonvoting locked gold to slash, calls into * `Election.slashVotes` to slash the remaining gold. If `account` does not have * `penalty` worth of locked gold, slashes `account`'s total locked gold. * Also sends `reward` gold to the reporter, and penalty-reward to the Community Fund. * @param account Address of account being slashed. * @param penalty Amount to slash account. * @param reporter Address of account reporting the slasher. * @param reward Reward to give reporter. * @param lessers The groups receiving fewer votes than i'th group, or 0 if the i'th group has * the fewest votes of any validator group. * @param greaters The groups receiving more votes than the i'th group, or 0 if the i'th group * has the most votes of any validator group. * @param indices The indices of the i'th group in `account`'s voting list. * @dev Fails if `reward` is greater than `account`'s total locked gold. */ function slash( address account, uint256 penalty, address reporter, uint256 reward, address[] calldata lessers, address[] calldata greaters, uint256[] calldata indices ) external onlySlasher { uint256 maxSlash = Math.min(penalty, getAccountTotalLockedGold(account)); require(maxSlash >= reward, "reward cannot exceed penalty."); // `reporter` receives the reward in locked CELO, so it must be given to an account // There is no reward for slashing via the GovernanceSlasher, and `reporter` // is set to 0x0. if (reporter != address(0)) { reporter = getAccounts().signerToAccount(reporter); } // Local scoping is required to avoid Solc "stack too deep" error from too many locals. { uint256 nonvotingBalance = balances[account].nonvoting; uint256 difference = 0; // If not enough nonvoting, revoke the difference if (nonvotingBalance < maxSlash) { difference = maxSlash.sub(nonvotingBalance); require( getElection().forceDecrementVotes(account, difference, lessers, greaters, indices) == difference, "Cannot revoke enough voting gold." ); } // forceDecrementVotes does not increment nonvoting account balance, so we can't double count _decrementNonvotingAccountBalance(account, maxSlash.sub(difference)); _incrementNonvotingAccountBalance(reporter, reward); } address communityFund = registry.getAddressForOrDie(GOVERNANCE_REGISTRY_ID); address payable communityFundPayable = address(uint160(communityFund)); require(maxSlash.sub(reward) <= address(this).balance, "Inconsistent balance"); communityFundPayable.sendValue(maxSlash.sub(reward)); emit AccountSlashed(account, maxSlash, reporter, reward); } }
/openzeppelin-solidity/contracts/GSN/Context.sol
pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
/openzeppelin-solidity/contracts/cryptography/ECDSA.sol
pragma solidity ^0.5.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * NOTE: This call _does not revert_ if the signature is invalid, or * if the signer is otherwise unable to be retrieved. In those scenarios, * the zero address is returned. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { return (address(0)); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return address(0); } if (v != 27 && v != 28) { return address(0); } // If the signature is valid (and not malleable), return the signer address return ecrecover(hash, v, r, s); } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } }
/openzeppelin-solidity/contracts/math/Math.sol
pragma solidity ^0.5.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
/openzeppelin-solidity/contracts/math/SafeMath.sol
pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
/openzeppelin-solidity/contracts/ownership/Ownable.sol
pragma solidity ^0.5.0; import "../GSN/Context.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. * * 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. */ 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 () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _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 onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = 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 onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
/openzeppelin-solidity/contracts/token/ERC20/IERC20.sol
pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ 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); }
/openzeppelin-solidity/contracts/utils/Address.sol
pragma solidity ^0.5.5; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Converts an `address` into `address payable`. Note that this is * simply a type cast: the actual underlying value is not changed. * * _Available since v2.4.0._ */ function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. * * _Available since v2.4.0._ */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } }
/openzeppelin-solidity/contracts/utils/EnumerableSet.sol
pragma solidity ^0.5.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * As of v2.5.0, only `address` sets are supported. * * Include with `using EnumerableSet for EnumerableSet.AddressSet;`. * * _Available since v2.5.0._ * * @author Alberto Cuesta Cañada */ library EnumerableSet { struct AddressSet { // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping (address => uint256) index; address[] values; } /** * @dev Add a value to a set. O(1). * Returns false if the value was already in the set. */ function add(AddressSet storage set, address value) internal returns (bool) { if (!contains(set, value)){ set.index[value] = set.values.push(value); return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * Returns false if the value was not present in the set. */ function remove(AddressSet storage set, address value) internal returns (bool) { if (contains(set, value)){ uint256 toDeleteIndex = set.index[value] - 1; uint256 lastIndex = set.values.length - 1; // If the element we're deleting is the last one, we can just remove it without doing a swap if (lastIndex != toDeleteIndex) { address lastValue = set.values[lastIndex]; // Move the last value to the index where the deleted value is set.values[toDeleteIndex] = lastValue; // Update the index for the moved value set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based } // Delete the index entry for the deleted value delete set.index[value]; // Delete the old entry for the moved value set.values.pop(); return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return set.index[value] != 0; } /** * @dev Returns an array with all values in the set. O(N). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * WARNING: This function may run out of gas on large sets: use {length} and * {get} instead in these cases. */ function enumerate(AddressSet storage set) internal view returns (address[] memory) { address[] memory output = new address[](set.values.length); for (uint256 i; i < set.values.length; i++){ output[i] = set.values[i]; } return output; } /** * @dev Returns the number of elements on the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return set.values.length; } /** @dev Returns the element stored at position `index` in the set. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function get(AddressSet storage set, uint256 index) internal view returns (address) { return set.values[index]; } }
/project:/contracts/common/FixidityLib.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; /** * @title FixidityLib * @author Gadi Guy, Alberto Cuesta Canada * @notice This library provides fixed point arithmetic with protection against * overflow. * All operations are done with uint256 and the operands must have been created * with any of the newFrom* functions, which shift the comma digits() to the * right and check for limits, or with wrap() which expects a number already * in the internal representation of a fraction. * When using this library be sure to use maxNewFixed() as the upper limit for * creation of fixed point numbers. * @dev All contained functions are pure and thus marked internal to be inlined * on consuming contracts at compile time for gas efficiency. */ library FixidityLib { struct Fraction { uint256 value; } /** * @notice Number of positions that the comma is shifted to the right. */ function digits() internal pure returns (uint8) { return 24; } uint256 private constant FIXED1_UINT = 1000000000000000000000000; /** * @notice This is 1 in the fixed point units used in this library. * @dev Test fixed1() equals 10^digits() * Hardcoded to 24 digits. */ function fixed1() internal pure returns (Fraction memory) { return Fraction(FIXED1_UINT); } /** * @notice Wrap a uint256 that represents a 24-decimal fraction in a Fraction * struct. * @param x Number that already represents a 24-decimal fraction. * @return A Fraction struct with contents x. */ function wrap(uint256 x) internal pure returns (Fraction memory) { return Fraction(x); } /** * @notice Unwraps the uint256 inside of a Fraction struct. */ function unwrap(Fraction memory x) internal pure returns (uint256) { return x.value; } /** * @notice The amount of decimals lost on each multiplication operand. * @dev Test mulPrecision() equals sqrt(fixed1) */ function mulPrecision() internal pure returns (uint256) { return 1000000000000; } /** * @notice Maximum value that can be converted to fixed point. Optimize for deployment. * @dev * Test maxNewFixed() equals maxUint256() / fixed1() */ function maxNewFixed() internal pure returns (uint256) { return 115792089237316195423570985008687907853269984665640564; } /** * @notice Converts a uint256 to fixed point Fraction * @dev Test newFixed(0) returns 0 * Test newFixed(1) returns fixed1() * Test newFixed(maxNewFixed()) returns maxNewFixed() * fixed1() * Test newFixed(maxNewFixed()+1) fails */ function newFixed(uint256 x) internal pure returns (Fraction memory) { require(x <= maxNewFixed(), "can't create fixidity number larger than maxNewFixed()"); return Fraction(x * FIXED1_UINT); } /** * @notice Converts a uint256 in the fixed point representation of this * library to a non decimal. All decimal digits will be truncated. */ function fromFixed(Fraction memory x) internal pure returns (uint256) { return x.value / FIXED1_UINT; } /** * @notice Converts two uint256 representing a fraction to fixed point units, * equivalent to multiplying dividend and divisor by 10^digits(). * @param numerator numerator must be <= maxNewFixed() * @param denominator denominator must be <= maxNewFixed() and denominator can't be 0 * @dev * Test newFixedFraction(1,0) fails * Test newFixedFraction(0,1) returns 0 * Test newFixedFraction(1,1) returns fixed1() * Test newFixedFraction(1,fixed1()) returns 1 */ function newFixedFraction(uint256 numerator, uint256 denominator) internal pure returns (Fraction memory) { Fraction memory convertedNumerator = newFixed(numerator); Fraction memory convertedDenominator = newFixed(denominator); return divide(convertedNumerator, convertedDenominator); } /** * @notice Returns the integer part of a fixed point number. * @dev * Test integer(0) returns 0 * Test integer(fixed1()) returns fixed1() * Test integer(newFixed(maxNewFixed())) returns maxNewFixed()*fixed1() */ function integer(Fraction memory x) internal pure returns (Fraction memory) { return Fraction((x.value / FIXED1_UINT) * FIXED1_UINT); // Can't overflow } /** * @notice Returns the fractional part of a fixed point number. * In the case of a negative number the fractional is also negative. * @dev * Test fractional(0) returns 0 * Test fractional(fixed1()) returns 0 * Test fractional(fixed1()-1) returns 10^24-1 */ function fractional(Fraction memory x) internal pure returns (Fraction memory) { return Fraction(x.value - (x.value / FIXED1_UINT) * FIXED1_UINT); // Can't overflow } /** * @notice x+y. * @dev The maximum value that can be safely used as an addition operator is defined as * maxFixedAdd = maxUint256()-1 / 2, or * 57896044618658097711785492504343953926634992332820282019728792003956564819967. * Test add(maxFixedAdd,maxFixedAdd) equals maxFixedAdd + maxFixedAdd * Test add(maxFixedAdd+1,maxFixedAdd+1) throws */ function add(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) { uint256 z = x.value + y.value; require(z >= x.value, "add overflow detected"); return Fraction(z); } /** * @notice x-y. * @dev * Test subtract(6, 10) fails */ function subtract(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) { require(x.value >= y.value, "substraction underflow detected"); return Fraction(x.value - y.value); } /** * @notice x*y. If any of the operators is higher than the max multiplier value it * might overflow. * @dev The maximum value that can be safely used as a multiplication operator * (maxFixedMul) is calculated as sqrt(maxUint256()*fixed1()), * or 340282366920938463463374607431768211455999999999999 * Test multiply(0,0) returns 0 * Test multiply(maxFixedMul,0) returns 0 * Test multiply(0,maxFixedMul) returns 0 * Test multiply(fixed1()/mulPrecision(),fixed1()*mulPrecision()) returns fixed1() * Test multiply(maxFixedMul,maxFixedMul) is around maxUint256() * Test multiply(maxFixedMul+1,maxFixedMul+1) fails */ function multiply(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) { if (x.value == 0 || y.value == 0) return Fraction(0); if (y.value == FIXED1_UINT) return x; if (x.value == FIXED1_UINT) return y; // Separate into integer and fractional parts // x = x1 + x2, y = y1 + y2 uint256 x1 = integer(x).value / FIXED1_UINT; uint256 x2 = fractional(x).value; uint256 y1 = integer(y).value / FIXED1_UINT; uint256 y2 = fractional(y).value; // (x1 + x2) * (y1 + y2) = (x1 * y1) + (x1 * y2) + (x2 * y1) + (x2 * y2) uint256 x1y1 = x1 * y1; if (x1 != 0) require(x1y1 / x1 == y1, "overflow x1y1 detected"); // x1y1 needs to be multiplied back by fixed1 // solium-disable-next-line mixedcase uint256 fixed_x1y1 = x1y1 * FIXED1_UINT; if (x1y1 != 0) require(fixed_x1y1 / x1y1 == FIXED1_UINT, "overflow x1y1 * fixed1 detected"); x1y1 = fixed_x1y1; uint256 x2y1 = x2 * y1; if (x2 != 0) require(x2y1 / x2 == y1, "overflow x2y1 detected"); uint256 x1y2 = x1 * y2; if (x1 != 0) require(x1y2 / x1 == y2, "overflow x1y2 detected"); x2 = x2 / mulPrecision(); y2 = y2 / mulPrecision(); uint256 x2y2 = x2 * y2; if (x2 != 0) require(x2y2 / x2 == y2, "overflow x2y2 detected"); // result = fixed1() * x1 * y1 + x1 * y2 + x2 * y1 + x2 * y2 / fixed1(); Fraction memory result = Fraction(x1y1); result = add(result, Fraction(x2y1)); // Add checks for overflow result = add(result, Fraction(x1y2)); // Add checks for overflow result = add(result, Fraction(x2y2)); // Add checks for overflow return result; } /** * @notice 1/x * @dev * Test reciprocal(0) fails * Test reciprocal(fixed1()) returns fixed1() * Test reciprocal(fixed1()*fixed1()) returns 1 // Testing how the fractional is truncated * Test reciprocal(1+fixed1()*fixed1()) returns 0 // Testing how the fractional is truncated * Test reciprocal(newFixedFraction(1, 1e24)) returns newFixed(1e24) */ function reciprocal(Fraction memory x) internal pure returns (Fraction memory) { require(x.value != 0, "can't call reciprocal(0)"); return Fraction((FIXED1_UINT * FIXED1_UINT) / x.value); // Can't overflow } /** * @notice x/y. If the dividend is higher than the max dividend value, it * might overflow. You can use multiply(x,reciprocal(y)) instead. * @dev The maximum value that can be safely used as a dividend (maxNewFixed) is defined as * divide(maxNewFixed,newFixedFraction(1,fixed1())) is around maxUint256(). * This yields the value 115792089237316195423570985008687907853269984665640564. * Test maxNewFixed equals maxUint256()/fixed1() * Test divide(maxNewFixed,1) equals maxNewFixed*(fixed1) * Test divide(maxNewFixed+1,multiply(mulPrecision(),mulPrecision())) throws * Test divide(fixed1(),0) fails * Test divide(maxNewFixed,1) = maxNewFixed*(10^digits()) * Test divide(maxNewFixed+1,1) throws */ function divide(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) { require(y.value != 0, "can't divide by 0"); uint256 X = x.value * FIXED1_UINT; require(X / FIXED1_UINT == x.value, "overflow at divide"); return Fraction(X / y.value); } /** * @notice x > y */ function gt(Fraction memory x, Fraction memory y) internal pure returns (bool) { return x.value > y.value; } /** * @notice x >= y */ function gte(Fraction memory x, Fraction memory y) internal pure returns (bool) { return x.value >= y.value; } /** * @notice x < y */ function lt(Fraction memory x, Fraction memory y) internal pure returns (bool) { return x.value < y.value; } /** * @notice x <= y */ function lte(Fraction memory x, Fraction memory y) internal pure returns (bool) { return x.value <= y.value; } /** * @notice x == y */ function equals(Fraction memory x, Fraction memory y) internal pure returns (bool) { return x.value == y.value; } /** * @notice x <= 1 */ function isProperFraction(Fraction memory x) internal pure returns (bool) { return lte(x, fixed1()); } }
/project:/contracts/common/Initializable.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; contract Initializable { bool public initialized; constructor(bool testingDeployment) public { if (!testingDeployment) { initialized = true; } } modifier initializer() { require(!initialized, "contract already initialized"); initialized = true; _; } }
/project:/contracts/common/Signatures.sol
pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/cryptography/ECDSA.sol"; library Signatures { /** * @notice Given a signed address, returns the signer of the address. * @param message The address that was signed. * @param v The recovery id of the incoming ECDSA signature. * @param r Output value r of the ECDSA signature. * @param s Output value s of the ECDSA signature. */ function getSignerOfAddress(address message, uint8 v, bytes32 r, bytes32 s) public pure returns (address) { bytes32 hash = keccak256(abi.encodePacked(message)); return getSignerOfMessageHash(hash, v, r, s); } /** * @notice Given a message hash, returns the signer of the address. * @param messageHash The hash of a message. * @param v The recovery id of the incoming ECDSA signature. * @param r Output value r of the ECDSA signature. * @param s Output value s of the ECDSA signature. */ function getSignerOfMessageHash(bytes32 messageHash, uint8 v, bytes32 r, bytes32 s) public pure returns (address) { bytes memory signature = new bytes(65); // Concatenate (r, s, v) into signature. assembly { mstore(add(signature, 32), r) mstore(add(signature, 64), s) mstore8(add(signature, 96), v) } bytes32 prefixedHash = ECDSA.toEthSignedMessageHash(messageHash); return ECDSA.recover(prefixedHash, signature); } /** * @notice Given a domain separator and a structHash, construct the typed data hash * @param eip712DomainSeparator Context specific domain separator * @param structHash hash of the typed data struct * @return The EIP712 typed data hash */ function toEthSignedTypedDataHash(bytes32 eip712DomainSeparator, bytes32 structHash) public pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", eip712DomainSeparator, structHash)); } /** * @notice Given a domain separator and a structHash and a signature return the signer * @param eip712DomainSeparator Context specific domain separator * @param structHash hash of the typed data struct * @param v The recovery id of the incoming ECDSA signature. * @param r Output value r of the ECDSA signature. * @param s Output value s of the ECDSA signature. */ function getSignerOfTypedDataHash( bytes32 eip712DomainSeparator, bytes32 structHash, uint8 v, bytes32 r, bytes32 s ) public pure returns (address) { bytes memory signature = new bytes(65); // Concatenate (r, s, v) into signature. assembly { mstore(add(signature, 32), r) mstore(add(signature, 64), s) mstore8(add(signature, 96), v) } bytes32 prefixedHash = toEthSignedTypedDataHash(eip712DomainSeparator, structHash); return ECDSA.recover(prefixedHash, signature); } }
/project:/contracts/common/UsingRegistry.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; import "./interfaces/IAccounts.sol"; import "./interfaces/IFeeCurrencyWhitelist.sol"; import "./interfaces/IFreezer.sol"; import "./interfaces/IRegistry.sol"; import "../governance/interfaces/IElection.sol"; import "../governance/interfaces/IGovernance.sol"; import "../governance/interfaces/ILockedGold.sol"; import "../governance/interfaces/IValidators.sol"; import "../identity/interfaces/IRandom.sol"; import "../identity/interfaces/IAttestations.sol"; import "../../lib/mento-core/contracts/interfaces/IExchange.sol"; import "../../lib/mento-core/contracts/interfaces/IReserve.sol"; import "../../lib/mento-core/contracts/interfaces/IStableToken.sol"; import "../stability/interfaces/ISortedOracles.sol"; contract UsingRegistry is Ownable { event RegistrySet(address indexed registryAddress); // solhint-disable state-visibility bytes32 constant ACCOUNTS_REGISTRY_ID = keccak256(abi.encodePacked("Accounts")); bytes32 constant ATTESTATIONS_REGISTRY_ID = keccak256(abi.encodePacked("Attestations")); bytes32 constant DOWNTIME_SLASHER_REGISTRY_ID = keccak256(abi.encodePacked("DowntimeSlasher")); bytes32 constant DOUBLE_SIGNING_SLASHER_REGISTRY_ID = keccak256( abi.encodePacked("DoubleSigningSlasher") ); bytes32 constant ELECTION_REGISTRY_ID = keccak256(abi.encodePacked("Election")); bytes32 constant EXCHANGE_REGISTRY_ID = keccak256(abi.encodePacked("Exchange")); bytes32 constant FEE_CURRENCY_WHITELIST_REGISTRY_ID = keccak256( abi.encodePacked("FeeCurrencyWhitelist") ); bytes32 constant FREEZER_REGISTRY_ID = keccak256(abi.encodePacked("Freezer")); bytes32 constant GOLD_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("GoldToken")); bytes32 constant GOVERNANCE_REGISTRY_ID = keccak256(abi.encodePacked("Governance")); bytes32 constant GOVERNANCE_SLASHER_REGISTRY_ID = keccak256( abi.encodePacked("GovernanceSlasher") ); bytes32 constant LOCKED_GOLD_REGISTRY_ID = keccak256(abi.encodePacked("LockedGold")); bytes32 constant RESERVE_REGISTRY_ID = keccak256(abi.encodePacked("Reserve")); bytes32 constant RANDOM_REGISTRY_ID = keccak256(abi.encodePacked("Random")); bytes32 constant SORTED_ORACLES_REGISTRY_ID = keccak256(abi.encodePacked("SortedOracles")); bytes32 constant STABLE_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("StableToken")); bytes32 constant VALIDATORS_REGISTRY_ID = keccak256(abi.encodePacked("Validators")); // solhint-enable state-visibility IRegistry public registry; modifier onlyRegisteredContract(bytes32 identifierHash) { require(registry.getAddressForOrDie(identifierHash) == msg.sender, "only registered contract"); _; } modifier onlyRegisteredContracts(bytes32[] memory identifierHashes) { require(registry.isOneOf(identifierHashes, msg.sender), "only registered contracts"); _; } /** * @notice Updates the address pointing to a Registry contract. * @param registryAddress The address of a registry contract for routing to other contracts. */ function setRegistry(address registryAddress) public onlyOwner { require(registryAddress != address(0), "Cannot register the null address"); registry = IRegistry(registryAddress); emit RegistrySet(registryAddress); } function getAccounts() internal view returns (IAccounts) { return IAccounts(registry.getAddressForOrDie(ACCOUNTS_REGISTRY_ID)); } function getAttestations() internal view returns (IAttestations) { return IAttestations(registry.getAddressForOrDie(ATTESTATIONS_REGISTRY_ID)); } function getElection() internal view returns (IElection) { return IElection(registry.getAddressForOrDie(ELECTION_REGISTRY_ID)); } function getExchange() internal view returns (IExchange) { return IExchange(registry.getAddressForOrDie(EXCHANGE_REGISTRY_ID)); } function getFeeCurrencyWhitelistRegistry() internal view returns (IFeeCurrencyWhitelist) { return IFeeCurrencyWhitelist(registry.getAddressForOrDie(FEE_CURRENCY_WHITELIST_REGISTRY_ID)); } function getFreezer() internal view returns (IFreezer) { return IFreezer(registry.getAddressForOrDie(FREEZER_REGISTRY_ID)); } function getGoldToken() internal view returns (IERC20) { return IERC20(registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID)); } function getGovernance() internal view returns (IGovernance) { return IGovernance(registry.getAddressForOrDie(GOVERNANCE_REGISTRY_ID)); } function getLockedGold() internal view returns (ILockedGold) { return ILockedGold(registry.getAddressForOrDie(LOCKED_GOLD_REGISTRY_ID)); } function getRandom() internal view returns (IRandom) { return IRandom(registry.getAddressForOrDie(RANDOM_REGISTRY_ID)); } function getReserve() internal view returns (IReserve) { return IReserve(registry.getAddressForOrDie(RESERVE_REGISTRY_ID)); } function getSortedOracles() internal view returns (ISortedOracles) { return ISortedOracles(registry.getAddressForOrDie(SORTED_ORACLES_REGISTRY_ID)); } function getStableToken() internal view returns (IStableToken) { return IStableToken(registry.getAddressForOrDie(STABLE_TOKEN_REGISTRY_ID)); } function getValidators() internal view returns (IValidators) { return IValidators(registry.getAddressForOrDie(VALIDATORS_REGISTRY_ID)); } }
/project:/contracts/common/interfaces/IAccounts.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface IAccounts { function isAccount(address) external view returns (bool); function voteSignerToAccount(address) external view returns (address); function validatorSignerToAccount(address) external view returns (address); function attestationSignerToAccount(address) external view returns (address); function signerToAccount(address) external view returns (address); function getAttestationSigner(address) external view returns (address); function getValidatorSigner(address) external view returns (address); function getVoteSigner(address) external view returns (address); function hasAuthorizedVoteSigner(address) external view returns (bool); function hasAuthorizedValidatorSigner(address) external view returns (bool); function hasAuthorizedAttestationSigner(address) external view returns (bool); function setAccountDataEncryptionKey(bytes calldata) external; function setMetadataURL(string calldata) external; function setName(string calldata) external; function setWalletAddress(address, uint8, bytes32, bytes32) external; function setAccount(string calldata, bytes calldata, address, uint8, bytes32, bytes32) external; function getDataEncryptionKey(address) external view returns (bytes memory); function getWalletAddress(address) external view returns (address); function getMetadataURL(address) external view returns (string memory); function batchGetMetadataURL(address[] calldata) external view returns (uint256[] memory, bytes memory); function getName(address) external view returns (string memory); function authorizeVoteSigner(address, uint8, bytes32, bytes32) external; function authorizeValidatorSigner(address, uint8, bytes32, bytes32) external; function authorizeValidatorSignerWithPublicKey(address, uint8, bytes32, bytes32, bytes calldata) external; function authorizeValidatorSignerWithKeys( address, uint8, bytes32, bytes32, bytes calldata, bytes calldata, bytes calldata ) external; function authorizeAttestationSigner(address, uint8, bytes32, bytes32) external; function createAccount() external returns (bool); function setPaymentDelegation(address, uint256) external; function getPaymentDelegation(address) external view returns (address, uint256); function isSigner(address, address, bytes32) external view returns (bool); }
/project:/contracts/common/interfaces/ICeloVersionedContract.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface ICeloVersionedContract { /** * @notice Returns the storage, major, minor, and patch version of the contract. * @return Storage version of the contract. * @return Major version of the contract. * @return Minor version of the contract. * @return Patch version of the contract. */ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256); }
/project:/contracts/common/interfaces/IFeeCurrencyWhitelist.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface IFeeCurrencyWhitelist { function addToken(address) external; function getWhitelist() external view returns (address[] memory); }
/project:/contracts/common/interfaces/IFreezer.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface IFreezer { function isFrozen(address) external view returns (bool); }
/project:/contracts/common/interfaces/IRegistry.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface IRegistry { function setAddressFor(string calldata, address) external; function getAddressForOrDie(bytes32) external view returns (address); function getAddressFor(bytes32) external view returns (address); function getAddressForStringOrDie(string calldata identifier) external view returns (address); function getAddressForString(string calldata identifier) external view returns (address); function isOneOf(bytes32[] calldata, address) external view returns (bool); }
/project:/contracts/common/libraries/ReentrancyGuard.sol
pragma solidity ^0.5.13; /** * @title Helps contracts guard against reentrancy attacks. * @author Remco Bloemen <remco@2π.com>, Eenae <alexey@mixbytes.io> * @dev If you mark a function `nonReentrant`, you should also * mark it `external`. */ contract ReentrancyGuard { /// @dev counter to allow mutex lock with only one SSTORE operation uint256 private _guardCounter; constructor() internal { // The counter starts at one to prevent changing it from zero to a non-zero // value, which is a more expensive operation. _guardCounter = 1; } /** * @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 make it call a * `private` function that does the actual work. */ modifier nonReentrant() { _guardCounter += 1; uint256 localCounter = _guardCounter; _; require(localCounter == _guardCounter, "reentrant call"); } }
/project:/contracts/governance/interfaces/IElection.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface IElection { function electValidatorSigners() external view returns (address[] memory); function electNValidatorSigners(uint256, uint256) external view returns (address[] memory); function vote(address, uint256, address, address) external returns (bool); function activate(address) external returns (bool); function revokeActive(address, uint256, address, address, uint256) external returns (bool); function revokeAllActive(address, address, address, uint256) external returns (bool); function revokePending(address, uint256, address, address, uint256) external returns (bool); function markGroupIneligible(address) external; function markGroupEligible(address, address, address) external; function allowedToVoteOverMaxNumberOfGroups(address) external returns (bool); function forceDecrementVotes( address, uint256, address[] calldata, address[] calldata, uint256[] calldata ) external returns (uint256); function setAllowedToVoteOverMaxNumberOfGroups(bool flag) external; // view functions function getElectableValidators() external view returns (uint256, uint256); function getElectabilityThreshold() external view returns (uint256); function getNumVotesReceivable(address) external view returns (uint256); function getTotalVotes() external view returns (uint256); function getActiveVotes() external view returns (uint256); function getTotalVotesByAccount(address) external view returns (uint256); function getPendingVotesForGroupByAccount(address, address) external view returns (uint256); function getActiveVotesForGroupByAccount(address, address) external view returns (uint256); function getTotalVotesForGroupByAccount(address, address) external view returns (uint256); function getActiveVoteUnitsForGroupByAccount(address, address) external view returns (uint256); function getTotalVotesForGroup(address) external view returns (uint256); function getActiveVotesForGroup(address) external view returns (uint256); function getPendingVotesForGroup(address) external view returns (uint256); function getGroupEligibility(address) external view returns (bool); function getGroupEpochRewards(address, uint256, uint256[] calldata) external view returns (uint256); function getGroupsVotedForByAccount(address) external view returns (address[] memory); function getEligibleValidatorGroups() external view returns (address[] memory); function getTotalVotesForEligibleValidatorGroups() external view returns (address[] memory, uint256[] memory); function getCurrentValidatorSigners() external view returns (address[] memory); function canReceiveVotes(address, uint256) external view returns (bool); function hasActivatablePendingVotes(address, address) external view returns (bool); function validatorSignerAddressFromCurrentSet(uint256 index) external view returns (address); function numberValidatorsInCurrentSet() external view returns (uint256); // only owner function setElectableValidators(uint256, uint256) external returns (bool); function setMaxNumGroupsVotedFor(uint256) external returns (bool); function setElectabilityThreshold(uint256) external returns (bool); // only VM function distributeEpochRewards(address, uint256, address, address) external; }
/project:/contracts/governance/interfaces/IGovernance.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface IGovernance { function removeVotesWhenRevokingDelegatedVotes(address account, uint256 maxAmountAllowed) external; function votePartially( uint256 proposalId, uint256 index, uint256 yesVotes, uint256 noVotes, uint256 abstainVotes ) external returns (bool); function isVoting(address) external view returns (bool); function getAmountOfGoldUsedForVoting(address account) external view returns (uint256); function getProposal(uint256 proposalId) external view returns (address, uint256, uint256, uint256, string memory, uint256, bool); function getReferendumStageDuration() external view returns (uint256); }
/project:/contracts/governance/interfaces/ILockedGold.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface ILockedGold { function lock() external payable; function incrementNonvotingAccountBalance(address, uint256) external; function decrementNonvotingAccountBalance(address, uint256) external; function getAccountTotalLockedGold(address) external view returns (uint256); function getTotalLockedGold() external view returns (uint256); function getPendingWithdrawals(address) external view returns (uint256[] memory, uint256[] memory); function getPendingWithdrawal(address account, uint256 index) external view returns (uint256, uint256); function getTotalPendingWithdrawals(address) external view returns (uint256); function unlock(uint256) external; function relock(uint256, uint256) external; function withdraw(uint256) external; function slash( address account, uint256 penalty, address reporter, uint256 reward, address[] calldata lessers, address[] calldata greaters, uint256[] calldata indices ) external; function isSlasher(address) external view returns (bool); function getAccountTotalDelegatedFraction(address account) external view returns (uint256); function getAccountTotalGovernanceVotingPower(address account) external view returns (uint256); function unlockingPeriod() external view returns (uint256); function getAccountNonvotingLockedGold(address account) external view returns (uint256); }
/project:/contracts/governance/interfaces/IValidators.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface IValidators { function registerValidator(bytes calldata, bytes calldata, bytes calldata) external returns (bool); function deregisterValidator(uint256) external returns (bool); function affiliate(address) external returns (bool); function deaffiliate() external returns (bool); function updateBlsPublicKey(bytes calldata, bytes calldata) external returns (bool); function registerValidatorGroup(uint256) external returns (bool); function deregisterValidatorGroup(uint256) external returns (bool); function addMember(address) external returns (bool); function addFirstMember(address, address, address) external returns (bool); function removeMember(address) external returns (bool); function reorderMember(address, address, address) external returns (bool); function updateCommission() external; function setNextCommissionUpdate(uint256) external; function resetSlashingMultiplier() external; // only owner function setCommissionUpdateDelay(uint256) external; function setMaxGroupSize(uint256) external returns (bool); function setMembershipHistoryLength(uint256) external returns (bool); function setValidatorScoreParameters(uint256, uint256) external returns (bool); function setGroupLockedGoldRequirements(uint256, uint256) external returns (bool); function setValidatorLockedGoldRequirements(uint256, uint256) external returns (bool); function setSlashingMultiplierResetPeriod(uint256) external; // view functions function getMaxGroupSize() external view returns (uint256); function getCommissionUpdateDelay() external view returns (uint256); function getValidatorScoreParameters() external view returns (uint256, uint256); function getMembershipHistory(address) external view returns (uint256[] memory, address[] memory, uint256, uint256); function calculateEpochScore(uint256) external view returns (uint256); function calculateGroupEpochScore(uint256[] calldata) external view returns (uint256); function getAccountLockedGoldRequirement(address) external view returns (uint256); function meetsAccountLockedGoldRequirements(address) external view returns (bool); function getValidatorBlsPublicKeyFromSigner(address) external view returns (bytes memory); function getValidator(address account) external view returns (bytes memory, bytes memory, address, uint256, address); function getValidatorGroup(address) external view returns (address[] memory, uint256, uint256, uint256, uint256[] memory, uint256, uint256); function getGroupNumMembers(address) external view returns (uint256); function getTopGroupValidators(address, uint256) external view returns (address[] memory); function getGroupsNumMembers(address[] calldata accounts) external view returns (uint256[] memory); function getNumRegisteredValidators() external view returns (uint256); function groupMembershipInEpoch(address, uint256, uint256) external view returns (address); // only registered contract function updateEcdsaPublicKey(address, address, bytes calldata) external returns (bool); function updatePublicKeys(address, address, bytes calldata, bytes calldata, bytes calldata) external returns (bool); function getValidatorLockedGoldRequirements() external view returns (uint256, uint256); function getGroupLockedGoldRequirements() external view returns (uint256, uint256); function getRegisteredValidators() external view returns (address[] memory); function getRegisteredValidatorSigners() external view returns (address[] memory); function getRegisteredValidatorGroups() external view returns (address[] memory); function isValidatorGroup(address) external view returns (bool); function isValidator(address) external view returns (bool); function getValidatorGroupSlashingMultiplier(address) external view returns (uint256); function getMembershipInLastEpoch(address) external view returns (address); function getMembershipInLastEpochFromSigner(address) external view returns (address); // only VM function updateValidatorScoreFromSigner(address, uint256) external; function distributeEpochPaymentsFromSigner(address, uint256) external returns (uint256); // only slasher function forceDeaffiliateIfValidator(address) external; function halveSlashingMultiplier(address) external; }
/project:/contracts/identity/interfaces/IAttestations.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface IAttestations { function revoke(bytes32, uint256) external; function withdraw(address) external; // view functions function getUnselectedRequest(bytes32, address) external view returns (uint32, uint32, address); function getAttestationIssuers(bytes32, address) external view returns (address[] memory); function getAttestationStats(bytes32, address) external view returns (uint32, uint32); function batchGetAttestationStats(bytes32[] calldata) external view returns (uint256[] memory, address[] memory, uint64[] memory, uint64[] memory); function getAttestationState(bytes32, address, address) external view returns (uint8, uint32, address); function getCompletableAttestations(bytes32, address) external view returns (uint32[] memory, address[] memory, uint256[] memory, bytes memory); function getAttestationRequestFee(address) external view returns (uint256); function getMaxAttestations() external view returns (uint256); function validateAttestationCode(bytes32, address, uint8, bytes32, bytes32) external view returns (address); function lookupAccountsForIdentifier(bytes32) external view returns (address[] memory); function requireNAttestationsRequested(bytes32, address, uint32) external view; // only owner function setAttestationRequestFee(address, uint256) external; function setAttestationExpiryBlocks(uint256) external; function setSelectIssuersWaitBlocks(uint256) external; function setMaxAttestations(uint256) external; }
/project:/contracts/identity/interfaces/IRandom.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface IRandom { function revealAndCommit(bytes32, bytes32, address) external; function randomnessBlockRetentionWindow() external view returns (uint256); function random() external view returns (bytes32); function getBlockRandomness(uint256) external view returns (bytes32); }
/project:/contracts/stability/interfaces/ISortedOracles.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.5.13 <0.9.0; interface ISortedOracles { function addOracle(address, address) external; function removeOracle(address, address, uint256) external; function report(address, uint256, address, address) external; function removeExpiredReports(address, uint256) external; function isOldestReportExpired(address token) external view returns (bool, address); function numRates(address) external view returns (uint256); function medianRate(address) external view returns (uint256, uint256); function numTimestamps(address) external view returns (uint256); function medianTimestamp(address) external view returns (uint256); }
/project:/lib/mento-core/contracts/interfaces/IExchange.sol
pragma solidity ^0.5.13; interface IExchange { function buy( uint256, uint256, bool ) external returns (uint256); function sell( uint256, uint256, bool ) external returns (uint256); function exchange( uint256, uint256, bool ) external returns (uint256); function setUpdateFrequency(uint256) external; function getBuyTokenAmount(uint256, bool) external view returns (uint256); function getSellTokenAmount(uint256, bool) external view returns (uint256); function getBuyAndSellBuckets(bool) external view returns (uint256, uint256); }
/project:/lib/mento-core/contracts/interfaces/IReserve.sol
pragma solidity ^0.5.13; interface IReserve { function setTobinTaxStalenessThreshold(uint256) external; function addToken(address) external returns (bool); function removeToken(address, uint256) external returns (bool); function transferGold(address payable, uint256) external returns (bool); function transferExchangeGold(address payable, uint256) external returns (bool); function getReserveGoldBalance() external view returns (uint256); function getUnfrozenReserveGoldBalance() external view returns (uint256); function getOrComputeTobinTax() external returns (uint256, uint256); function getTokens() external view returns (address[] memory); function getReserveRatio() external view returns (uint256); function addExchangeSpender(address) external; function removeExchangeSpender(address, uint256) external; function addSpender(address) external; function removeSpender(address) external; }
/project:/lib/mento-core/contracts/interfaces/IStableToken.sol
pragma solidity ^0.5.13; /** * @title This interface describes the functions specific to Celo Stable Tokens, and in the * absence of interface inheritance is intended as a companion to IERC20.sol and ICeloToken.sol. */ interface IStableToken { function mint(address, uint256) external returns (bool); function burn(uint256) external returns (bool); function setInflationParameters(uint256, uint256) external; function valueToUnits(uint256) external view returns (uint256); function unitsToValue(uint256) external view returns (uint256); function getInflationParameters() external view returns ( uint256, uint256, uint256, uint256 ); // NOTE: duplicated with IERC20.sol, remove once interface inheritance is supported. function balanceOf(address) external view returns (uint256); }
Compiler Settings
{"remappings":[],"optimizer":{"runs":200,"enabled":false},"metadata":{"useLiteralContent":true},"libraries":{},"evmVersion":"istanbul","compilationTarget":{"project:/contracts/governance/LockedGold.sol":"LockedGold"}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[{"type":"bool","name":"test","internalType":"bool"}]},{"type":"event","name":"AccountSlashed","inputs":[{"type":"address","name":"slashed","internalType":"address","indexed":true},{"type":"uint256","name":"penalty","internalType":"uint256","indexed":false},{"type":"address","name":"reporter","internalType":"address","indexed":true},{"type":"uint256","name":"reward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CeloDelegated","inputs":[{"type":"address","name":"delegator","internalType":"address","indexed":true},{"type":"address","name":"delegatee","internalType":"address","indexed":true},{"type":"uint256","name":"percent","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DelegatedCeloRevoked","inputs":[{"type":"address","name":"delegator","internalType":"address","indexed":true},{"type":"address","name":"delegatee","internalType":"address","indexed":true},{"type":"uint256","name":"percent","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GoldLocked","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GoldRelocked","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GoldUnlocked","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"uint256","name":"available","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GoldWithdrawn","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MaxDelegateesCountSet","inputs":[{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"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":"RegistrySet","inputs":[{"type":"address","name":"registryAddress","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SlasherWhitelistAdded","inputs":[{"type":"string","name":"slasherIdentifier","internalType":"string","indexed":true}],"anonymous":false},{"type":"event","name":"SlasherWhitelistRemoved","inputs":[{"type":"string","name":"slasherIdentifier","internalType":"string","indexed":true}],"anonymous":false},{"type":"event","name":"UnlockingPeriodSet","inputs":[{"type":"uint256","name":"period","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addSlasher","inputs":[{"type":"string","name":"slasherIdentifier","internalType":"string"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"decrementNonvotingAccountBalance","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"delegateGovernanceVotes","inputs":[{"type":"address","name":"delegatee","internalType":"address"},{"type":"uint256","name":"delegateFraction","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAccountNonvotingLockedGold","inputs":[{"type":"address","name":"account","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAccountTotalDelegatedFraction","inputs":[{"type":"address","name":"account","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAccountTotalGovernanceVotingPower","inputs":[{"type":"address","name":"account","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAccountTotalLockedGold","inputs":[{"type":"address","name":"account","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getDelegateesOfDelegator","inputs":[{"type":"address","name":"delegator","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"expected","internalType":"uint256"},{"type":"uint256","name":"real","internalType":"uint256"}],"name":"getDelegatorDelegateeExpectedAndRealAmount","inputs":[{"type":"address","name":"delegator","internalType":"address"},{"type":"address","name":"delegatee","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"fraction","internalType":"uint256"},{"type":"uint256","name":"currentAmount","internalType":"uint256"}],"name":"getDelegatorDelegateeInfo","inputs":[{"type":"address","name":"delegator","internalType":"address"},{"type":"address","name":"delegatee","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getNonvotingLockedGold","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPendingWithdrawal","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"index","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"},{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getPendingWithdrawals","inputs":[{"type":"address","name":"account","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32[]","name":"","internalType":"bytes32[]"}],"name":"getSlashingWhitelist","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalLockedGold","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalPendingWithdrawals","inputs":[{"type":"address","name":"account","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalPendingWithdrawalsCount","inputs":[{"type":"address","name":"account","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getVersionNumber","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"incrementNonvotingAccountBalance","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"address","name":"registryAddress","internalType":"address"},{"type":"uint256","name":"_unlockingPeriod","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"initialized","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isOwner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isSlasher","inputs":[{"type":"address","name":"slasher","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"payable","payable":true,"outputs":[],"name":"lock","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"contract IRegistry"}],"name":"registry","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"relock","inputs":[{"type":"uint256","name":"index","internalType":"uint256"},{"type":"uint256","name":"value","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeSlasher","inputs":[{"type":"string","name":"slasherIdentifier","internalType":"string"},{"type":"uint256","name":"index","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"revokeDelegatedGovernanceVotes","inputs":[{"type":"address","name":"delegatee","internalType":"address"},{"type":"uint256","name":"revokeFraction","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setMaxDelegateesCount","inputs":[{"type":"uint256","name":"value","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setRegistry","inputs":[{"type":"address","name":"registryAddress","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setUnlockingPeriod","inputs":[{"type":"uint256","name":"value","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"slash","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"penalty","internalType":"uint256"},{"type":"address","name":"reporter","internalType":"address"},{"type":"uint256","name":"reward","internalType":"uint256"},{"type":"address[]","name":"lessers","internalType":"address[]"},{"type":"address[]","name":"greaters","internalType":"address[]"},{"type":"uint256[]","name":"indices","internalType":"uint256[]"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"slashingWhitelist","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalDelegatedCelo","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalNonvoting","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"unlock","inputs":[{"type":"uint256","name":"value","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"unlockingPeriod","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"updateDelegatedAmount","inputs":[{"type":"address","name":"delegator","internalType":"address"},{"type":"address","name":"delegatee","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateDelegatedAmount","inputs":[{"type":"address","name":"delegator","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"withdraw","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}],"constant":false}]
Contract Creation Code
0x60806040523480156200001157600080fd5b50604051620081e6380380620081e6833981810160405260208110156200003757600080fd5b810190808051906020019092919050505080600160008190555080620000725760018060006101000a81548160ff0219169083151502179055505b506000620000856200012a60201b60201c565b9050806001806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3505062000132565b600033905090565b6180a480620001426000396000f3fe60806040526004361061025c5760003560e01c80636489119811610144578063b2fb30cb116100b6578063cd6dc6871161007a578063cd6dc68714611022578063d15ca4ed1461107d578063f24b39fc146110f3578063f2fde38b14611144578063f340c0d014611195578063f83d08ba146112835761025c565b8063b2fb30cb14610e83578063b6e1e49d14610ec8578063c1867f6d14610f2d578063c70f35ea14610f58578063c95b241b14610fbd5761025c565b80637b103999116101085780637b10399914610c84578063807876b714610cdb5780638a9c2bbe14610d065780638da5cb5b14610dac5780638f32d59b14610e03578063a91ee0dc14610e325761025c565b80636489119814610b0257806366f0633b14610b885780636adcc93814610bc35780636edf77a514610c12578063715018a614610c6d5761025c565b8063296673a9116101dd5780633f199b40116101a15780633f199b40146108f957806354255be01461095e57806357601c5d1461099e57806358f84a7814610a075780636198e33914610a6257806361d5c57014610a9d5761025c565b8063296673a91461061e5780632e1a7d4d146106aa57806330a61d59146106e557806330ec70f51461071057806331993fc9146107755761025c565b806318a4ff8c1161022457806318a4ff8c146104485780631d1dd1a7146104a35780631fe2dfda146104de57806320637d8e1461056e578063227320a7146105995761025c565b806308764ee2146102615780630cdbac28146102cd578063158ef93e1461035957806315952ae71461038857806318629a92146103ed575b600080fd5b34801561026d57600080fd5b5061027661128d565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156102b957808201518184015260208101905061029e565b505050509050019250505060405180910390f35b3480156102d957600080fd5b5061033c600480360360408110156102f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506112e5565b604051808381526020018281526020019250505060405180910390f35b34801561036557600080fd5b5061036e611489565b604051808215151515815260200191505060405180910390f35b34801561039457600080fd5b506103d7600480360360208110156103ab57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061149c565b6040518082815260200191505060405180910390f35b3480156103f957600080fd5b506104466004803603604081101561041057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611509565b005b34801561045457600080fd5b506104a16004803603604081101561046b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611a5d565b005b3480156104af57600080fd5b506104dc600480360360208110156104c657600080fd5b8101908080359060200190929190505050611c01565b005b3480156104ea57600080fd5b5061056c6004803603604081101561050157600080fd5b810190808035906020019064010000000081111561051e57600080fd5b82018360208201111561053057600080fd5b8035906020019184600183028401116401000000008311171561055257600080fd5b909192939192939080359060200190929190505050611cbc565b005b34801561057a57600080fd5b50610583611fa2565b6040518082815260200191505060405180910390f35b3480156105a557600080fd5b50610608600480360360408110156105bc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611fa8565b6040518082815260200191505060405180910390f35b34801561062a57600080fd5b5061068d6004803603604081101561064157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612143565b604051808381526020018281526020019250505060405180910390f35b3480156106b657600080fd5b506106e3600480360360208110156106cd57600080fd5b81019080803590602001909291905050506121fb565b005b3480156106f157600080fd5b506106fa612600565b6040518082815260200191505060405180910390f35b34801561071c57600080fd5b5061075f6004803603602081101561073357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506126a3565b6040518082815260200191505060405180910390f35b34801561078157600080fd5b506108f7600480360360e081101561079857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561080957600080fd5b82018360208201111561081b57600080fd5b8035906020019184602083028401116401000000008311171561083d57600080fd5b90919293919293908035906020019064010000000081111561085e57600080fd5b82018360208201111561087057600080fd5b8035906020019184602083028401116401000000008311171561089257600080fd5b9091929391929390803590602001906401000000008111156108b357600080fd5b8201836020820111156108c557600080fd5b803590602001918460208302840111640100000000831117156108e757600080fd5b90919293919293905050506127c4565b005b34801561090557600080fd5b506109486004803603602081101561091c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612f4f565b6040518082815260200191505060405180910390f35b34801561096a57600080fd5b50610973612f9b565b6040518085815260200184815260200183815260200182815260200194505050505060405180910390f35b3480156109aa57600080fd5b506109ed600480360360208110156109c157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612fc2565b604051808215151515815260200191505060405180910390f35b348015610a1357600080fd5b50610a6060048036036040811015610a2a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506130ec565b005b348015610a6e57600080fd5b50610a9b60048036036020811015610a8557600080fd5b8101908080359060200190929190505050613bf4565b005b348015610aa957600080fd5b50610aec60048036036020811015610ac057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506141a2565b6040518082815260200191505060405180910390f35b348015610b0e57600080fd5b50610b8660048036036020811015610b2557600080fd5b8101908080359060200190640100000000811115610b4257600080fd5b820183602082011115610b5457600080fd5b80359060200191846001830284011164010000000083111715610b7657600080fd5b9091929391929390505050614268565b005b348015610b9457600080fd5b50610bc160048036036020811015610bab57600080fd5b81019080803590602001909291905050506145a2565b005b348015610bcf57600080fd5b50610bfc60048036036020811015610be657600080fd5b81019080803590602001909291905050506146d5565b6040518082815260200191505060405180910390f35b348015610c1e57600080fd5b50610c6b60048036036040811015610c3557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506146f6565b005b348015610c7957600080fd5b50610c8261489a565b005b348015610c9057600080fd5b50610c996149d3565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610ce757600080fd5b50610cf06149f9565b6040518082815260200191505060405180910390f35b348015610d1257600080fd5b50610d5560048036036020811015610d2957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614a03565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610d98578082015181840152602081019050610d7d565b505050509050019250505060405180910390f35b348015610db857600080fd5b50610dc1614a5b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610e0f57600080fd5b50610e18614a84565b604051808215151515815260200191505060405180910390f35b348015610e3e57600080fd5b50610e8160048036036020811015610e5557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614ae2565b005b348015610e8f57600080fd5b50610ec660048036036040811015610ea657600080fd5b810190808035906020019092919080359060200190929190505050614c86565b005b348015610ed457600080fd5b50610f1760048036036020811015610eeb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061500a565b6040518082815260200191505060405180910390f35b348015610f3957600080fd5b50610f42615122565b6040518082815260200191505060405180910390f35b348015610f6457600080fd5b50610fa760048036036020811015610f7b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050615128565b6040518082815260200191505060405180910390f35b348015610fc957600080fd5b5061100c60048036036020811015610fe057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050615140565b6040518082815260200191505060405180910390f35b34801561102e57600080fd5b5061107b6004803603604081101561104557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061518f565b005b34801561108957600080fd5b506110d6600480360360408110156110a057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050615252565b604051808381526020018281526020019250505060405180910390f35b3480156110ff57600080fd5b506111426004803603602081101561111657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506154bd565b005b34801561115057600080fd5b506111936004803603602081101561116757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061558d565b005b3480156111a157600080fd5b506111e4600480360360208110156111b857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050615613565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561122b578082015181840152602081019050611210565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561126d578082015181840152602081019050611252565b5050505090500194505050505060405180910390f35b61128b6158d3565b005b606060058054806020026020016040519081016040528092919081815260200182805480156112db57602002820191906000526020600020905b8154815260200190600101908083116112c7575b5050505050905090565b60008060006112f2615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561136e57600080fd5b505afa158015611382573d6000803e3d6000fd5b505050506040513d602081101561139857600080fd5b8101908080519060200190929190505050905060006113b5615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561143157600080fd5b505afa158015611445573d6000803e3d6000fd5b505050506040513d602081101561145b57600080fd5b810190808051906020019092919050505090506114788282615bd3565b809450819550505050509250929050565b600160009054906101000a900460ff1681565b600080600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061150181600301604051806020016040529081600082015481525050615cb3565b915050919050565b611511617b51565b61151a82615cc1565b905061152d81611528615cdf565b615d05565b611582576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602f815260200180617f55602f913960400191505060405180910390fd5b600061158c615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561160857600080fd5b505afa15801561161c573d6000803e3d6000fd5b505050506040513d602081101561163257600080fd5b810190808051906020019092919050505090506000600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506116aa8160030160405180602001604052908160008201548152505084615d1b565b6116ff576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180617cc76023913960400191505060405180910390fd5b6000611709615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594876040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561178557600080fd5b505afa158015611799573d6000803e3d6000fd5b505050506040513d60208110156117af57600080fd5b810190808051906020019092919050505090506117cc8382615d31565b5060008260020160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506118348160000160405180602001604052908160008201548152505086615d1b565b6118a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f4e6f7420656e6f7567682064656c6567617465642070657263656e747300000081525060200191505060405180910390fd5b6118d18582600001604051806020016040529081600082015481525050615f9990919063ffffffff16565b816000016000820151816000015590505060006118ed856126a3565b905060008061191384600001604051806020016040529081600082015481525050615cb3565b1461194d5761194861193e6119398961192b86616040565b6160ca90919063ffffffff16565b616529565b846001015461654a565b611953565b82600101545b9050611960848285616563565b61198b8786600301604051806020016040529081600082015481525050615f9990919063ffffffff16565b856003016000820151816000015590505060006119bf84600001604051806020016040529081600082015481525050615cb3565b14156119dd576119db84866000016167c790919063ffffffff16565b505b8373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fc27c2c089d7c6709b0a8e68031ecc1c43dd5e4146d5d3aadad05f72a90bbf8ba611a358a615cb3565b84604051808381526020018281526020019250505060405180910390a3505050505050505050565b60405160200180807f456c656374696f6e0000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001203373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611b2e57600080fd5b505afa158015611b42573d6000803e3d6000fd5b505050506040513d6020811015611b5857600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614611bf2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f6f6e6c79207265676973746572656420636f6e7472616374000000000000000081525060200191505060405180910390fd5b611bfc83836169b5565b505050565b611c09614a84565b611c7b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80600a819055507f7e524139f5fe281f1ed40d0f650ab4edfb555978755a170ceda325e8968641b0816040518082815260200191505060405180910390a150565b611cc4614a84565b611d36576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600083836040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090506004600082815260200190815260200160002060009054906101000a900460ff16611de0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526027815260200180617f2e6027913960400191505060405180910390fd5b6005805490508210611e3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180617ed36028913960400191505060405180910390fd5b8060058381548110611e4b57fe5b906000526020600020015414611ec9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e64657820646f65736e2774206d61746368206964656e746966696572000081525060200191505060405180910390fd5b600560016005805490500381548110611ede57fe5b906000526020600020015460058381548110611ef657fe5b90600052602060002001819055506005805480611f0f57fe5b6001900381819060005260206000200160009055905560006004600083815260200190815260200160002060006101000a81548160ff021916908315150217905550838360405180838380828437808301925050509250505060405180910390207faee8df56d95b5766042c2ff4dcb39a120f0a09dd21bb9c143f86a314eff4b71460405160405180910390a250505050565b60075481565b600080611fb3615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561202f57600080fd5b505afa158015612043573d6000803e3d6000fd5b505050506040513d602081101561205957600080fd5b810190808051906020019092919050505090506000612076615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156120f257600080fd5b505afa158015612106573d6000803e3d6000fd5b505050506040513d602081101561211c57600080fd5b810190808051906020019092919050505090506121398282615d31565b9250505092915050565b6000806000600860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506121ea81600001604051806020016040529081600082015481525050615cb3565b925080600101549150509250929050565b60016000808282540192505081905550600080549050612219615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561229557600080fd5b505afa1580156122a9573d6000803e3d6000fd5b505050506040513d60208110156122bf57600080fd5b8101908080519060200190929190505050612325576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526040815260200180617de26040913960400191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806001018054905083106123e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4261642070656e64696e67207769746864726177616c20696e6465780000000081525060200191505060405180910390fd5b60008160010184815481106123f557fe5b90600052602060002090600202019050806001015442101561247f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f50656e64696e67207769746864726177616c206e6f7420617661696c61626c6581525060200191505060405180910390fd5b6000816000015490506124958360010186616a6f565b4781111561250b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f496e636f6e73697374656e742062616c616e636500000000000000000000000081525060200191505060405180910390fd5b612534813373ffffffffffffffffffffffffffffffffffffffff16616ae990919063ffffffff16565b3373ffffffffffffffffffffffffffffffffffffffff167f292d39ba701489b7f640c83806d3eeabe0a32c9f0a61b49e95612ebad42211cd826040518082815260200191505060405180910390a250505060005481146125fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5050565b600061269e61260d616c23565b73ffffffffffffffffffffffffffffffffffffffff16639a0e7d666040518163ffffffff1660e01b815260040160206040518083038186803b15801561265257600080fd5b505afa158015612666573d6000803e3d6000fd5b505050506040513d602081101561267c57600080fd5b8101908080519060200190929190505050600654616d1e90919063ffffffff16565b905090565b600080600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000015490506127bc6126f6616c23565b73ffffffffffffffffffffffffffffffffffffffff16636c781a2c856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561277257600080fd5b505afa158015612786573d6000803e3d6000fd5b505050506040513d602081101561279c57600080fd5b810190808051906020019092919050505082616d1e90919063ffffffff16565b915050919050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166317c508186005336040518363ffffffff1660e01b815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818154815260200191508054801561288b57602002820191906000526020600020905b815481526020019060010190808311612877575b5050935050505060206040518083038186803b1580156128aa57600080fd5b505afa1580156128be573d6000803e3d6000fd5b505050506040513d60208110156128d457600080fd5b810190808051906020019092919050505061293a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180617c7d6024913960400191505060405180910390fd5b600061294e8a6129498d6126a3565b61654a565b9050878110156129c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f7265776172642063616e6e6f74206578636565642070656e616c74792e00000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614612abc57612a02615ad8565b73ffffffffffffffffffffffffffffffffffffffff166393c5c4878a6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612a7e57600080fd5b505afa158015612a92573d6000803e3d6000fd5b505050506040513d6020811015612aa857600080fd5b810190808051906020019092919050505098505b6000600360008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050600080905082821015612ceb57612b238284616da690919063ffffffff16565b905080612b2e616c23565b73ffffffffffffffffffffffffffffffffffffffff16638ef01def8f848d8d8d8d8d8d6040518963ffffffff1660e01b8152600401808973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200188815260200180602001806020018060200184810384528a8a82818152602001925060200280828437600081840152601f19601f8201169050808301925050508481038352888882818152602001925060200280828437600081840152601f19601f8201169050808301925050508481038252868682818152602001925060200280828437600081840152601f19601f8201169050808301925050509b505050505050505050505050602060405180830381600087803b158015612c5957600080fd5b505af1158015612c6d573d6000803e3d6000fd5b505050506040513d6020811015612c8357600080fd5b810190808051906020019092919050505014612cea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061804f6021913960400191505060405180910390fd5b5b612d078d612d028386616da690919063ffffffff16565b6169b5565b612d118b8b616df0565b50506000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f476f7665726e616e636500000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015612dce57600080fd5b505afa158015612de2573d6000803e3d6000fd5b505050506040513d6020811015612df857600080fd5b81019080805190602001909291905050509050600081905047612e248b85616da690919063ffffffff16565b1115612e98576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f496e636f6e73697374656e742062616c616e636500000000000000000000000081525060200191505060405180910390fd5b612ed3612eae8b85616da690919063ffffffff16565b8273ffffffffffffffffffffffffffffffffffffffff16616ae990919063ffffffff16565b8a73ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167f7abcb995a115c34a67528d58d5fc5ce02c22cb835ce1685046163f7d366d7111858d604051808381526020018281526020019250505060405180910390a350505050505050505050505050565b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b60008060008060018060046000839350829250819150809050935093509350935090919293565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166317c508186005846040518363ffffffff1660e01b815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818154815260200191508054801561308b57602002820191906000526020600020905b815481526020019060010190808311613077575b5050935050505060206040518083038186803b1580156130aa57600080fd5b505afa1580156130be573d6000803e3d6000fd5b505050506040513d60208110156130d457600080fd5b81019080805190602001909291905050509050919050565b6130f4617b51565b6130fd82615cc1565b90506131108161310b615cdf565b615d05565b613165576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526031815260200180617e796031913960400191505060405180910390fd5b600061316f615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156131eb57600080fd5b505afa1580156131ff573d6000803e3d6000fd5b505050506040513d602081101561321557600080fd5b810190808051906020019092919050505090506000613232615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156132ae57600080fd5b505afa1580156132c2573d6000803e3d6000fd5b505050506040513d60208110156132d857600080fd5b8101908080519060200190929190505050905060006132f5616eaa565b90508073ffffffffffffffffffffffffffffffffffffffff1663facd743b846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561337457600080fd5b505afa158015613388573d6000803e3d6000fd5b505050506040513d602081101561339e57600080fd5b810190808051906020019092919050505015613405576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180617c5c6021913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166352f13a4e846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561348257600080fd5b505afa158015613496573d6000803e3d6000fd5b505050506040513d60208110156134ac57600080fd5b810190808051906020019092919050505015613513576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526027815260200180617fca6027913960400191505060405180910390fd5b6000600860008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061356c8382600001616fa590919063ffffffff16565b50600a5461357c82600001617075565b11156135f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f546f6f206d616e792064656c656761746565730000000000000000000000000081525060200191505060405180910390fd5b60008160020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506136578682600001604051806020016040529081600082015481525050615d1b565b6136ac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526046815260200180617c166046913960600191505060405180910390fd5b6136b4617b51565b613709876136fb8460000160405180602001604052908160008201548152505086600301604051806020016040529081600082015481525050615f9990919063ffffffff16565b61708690919063ffffffff16565b905061371c81613717615cdf565b615d05565b61378e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f43616e6e6f742064656c6567617465206d6f7265207468616e2031303025000081525060200191505060405180910390fd5b6000613799876126a3565b905060008114156138a2576137f9886137eb8560000160405180602001604052908160008201548152505087600301604051806020016040529081600082015481525050615f9990919063ffffffff16565b61708690919063ffffffff16565b84600301600082015181600001559050508783600001600082015181600001559050508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fc4ed9e859cb808c8bf287ad013d5178069b5e94d91819c335ba2e407fbed90446138748b615cb3565b8660010154604051808381526020018281526020019250505060405180910390a35050505050505050613bf0565b60006138ac61712f565b73ffffffffffffffffffffffffffffffffffffffff166366547163896040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561392857600080fd5b505afa15801561393c573d6000803e3d6000fd5b505050506040513d602081101561395257600080fd5b81019080805190602001909291905050509050600081146139fb57613975617b51565b61397f828461722a565b90506139a4613997858361708690919063ffffffff16565b61399f615cdf565b615d05565b6139f9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526033815260200180617efb6033913960400191505060405180910390fd5b505b6000613a3e613a39613a108760010154616040565b613a2b8d613a1d88616040565b6160ca90919063ffffffff16565b615f9990919063ffffffff16565b616529565b9050613a958a613a878760000160405180602001604052908160008201548152505089600301604051806020016040529081600082015481525050615f9990919063ffffffff16565b61708690919063ffffffff16565b8660030160008201518160000155905050898560000160008201518160000155905050613acf818660010154616d1e90919063ffffffff16565b8560010181905550613b2981600960008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054616d1e90919063ffffffff16565b600960008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff167fc4ed9e859cb808c8bf287ad013d5178069b5e94d91819c335ba2e407fbed9044613bc48d615cb3565b8860010154604051808381526020018281526020019250505060405180910390a3505050505050505050505b5050565b60016000808282540192505081905550600080549050613c12615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613c8e57600080fd5b505afa158015613ca2573d6000803e3d6000fd5b505050506040513d6020811015613cb857600080fd5b8101908080519060200190929190505050613d1e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526046815260200180617f846046913960600191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000613d6c336126a3565b90506000613d838583616da690919063ffffffff16565b90506000613d8f61712f565b73ffffffffffffffffffffffffffffffffffffffff166366547163336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613e0b57600080fd5b505afa158015613e1f573d6000803e3d6000fd5b505050506040513d6020811015613e3557600080fd5b8101908080519060200190929190505050905080821015613ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603581526020018061801a6035913960400191505060405180910390fd5b613ea9617b51565b600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003016040518060200160405290816000820154815250509050613f1581613f106000616040565b61726c565b15613f2557613f243388617281565b5b6000613f2f616eaa565b73ffffffffffffffffffffffffffffffffffffffff1663dcff4cf6336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613fab57600080fd5b505afa158015613fbf573d6000803e3d6000fd5b505050506040513d6020811015613fd557600080fd5b810190808051906020019092919050505090506000811480613ff75750838111155b61404c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526057815260200180617e226057913960600191505060405180910390fd5b61405633896169b5565b600061406d60075442616d1e90919063ffffffff16565b90508660010160405180604001604052808b8152602001838152509080600181540180825580915050906001820390600052602060002090600202016000909192909190915060008201518160000155602082015181600101555050503373ffffffffffffffffffffffffffffffffffffffff167fb1a3aef2a332070da206ad1868a5e327f5aa5144e00e9a7b40717c153158a5888a83604051808381526020018281526020019250505060405180910390a250505050505050600054811461419e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5050565b60006141ac617b51565b6141d66141c06141bb8561149c565b615cc1565b6141c8615cdf565b615f9990919063ffffffff16565b905060006141e3846126a3565b9050600061420a614205846141f785616040565b6160ca90919063ffffffff16565b616529565b905061425e600960008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482616d1e90919063ffffffff16565b9350505050919050565b614270614a84565b6142e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b60008282604051602001808383808284378083019250505092505050604051602081830303815290604052805190602001209050600073ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd927233836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156143a157600080fd5b505afa1580156143b5573d6000803e3d6000fd5b505050506040513d60208110156143cb57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161415614466576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4964656e746966696572206973206e6f7420726567697374657265640000000081525060200191505060405180910390fd5b6004600082815260200190815260200160002060009054906101000a900460ff16156144fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f43616e6e6f742061646420736c61736865722049442074776963652e0000000081525060200191505060405180910390fd5b600581908060018154018082558091505090600182039060005260206000200160009091929091909150555060016004600083815260200190815260200160002060006101000a81548160ff021916908315150217905550828260405180838380828437808301925050509250505060405180910390207f92a16cb9e1846d175c3007fc61953d186452c9ea1aa34183eb4b7f88cd3f07bb60405160405180910390a2505050565b6145aa614a84565b61461c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600754811415614694576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f556e6c6f636b696e6720706572696f64206e6f74206368616e6765640000000081525060200191505060405180910390fd5b806007819055507fd9274a7c98edc7c66931fc71872764091e7023fe3867358f8504d4c21b161fc5816040518082815260200191505060405180910390a150565b600581815481106146e257fe5b906000526020600020016000915090505481565b60405160200180807f456c656374696f6e0000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001203373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156147c757600080fd5b505afa1580156147db573d6000803e3d6000fd5b505050506040513d60208110156147f157600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161461488b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f6f6e6c79207265676973746572656420636f6e7472616374000000000000000081525060200191505060405180910390fd5b6148958383616df0565b505050565b6148a2614a84565b614914576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166001809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360006001806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600654905090565b606080614a50600860008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001617487565b905080915050919050565b60006001809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006001809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16614ac661756c565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b614aea614a84565b614b5c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415614bff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f43616e6e6f7420726567697374657220746865206e756c6c206164647265737381525060200191505060405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b60405160405180910390a250565b60016000808282540192505081905550600080549050614ca4615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015614d2057600080fd5b505afa158015614d34573d6000803e3d6000fd5b505050506040513d6020811015614d4a57600080fd5b8101908080519060200190929190505050614db0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526046815260200180617d2c6046913960600191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905080600101805490508410614e6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4261642070656e64696e67207769746864726177616c20696e6465780000000081525060200191505060405180910390fd5b6000816001018581548110614e8057fe5b906000526020600020906002020190508060000154841115614eed576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526029815260200180617eaa6029913960400191505060405180910390fd5b8060000154841415614f0b57614f068260010186616a6f565b614f2b565b614f22848260000154616da690919063ffffffff16565b81600001819055505b614f353385616df0565b614f3e33617574565b3373ffffffffffffffffffffffffffffffffffffffff167fa823fc38a01c2f76d7057a79bb5c317710f26f7dbdea78634598d5519d0f7cb0856040518082815260200191505060405180910390a250506000548114615005576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b505050565b600080600090506060600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101805480602002602001604051908101604052809291908181526020016000905b828210156150bb57838290600052602060002090600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190615075565b50505050905060008090505b8151811015615117576150fa8282815181106150df57fe5b60200260200101516000015184616d1e90919063ffffffff16565b9250615110600182616d1e90919063ffffffff16565b90506150c7565b508192505050919050565b60065481565b60096020528060005260406000206000915090505481565b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101805490509050919050565b600160009054906101000a900460ff1615615212576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b60018060006101000a81548160ff021916908315150217905550615235336176d1565b61523e82614ae2565b615247816145a2565b600a80819055505050565b60008061525d615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156152d957600080fd5b505afa1580156152ed573d6000803e3d6000fd5b505050506040513d602081101561530357600080fd5b8101908080519060200190929190505050615369576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526042815260200180617cea6042913960600191505060405180910390fd5b600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101805490508310615423576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4261642070656e64696e67207769746864726177616c20696e6465780000000081525060200191505060405180910390fd5b61542b617b64565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101848154811061547857fe5b90600052602060002090600202016040518060400160405290816000820154815260200160018201548152505090508060000151816020015192509250509250929050565b60006154c7615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561554357600080fd5b505afa158015615557573d6000803e3d6000fd5b505050506040513d602081101561556d57600080fd5b8101908080519060200190929190505050905061558981617574565b5050565b615595614a84565b615607576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b615610816176d1565b50565b60608061561e615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561569a57600080fd5b505afa1580156156ae573d6000803e3d6000fd5b505050506040513d60208110156156c457600080fd5b810190808051906020019092919050505061572a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526042815260200180617cea6042913960600191505060405180910390fd5b6000600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018054905090506060816040519080825280602002602001820160405280156157a55781602001602082028038833980820191505090505b5090506060826040519080825280602002602001820160405280156157d95781602001602082028038833980820191505090505b50905060008090505b838110156158c4576157f2617b64565b600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101828154811061583f57fe5b9060005260206000209060020201604051806040016040529081600082015481526020016001820154815250509050806000015184838151811061587f57fe5b602002602001018181525050806020015183838151811061589c57fe5b602002602001018181525050506158bd600182616d1e90919063ffffffff16565b90506157e2565b50818194509450505050915091565b600160008082825401925050819055506000805490506158f1615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561596d57600080fd5b505afa158015615981573d6000803e3d6000fd5b505050506040513d602081101561599757600080fd5b81019080805190602001909291905050506159fd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526036815260200180617be06036913960400191505060405180910390fd5b615a073334616df0565b615a1033617574565b3373ffffffffffffffffffffffffffffffffffffffff167f0f0f2fc5b4c987a49e1663ce2c2d65de12f3b701ff02b4d09461421e63e609e7346040518082815260200191505060405180910390a26000548114615ad5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015615b9357600080fd5b505afa158015615ba7573d6000803e3d6000fd5b505050506040513d6020811015615bbd57600080fd5b8101908080519060200190929190505050905090565b6000806000600860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000615c9e615c9983600001604051806020016040529081600082015481525050615c8b615c868a6126a3565b616040565b6160ca90919063ffffffff16565b616529565b90508093508160010154925050509250929050565b600081600001519050919050565b615cc9617b51565b6040518060200160405280838152509050919050565b615ce7617b51565b604051806020016040528069d3c21bcecceda1000000815250905090565b6000816000015183600001511115905092915050565b6000816000015183600001511015905092915050565b600080600860008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000615d9882600301604051806020016040529081600082015481525050615cb3565b1415615e0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f64656c656761746f72206973206e6f742064656c65676174696e67000000000081525060200191505060405180910390fd5b60008160020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000615e7482600001604051806020016040529081600082015481525050615cb3565b1415615ecb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526029815260200180617ff16029913960400191505060405180910390fd5b600080615ed887876112e5565b91509150818360010181905550615f4982615f3b83600960008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054616da690919063ffffffff16565b616d1e90919063ffffffff16565b600960008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508194505050505092915050565b615fa1617b51565b81600001518360000151101561601f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f737562737472616374696f6e20756e646572666c6f772064657465637465640081525060200191505060405180910390fd5b60405180602001604052808360000151856000015103815250905092915050565b616048617b51565b616050617815565b8211156160a8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526036815260200180617dac6036913960400191505060405180910390fd5b604051806020016040528069d3c21bcecceda100000084028152509050919050565b6160d2617b51565b6000836000015114806160e9575060008260000151145b1561610557604051806020016040528060008152509050616523565b69d3c21bcecceda10000008260000151141561612357829050616523565b69d3c21bcecceda10000008360000151141561614157819050616523565b600069d3c21bcecceda100000061615785617834565b600001518161616257fe5b04905060006161708561786b565b600001519050600069d3c21bcecceda100000061618c86617834565b600001518161619757fe5b04905060006161a58661786b565b600001519050600082850290506000851461623957828582816161c457fe5b0414616238576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b600069d3c21bcecceda100000082029050600082146162db5769d3c21bcecceda100000082828161626657fe5b04146162da576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f6f766572666c6f772078317931202a206669786564312064657465637465640081525060200191505060405180910390fd5b5b809150600084860290506000861461636c57848682816162f757fe5b041461636b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b60008488029050600088146163fa578488828161638557fe5b04146163f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b6164026178a8565b878161640a57fe5b0496506164156178a8565b858161641d57fe5b04945060008588029050600088146164ae578588828161643957fe5b04146164ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b6164b6617b51565b60405180602001604052808781525090506164df81604051806020016040528087815250617086565b90506164f981604051806020016040528086815250617086565b905061651381604051806020016040528085815250617086565b9050809a50505050505050505050505b92915050565b600069d3c21bcecceda100000082600001518161654257fe5b049050919050565b6000818310616559578161655b565b825b905092915050565b600061656e846141a2565b9050600061657a61712f565b73ffffffffffffffffffffffffffffffffffffffff166366547163866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156165f657600080fd5b505afa15801561660a573d6000803e3d6000fd5b505050506040513d602081101561662057600080fd5b8101908080519060200190929190505050905060006166488284616da690919063ffffffff16565b90508481101561670b5761665a61712f565b73ffffffffffffffffffffffffffffffffffffffff1663f3f6da2c876166898887616da690919063ffffffff16565b6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156166f257600080fd5b505af1158015616706573d6000803e3d6000fd5b505050505b616722858560010154616da690919063ffffffff16565b846001018190555061677c85600960008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054616da690919063ffffffff16565b600960008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050505050565b60006167d383836178b5565b156169aa57600060018460000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403905060006001856001018054905003905081811461691857600085600101828154811061684857fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508086600101848154811061688557fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600183018660000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505b8460000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600090558460010180548061696a57fe5b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590556001925050506169af565b600090505b92915050565b616a0a81600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154616da690919063ffffffff16565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000181905550616a6581600654616da690919063ffffffff16565b6006819055505050565b6000616a8960018480549050616da690919063ffffffff16565b9050828181548110616a9757fe5b9060005260206000209060020201838381548110616ab157fe5b90600052602060002090600202016000820154816000015560018201548160010155905050808381616ae39190617b7e565b50505050565b80471015616b5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f416464726573733a20696e73756666696369656e742062616c616e636500000081525060200191505060405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405180600001905060006040518083038185875af1925050503d8060008114616bbf576040519150601f19603f3d011682016040523d82523d6000602084013e616bc4565b606091505b5050905080616c1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603a815260200180617d72603a913960400191505060405180910390fd5b505050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f456c656374696f6e0000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015616cde57600080fd5b505afa158015616cf2573d6000803e3d6000fd5b505050506040513d6020811015616d0857600080fd5b8101908080519060200190929190505050905090565b600080828401905083811015616d9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b6000616de883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250617904565b905092915050565b616e4581600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154616d1e90919063ffffffff16565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000181905550616ea081600654616d1e90919063ffffffff16565b6006819055505050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f56616c696461746f727300000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015616f6557600080fd5b505afa158015616f79573d6000803e3d6000fd5b505050506040513d6020811015616f8f57600080fd5b8101908080519060200190929190505050905090565b6000616fb183836178b5565b61706a57826001018290806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001905061706f565b600090505b92915050565b600081600101805490509050919050565b61708e617b51565b6000826000015184600001510190508360000151811015617117576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f616464206f766572666c6f77206465746563746564000000000000000000000081525060200191505060405180910390fd5b60405180602001604052808281525091505092915050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f476f7665726e616e636500000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156171ea57600080fd5b505afa1580156171fe573d6000803e3d6000fd5b505050506040513d602081101561721457600080fd5b8101908080519060200190929190505050905090565b617232617b51565b61723a617b51565b61724384616040565b905061724d617b51565b61725684616040565b905061726282826179c4565b9250505092915050565b60008160000151836000015111905092915050565b606061728c83614a03565b90506000600860008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008090505b82518110156174805760008260020160008584815181106172f457fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000806173588887868151811061734b57fe5b6020026020010151615bd3565b915091506000617399617394856000016040518060200160405290816000820154815250506173868b616040565b6160ca90919063ffffffff16565b616529565b90506173c06173b18385616da690919063ffffffff16565b82616da690919063ffffffff16565b90506173e08786815181106173d157fe5b60200260200101518286616563565b8685815181106173ec57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff167fc27c2c089d7c6709b0a8e68031ecc1c43dd5e4146d5d3aadad05f72a90bbf8ba600084604051808381526020018281526020019250505060405180910390a350505050617479600182616d1e90919063ffffffff16565b90506172d7565b5050505050565b60608082600101805490506040519080825280602002602001820160405280156174c05781602001602082028038833980820191505090505b50905060005b8360010180549050811015617562578360010181815481106174e457fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682828151811061751b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080806001019150506174c6565b5080915050919050565b600033905090565b600061757e615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156175fa57600080fd5b505afa15801561760e573d6000803e3d6000fd5b505050506040513d602081101561762457600080fd5b810190808051906020019092919050505090506000600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001905060008090505b61768c82617075565b8110156176cb576176af836176aa8385617b0d90919063ffffffff16565b615d31565b506176c4600182616d1e90919063ffffffff16565b9050617683565b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415617757576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180617ca16026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166001809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806001806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60007601357c299a88ea76a58924d52ce4f26a85af186c2b9e74905090565b61783c617b51565b604051806020016040528069d3c21bcecceda10000008085600001518161785f57fe5b04028152509050919050565b617873617b51565b604051806020016040528069d3c21bcecceda10000008085600001518161789657fe5b04028460000151038152509050919050565b600064e8d4a51000905090565b6000808360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541415905092915050565b60008383111582906179b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561797657808201518184015260208101905061795b565b50505050905090810190601f1680156179a35780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b6179cc617b51565b600082600001511415617a47576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f63616e277420646976696465206279203000000000000000000000000000000081525060200191505060405180910390fd5b600069d3c21bcecceda10000008460000151029050836000015169d3c21bcecceda10000008281617a7457fe5b0414617ae8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f6f766572666c6f7720617420646976696465000000000000000000000000000081525060200191505060405180910390fd5b604051806020016040528084600001518381617b0057fe5b0481525091505092915050565b6000826001018281548110617b1e57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905092915050565b6040518060200160405280600081525090565b604051806040016040528060008152602001600081525090565b815481835581811115617bab57600202816002028360005260206000209182019101617baa9190617bb0565b5b505050565b617bdc91905b80821115617bd857600080820160009055600182016000905550600201617bb6565b5090565b9056fe4d75737420666972737420726567697374657220616464726573732077697468204163636f756e742e6372656174654163636f756e7443616e6e6f742064656372656173652064656c65676174656420616d6f756e74202d20757365207265766f6b6544656c656761746564476f7665726e616e6365566f7465732e56616c696461746f72732063616e6e6f742064656c656761746520766f7465732e43616c6c6572206973206e6f7420612077686974656c697374656420736c61736865722e4f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734e6f7420656e6f75676820746f74616c2064656c6567617465642070657263656e7473556e6b6e6f776e206163636f756e743a206f6e6c792072656769737465726564206163636f756e747320686176652070656e64696e67207769746864726177616c7353656e646572206d75737420626520726567697374657265642077697468204163636f756e742e6372656174654163636f756e7420746f206c6f636b206f722072656c6f636b416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d6179206861766520726576657274656463616e277420637265617465206669786964697479206e756d626572206c6172676572207468616e206d61784e65774669786564282953656e646572206d75737420626520726567697374657265642077697468204163636f756e742e6372656174654163636f756e7420746f207769746864726177456974686572206163636f756e7420646f65736e2774206861766520656e6f756768206c6f636b65642043656c6f206f72206c6f636b65642043656c6f206973206265696e67207573656420666f7220766f74696e672e44656c6567617465206672616374696f6e206d757374206265206c657373207468616e206f7220657175616c20746f20315265717565737465642076616c7565206c6172676572207468616e2070656e64696e672076616c756550726f766964656420696e64657820657863656564732077686974656c69737420626f756e64732e43616e6e6f742064656c656761746520766f74657320746861742061726520766f74696e6720696e207265666572656e64756d43616e6e6f742072656d6f766520736c6173686572204944206e6f74207965742061646465642e5265766f6b65206672616374696f6e206d757374206265206c657373207468616e206f7220657175616c20746f203153656e646572206d75737420626520726567697374657265642077697468204163636f756e742e6372656174654163636f756e7420746f206c6f636b206f7220756e6c6f636b56616c696461746f722067726f7570732063616e6e6f742064656c656761746520766f7465732e64656c656761746f72206973206e6f742064656c65676174696e6720666f722064656c6567617465654e6f7420656e6f75676820756e6c6f636b61626c652063656c6f2e2043656c6f206973206c6f636b656420696e20766f74696e672e43616e6e6f74207265766f6b6520656e6f75676820766f74696e6720676f6c642ea265627a7a72315820fa955df143e228c48555be73b4ae9451b451b9538eb849f1c7d36b0f5e2d85f064736f6c634300050d00320000000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x60806040526004361061025c5760003560e01c80636489119811610144578063b2fb30cb116100b6578063cd6dc6871161007a578063cd6dc68714611022578063d15ca4ed1461107d578063f24b39fc146110f3578063f2fde38b14611144578063f340c0d014611195578063f83d08ba146112835761025c565b8063b2fb30cb14610e83578063b6e1e49d14610ec8578063c1867f6d14610f2d578063c70f35ea14610f58578063c95b241b14610fbd5761025c565b80637b103999116101085780637b10399914610c84578063807876b714610cdb5780638a9c2bbe14610d065780638da5cb5b14610dac5780638f32d59b14610e03578063a91ee0dc14610e325761025c565b80636489119814610b0257806366f0633b14610b885780636adcc93814610bc35780636edf77a514610c12578063715018a614610c6d5761025c565b8063296673a9116101dd5780633f199b40116101a15780633f199b40146108f957806354255be01461095e57806357601c5d1461099e57806358f84a7814610a075780636198e33914610a6257806361d5c57014610a9d5761025c565b8063296673a91461061e5780632e1a7d4d146106aa57806330a61d59146106e557806330ec70f51461071057806331993fc9146107755761025c565b806318a4ff8c1161022457806318a4ff8c146104485780631d1dd1a7146104a35780631fe2dfda146104de57806320637d8e1461056e578063227320a7146105995761025c565b806308764ee2146102615780630cdbac28146102cd578063158ef93e1461035957806315952ae71461038857806318629a92146103ed575b600080fd5b34801561026d57600080fd5b5061027661128d565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156102b957808201518184015260208101905061029e565b505050509050019250505060405180910390f35b3480156102d957600080fd5b5061033c600480360360408110156102f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506112e5565b604051808381526020018281526020019250505060405180910390f35b34801561036557600080fd5b5061036e611489565b604051808215151515815260200191505060405180910390f35b34801561039457600080fd5b506103d7600480360360208110156103ab57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061149c565b6040518082815260200191505060405180910390f35b3480156103f957600080fd5b506104466004803603604081101561041057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611509565b005b34801561045457600080fd5b506104a16004803603604081101561046b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611a5d565b005b3480156104af57600080fd5b506104dc600480360360208110156104c657600080fd5b8101908080359060200190929190505050611c01565b005b3480156104ea57600080fd5b5061056c6004803603604081101561050157600080fd5b810190808035906020019064010000000081111561051e57600080fd5b82018360208201111561053057600080fd5b8035906020019184600183028401116401000000008311171561055257600080fd5b909192939192939080359060200190929190505050611cbc565b005b34801561057a57600080fd5b50610583611fa2565b6040518082815260200191505060405180910390f35b3480156105a557600080fd5b50610608600480360360408110156105bc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611fa8565b6040518082815260200191505060405180910390f35b34801561062a57600080fd5b5061068d6004803603604081101561064157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612143565b604051808381526020018281526020019250505060405180910390f35b3480156106b657600080fd5b506106e3600480360360208110156106cd57600080fd5b81019080803590602001909291905050506121fb565b005b3480156106f157600080fd5b506106fa612600565b6040518082815260200191505060405180910390f35b34801561071c57600080fd5b5061075f6004803603602081101561073357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506126a3565b6040518082815260200191505060405180910390f35b34801561078157600080fd5b506108f7600480360360e081101561079857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561080957600080fd5b82018360208201111561081b57600080fd5b8035906020019184602083028401116401000000008311171561083d57600080fd5b90919293919293908035906020019064010000000081111561085e57600080fd5b82018360208201111561087057600080fd5b8035906020019184602083028401116401000000008311171561089257600080fd5b9091929391929390803590602001906401000000008111156108b357600080fd5b8201836020820111156108c557600080fd5b803590602001918460208302840111640100000000831117156108e757600080fd5b90919293919293905050506127c4565b005b34801561090557600080fd5b506109486004803603602081101561091c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612f4f565b6040518082815260200191505060405180910390f35b34801561096a57600080fd5b50610973612f9b565b6040518085815260200184815260200183815260200182815260200194505050505060405180910390f35b3480156109aa57600080fd5b506109ed600480360360208110156109c157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612fc2565b604051808215151515815260200191505060405180910390f35b348015610a1357600080fd5b50610a6060048036036040811015610a2a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506130ec565b005b348015610a6e57600080fd5b50610a9b60048036036020811015610a8557600080fd5b8101908080359060200190929190505050613bf4565b005b348015610aa957600080fd5b50610aec60048036036020811015610ac057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506141a2565b6040518082815260200191505060405180910390f35b348015610b0e57600080fd5b50610b8660048036036020811015610b2557600080fd5b8101908080359060200190640100000000811115610b4257600080fd5b820183602082011115610b5457600080fd5b80359060200191846001830284011164010000000083111715610b7657600080fd5b9091929391929390505050614268565b005b348015610b9457600080fd5b50610bc160048036036020811015610bab57600080fd5b81019080803590602001909291905050506145a2565b005b348015610bcf57600080fd5b50610bfc60048036036020811015610be657600080fd5b81019080803590602001909291905050506146d5565b6040518082815260200191505060405180910390f35b348015610c1e57600080fd5b50610c6b60048036036040811015610c3557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506146f6565b005b348015610c7957600080fd5b50610c8261489a565b005b348015610c9057600080fd5b50610c996149d3565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610ce757600080fd5b50610cf06149f9565b6040518082815260200191505060405180910390f35b348015610d1257600080fd5b50610d5560048036036020811015610d2957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614a03565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610d98578082015181840152602081019050610d7d565b505050509050019250505060405180910390f35b348015610db857600080fd5b50610dc1614a5b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610e0f57600080fd5b50610e18614a84565b604051808215151515815260200191505060405180910390f35b348015610e3e57600080fd5b50610e8160048036036020811015610e5557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614ae2565b005b348015610e8f57600080fd5b50610ec660048036036040811015610ea657600080fd5b810190808035906020019092919080359060200190929190505050614c86565b005b348015610ed457600080fd5b50610f1760048036036020811015610eeb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061500a565b6040518082815260200191505060405180910390f35b348015610f3957600080fd5b50610f42615122565b6040518082815260200191505060405180910390f35b348015610f6457600080fd5b50610fa760048036036020811015610f7b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050615128565b6040518082815260200191505060405180910390f35b348015610fc957600080fd5b5061100c60048036036020811015610fe057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050615140565b6040518082815260200191505060405180910390f35b34801561102e57600080fd5b5061107b6004803603604081101561104557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061518f565b005b34801561108957600080fd5b506110d6600480360360408110156110a057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050615252565b604051808381526020018281526020019250505060405180910390f35b3480156110ff57600080fd5b506111426004803603602081101561111657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506154bd565b005b34801561115057600080fd5b506111936004803603602081101561116757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061558d565b005b3480156111a157600080fd5b506111e4600480360360208110156111b857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050615613565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561122b578082015181840152602081019050611210565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561126d578082015181840152602081019050611252565b5050505090500194505050505060405180910390f35b61128b6158d3565b005b606060058054806020026020016040519081016040528092919081815260200182805480156112db57602002820191906000526020600020905b8154815260200190600101908083116112c7575b5050505050905090565b60008060006112f2615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561136e57600080fd5b505afa158015611382573d6000803e3d6000fd5b505050506040513d602081101561139857600080fd5b8101908080519060200190929190505050905060006113b5615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561143157600080fd5b505afa158015611445573d6000803e3d6000fd5b505050506040513d602081101561145b57600080fd5b810190808051906020019092919050505090506114788282615bd3565b809450819550505050509250929050565b600160009054906101000a900460ff1681565b600080600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061150181600301604051806020016040529081600082015481525050615cb3565b915050919050565b611511617b51565b61151a82615cc1565b905061152d81611528615cdf565b615d05565b611582576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602f815260200180617f55602f913960400191505060405180910390fd5b600061158c615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561160857600080fd5b505afa15801561161c573d6000803e3d6000fd5b505050506040513d602081101561163257600080fd5b810190808051906020019092919050505090506000600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506116aa8160030160405180602001604052908160008201548152505084615d1b565b6116ff576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180617cc76023913960400191505060405180910390fd5b6000611709615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594876040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561178557600080fd5b505afa158015611799573d6000803e3d6000fd5b505050506040513d60208110156117af57600080fd5b810190808051906020019092919050505090506117cc8382615d31565b5060008260020160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506118348160000160405180602001604052908160008201548152505086615d1b565b6118a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f4e6f7420656e6f7567682064656c6567617465642070657263656e747300000081525060200191505060405180910390fd5b6118d18582600001604051806020016040529081600082015481525050615f9990919063ffffffff16565b816000016000820151816000015590505060006118ed856126a3565b905060008061191384600001604051806020016040529081600082015481525050615cb3565b1461194d5761194861193e6119398961192b86616040565b6160ca90919063ffffffff16565b616529565b846001015461654a565b611953565b82600101545b9050611960848285616563565b61198b8786600301604051806020016040529081600082015481525050615f9990919063ffffffff16565b856003016000820151816000015590505060006119bf84600001604051806020016040529081600082015481525050615cb3565b14156119dd576119db84866000016167c790919063ffffffff16565b505b8373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fc27c2c089d7c6709b0a8e68031ecc1c43dd5e4146d5d3aadad05f72a90bbf8ba611a358a615cb3565b84604051808381526020018281526020019250505060405180910390a3505050505050505050565b60405160200180807f456c656374696f6e0000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001203373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611b2e57600080fd5b505afa158015611b42573d6000803e3d6000fd5b505050506040513d6020811015611b5857600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614611bf2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f6f6e6c79207265676973746572656420636f6e7472616374000000000000000081525060200191505060405180910390fd5b611bfc83836169b5565b505050565b611c09614a84565b611c7b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80600a819055507f7e524139f5fe281f1ed40d0f650ab4edfb555978755a170ceda325e8968641b0816040518082815260200191505060405180910390a150565b611cc4614a84565b611d36576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600083836040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090506004600082815260200190815260200160002060009054906101000a900460ff16611de0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526027815260200180617f2e6027913960400191505060405180910390fd5b6005805490508210611e3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180617ed36028913960400191505060405180910390fd5b8060058381548110611e4b57fe5b906000526020600020015414611ec9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e64657820646f65736e2774206d61746368206964656e746966696572000081525060200191505060405180910390fd5b600560016005805490500381548110611ede57fe5b906000526020600020015460058381548110611ef657fe5b90600052602060002001819055506005805480611f0f57fe5b6001900381819060005260206000200160009055905560006004600083815260200190815260200160002060006101000a81548160ff021916908315150217905550838360405180838380828437808301925050509250505060405180910390207faee8df56d95b5766042c2ff4dcb39a120f0a09dd21bb9c143f86a314eff4b71460405160405180910390a250505050565b60075481565b600080611fb3615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561202f57600080fd5b505afa158015612043573d6000803e3d6000fd5b505050506040513d602081101561205957600080fd5b810190808051906020019092919050505090506000612076615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156120f257600080fd5b505afa158015612106573d6000803e3d6000fd5b505050506040513d602081101561211c57600080fd5b810190808051906020019092919050505090506121398282615d31565b9250505092915050565b6000806000600860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506121ea81600001604051806020016040529081600082015481525050615cb3565b925080600101549150509250929050565b60016000808282540192505081905550600080549050612219615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561229557600080fd5b505afa1580156122a9573d6000803e3d6000fd5b505050506040513d60208110156122bf57600080fd5b8101908080519060200190929190505050612325576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526040815260200180617de26040913960400191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806001018054905083106123e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4261642070656e64696e67207769746864726177616c20696e6465780000000081525060200191505060405180910390fd5b60008160010184815481106123f557fe5b90600052602060002090600202019050806001015442101561247f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f50656e64696e67207769746864726177616c206e6f7420617661696c61626c6581525060200191505060405180910390fd5b6000816000015490506124958360010186616a6f565b4781111561250b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f496e636f6e73697374656e742062616c616e636500000000000000000000000081525060200191505060405180910390fd5b612534813373ffffffffffffffffffffffffffffffffffffffff16616ae990919063ffffffff16565b3373ffffffffffffffffffffffffffffffffffffffff167f292d39ba701489b7f640c83806d3eeabe0a32c9f0a61b49e95612ebad42211cd826040518082815260200191505060405180910390a250505060005481146125fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5050565b600061269e61260d616c23565b73ffffffffffffffffffffffffffffffffffffffff16639a0e7d666040518163ffffffff1660e01b815260040160206040518083038186803b15801561265257600080fd5b505afa158015612666573d6000803e3d6000fd5b505050506040513d602081101561267c57600080fd5b8101908080519060200190929190505050600654616d1e90919063ffffffff16565b905090565b600080600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000015490506127bc6126f6616c23565b73ffffffffffffffffffffffffffffffffffffffff16636c781a2c856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561277257600080fd5b505afa158015612786573d6000803e3d6000fd5b505050506040513d602081101561279c57600080fd5b810190808051906020019092919050505082616d1e90919063ffffffff16565b915050919050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166317c508186005336040518363ffffffff1660e01b815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818154815260200191508054801561288b57602002820191906000526020600020905b815481526020019060010190808311612877575b5050935050505060206040518083038186803b1580156128aa57600080fd5b505afa1580156128be573d6000803e3d6000fd5b505050506040513d60208110156128d457600080fd5b810190808051906020019092919050505061293a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180617c7d6024913960400191505060405180910390fd5b600061294e8a6129498d6126a3565b61654a565b9050878110156129c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f7265776172642063616e6e6f74206578636565642070656e616c74792e00000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614612abc57612a02615ad8565b73ffffffffffffffffffffffffffffffffffffffff166393c5c4878a6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612a7e57600080fd5b505afa158015612a92573d6000803e3d6000fd5b505050506040513d6020811015612aa857600080fd5b810190808051906020019092919050505098505b6000600360008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050600080905082821015612ceb57612b238284616da690919063ffffffff16565b905080612b2e616c23565b73ffffffffffffffffffffffffffffffffffffffff16638ef01def8f848d8d8d8d8d8d6040518963ffffffff1660e01b8152600401808973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200188815260200180602001806020018060200184810384528a8a82818152602001925060200280828437600081840152601f19601f8201169050808301925050508481038352888882818152602001925060200280828437600081840152601f19601f8201169050808301925050508481038252868682818152602001925060200280828437600081840152601f19601f8201169050808301925050509b505050505050505050505050602060405180830381600087803b158015612c5957600080fd5b505af1158015612c6d573d6000803e3d6000fd5b505050506040513d6020811015612c8357600080fd5b810190808051906020019092919050505014612cea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061804f6021913960400191505060405180910390fd5b5b612d078d612d028386616da690919063ffffffff16565b6169b5565b612d118b8b616df0565b50506000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f476f7665726e616e636500000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015612dce57600080fd5b505afa158015612de2573d6000803e3d6000fd5b505050506040513d6020811015612df857600080fd5b81019080805190602001909291905050509050600081905047612e248b85616da690919063ffffffff16565b1115612e98576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f496e636f6e73697374656e742062616c616e636500000000000000000000000081525060200191505060405180910390fd5b612ed3612eae8b85616da690919063ffffffff16565b8273ffffffffffffffffffffffffffffffffffffffff16616ae990919063ffffffff16565b8a73ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167f7abcb995a115c34a67528d58d5fc5ce02c22cb835ce1685046163f7d366d7111858d604051808381526020018281526020019250505060405180910390a350505050505050505050505050565b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b60008060008060018060046000839350829250819150809050935093509350935090919293565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166317c508186005846040518363ffffffff1660e01b815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818154815260200191508054801561308b57602002820191906000526020600020905b815481526020019060010190808311613077575b5050935050505060206040518083038186803b1580156130aa57600080fd5b505afa1580156130be573d6000803e3d6000fd5b505050506040513d60208110156130d457600080fd5b81019080805190602001909291905050509050919050565b6130f4617b51565b6130fd82615cc1565b90506131108161310b615cdf565b615d05565b613165576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526031815260200180617e796031913960400191505060405180910390fd5b600061316f615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156131eb57600080fd5b505afa1580156131ff573d6000803e3d6000fd5b505050506040513d602081101561321557600080fd5b810190808051906020019092919050505090506000613232615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156132ae57600080fd5b505afa1580156132c2573d6000803e3d6000fd5b505050506040513d60208110156132d857600080fd5b8101908080519060200190929190505050905060006132f5616eaa565b90508073ffffffffffffffffffffffffffffffffffffffff1663facd743b846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561337457600080fd5b505afa158015613388573d6000803e3d6000fd5b505050506040513d602081101561339e57600080fd5b810190808051906020019092919050505015613405576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180617c5c6021913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166352f13a4e846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561348257600080fd5b505afa158015613496573d6000803e3d6000fd5b505050506040513d60208110156134ac57600080fd5b810190808051906020019092919050505015613513576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526027815260200180617fca6027913960400191505060405180910390fd5b6000600860008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061356c8382600001616fa590919063ffffffff16565b50600a5461357c82600001617075565b11156135f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f546f6f206d616e792064656c656761746565730000000000000000000000000081525060200191505060405180910390fd5b60008160020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506136578682600001604051806020016040529081600082015481525050615d1b565b6136ac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526046815260200180617c166046913960600191505060405180910390fd5b6136b4617b51565b613709876136fb8460000160405180602001604052908160008201548152505086600301604051806020016040529081600082015481525050615f9990919063ffffffff16565b61708690919063ffffffff16565b905061371c81613717615cdf565b615d05565b61378e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f43616e6e6f742064656c6567617465206d6f7265207468616e2031303025000081525060200191505060405180910390fd5b6000613799876126a3565b905060008114156138a2576137f9886137eb8560000160405180602001604052908160008201548152505087600301604051806020016040529081600082015481525050615f9990919063ffffffff16565b61708690919063ffffffff16565b84600301600082015181600001559050508783600001600082015181600001559050508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fc4ed9e859cb808c8bf287ad013d5178069b5e94d91819c335ba2e407fbed90446138748b615cb3565b8660010154604051808381526020018281526020019250505060405180910390a35050505050505050613bf0565b60006138ac61712f565b73ffffffffffffffffffffffffffffffffffffffff166366547163896040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561392857600080fd5b505afa15801561393c573d6000803e3d6000fd5b505050506040513d602081101561395257600080fd5b81019080805190602001909291905050509050600081146139fb57613975617b51565b61397f828461722a565b90506139a4613997858361708690919063ffffffff16565b61399f615cdf565b615d05565b6139f9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526033815260200180617efb6033913960400191505060405180910390fd5b505b6000613a3e613a39613a108760010154616040565b613a2b8d613a1d88616040565b6160ca90919063ffffffff16565b615f9990919063ffffffff16565b616529565b9050613a958a613a878760000160405180602001604052908160008201548152505089600301604051806020016040529081600082015481525050615f9990919063ffffffff16565b61708690919063ffffffff16565b8660030160008201518160000155905050898560000160008201518160000155905050613acf818660010154616d1e90919063ffffffff16565b8560010181905550613b2981600960008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054616d1e90919063ffffffff16565b600960008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff167fc4ed9e859cb808c8bf287ad013d5178069b5e94d91819c335ba2e407fbed9044613bc48d615cb3565b8860010154604051808381526020018281526020019250505060405180910390a3505050505050505050505b5050565b60016000808282540192505081905550600080549050613c12615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613c8e57600080fd5b505afa158015613ca2573d6000803e3d6000fd5b505050506040513d6020811015613cb857600080fd5b8101908080519060200190929190505050613d1e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526046815260200180617f846046913960600191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000613d6c336126a3565b90506000613d838583616da690919063ffffffff16565b90506000613d8f61712f565b73ffffffffffffffffffffffffffffffffffffffff166366547163336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613e0b57600080fd5b505afa158015613e1f573d6000803e3d6000fd5b505050506040513d6020811015613e3557600080fd5b8101908080519060200190929190505050905080821015613ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603581526020018061801a6035913960400191505060405180910390fd5b613ea9617b51565b600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003016040518060200160405290816000820154815250509050613f1581613f106000616040565b61726c565b15613f2557613f243388617281565b5b6000613f2f616eaa565b73ffffffffffffffffffffffffffffffffffffffff1663dcff4cf6336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613fab57600080fd5b505afa158015613fbf573d6000803e3d6000fd5b505050506040513d6020811015613fd557600080fd5b810190808051906020019092919050505090506000811480613ff75750838111155b61404c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526057815260200180617e226057913960600191505060405180910390fd5b61405633896169b5565b600061406d60075442616d1e90919063ffffffff16565b90508660010160405180604001604052808b8152602001838152509080600181540180825580915050906001820390600052602060002090600202016000909192909190915060008201518160000155602082015181600101555050503373ffffffffffffffffffffffffffffffffffffffff167fb1a3aef2a332070da206ad1868a5e327f5aa5144e00e9a7b40717c153158a5888a83604051808381526020018281526020019250505060405180910390a250505050505050600054811461419e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5050565b60006141ac617b51565b6141d66141c06141bb8561149c565b615cc1565b6141c8615cdf565b615f9990919063ffffffff16565b905060006141e3846126a3565b9050600061420a614205846141f785616040565b6160ca90919063ffffffff16565b616529565b905061425e600960008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482616d1e90919063ffffffff16565b9350505050919050565b614270614a84565b6142e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b60008282604051602001808383808284378083019250505092505050604051602081830303815290604052805190602001209050600073ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd927233836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156143a157600080fd5b505afa1580156143b5573d6000803e3d6000fd5b505050506040513d60208110156143cb57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161415614466576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4964656e746966696572206973206e6f7420726567697374657265640000000081525060200191505060405180910390fd5b6004600082815260200190815260200160002060009054906101000a900460ff16156144fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f43616e6e6f742061646420736c61736865722049442074776963652e0000000081525060200191505060405180910390fd5b600581908060018154018082558091505090600182039060005260206000200160009091929091909150555060016004600083815260200190815260200160002060006101000a81548160ff021916908315150217905550828260405180838380828437808301925050509250505060405180910390207f92a16cb9e1846d175c3007fc61953d186452c9ea1aa34183eb4b7f88cd3f07bb60405160405180910390a2505050565b6145aa614a84565b61461c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600754811415614694576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f556e6c6f636b696e6720706572696f64206e6f74206368616e6765640000000081525060200191505060405180910390fd5b806007819055507fd9274a7c98edc7c66931fc71872764091e7023fe3867358f8504d4c21b161fc5816040518082815260200191505060405180910390a150565b600581815481106146e257fe5b906000526020600020016000915090505481565b60405160200180807f456c656374696f6e0000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001203373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156147c757600080fd5b505afa1580156147db573d6000803e3d6000fd5b505050506040513d60208110156147f157600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161461488b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f6f6e6c79207265676973746572656420636f6e7472616374000000000000000081525060200191505060405180910390fd5b6148958383616df0565b505050565b6148a2614a84565b614914576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166001809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360006001806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600654905090565b606080614a50600860008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001617487565b905080915050919050565b60006001809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006001809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16614ac661756c565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b614aea614a84565b614b5c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415614bff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f43616e6e6f7420726567697374657220746865206e756c6c206164647265737381525060200191505060405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b60405160405180910390a250565b60016000808282540192505081905550600080549050614ca4615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015614d2057600080fd5b505afa158015614d34573d6000803e3d6000fd5b505050506040513d6020811015614d4a57600080fd5b8101908080519060200190929190505050614db0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526046815260200180617d2c6046913960600191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905080600101805490508410614e6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4261642070656e64696e67207769746864726177616c20696e6465780000000081525060200191505060405180910390fd5b6000816001018581548110614e8057fe5b906000526020600020906002020190508060000154841115614eed576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526029815260200180617eaa6029913960400191505060405180910390fd5b8060000154841415614f0b57614f068260010186616a6f565b614f2b565b614f22848260000154616da690919063ffffffff16565b81600001819055505b614f353385616df0565b614f3e33617574565b3373ffffffffffffffffffffffffffffffffffffffff167fa823fc38a01c2f76d7057a79bb5c317710f26f7dbdea78634598d5519d0f7cb0856040518082815260200191505060405180910390a250506000548114615005576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b505050565b600080600090506060600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101805480602002602001604051908101604052809291908181526020016000905b828210156150bb57838290600052602060002090600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190615075565b50505050905060008090505b8151811015615117576150fa8282815181106150df57fe5b60200260200101516000015184616d1e90919063ffffffff16565b9250615110600182616d1e90919063ffffffff16565b90506150c7565b508192505050919050565b60065481565b60096020528060005260406000206000915090505481565b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101805490509050919050565b600160009054906101000a900460ff1615615212576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b60018060006101000a81548160ff021916908315150217905550615235336176d1565b61523e82614ae2565b615247816145a2565b600a80819055505050565b60008061525d615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156152d957600080fd5b505afa1580156152ed573d6000803e3d6000fd5b505050506040513d602081101561530357600080fd5b8101908080519060200190929190505050615369576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526042815260200180617cea6042913960600191505060405180910390fd5b600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101805490508310615423576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4261642070656e64696e67207769746864726177616c20696e6465780000000081525060200191505060405180910390fd5b61542b617b64565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101848154811061547857fe5b90600052602060002090600202016040518060400160405290816000820154815260200160018201548152505090508060000151816020015192509250509250929050565b60006154c7615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561554357600080fd5b505afa158015615557573d6000803e3d6000fd5b505050506040513d602081101561556d57600080fd5b8101908080519060200190929190505050905061558981617574565b5050565b615595614a84565b615607576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b615610816176d1565b50565b60608061561e615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561569a57600080fd5b505afa1580156156ae573d6000803e3d6000fd5b505050506040513d60208110156156c457600080fd5b810190808051906020019092919050505061572a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526042815260200180617cea6042913960600191505060405180910390fd5b6000600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018054905090506060816040519080825280602002602001820160405280156157a55781602001602082028038833980820191505090505b5090506060826040519080825280602002602001820160405280156157d95781602001602082028038833980820191505090505b50905060008090505b838110156158c4576157f2617b64565b600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101828154811061583f57fe5b9060005260206000209060020201604051806040016040529081600082015481526020016001820154815250509050806000015184838151811061587f57fe5b602002602001018181525050806020015183838151811061589c57fe5b602002602001018181525050506158bd600182616d1e90919063ffffffff16565b90506157e2565b50818194509450505050915091565b600160008082825401925050819055506000805490506158f1615ad8565b73ffffffffffffffffffffffffffffffffffffffff166325ca4c9c336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561596d57600080fd5b505afa158015615981573d6000803e3d6000fd5b505050506040513d602081101561599757600080fd5b81019080805190602001909291905050506159fd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526036815260200180617be06036913960400191505060405180910390fd5b615a073334616df0565b615a1033617574565b3373ffffffffffffffffffffffffffffffffffffffff167f0f0f2fc5b4c987a49e1663ce2c2d65de12f3b701ff02b4d09461421e63e609e7346040518082815260200191505060405180910390a26000548114615ad5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015615b9357600080fd5b505afa158015615ba7573d6000803e3d6000fd5b505050506040513d6020811015615bbd57600080fd5b8101908080519060200190929190505050905090565b6000806000600860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000615c9e615c9983600001604051806020016040529081600082015481525050615c8b615c868a6126a3565b616040565b6160ca90919063ffffffff16565b616529565b90508093508160010154925050509250929050565b600081600001519050919050565b615cc9617b51565b6040518060200160405280838152509050919050565b615ce7617b51565b604051806020016040528069d3c21bcecceda1000000815250905090565b6000816000015183600001511115905092915050565b6000816000015183600001511015905092915050565b600080600860008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000615d9882600301604051806020016040529081600082015481525050615cb3565b1415615e0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f64656c656761746f72206973206e6f742064656c65676174696e67000000000081525060200191505060405180910390fd5b60008160020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000615e7482600001604051806020016040529081600082015481525050615cb3565b1415615ecb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526029815260200180617ff16029913960400191505060405180910390fd5b600080615ed887876112e5565b91509150818360010181905550615f4982615f3b83600960008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054616da690919063ffffffff16565b616d1e90919063ffffffff16565b600960008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508194505050505092915050565b615fa1617b51565b81600001518360000151101561601f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f737562737472616374696f6e20756e646572666c6f772064657465637465640081525060200191505060405180910390fd5b60405180602001604052808360000151856000015103815250905092915050565b616048617b51565b616050617815565b8211156160a8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526036815260200180617dac6036913960400191505060405180910390fd5b604051806020016040528069d3c21bcecceda100000084028152509050919050565b6160d2617b51565b6000836000015114806160e9575060008260000151145b1561610557604051806020016040528060008152509050616523565b69d3c21bcecceda10000008260000151141561612357829050616523565b69d3c21bcecceda10000008360000151141561614157819050616523565b600069d3c21bcecceda100000061615785617834565b600001518161616257fe5b04905060006161708561786b565b600001519050600069d3c21bcecceda100000061618c86617834565b600001518161619757fe5b04905060006161a58661786b565b600001519050600082850290506000851461623957828582816161c457fe5b0414616238576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b600069d3c21bcecceda100000082029050600082146162db5769d3c21bcecceda100000082828161626657fe5b04146162da576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f6f766572666c6f772078317931202a206669786564312064657465637465640081525060200191505060405180910390fd5b5b809150600084860290506000861461636c57848682816162f757fe5b041461636b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b60008488029050600088146163fa578488828161638557fe5b04146163f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b6164026178a8565b878161640a57fe5b0496506164156178a8565b858161641d57fe5b04945060008588029050600088146164ae578588828161643957fe5b04146164ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b6164b6617b51565b60405180602001604052808781525090506164df81604051806020016040528087815250617086565b90506164f981604051806020016040528086815250617086565b905061651381604051806020016040528085815250617086565b9050809a50505050505050505050505b92915050565b600069d3c21bcecceda100000082600001518161654257fe5b049050919050565b6000818310616559578161655b565b825b905092915050565b600061656e846141a2565b9050600061657a61712f565b73ffffffffffffffffffffffffffffffffffffffff166366547163866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156165f657600080fd5b505afa15801561660a573d6000803e3d6000fd5b505050506040513d602081101561662057600080fd5b8101908080519060200190929190505050905060006166488284616da690919063ffffffff16565b90508481101561670b5761665a61712f565b73ffffffffffffffffffffffffffffffffffffffff1663f3f6da2c876166898887616da690919063ffffffff16565b6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156166f257600080fd5b505af1158015616706573d6000803e3d6000fd5b505050505b616722858560010154616da690919063ffffffff16565b846001018190555061677c85600960008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054616da690919063ffffffff16565b600960008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050505050565b60006167d383836178b5565b156169aa57600060018460000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403905060006001856001018054905003905081811461691857600085600101828154811061684857fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508086600101848154811061688557fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600183018660000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505b8460000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600090558460010180548061696a57fe5b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590556001925050506169af565b600090505b92915050565b616a0a81600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154616da690919063ffffffff16565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000181905550616a6581600654616da690919063ffffffff16565b6006819055505050565b6000616a8960018480549050616da690919063ffffffff16565b9050828181548110616a9757fe5b9060005260206000209060020201838381548110616ab157fe5b90600052602060002090600202016000820154816000015560018201548160010155905050808381616ae39190617b7e565b50505050565b80471015616b5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f416464726573733a20696e73756666696369656e742062616c616e636500000081525060200191505060405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405180600001905060006040518083038185875af1925050503d8060008114616bbf576040519150601f19603f3d011682016040523d82523d6000602084013e616bc4565b606091505b5050905080616c1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603a815260200180617d72603a913960400191505060405180910390fd5b505050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f456c656374696f6e0000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015616cde57600080fd5b505afa158015616cf2573d6000803e3d6000fd5b505050506040513d6020811015616d0857600080fd5b8101908080519060200190929190505050905090565b600080828401905083811015616d9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b6000616de883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250617904565b905092915050565b616e4581600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154616d1e90919063ffffffff16565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000181905550616ea081600654616d1e90919063ffffffff16565b6006819055505050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f56616c696461746f727300000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015616f6557600080fd5b505afa158015616f79573d6000803e3d6000fd5b505050506040513d6020811015616f8f57600080fd5b8101908080519060200190929190505050905090565b6000616fb183836178b5565b61706a57826001018290806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001905061706f565b600090505b92915050565b600081600101805490509050919050565b61708e617b51565b6000826000015184600001510190508360000151811015617117576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f616464206f766572666c6f77206465746563746564000000000000000000000081525060200191505060405180910390fd5b60405180602001604052808281525091505092915050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f476f7665726e616e636500000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156171ea57600080fd5b505afa1580156171fe573d6000803e3d6000fd5b505050506040513d602081101561721457600080fd5b8101908080519060200190929190505050905090565b617232617b51565b61723a617b51565b61724384616040565b905061724d617b51565b61725684616040565b905061726282826179c4565b9250505092915050565b60008160000151836000015111905092915050565b606061728c83614a03565b90506000600860008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008090505b82518110156174805760008260020160008584815181106172f457fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000806173588887868151811061734b57fe5b6020026020010151615bd3565b915091506000617399617394856000016040518060200160405290816000820154815250506173868b616040565b6160ca90919063ffffffff16565b616529565b90506173c06173b18385616da690919063ffffffff16565b82616da690919063ffffffff16565b90506173e08786815181106173d157fe5b60200260200101518286616563565b8685815181106173ec57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff167fc27c2c089d7c6709b0a8e68031ecc1c43dd5e4146d5d3aadad05f72a90bbf8ba600084604051808381526020018281526020019250505060405180910390a350505050617479600182616d1e90919063ffffffff16565b90506172d7565b5050505050565b60608082600101805490506040519080825280602002602001820160405280156174c05781602001602082028038833980820191505090505b50905060005b8360010180549050811015617562578360010181815481106174e457fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682828151811061751b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080806001019150506174c6565b5080915050919050565b600033905090565b600061757e615ad8565b73ffffffffffffffffffffffffffffffffffffffff16636642d594836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156175fa57600080fd5b505afa15801561760e573d6000803e3d6000fd5b505050506040513d602081101561762457600080fd5b810190808051906020019092919050505090506000600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001905060008090505b61768c82617075565b8110156176cb576176af836176aa8385617b0d90919063ffffffff16565b615d31565b506176c4600182616d1e90919063ffffffff16565b9050617683565b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415617757576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180617ca16026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166001809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806001806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60007601357c299a88ea76a58924d52ce4f26a85af186c2b9e74905090565b61783c617b51565b604051806020016040528069d3c21bcecceda10000008085600001518161785f57fe5b04028152509050919050565b617873617b51565b604051806020016040528069d3c21bcecceda10000008085600001518161789657fe5b04028460000151038152509050919050565b600064e8d4a51000905090565b6000808360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541415905092915050565b60008383111582906179b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561797657808201518184015260208101905061795b565b50505050905090810190601f1680156179a35780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b6179cc617b51565b600082600001511415617a47576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f63616e277420646976696465206279203000000000000000000000000000000081525060200191505060405180910390fd5b600069d3c21bcecceda10000008460000151029050836000015169d3c21bcecceda10000008281617a7457fe5b0414617ae8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f6f766572666c6f7720617420646976696465000000000000000000000000000081525060200191505060405180910390fd5b604051806020016040528084600001518381617b0057fe5b0481525091505092915050565b6000826001018281548110617b1e57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905092915050565b6040518060200160405280600081525090565b604051806040016040528060008152602001600081525090565b815481835581811115617bab57600202816002028360005260206000209182019101617baa9190617bb0565b5b505050565b617bdc91905b80821115617bd857600080820160009055600182016000905550600201617bb6565b5090565b9056fe4d75737420666972737420726567697374657220616464726573732077697468204163636f756e742e6372656174654163636f756e7443616e6e6f742064656372656173652064656c65676174656420616d6f756e74202d20757365207265766f6b6544656c656761746564476f7665726e616e6365566f7465732e56616c696461746f72732063616e6e6f742064656c656761746520766f7465732e43616c6c6572206973206e6f7420612077686974656c697374656420736c61736865722e4f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734e6f7420656e6f75676820746f74616c2064656c6567617465642070657263656e7473556e6b6e6f776e206163636f756e743a206f6e6c792072656769737465726564206163636f756e747320686176652070656e64696e67207769746864726177616c7353656e646572206d75737420626520726567697374657265642077697468204163636f756e742e6372656174654163636f756e7420746f206c6f636b206f722072656c6f636b416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d6179206861766520726576657274656463616e277420637265617465206669786964697479206e756d626572206c6172676572207468616e206d61784e65774669786564282953656e646572206d75737420626520726567697374657265642077697468204163636f756e742e6372656174654163636f756e7420746f207769746864726177456974686572206163636f756e7420646f65736e2774206861766520656e6f756768206c6f636b65642043656c6f206f72206c6f636b65642043656c6f206973206265696e67207573656420666f7220766f74696e672e44656c6567617465206672616374696f6e206d757374206265206c657373207468616e206f7220657175616c20746f20315265717565737465642076616c7565206c6172676572207468616e2070656e64696e672076616c756550726f766964656420696e64657820657863656564732077686974656c69737420626f756e64732e43616e6e6f742064656c656761746520766f74657320746861742061726520766f74696e6720696e207265666572656e64756d43616e6e6f742072656d6f766520736c6173686572204944206e6f74207965742061646465642e5265766f6b65206672616374696f6e206d757374206265206c657373207468616e206f7220657175616c20746f203153656e646572206d75737420626520726567697374657265642077697468204163636f756e742e6372656174654163636f756e7420746f206c6f636b206f7220756e6c6f636b56616c696461746f722067726f7570732063616e6e6f742064656c656761746520766f7465732e64656c656761746f72206973206e6f742064656c65676174696e6720666f722064656c6567617465654e6f7420656e6f75676820756e6c6f636b61626c652063656c6f2e2043656c6f206973206c6f636b656420696e20766f74696e672e43616e6e6f74207265766f6b6520656e6f75676820766f74696e6720676f6c642ea265627a7a72315820fa955df143e228c48555be73b4ae9451b451b9538eb849f1c7d36b0f5e2d85f064736f6c634300050d0032