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