Address Details
contract

0x07D951465be79619A36B5E749132AF32DbcAc9BC

Contract Name
Reserve
Creator
0x0cc59e–f1502d at 0x7e44bd–15b7db
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
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
2159393
Contract name:
Reserve




Optimization enabled
false
Compiler version
v0.5.8+commit.23d335f2




Verified at
2020-08-11T19:18:24.920770Z

Contract source code

pragma solidity ^0.5.3;


library SafeMath {
    
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        
        
        
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        
        require(b > 0, errorMessage);
        uint256 c = a / b;
        

        return c;
    }

    
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

contract Context {
    
    
    constructor () internal { }
    

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; 
        return msg.data;
    }
}

contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    
    function owner() public view returns (address) {
        return _owner;
    }

    
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    
    function isOwner() public view returns (bool) {
        return _msgSender() == _owner;
    }

    
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

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);
}

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);
}

library FixidityLib {
  struct Fraction {
    uint256 value;
  }

  
  function digits() internal pure returns (uint8) {
    return 24;
  }

  uint256 private constant FIXED1_UINT = 1000000000000000000000000;

  
  function fixed1() internal pure returns (Fraction memory) {
    return Fraction(FIXED1_UINT);
  }

  
  function wrap(uint256 x) internal pure returns (Fraction memory) {
    return Fraction(x);
  }

  
  function unwrap(Fraction memory x) internal pure returns (uint256) {
    return x.value;
  }

  
  function mulPrecision() internal pure returns (uint256) {
    return 1000000000000;
  }

  
  function maxNewFixed() internal pure returns (uint256) {
    return 115792089237316195423570985008687907853269984665640564;
  }

  
  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);
  }

  
  function fromFixed(Fraction memory x) internal pure returns (uint256) {
    return x.value / FIXED1_UINT;
  }

  
  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);
  }

  
  function integer(Fraction memory x) internal pure returns (Fraction memory) {
    return Fraction((x.value / FIXED1_UINT) * FIXED1_UINT); 
  }

  
  function fractional(Fraction memory x) internal pure returns (Fraction memory) {
    return Fraction(x.value - (x.value / FIXED1_UINT) * FIXED1_UINT); 
  }

  
  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);
  }

  
  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);
  }

  
  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;

    
    
    uint256 x1 = integer(x).value / FIXED1_UINT;
    uint256 x2 = fractional(x).value;
    uint256 y1 = integer(y).value / FIXED1_UINT;
    uint256 y2 = fractional(y).value;

    
    uint256 x1y1 = x1 * y1;
    if (x1 != 0) require(x1y1 / x1 == y1, "overflow x1y1 detected");

    
    
    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");

    
    Fraction memory result = Fraction(x1y1);
    result = add(result, Fraction(x2y1)); 
    result = add(result, Fraction(x1y2)); 
    result = add(result, Fraction(x2y2)); 
    return result;
  }

  
  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); 
  }

  
  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);
  }

  
  function gt(Fraction memory x, Fraction memory y) internal pure returns (bool) {
    return x.value > y.value;
  }

  
  function gte(Fraction memory x, Fraction memory y) internal pure returns (bool) {
    return x.value >= y.value;
  }

  
  function lt(Fraction memory x, Fraction memory y) internal pure returns (bool) {
    return x.value < y.value;
  }

  
  function lte(Fraction memory x, Fraction memory y) internal pure returns (bool) {
    return x.value <= y.value;
  }

  
  function equals(Fraction memory x, Fraction memory y) internal pure returns (bool) {
    return x.value == y.value;
  }

  
  function isProperFraction(Fraction memory x) internal pure returns (bool) {
    return lte(x, fixed1());
  }
}

contract Initializable {
  bool public initialized;

  modifier initializer() {
    require(!initialized, "contract already initialized");
    initialized = true;
    _;
  }
}

interface IERC20 {
    
    function totalSupply() external view returns (uint256);

    
    function balanceOf(address account) external view returns (uint256);

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

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

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

    
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    
    event Transfer(address indexed from, address indexed to, uint256 value);

    
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

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);
}

interface IFeeCurrencyWhitelist {
  function addToken(address) external;
  function getWhitelist() external view returns (address[] memory);
}

interface IFreezer {
  function isFrozen(address) external view returns (bool);
}

interface IRegistry {
  function setAddressFor(string calldata, address) external;
  function getAddressForOrDie(bytes32) external view returns (address);
  function getAddressFor(bytes32) external view returns (address);
  function isOneOf(bytes32[] calldata, address) external view returns (bool);
}

interface IElection {
  function getTotalVotes() external view returns (uint256);
  function getActiveVotes() external view returns (uint256);
  function getTotalVotesByAccount(address) external view returns (uint256);
  function markGroupIneligible(address) external;
  function markGroupEligible(address, address, address) external;
  function electValidatorSigners() 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 forceDecrementVotes(
    address,
    uint256,
    address[] calldata,
    address[] calldata,
    uint256[] calldata
  ) external returns (uint256);
}

interface IGovernance {
  function isVoting(address) external view returns (bool);
}

interface ILockedGold {
  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 getTotalPendingWithdrawals(address) external view returns (uint256);
  function lock() external payable;
  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);
}

interface IValidators {
  function getAccountLockedGoldRequirement(address) external view returns (uint256);
  function meetsAccountLockedGoldRequirements(address) external view returns (bool);
  function getGroupNumMembers(address) external view returns (uint256);
  function getGroupsNumMembers(address[] calldata) external view returns (uint256[] memory);
  function getNumRegisteredValidators() external view returns (uint256);
  function getTopGroupValidators(address, uint256) external view returns (address[] memory);
  function updateEcdsaPublicKey(address, address, bytes calldata) external returns (bool);
  function updatePublicKeys(address, address, bytes calldata, bytes calldata, bytes calldata)
    external
    returns (bool);
  function isValidator(address) external view returns (bool);
  function isValidatorGroup(address) external view returns (bool);
  function calculateGroupEpochScore(uint256[] calldata uptimes) external view returns (uint256);
  function groupMembershipInEpoch(address account, uint256 epochNumber, uint256 index)
    external
    view
    returns (address);
  function halveSlashingMultiplier(address group) external;
  function forceDeaffiliateIfValidator(address validator) external;
  function getValidatorGroupSlashingMultiplier(address) external view returns (uint256);
  function affiliate(address group) external returns (bool);
}

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);
}

interface IAttestations {
  function setAttestationRequestFee(address, uint256) external;
  function request(bytes32, uint256, address) external;
  function selectIssuers(bytes32) external;
  function complete(bytes32, uint8, bytes32, bytes32) external;
  function revoke(bytes32, uint256) external;
  function withdraw(address) external;

  function setAttestationExpiryBlocks(uint256) external;

  function getMaxAttestations() external view returns (uint256);

  function getUnselectedRequest(bytes32, address) external view returns (uint32, uint32, address);
  function getAttestationRequestFee(address) external view returns (uint256);

  function lookupAccountsForIdentifier(bytes32) external view returns (address[] memory);

  function getAttestationStats(bytes32, address) external view returns (uint32, uint32);

  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);
}

interface IExchange {
  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);
}

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);

  
  function balanceOf(address) external view returns (uint256);
}

contract UsingRegistry is Ownable {
  event RegistrySet(address indexed registryAddress);

  
  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"));
  

  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");
    _;
  }

  
  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));
  }
}

contract ReentrancyGuard {
  
  uint256 private _guardCounter;

  constructor() internal {
    
    
    _guardCounter = 1;
  }

  
  modifier nonReentrant() {
    _guardCounter += 1;
    uint256 localCounter = _guardCounter;
    _;
    require(localCounter == _guardCounter, "reentrant call");
  }
}

contract Reserve is IReserve, Ownable, Initializable, UsingRegistry, ReentrancyGuard {
  using SafeMath for uint256;
  using FixidityLib for FixidityLib.Fraction;

  struct TobinTaxCache {
    uint128 numerator;
    uint128 timestamp;
  }

  mapping(address => bool) public isToken;
  address[] private _tokens;
  TobinTaxCache public tobinTaxCache;
  uint256 public tobinTaxStalenessThreshold;
  uint256 public tobinTax;
  uint256 public tobinTaxReserveRatio;
  mapping(address => bool) public isSpender;

  mapping(address => bool) public isOtherReserveAddress;
  address[] public otherReserveAddresses;

  bytes32[] public assetAllocationSymbols;
  mapping(bytes32 => uint256) public assetAllocationWeights;

  uint256 public lastSpendingDay;
  uint256 public spendingLimit;
  FixidityLib.Fraction private spendingRatio;

  uint256 public frozenReserveGoldStartBalance;
  uint256 public frozenReserveGoldStartDay;
  uint256 public frozenReserveGoldDays;

  event TobinTaxStalenessThresholdSet(uint256 value);
  event DailySpendingRatioSet(uint256 ratio);
  event TokenAdded(address indexed token);
  event TokenRemoved(address indexed token, uint256 index);
  event SpenderAdded(address indexed spender);
  event SpenderRemoved(address indexed spender);
  event OtherReserveAddressAdded(address indexed otherReserveAddress);
  event OtherReserveAddressRemoved(address indexed otherReserveAddress, uint256 index);
  event AssetAllocationSet(bytes32[] symbols, uint256[] weights);
  event ReserveGoldTransferred(address indexed spender, address indexed to, uint256 value);
  event TobinTaxSet(uint256 value);
  event TobinTaxReserveRatioSet(uint256 value);

  modifier isStableToken(address token) {
    require(isToken[token], "token addr was never registered");
    _;
  }

  function() external payable {} 

  
  function initialize(
    address registryAddress,
    uint256 _tobinTaxStalenessThreshold,
    uint256 _spendingRatio,
    uint256 _frozenGold,
    uint256 _frozenDays,
    bytes32[] calldata _assetAllocationSymbols,
    uint256[] calldata _assetAllocationWeights,
    uint256 _tobinTax,
    uint256 _tobinTaxReserveRatio
  ) external initializer {
    _transferOwnership(msg.sender);
    setRegistry(registryAddress);
    setTobinTaxStalenessThreshold(_tobinTaxStalenessThreshold);
    setDailySpendingRatio(_spendingRatio);
    setFrozenGold(_frozenGold, _frozenDays);
    setAssetAllocations(_assetAllocationSymbols, _assetAllocationWeights);
    setTobinTax(_tobinTax);
    setTobinTaxReserveRatio(_tobinTaxReserveRatio);
  }

  
  function setTobinTaxStalenessThreshold(uint256 value) public onlyOwner {
    require(value > 0, "value was zero");
    tobinTaxStalenessThreshold = value;
    emit TobinTaxStalenessThresholdSet(value);
  }

  
  function setTobinTax(uint256 value) public onlyOwner {
    require(FixidityLib.wrap(value).lte(FixidityLib.fixed1()), "tobin tax cannot be larger than 1");
    tobinTax = value;
    emit TobinTaxSet(value);
  }

  
  function setTobinTaxReserveRatio(uint256 value) public onlyOwner {
    tobinTaxReserveRatio = value;
    emit TobinTaxReserveRatioSet(value);
  }

  
  function setDailySpendingRatio(uint256 ratio) public onlyOwner {
    spendingRatio = FixidityLib.wrap(ratio);
    require(spendingRatio.lte(FixidityLib.fixed1()), "spending ratio cannot be larger than 1");
    emit DailySpendingRatioSet(ratio);
  }

  
  function getDailySpendingRatio() public view returns (uint256) {
    return spendingRatio.unwrap();
  }

  
  function setFrozenGold(uint256 frozenGold, uint256 frozenDays) public onlyOwner {
    require(frozenGold <= address(this).balance, "Cannot freeze more than balance");
    frozenReserveGoldStartBalance = frozenGold;
    frozenReserveGoldStartDay = now / 1 days;
    frozenReserveGoldDays = frozenDays;
  }

  
  function setAssetAllocations(bytes32[] memory symbols, uint256[] memory weights)
    public
    onlyOwner
  {
    require(symbols.length == weights.length, "Array length mismatch");
    FixidityLib.Fraction memory sum = FixidityLib.wrap(0);
    for (uint256 i = 0; i < weights.length; i = i.add(1)) {
      sum = sum.add(FixidityLib.wrap(weights[i]));
    }
    require(sum.equals(FixidityLib.fixed1()), "Sum of asset allocation must be 1");
    for (uint256 i = 0; i < assetAllocationSymbols.length; i = i.add(1)) {
      delete assetAllocationWeights[assetAllocationSymbols[i]];
    }
    assetAllocationSymbols = symbols;
    for (uint256 i = 0; i < symbols.length; i = i.add(1)) {
      require(assetAllocationWeights[symbols[i]] == 0, "Cannot set weight twice");
      assetAllocationWeights[symbols[i]] = weights[i];
    }
    require(assetAllocationWeights["cGLD"] != 0, "Must set cGLD asset weight");
    emit AssetAllocationSet(symbols, weights);
  }

  
  function addToken(address token) external onlyOwner nonReentrant returns (bool) {
    require(!isToken[token], "token addr already registered");
    
    address sortedOraclesAddress = registry.getAddressForOrDie(SORTED_ORACLES_REGISTRY_ID);
    ISortedOracles sortedOracles = ISortedOracles(sortedOraclesAddress);
    uint256 tokenAmount;
    uint256 goldAmount;
    (tokenAmount, goldAmount) = sortedOracles.medianRate(token);
    require(goldAmount > 0, "median rate returned 0 gold");
    isToken[token] = true;
    _tokens.push(token);
    emit TokenAdded(token);
    return true;
  }

  
  function removeToken(address token, uint256 index)
    external
    onlyOwner
    isStableToken(token)
    returns (bool)
  {
    require(
      index < _tokens.length && _tokens[index] == token,
      "index into tokens list not mapped to token"
    );
    isToken[token] = false;
    address lastItem = _tokens[_tokens.length.sub(1)];
    _tokens[index] = lastItem;
    _tokens.length = _tokens.length.sub(1);
    emit TokenRemoved(token, index);
    return true;
  }

  
  function addOtherReserveAddress(address reserveAddress)
    external
    onlyOwner
    nonReentrant
    returns (bool)
  {
    require(!isOtherReserveAddress[reserveAddress], "reserve addr already added");
    isOtherReserveAddress[reserveAddress] = true;
    otherReserveAddresses.push(reserveAddress);
    emit OtherReserveAddressAdded(reserveAddress);
    return true;
  }

  
  function removeOtherReserveAddress(address reserveAddress, uint256 index)
    external
    onlyOwner
    returns (bool)
  {
    require(isOtherReserveAddress[reserveAddress], "reserve addr was never added");
    require(
      index < otherReserveAddresses.length && otherReserveAddresses[index] == reserveAddress,
      "index into reserve list not mapped to address"
    );
    isOtherReserveAddress[reserveAddress] = false;
    address lastItem = otherReserveAddresses[otherReserveAddresses.length.sub(1)];
    otherReserveAddresses[index] = lastItem;
    otherReserveAddresses.length = otherReserveAddresses.length.sub(1);
    emit OtherReserveAddressRemoved(reserveAddress, index);
    return true;
  }

  
  function addSpender(address spender) external onlyOwner {
    isSpender[spender] = true;
    emit SpenderAdded(spender);
  }

  
  function removeSpender(address spender) external onlyOwner {
    isSpender[spender] = false;
    emit SpenderRemoved(spender);
  }

  
  function transferGold(address payable to, uint256 value) external returns (bool) {
    require(isSpender[msg.sender], "sender not allowed to transfer Reserve funds");
    require(isOtherReserveAddress[to], "can only transfer to other reserve address");
    uint256 currentDay = now / 1 days;
    if (currentDay > lastSpendingDay) {
      uint256 balance = getUnfrozenReserveGoldBalance();
      lastSpendingDay = currentDay;
      spendingLimit = spendingRatio.multiply(FixidityLib.newFixed(balance)).fromFixed();
    }
    require(spendingLimit >= value, "Exceeding spending limit");
    spendingLimit = spendingLimit.sub(value);
    return _transferGold(to, value);
  }

  
  function _transferGold(address payable to, uint256 value) internal returns (bool) {
    require(value <= getUnfrozenBalance(), "Exceeding unfrozen reserves");
    to.transfer(value);
    emit ReserveGoldTransferred(msg.sender, to, value);
    return true;
  }

  
  function transferExchangeGold(address payable to, uint256 value)
    external
    onlyRegisteredContract(EXCHANGE_REGISTRY_ID)
    returns (bool)
  {
    return _transferGold(to, value);
  }

  
  function getOrComputeTobinTax() external nonReentrant returns (uint256, uint256) {
    
    if (now.sub(tobinTaxCache.timestamp) > tobinTaxStalenessThreshold) {
      tobinTaxCache.numerator = uint128(computeTobinTax().unwrap());
      tobinTaxCache.timestamp = uint128(now); 
    }
    return (uint256(tobinTaxCache.numerator), FixidityLib.fixed1().unwrap());
  }

  
  function getTokens() external view returns (address[] memory) {
    return _tokens;
  }

  
  function getOtherReserveAddresses() external view returns (address[] memory) {
    return otherReserveAddresses;
  }

  
  function getAssetAllocationSymbols() external view returns (bytes32[] memory) {
    return assetAllocationSymbols;
  }

  
  function getAssetAllocationWeights() external view returns (uint256[] memory) {
    uint256[] memory weights = new uint256[](assetAllocationSymbols.length);
    for (uint256 i = 0; i < assetAllocationSymbols.length; i = i.add(1)) {
      weights[i] = assetAllocationWeights[assetAllocationSymbols[i]];
    }
    return weights;
  }

  
  function getUnfrozenBalance() public view returns (uint256) {
    uint256 balance = address(this).balance;
    uint256 frozenReserveGold = getFrozenReserveGoldBalance();
    return balance > frozenReserveGold ? balance.sub(frozenReserveGold) : 0;
  }

  
  function getReserveGoldBalance() public view returns (uint256) {
    return address(this).balance.add(getOtherReserveAddressesGoldBalance());
  }

  
  function getOtherReserveAddressesGoldBalance() public view returns (uint256) {
    uint256 reserveGoldBalance = 0;
    for (uint256 i = 0; i < otherReserveAddresses.length; i = i.add(1)) {
      reserveGoldBalance = reserveGoldBalance.add(otherReserveAddresses[i].balance);
    }
    return reserveGoldBalance;
  }

  
  function getUnfrozenReserveGoldBalance() public view returns (uint256) {
    return getUnfrozenBalance().add(getOtherReserveAddressesGoldBalance());
  }

  
  function getFrozenReserveGoldBalance() public view returns (uint256) {
    uint256 currentDay = now / 1 days;
    uint256 frozenDays = currentDay.sub(frozenReserveGoldStartDay);
    if (frozenDays >= frozenReserveGoldDays) return 0;
    return
      frozenReserveGoldStartBalance.sub(
        frozenReserveGoldStartBalance.mul(frozenDays).div(frozenReserveGoldDays)
      );
  }

  
  function getReserveRatio() public view returns (uint256) {
    address sortedOraclesAddress = registry.getAddressForOrDie(SORTED_ORACLES_REGISTRY_ID);
    ISortedOracles sortedOracles = ISortedOracles(sortedOraclesAddress);
    uint256 reserveGoldBalance = getUnfrozenReserveGoldBalance();
    uint256 stableTokensValueInGold = 0;
    FixidityLib.Fraction memory cgldWeight = FixidityLib.wrap(assetAllocationWeights["cGLD"]);

    for (uint256 i = 0; i < _tokens.length; i = i.add(1)) {
      uint256 stableAmount;
      uint256 goldAmount;
      (stableAmount, goldAmount) = sortedOracles.medianRate(_tokens[i]);
      uint256 stableTokenSupply = IERC20(_tokens[i]).totalSupply();
      uint256 aStableTokenValueInGold = stableTokenSupply.mul(goldAmount).div(stableAmount);
      stableTokensValueInGold = stableTokensValueInGold.add(aStableTokenValueInGold);
    }
    return
      FixidityLib
        .newFixed(reserveGoldBalance)
        .divide(cgldWeight)
        .divide(FixidityLib.newFixed(stableTokensValueInGold))
        .unwrap();
  }

  

  
  function computeTobinTax() private view returns (FixidityLib.Fraction memory) {
    FixidityLib.Fraction memory ratio = FixidityLib.wrap(getReserveRatio());
    if (ratio.gte(FixidityLib.wrap(tobinTaxReserveRatio))) {
      return FixidityLib.wrap(0);
    } else {
      return FixidityLib.wrap(tobinTax);
    }
  }
}
        

Contract ABI

[{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setDailySpendingRatio","inputs":[{"type":"uint256","name":"ratio"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"transferExchangeGold","inputs":[{"type":"address","name":"to"},{"type":"uint256","name":"value"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"frozenReserveGoldStartBalance","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"assetAllocationSymbols","inputs":[{"type":"uint256","name":""}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"removeToken","inputs":[{"type":"address","name":"token"},{"type":"uint256","name":"index"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"initialized","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"getOrComputeTobinTax","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isToken","inputs":[{"type":"address","name":""}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"transferGold","inputs":[{"type":"address","name":"to"},{"type":"uint256","name":"value"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"addOtherReserveAddress","inputs":[{"type":"address","name":"reserveAddress"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint128","name":"numerator"},{"type":"uint128","name":"timestamp"}],"name":"tobinTaxCache","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getFrozenReserveGoldBalance","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"spendingLimit","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"otherReserveAddresses","inputs":[{"type":"uint256","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getReserveRatio","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"removeOtherReserveAddress","inputs":[{"type":"address","name":"reserveAddress"},{"type":"uint256","name":"index"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"frozenReserveGoldDays","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getOtherReserveAddressesGoldBalance","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"tobinTaxReserveRatio","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getDailySpendingRatio","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"registry","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isOtherReserveAddress","inputs":[{"type":"address","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"frozenReserveGoldStartDay","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32[]","name":""}],"name":"getAssetAllocationSymbols","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"tobinTax","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getUnfrozenReserveGoldBalance","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeSpender","inputs":[{"type":"address","name":"spender"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getReserveGoldBalance","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isOwner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isSpender","inputs":[{"type":"address","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":""}],"name":"getOtherReserveAddresses","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setTobinTaxStalenessThreshold","inputs":[{"type":"uint256","name":"value"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"address","name":"registryAddress"},{"type":"uint256","name":"_tobinTaxStalenessThreshold"},{"type":"uint256","name":"_spendingRatio"},{"type":"uint256","name":"_frozenGold"},{"type":"uint256","name":"_frozenDays"},{"type":"bytes32[]","name":"_assetAllocationSymbols"},{"type":"uint256[]","name":"_assetAllocationWeights"},{"type":"uint256","name":"_tobinTax"},{"type":"uint256","name":"_tobinTaxReserveRatio"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setRegistry","inputs":[{"type":"address","name":"registryAddress"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":""}],"name":"getTokens","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setTobinTaxReserveRatio","inputs":[{"type":"uint256","name":"value"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setAssetAllocations","inputs":[{"type":"bytes32[]","name":"symbols"},{"type":"uint256[]","name":"weights"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"addToken","inputs":[{"type":"address","name":"token"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getUnfrozenBalance","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"tobinTaxStalenessThreshold","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":""}],"name":"getAssetAllocationWeights","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setTobinTax","inputs":[{"type":"uint256","name":"value"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addSpender","inputs":[{"type":"address","name":"spender"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setFrozenGold","inputs":[{"type":"uint256","name":"frozenGold"},{"type":"uint256","name":"frozenDays"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"assetAllocationWeights","inputs":[{"type":"bytes32","name":""}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"lastSpendingDay","inputs":[],"constant":true},{"type":"fallback","stateMutability":"payable","payable":true},{"type":"event","name":"TobinTaxStalenessThresholdSet","inputs":[{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"DailySpendingRatioSet","inputs":[{"type":"uint256","name":"ratio","indexed":false}],"anonymous":false},{"type":"event","name":"TokenAdded","inputs":[{"type":"address","name":"token","indexed":true}],"anonymous":false},{"type":"event","name":"TokenRemoved","inputs":[{"type":"address","name":"token","indexed":true},{"type":"uint256","name":"index","indexed":false}],"anonymous":false},{"type":"event","name":"SpenderAdded","inputs":[{"type":"address","name":"spender","indexed":true}],"anonymous":false},{"type":"event","name":"SpenderRemoved","inputs":[{"type":"address","name":"spender","indexed":true}],"anonymous":false},{"type":"event","name":"OtherReserveAddressAdded","inputs":[{"type":"address","name":"otherReserveAddress","indexed":true}],"anonymous":false},{"type":"event","name":"OtherReserveAddressRemoved","inputs":[{"type":"address","name":"otherReserveAddress","indexed":true},{"type":"uint256","name":"index","indexed":false}],"anonymous":false},{"type":"event","name":"AssetAllocationSet","inputs":[{"type":"bytes32[]","name":"symbols","indexed":false},{"type":"uint256[]","name":"weights","indexed":false}],"anonymous":false},{"type":"event","name":"ReserveGoldTransferred","inputs":[{"type":"address","name":"spender","indexed":true},{"type":"address","name":"to","indexed":true},{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"TobinTaxSet","inputs":[{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"TobinTaxReserveRatioSet","inputs":[{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"RegistrySet","inputs":[{"type":"address","name":"registryAddress","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false}]
              

Contract Creation Code

0x6080604052600062000016620000c260201b60201c565b9050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3506001600281905550620000ca565b600033905090565b61539780620000da6000396000f3fe6080604052600436106102ae5760003560e01c80638438796a11610175578063aa6ca808116100dc578063e50a6c1e11610095578063e83b373b1161006f578063e83b373b1461119c578063ec4f797b146111e1578063f2fde38b14611230578063fa9ed95a14611281576102ae565b8063e50a6c1e146110a4578063e6b76e9c14611110578063e7e31e7a1461114b576102ae565b8063aa6ca80814610de5578063ad62ad1014610e51578063ca56d33b14610e8c578063d48bfca714610fe5578063e30f579d1461104e578063e33a88e714611079576102ae565b80638f32d59b1161012e5780638f32d59b14610b1d5780639a206ece14610b4c5780639c3e2f0f14610bb5578063a1ab55b314610c21578063a3e1f00d14610c5c578063a91ee0dc14610d94576102ae565b80638438796a14610988578063894098d6146109f45780638b7df8d414610a1f5780638ce5877c14610a4a5780638d9a5e6f14610a9b5780638da5cb5b14610ac6576102ae565b806339d7f76e11610219578063765c1fe9116101d2578063765c1fe91461081c57806376769a60146108475780637897a78e146108725780637b1039991461089d5780637b522075146108f457806381b861a61461095d576102ae565b806339d7f76e1461069657806340899365146106c157806356b6d0d51461073c5780635c4a3145146107675780637090db4e146107da578063715018a614610805576102ae565b806317f9a6f71161026b57806317f9a6f71461047a57806319f37361146104ac5780631c39c7d514610515578063220159681461058857806322796e83146105f15780632aa1c16d1461066b576102ae565b806301da32bd146102b057806303a0fea3146102eb57806303d835f31461035e5780630db279be1461038957806313baf1e6146103d8578063158ef93e1461044b575b005b3480156102bc57600080fd5b506102e9600480360360208110156102d357600080fd5b81019080803590602001909291905050506112ac565b005b3480156102f757600080fd5b506103446004803603604081101561030e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506113fd565b604051808215151515815260200191505060405180910390f35b34801561036a57600080fd5b506103736115a7565b6040518082815260200191505060405180910390f35b34801561039557600080fd5b506103c2600480360360208110156103ac57600080fd5b81019080803590602001909291905050506115ad565b6040518082815260200191505060405180910390f35b3480156103e457600080fd5b50610431600480360360408110156103fb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115ce565b604051808215151515815260200191505060405180910390f35b34801561045757600080fd5b50610460611958565b604051808215151515815260200191505060405180910390f35b34801561048657600080fd5b5061048f61196b565b604051808381526020018281526020019250505060405180910390f35b3480156104b857600080fd5b506104fb600480360360208110156104cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611b21565b604051808215151515815260200191505060405180910390f35b34801561052157600080fd5b5061056e6004803603604081101561053857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611b41565b604051808215151515815260200191505060405180910390f35b34801561059457600080fd5b506105d7600480360360208110156105ab57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611d9c565b604051808215151515815260200191505060405180910390f35b3480156105fd57600080fd5b50610606612072565b60405180836fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168152602001826fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020019250505060405180910390f35b34801561067757600080fd5b506106806120bc565b6040518082815260200191505060405180910390f35b3480156106a257600080fd5b506106ab612140565b6040518082815260200191505060405180910390f35b3480156106cd57600080fd5b506106fa600480360360208110156106e457600080fd5b8101908080359060200190929190505050612146565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074857600080fd5b50610751612182565b6040518082815260200191505060405180910390f35b34801561077357600080fd5b506107c06004803603604081101561078a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061254e565b604051808215151515815260200191505060405180910390f35b3480156107e657600080fd5b506107ef6128d6565b6040518082815260200191505060405180910390f35b34801561081157600080fd5b5061081a6128dc565b005b34801561082857600080fd5b50610831612a15565b6040518082815260200191505060405180910390f35b34801561085357600080fd5b5061085c612ab5565b6040518082815260200191505060405180910390f35b34801561087e57600080fd5b50610887612abb565b6040518082815260200191505060405180910390f35b3480156108a957600080fd5b506108b2612ae1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561090057600080fd5b506109436004803603602081101561091757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612b07565b604051808215151515815260200191505060405180910390f35b34801561096957600080fd5b50610972612b27565b6040518082815260200191505060405180910390f35b34801561099457600080fd5b5061099d612b2d565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156109e05780820151818401526020810190506109c5565b505050509050019250505060405180910390f35b348015610a0057600080fd5b50610a09612b85565b6040518082815260200191505060405180910390f35b348015610a2b57600080fd5b50610a34612b8b565b6040518082815260200191505060405180910390f35b348015610a5657600080fd5b50610a9960048036036020811015610a6d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612bb3565b005b348015610aa757600080fd5b50610ab0612ccb565b6040518082815260200191505060405180910390f35b348015610ad257600080fd5b50610adb612d03565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610b2957600080fd5b50610b32612d2c565b604051808215151515815260200191505060405180910390f35b348015610b5857600080fd5b50610b9b60048036036020811015610b6f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612d8a565b604051808215151515815260200191505060405180910390f35b348015610bc157600080fd5b50610bca612daa565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610c0d578082015181840152602081019050610bf2565b505050509050019250505060405180910390f35b348015610c2d57600080fd5b50610c5a60048036036020811015610c4457600080fd5b8101908080359060200190929190505050612e38565b005b348015610c6857600080fd5b50610d926004803603610120811015610c8057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190640100000000811115610ce557600080fd5b820183602082011115610cf757600080fd5b80359060200191846020830284011164010000000083111715610d1957600080fd5b909192939192939080359060200190640100000000811115610d3a57600080fd5b820183602082011115610d4c57600080fd5b80359060200191846020830284011164010000000083111715610d6e57600080fd5b90919293919293908035906020019092919080359060200190929190505050612f69565b005b348015610da057600080fd5b50610de360048036036020811015610db757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506130e0565b005b348015610df157600080fd5b50610dfa613284565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610e3d578082015181840152602081019050610e22565b505050509050019250505060405180910390f35b348015610e5d57600080fd5b50610e8a60048036036020811015610e7457600080fd5b8101908080359060200190929190505050613312565b005b348015610e9857600080fd5b50610fe360048036036040811015610eaf57600080fd5b8101908080359060200190640100000000811115610ecc57600080fd5b820183602082011115610ede57600080fd5b80359060200191846020830284011164010000000083111715610f0057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610f6057600080fd5b820183602082011115610f7257600080fd5b80359060200191846020830284011164010000000083111715610f9457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505091929192905050506133cd565b005b348015610ff157600080fd5b506110346004803603602081101561100857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613885565b604051808215151515815260200191505060405180910390f35b34801561105a57600080fd5b50611063613d9e565b6040518082815260200191505060405180910390f35b34801561108557600080fd5b5061108e613df0565b6040518082815260200191505060405180910390f35b3480156110b057600080fd5b506110b9613df6565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156110fc5780820151818401526020810190506110e1565b505050509050019250505060405180910390f35b34801561111c57600080fd5b506111496004803603602081101561113357600080fd5b8101908080359060200190929190505050613ea9565b005b34801561115757600080fd5b5061119a6004803603602081101561116e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613fdb565b005b3480156111a857600080fd5b506111df600480360360408110156111bf57600080fd5b8101908080359060200190929190803590602001909291905050506140f3565b005b3480156111ed57600080fd5b5061121a6004803603602081101561120457600080fd5b810190808035906020019092919050505061421f565b6040518082815260200191505060405180910390f35b34801561123c57600080fd5b5061127f6004803603602081101561125357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614237565b005b34801561128d57600080fd5b506112966142bd565b6040518082815260200191505060405180910390f35b6112b4612d2c565b611326576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b61132f816142c3565b60106000820151816000015590505061136e6113496142e1565b601060405180602001604052908160008201548152505061430790919063ffffffff16565b6113c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806152c66026913960400191505060405180910390fd5b7fb08f0607338ad77f5b08ccf831e533cefcc2d373c173e87a8f61144f1d82be1e816040518082815260200191505060405180910390a150565b600060405160200180807f45786368616e67650000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001203373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156114d057600080fd5b505afa1580156114e4573d6000803e3d6000fd5b505050506040513d60208110156114fa57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614611594576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f6f6e6c79207265676973746572656420636f6e7472616374000000000000000081525060200191505060405180910390fd5b61159e848461431d565b91505092915050565b60115481565b600c81815481106115ba57fe5b906000526020600020016000915090505481565b60006115d8612d2c565b61164a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b82600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661170a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f746f6b656e206164647220776173206e6576657220726567697374657265640081525060200191505060405180910390fd5b6004805490508310801561178057508373ffffffffffffffffffffffffffffffffffffffff166004848154811061173d57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b6117d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a8152602001806152ec602a913960400191505060405180910390fd5b6000600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600461184a600160048054905061445290919063ffffffff16565b8154811061185457fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050806004858154811061188f57fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506118f0600160048054905061445290919063ffffffff16565b6004816118fd9190615103565b508473ffffffffffffffffffffffffffffffffffffffff167fbe9bb4bdca0a094babd75e3a98b1d2e2390633430d0a2f6e2b9970e2ee03fb2e856040518082815260200191505060405180910390a260019250505092915050565b600060149054906101000a900460ff1681565b6000806001600260008282540192505081905550600060025490506006546119cf600560000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff164261445290919063ffffffff16565b1115611a5d576119e56119e061449c565b614504565b600560000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555042600560000160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505b600560000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16611aa1611a9c6142e1565b614504565b925092506002548114611b1c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b509091565b60036020528060005260406000206000915054906101000a900460ff1681565b6000600960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16611be5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615340602c913960400191505060405180910390fd5b600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16611c87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180615316602a913960400191505060405180910390fd5b6000620151804281611c9557fe5b049050600e54811115611cf6576000611cac612b8b565b905081600e81905550611cee611ce9611cc483614512565b601060405180602001604052908160008201548152505061459c90919063ffffffff16565b6149fb565b600f81905550505b82600f541015611d6e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f457863656564696e67207370656e64696e67206c696d6974000000000000000081525060200191505060405180910390fd5b611d8383600f5461445290919063ffffffff16565b600f81905550611d93848461431d565b91505092915050565b6000611da6612d2c565b611e18576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600160026000828254019250508190555060006002549050600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611ef0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f72657365727665206164647220616c726561647920616464656400000000000081525060200191505060405180910390fd5b6001600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600b8390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508273ffffffffffffffffffffffffffffffffffffffff167fd78793225285ecf9cf5f0f84b1cdc335c2cb4d6810ff0b9fd156ad6026c89cea60405160405180910390a260019150600254811461206c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b60058060000160009054906101000a90046fffffffffffffffffffffffffffffffff16908060000160109054906101000a90046fffffffffffffffffffffffffffffffff16905082565b6000806201518042816120cb57fe5b04905060006120e56012548361445290919063ffffffff16565b905060135481106120fb5760009250505061213d565b61213861212760135461211984601154614a1c90919063ffffffff16565b614aa290919063ffffffff16565b60115461445290919063ffffffff16565b925050505b90565b600f5481565b600b818154811061215357fe5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f536f727465644f7261636c657300000000000000000000000000000000000000815250600d019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561223e57600080fd5b505afa158015612252573d6000803e3d6000fd5b505050506040513d602081101561226857600080fd5b810190808051906020019092919050505090506000819050600061228a612b8b565b9050600080905061229961512f565b6122d5600d60007f63474c44000000000000000000000000000000000000000000000000000000008152602001908152602001600020546142c3565b905060008090505b600480549050811015612506576000808673ffffffffffffffffffffffffffffffffffffffff1663ef90e1b06004858154811061231657fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050604080518083038186803b1580156123a057600080fd5b505afa1580156123b4573d6000803e3d6000fd5b505050506040513d60408110156123ca57600080fd5b81019080805190602001909291908051906020019092919050505080925081935050506000600484815481106123fc57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561246c57600080fd5b505afa158015612480573d6000803e3d6000fd5b505050506040513d602081101561249657600080fd5b8101908080519060200190929190505050905060006124d0846124c28585614a1c90919063ffffffff16565b614aa290919063ffffffff16565b90506124e58188614aec90919063ffffffff16565b9650505050506124ff600182614aec90919063ffffffff16565b90506122dd565b5061254461253f61251684614512565b6125318461252388614512565b614b7490919063ffffffff16565b614b7490919063ffffffff16565b614504565b9550505050505090565b6000612558612d2c565b6125ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16612689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f72657365727665206164647220776173206e657665722061646465640000000081525060200191505060405180910390fd5b600b80549050821080156126ff57508273ffffffffffffffffffffffffffffffffffffffff16600b83815481106126bc57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b612754576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602d815260200180615299602d913960400191505060405180910390fd5b6000600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600b6127c96001600b8054905061445290919063ffffffff16565b815481106127d357fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905080600b848154811061280e57fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061286f6001600b8054905061445290919063ffffffff16565b600b8161287c9190615103565b508373ffffffffffffffffffffffffffffffffffffffff167f89b4ee5cecfdfb246ede373c10283b5038afe56a531fc1d2f3ed8c5507a52fcb846040518082815260200191505060405180910390a2600191505092915050565b60135481565b6128e4612d2c565b612956576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000806000905060008090505b600b80549050811015612aad57612a90600b8281548110612a3f57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163183614aec90919063ffffffff16565b9150612aa6600182614aec90919063ffffffff16565b9050612a22565b508091505090565b60085481565b6000612adc6010604051806020016040529081600082015481525050614504565b905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600a6020528060005260406000206000915054906101000a900460ff1681565b60125481565b6060600c805480602002602001604051908101604052809291908181526020018280548015612b7b57602002820191906000526020600020905b815481526020019060010190808311612b67575b5050505050905090565b60075481565b6000612bae612b98612a15565b612ba0613d9e565b614aec90919063ffffffff16565b905090565b612bbb612d2c565b612c2d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6000600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508073ffffffffffffffffffffffffffffffffffffffff167fab8cff50266d80b9c9d9703af934ca455b9218286bf4fcaa05653a564c499e4b60405160405180910390a250565b6000612cfe612cd8612a15565b3073ffffffffffffffffffffffffffffffffffffffff1631614aec90919063ffffffff16565b905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612d6e614cbd565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60096020528060005260406000206000915054906101000a900460ff1681565b6060600b805480602002602001604051908101604052809291908181526020018280548015612e2e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612de4575b5050505050905090565b612e40612d2c565b612eb2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b60008111612f28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f76616c756520776173207a65726f00000000000000000000000000000000000081525060200191505060405180910390fd5b806006819055507f7bfe94ca3147f135fcd6d94ebf61d33fa34fbe904f933ccae66911b9548544f2816040518082815260200191505060405180910390a150565b600060149054906101000a900460ff1615612fec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b6001600060146101000a81548160ff02191690831515021790555061301033614cc5565b6130198b6130e0565b6130228a612e38565b61302b896112ac565b61303588886140f3565b6130c1868680806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050858580806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050506133cd565b6130ca82613ea9565b6130d381613312565b5050505050505050505050565b6130e8612d2c565b61315a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156131fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f43616e6e6f7420726567697374657220746865206e756c6c206164647265737381525060200191505060405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b60405160405180910390a250565b6060600480548060200260200160405190810160405280929190818152602001828054801561330857602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116132be575b5050505050905090565b61331a612d2c565b61338c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b806008819055507f4da8e8b2223fbbb897200fb9dfb6b986c1b4188621114d407ee8ec363569fc37816040518082815260200191505060405180910390a150565b6133d5612d2c565b613447576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80518251146134be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4172726179206c656e677468206d69736d61746368000000000000000000000081525060200191505060405180910390fd5b6134c661512f565b6134d060006142c3565b905060008090505b825181101561352c5761350f6135008483815181106134f357fe5b60200260200101516142c3565b83614e0990919063ffffffff16565b9150613525600182614aec90919063ffffffff16565b90506134d8565b506135476135386142e1565b82614eb290919063ffffffff16565b61359c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806152576021913960400191505060405180910390fd5b60008090505b600c805490508110156135f857600d6000600c83815481106135c057fe5b90600052602060002001548152602001908152602001600020600090556135f1600182614aec90919063ffffffff16565b90506135a2565b5082600c908051906020019061360f929190615142565b5060008090505b8351811015613714576000600d600086848151811061363157fe5b6020026020010151815260200190815260200160002054146136bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f43616e6e6f74207365742077656967687420747769636500000000000000000081525060200191505060405180910390fd5b8281815181106136c757fe5b6020026020010151600d60008684815181106136df57fe5b602002602001015181526020019081526020016000208190555061370d600182614aec90919063ffffffff16565b9050613616565b506000600d60007f63474c440000000000000000000000000000000000000000000000000000000081526020019081526020016000205414156137bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4d757374207365742063474c442061737365742077656967687400000000000081525060200191505060405180910390fd5b7f55b488abd19ae7621712324d3d42c2ef7a9575f64f5503103286a1161fb408558383604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561382957808201518184015260208101905061380e565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561386b578082015181840152602081019050613850565b5050505090500194505050505060405180910390a1505050565b600061388f612d2c565b613901576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600160026000828254019250508190555060006002549050600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156139d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f746f6b656e206164647220616c7265616479207265676973746572656400000081525060200191505060405180910390fd5b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f536f727465644f7261636c657300000000000000000000000000000000000000815250600d019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015613a9457600080fd5b505afa158015613aa8573d6000803e3d6000fd5b505050506040513d6020811015613abe57600080fd5b8101908080519060200190929190505050905060008190506000808273ffffffffffffffffffffffffffffffffffffffff1663ef90e1b0886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050604080518083038186803b158015613b5557600080fd5b505afa158015613b69573d6000803e3d6000fd5b505050506040513d6040811015613b7f57600080fd5b810190808051906020019092919080519060200190929190505050809250819350505060008111613c18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f6d656469616e20726174652072657475726e6564203020676f6c64000000000081525060200191505060405180910390fd5b6001600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060048790806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508673ffffffffffffffffffffffffffffffffffffffff167f784c8f4dbf0ffedd6e72c76501c545a70f8b203b30a26ce542bf92ba87c248a460405160405180910390a260019550505050506002548114613d98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b6000803073ffffffffffffffffffffffffffffffffffffffff163190506000613dc56120bc565b9050808211613dd5576000613de9565b613de8818361445290919063ffffffff16565b5b9250505090565b60065481565b606080600c80549050604051908082528060200260200182016040528015613e2d5781602001602082028038833980820191505090505b50905060008090505b600c80549050811015613ea157600d6000600c8381548110613e5457fe5b9060005260206000200154815260200190815260200160002054828281518110613e7a57fe5b602002602001018181525050613e9a600182614aec90919063ffffffff16565b9050613e36565b508091505090565b613eb1612d2c565b613f23576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b613f45613f2e6142e1565b613f37836142c3565b61430790919063ffffffff16565b613f9a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806152006021913960400191505060405180910390fd5b806007819055507ffe69856ffb1b1d6cb00c1d8151726e6e95032b1666282eeb293ecadd58b29a6e816040518082815260200191505060405180910390a150565b613fe3612d2c565b614055576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6001600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508073ffffffffffffffffffffffffffffffffffffffff167f3139419c41cdd7abca84fa19dd21118cd285d3e2ce1a9444e8161ce9fa62fdcd60405160405180910390a250565b6140fb612d2c565b61416d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff16318211156141fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f43616e6e6f7420667265657a65206d6f7265207468616e2062616c616e63650081525060200191505060405180910390fd5b8160118190555062015180428161420d57fe5b04601281905550806013819055505050565b600d6020528060005260406000206000915090505481565b61423f612d2c565b6142b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6142ba81614cc5565b50565b600e5481565b6142cb61512f565b6040518060200160405280838152509050919050565b6142e961512f565b604051806020016040528069d3c21bcecceda1000000815250905090565b6000816000015183600001511115905092915050565b6000614327613d9e565b82111561439c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f457863656564696e6720756e66726f7a656e207265736572766573000000000081525060200191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156143e2573d6000803e3d6000fd5b508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4dd1abe16ad3d4f829372dc77766ca2cce34e205af9b10f8cc1fab370425864f846040518082815260200191505060405180910390a36001905092915050565b600061449483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614ec7565b905092915050565b6144a461512f565b6144ac61512f565b6144bc6144b7612182565b6142c3565b90506144db6144cc6008546142c3565b82614f8790919063ffffffff16565b156144f2576144ea60006142c3565b915050614501565b6144fd6007546142c3565b9150505b90565b600081600001519050919050565b61451a61512f565b614522614f9d565b82111561457a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260368152602001806152216036913960400191505060405180910390fd5b604051806020016040528069d3c21bcecceda100000084028152509050919050565b6145a461512f565b6000836000015114806145bb575060008260000151145b156145d7576040518060200160405280600081525090506149f5565b69d3c21bcecceda1000000826000015114156145f5578290506149f5565b69d3c21bcecceda100000083600001511415614613578190506149f5565b600069d3c21bcecceda100000061462985614fbc565b600001518161463457fe5b049050600061464285614ff3565b600001519050600069d3c21bcecceda100000061465e86614fbc565b600001518161466957fe5b049050600061467786614ff3565b600001519050600082850290506000851461470b578285828161469657fe5b041461470a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b600069d3c21bcecceda100000082029050600082146147ad5769d3c21bcecceda100000082828161473857fe5b04146147ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f6f766572666c6f772078317931202a206669786564312064657465637465640081525060200191505060405180910390fd5b5b809150600084860290506000861461483e57848682816147c957fe5b041461483d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b60008488029050600088146148cc578488828161485757fe5b04146148cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b6148d4615030565b87816148dc57fe5b0496506148e7615030565b85816148ef57fe5b0494506000858802905060008814614980578588828161490b57fe5b041461497f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b61498861512f565b60405180602001604052808781525090506149b181604051806020016040528087815250614e09565b90506149cb81604051806020016040528086815250614e09565b90506149e581604051806020016040528085815250614e09565b9050809a50505050505050505050505b92915050565b600069d3c21bcecceda1000000826000015181614a1457fe5b049050919050565b600080831415614a2f5760009050614a9c565b6000828402905082848281614a4057fe5b0414614a97576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806152786021913960400191505060405180910390fd5b809150505b92915050565b6000614ae483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061503d565b905092915050565b600080828401905083811015614b6a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b614b7c61512f565b600082600001511415614bf7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f63616e277420646976696465206279203000000000000000000000000000000081525060200191505060405180910390fd5b600069d3c21bcecceda10000008460000151029050836000015169d3c21bcecceda10000008281614c2457fe5b0414614c98576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f6f766572666c6f7720617420646976696465000000000000000000000000000081525060200191505060405180910390fd5b604051806020016040528084600001518381614cb057fe5b0481525091505092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415614d4b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806151da6026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b614e1161512f565b6000826000015184600001510190508360000151811015614e9a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f616464206f766572666c6f77206465746563746564000000000000000000000081525060200191505060405180910390fd5b60405180602001604052808281525091505092915050565b60008160000151836000015114905092915050565b6000838311158290614f74576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614f39578082015181840152602081019050614f1e565b50505050905090810190601f168015614f665780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b6000816000015183600001511015905092915050565b60007601357c299a88ea76a58924d52ce4f26a85af186c2b9e74905090565b614fc461512f565b604051806020016040528069d3c21bcecceda100000080856000015181614fe757fe5b04028152509050919050565b614ffb61512f565b604051806020016040528069d3c21bcecceda10000008085600001518161501e57fe5b04028460000151038152509050919050565b600064e8d4a51000905090565b600080831182906150e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156150ae578082015181840152602081019050615093565b50505050905090810190601f1680156150db5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816150f557fe5b049050809150509392505050565b81548183558181111561512a57818360005260206000209182019101615129919061518f565b5b505050565b6040518060200160405280600081525090565b82805482825590600052602060002090810192821561517e579160200282015b8281111561517d578251825591602001919060010190615162565b5b50905061518b91906151b4565b5090565b6151b191905b808211156151ad576000816000905550600101615195565b5090565b90565b6151d691905b808211156151d25760008160009055506001016151ba565b5090565b9056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373746f62696e207461782063616e6e6f74206265206c6172676572207468616e203163616e277420637265617465206669786964697479206e756d626572206c6172676572207468616e206d61784e65774669786564282953756d206f6620617373657420616c6c6f636174696f6e206d7573742062652031536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77696e64657820696e746f2072657365727665206c697374206e6f74206d617070656420746f20616464726573737370656e64696e6720726174696f2063616e6e6f74206265206c6172676572207468616e2031696e64657820696e746f20746f6b656e73206c697374206e6f74206d617070656420746f20746f6b656e63616e206f6e6c79207472616e7366657220746f206f746865722072657365727665206164647265737373656e646572206e6f7420616c6c6f77656420746f207472616e7366657220526573657276652066756e6473a165627a7a723058206b5cc933ad945f41cfe633d1b66a697352e16d012acfd631c195b33817d381420029

Deployed ByteCode

0x6080604052600436106102ae5760003560e01c80638438796a11610175578063aa6ca808116100dc578063e50a6c1e11610095578063e83b373b1161006f578063e83b373b1461119c578063ec4f797b146111e1578063f2fde38b14611230578063fa9ed95a14611281576102ae565b8063e50a6c1e146110a4578063e6b76e9c14611110578063e7e31e7a1461114b576102ae565b8063aa6ca80814610de5578063ad62ad1014610e51578063ca56d33b14610e8c578063d48bfca714610fe5578063e30f579d1461104e578063e33a88e714611079576102ae565b80638f32d59b1161012e5780638f32d59b14610b1d5780639a206ece14610b4c5780639c3e2f0f14610bb5578063a1ab55b314610c21578063a3e1f00d14610c5c578063a91ee0dc14610d94576102ae565b80638438796a14610988578063894098d6146109f45780638b7df8d414610a1f5780638ce5877c14610a4a5780638d9a5e6f14610a9b5780638da5cb5b14610ac6576102ae565b806339d7f76e11610219578063765c1fe9116101d2578063765c1fe91461081c57806376769a60146108475780637897a78e146108725780637b1039991461089d5780637b522075146108f457806381b861a61461095d576102ae565b806339d7f76e1461069657806340899365146106c157806356b6d0d51461073c5780635c4a3145146107675780637090db4e146107da578063715018a614610805576102ae565b806317f9a6f71161026b57806317f9a6f71461047a57806319f37361146104ac5780631c39c7d514610515578063220159681461058857806322796e83146105f15780632aa1c16d1461066b576102ae565b806301da32bd146102b057806303a0fea3146102eb57806303d835f31461035e5780630db279be1461038957806313baf1e6146103d8578063158ef93e1461044b575b005b3480156102bc57600080fd5b506102e9600480360360208110156102d357600080fd5b81019080803590602001909291905050506112ac565b005b3480156102f757600080fd5b506103446004803603604081101561030e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506113fd565b604051808215151515815260200191505060405180910390f35b34801561036a57600080fd5b506103736115a7565b6040518082815260200191505060405180910390f35b34801561039557600080fd5b506103c2600480360360208110156103ac57600080fd5b81019080803590602001909291905050506115ad565b6040518082815260200191505060405180910390f35b3480156103e457600080fd5b50610431600480360360408110156103fb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115ce565b604051808215151515815260200191505060405180910390f35b34801561045757600080fd5b50610460611958565b604051808215151515815260200191505060405180910390f35b34801561048657600080fd5b5061048f61196b565b604051808381526020018281526020019250505060405180910390f35b3480156104b857600080fd5b506104fb600480360360208110156104cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611b21565b604051808215151515815260200191505060405180910390f35b34801561052157600080fd5b5061056e6004803603604081101561053857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611b41565b604051808215151515815260200191505060405180910390f35b34801561059457600080fd5b506105d7600480360360208110156105ab57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611d9c565b604051808215151515815260200191505060405180910390f35b3480156105fd57600080fd5b50610606612072565b60405180836fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168152602001826fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020019250505060405180910390f35b34801561067757600080fd5b506106806120bc565b6040518082815260200191505060405180910390f35b3480156106a257600080fd5b506106ab612140565b6040518082815260200191505060405180910390f35b3480156106cd57600080fd5b506106fa600480360360208110156106e457600080fd5b8101908080359060200190929190505050612146565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074857600080fd5b50610751612182565b6040518082815260200191505060405180910390f35b34801561077357600080fd5b506107c06004803603604081101561078a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061254e565b604051808215151515815260200191505060405180910390f35b3480156107e657600080fd5b506107ef6128d6565b6040518082815260200191505060405180910390f35b34801561081157600080fd5b5061081a6128dc565b005b34801561082857600080fd5b50610831612a15565b6040518082815260200191505060405180910390f35b34801561085357600080fd5b5061085c612ab5565b6040518082815260200191505060405180910390f35b34801561087e57600080fd5b50610887612abb565b6040518082815260200191505060405180910390f35b3480156108a957600080fd5b506108b2612ae1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561090057600080fd5b506109436004803603602081101561091757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612b07565b604051808215151515815260200191505060405180910390f35b34801561096957600080fd5b50610972612b27565b6040518082815260200191505060405180910390f35b34801561099457600080fd5b5061099d612b2d565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156109e05780820151818401526020810190506109c5565b505050509050019250505060405180910390f35b348015610a0057600080fd5b50610a09612b85565b6040518082815260200191505060405180910390f35b348015610a2b57600080fd5b50610a34612b8b565b6040518082815260200191505060405180910390f35b348015610a5657600080fd5b50610a9960048036036020811015610a6d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612bb3565b005b348015610aa757600080fd5b50610ab0612ccb565b6040518082815260200191505060405180910390f35b348015610ad257600080fd5b50610adb612d03565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610b2957600080fd5b50610b32612d2c565b604051808215151515815260200191505060405180910390f35b348015610b5857600080fd5b50610b9b60048036036020811015610b6f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612d8a565b604051808215151515815260200191505060405180910390f35b348015610bc157600080fd5b50610bca612daa565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610c0d578082015181840152602081019050610bf2565b505050509050019250505060405180910390f35b348015610c2d57600080fd5b50610c5a60048036036020811015610c4457600080fd5b8101908080359060200190929190505050612e38565b005b348015610c6857600080fd5b50610d926004803603610120811015610c8057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190640100000000811115610ce557600080fd5b820183602082011115610cf757600080fd5b80359060200191846020830284011164010000000083111715610d1957600080fd5b909192939192939080359060200190640100000000811115610d3a57600080fd5b820183602082011115610d4c57600080fd5b80359060200191846020830284011164010000000083111715610d6e57600080fd5b90919293919293908035906020019092919080359060200190929190505050612f69565b005b348015610da057600080fd5b50610de360048036036020811015610db757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506130e0565b005b348015610df157600080fd5b50610dfa613284565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610e3d578082015181840152602081019050610e22565b505050509050019250505060405180910390f35b348015610e5d57600080fd5b50610e8a60048036036020811015610e7457600080fd5b8101908080359060200190929190505050613312565b005b348015610e9857600080fd5b50610fe360048036036040811015610eaf57600080fd5b8101908080359060200190640100000000811115610ecc57600080fd5b820183602082011115610ede57600080fd5b80359060200191846020830284011164010000000083111715610f0057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610f6057600080fd5b820183602082011115610f7257600080fd5b80359060200191846020830284011164010000000083111715610f9457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505091929192905050506133cd565b005b348015610ff157600080fd5b506110346004803603602081101561100857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613885565b604051808215151515815260200191505060405180910390f35b34801561105a57600080fd5b50611063613d9e565b6040518082815260200191505060405180910390f35b34801561108557600080fd5b5061108e613df0565b6040518082815260200191505060405180910390f35b3480156110b057600080fd5b506110b9613df6565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156110fc5780820151818401526020810190506110e1565b505050509050019250505060405180910390f35b34801561111c57600080fd5b506111496004803603602081101561113357600080fd5b8101908080359060200190929190505050613ea9565b005b34801561115757600080fd5b5061119a6004803603602081101561116e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613fdb565b005b3480156111a857600080fd5b506111df600480360360408110156111bf57600080fd5b8101908080359060200190929190803590602001909291905050506140f3565b005b3480156111ed57600080fd5b5061121a6004803603602081101561120457600080fd5b810190808035906020019092919050505061421f565b6040518082815260200191505060405180910390f35b34801561123c57600080fd5b5061127f6004803603602081101561125357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614237565b005b34801561128d57600080fd5b506112966142bd565b6040518082815260200191505060405180910390f35b6112b4612d2c565b611326576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b61132f816142c3565b60106000820151816000015590505061136e6113496142e1565b601060405180602001604052908160008201548152505061430790919063ffffffff16565b6113c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806152c66026913960400191505060405180910390fd5b7fb08f0607338ad77f5b08ccf831e533cefcc2d373c173e87a8f61144f1d82be1e816040518082815260200191505060405180910390a150565b600060405160200180807f45786368616e67650000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001203373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156114d057600080fd5b505afa1580156114e4573d6000803e3d6000fd5b505050506040513d60208110156114fa57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614611594576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f6f6e6c79207265676973746572656420636f6e7472616374000000000000000081525060200191505060405180910390fd5b61159e848461431d565b91505092915050565b60115481565b600c81815481106115ba57fe5b906000526020600020016000915090505481565b60006115d8612d2c565b61164a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b82600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661170a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f746f6b656e206164647220776173206e6576657220726567697374657265640081525060200191505060405180910390fd5b6004805490508310801561178057508373ffffffffffffffffffffffffffffffffffffffff166004848154811061173d57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b6117d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a8152602001806152ec602a913960400191505060405180910390fd5b6000600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600461184a600160048054905061445290919063ffffffff16565b8154811061185457fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050806004858154811061188f57fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506118f0600160048054905061445290919063ffffffff16565b6004816118fd9190615103565b508473ffffffffffffffffffffffffffffffffffffffff167fbe9bb4bdca0a094babd75e3a98b1d2e2390633430d0a2f6e2b9970e2ee03fb2e856040518082815260200191505060405180910390a260019250505092915050565b600060149054906101000a900460ff1681565b6000806001600260008282540192505081905550600060025490506006546119cf600560000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff164261445290919063ffffffff16565b1115611a5d576119e56119e061449c565b614504565b600560000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555042600560000160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505b600560000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16611aa1611a9c6142e1565b614504565b925092506002548114611b1c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b509091565b60036020528060005260406000206000915054906101000a900460ff1681565b6000600960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16611be5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615340602c913960400191505060405180910390fd5b600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16611c87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180615316602a913960400191505060405180910390fd5b6000620151804281611c9557fe5b049050600e54811115611cf6576000611cac612b8b565b905081600e81905550611cee611ce9611cc483614512565b601060405180602001604052908160008201548152505061459c90919063ffffffff16565b6149fb565b600f81905550505b82600f541015611d6e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f457863656564696e67207370656e64696e67206c696d6974000000000000000081525060200191505060405180910390fd5b611d8383600f5461445290919063ffffffff16565b600f81905550611d93848461431d565b91505092915050565b6000611da6612d2c565b611e18576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600160026000828254019250508190555060006002549050600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611ef0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f72657365727665206164647220616c726561647920616464656400000000000081525060200191505060405180910390fd5b6001600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600b8390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508273ffffffffffffffffffffffffffffffffffffffff167fd78793225285ecf9cf5f0f84b1cdc335c2cb4d6810ff0b9fd156ad6026c89cea60405160405180910390a260019150600254811461206c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b60058060000160009054906101000a90046fffffffffffffffffffffffffffffffff16908060000160109054906101000a90046fffffffffffffffffffffffffffffffff16905082565b6000806201518042816120cb57fe5b04905060006120e56012548361445290919063ffffffff16565b905060135481106120fb5760009250505061213d565b61213861212760135461211984601154614a1c90919063ffffffff16565b614aa290919063ffffffff16565b60115461445290919063ffffffff16565b925050505b90565b600f5481565b600b818154811061215357fe5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f536f727465644f7261636c657300000000000000000000000000000000000000815250600d019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561223e57600080fd5b505afa158015612252573d6000803e3d6000fd5b505050506040513d602081101561226857600080fd5b810190808051906020019092919050505090506000819050600061228a612b8b565b9050600080905061229961512f565b6122d5600d60007f63474c44000000000000000000000000000000000000000000000000000000008152602001908152602001600020546142c3565b905060008090505b600480549050811015612506576000808673ffffffffffffffffffffffffffffffffffffffff1663ef90e1b06004858154811061231657fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050604080518083038186803b1580156123a057600080fd5b505afa1580156123b4573d6000803e3d6000fd5b505050506040513d60408110156123ca57600080fd5b81019080805190602001909291908051906020019092919050505080925081935050506000600484815481106123fc57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561246c57600080fd5b505afa158015612480573d6000803e3d6000fd5b505050506040513d602081101561249657600080fd5b8101908080519060200190929190505050905060006124d0846124c28585614a1c90919063ffffffff16565b614aa290919063ffffffff16565b90506124e58188614aec90919063ffffffff16565b9650505050506124ff600182614aec90919063ffffffff16565b90506122dd565b5061254461253f61251684614512565b6125318461252388614512565b614b7490919063ffffffff16565b614b7490919063ffffffff16565b614504565b9550505050505090565b6000612558612d2c565b6125ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16612689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f72657365727665206164647220776173206e657665722061646465640000000081525060200191505060405180910390fd5b600b80549050821080156126ff57508273ffffffffffffffffffffffffffffffffffffffff16600b83815481106126bc57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b612754576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602d815260200180615299602d913960400191505060405180910390fd5b6000600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600b6127c96001600b8054905061445290919063ffffffff16565b815481106127d357fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905080600b848154811061280e57fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061286f6001600b8054905061445290919063ffffffff16565b600b8161287c9190615103565b508373ffffffffffffffffffffffffffffffffffffffff167f89b4ee5cecfdfb246ede373c10283b5038afe56a531fc1d2f3ed8c5507a52fcb846040518082815260200191505060405180910390a2600191505092915050565b60135481565b6128e4612d2c565b612956576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000806000905060008090505b600b80549050811015612aad57612a90600b8281548110612a3f57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163183614aec90919063ffffffff16565b9150612aa6600182614aec90919063ffffffff16565b9050612a22565b508091505090565b60085481565b6000612adc6010604051806020016040529081600082015481525050614504565b905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600a6020528060005260406000206000915054906101000a900460ff1681565b60125481565b6060600c805480602002602001604051908101604052809291908181526020018280548015612b7b57602002820191906000526020600020905b815481526020019060010190808311612b67575b5050505050905090565b60075481565b6000612bae612b98612a15565b612ba0613d9e565b614aec90919063ffffffff16565b905090565b612bbb612d2c565b612c2d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6000600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508073ffffffffffffffffffffffffffffffffffffffff167fab8cff50266d80b9c9d9703af934ca455b9218286bf4fcaa05653a564c499e4b60405160405180910390a250565b6000612cfe612cd8612a15565b3073ffffffffffffffffffffffffffffffffffffffff1631614aec90919063ffffffff16565b905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612d6e614cbd565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60096020528060005260406000206000915054906101000a900460ff1681565b6060600b805480602002602001604051908101604052809291908181526020018280548015612e2e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612de4575b5050505050905090565b612e40612d2c565b612eb2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b60008111612f28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f76616c756520776173207a65726f00000000000000000000000000000000000081525060200191505060405180910390fd5b806006819055507f7bfe94ca3147f135fcd6d94ebf61d33fa34fbe904f933ccae66911b9548544f2816040518082815260200191505060405180910390a150565b600060149054906101000a900460ff1615612fec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b6001600060146101000a81548160ff02191690831515021790555061301033614cc5565b6130198b6130e0565b6130228a612e38565b61302b896112ac565b61303588886140f3565b6130c1868680806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050858580806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050506133cd565b6130ca82613ea9565b6130d381613312565b5050505050505050505050565b6130e8612d2c565b61315a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156131fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f43616e6e6f7420726567697374657220746865206e756c6c206164647265737381525060200191505060405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b60405160405180910390a250565b6060600480548060200260200160405190810160405280929190818152602001828054801561330857602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116132be575b5050505050905090565b61331a612d2c565b61338c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b806008819055507f4da8e8b2223fbbb897200fb9dfb6b986c1b4188621114d407ee8ec363569fc37816040518082815260200191505060405180910390a150565b6133d5612d2c565b613447576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80518251146134be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4172726179206c656e677468206d69736d61746368000000000000000000000081525060200191505060405180910390fd5b6134c661512f565b6134d060006142c3565b905060008090505b825181101561352c5761350f6135008483815181106134f357fe5b60200260200101516142c3565b83614e0990919063ffffffff16565b9150613525600182614aec90919063ffffffff16565b90506134d8565b506135476135386142e1565b82614eb290919063ffffffff16565b61359c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806152576021913960400191505060405180910390fd5b60008090505b600c805490508110156135f857600d6000600c83815481106135c057fe5b90600052602060002001548152602001908152602001600020600090556135f1600182614aec90919063ffffffff16565b90506135a2565b5082600c908051906020019061360f929190615142565b5060008090505b8351811015613714576000600d600086848151811061363157fe5b6020026020010151815260200190815260200160002054146136bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f43616e6e6f74207365742077656967687420747769636500000000000000000081525060200191505060405180910390fd5b8281815181106136c757fe5b6020026020010151600d60008684815181106136df57fe5b602002602001015181526020019081526020016000208190555061370d600182614aec90919063ffffffff16565b9050613616565b506000600d60007f63474c440000000000000000000000000000000000000000000000000000000081526020019081526020016000205414156137bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4d757374207365742063474c442061737365742077656967687400000000000081525060200191505060405180910390fd5b7f55b488abd19ae7621712324d3d42c2ef7a9575f64f5503103286a1161fb408558383604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561382957808201518184015260208101905061380e565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561386b578082015181840152602081019050613850565b5050505090500194505050505060405180910390a1505050565b600061388f612d2c565b613901576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600160026000828254019250508190555060006002549050600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156139d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f746f6b656e206164647220616c7265616479207265676973746572656400000081525060200191505060405180910390fd5b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f536f727465644f7261636c657300000000000000000000000000000000000000815250600d019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015613a9457600080fd5b505afa158015613aa8573d6000803e3d6000fd5b505050506040513d6020811015613abe57600080fd5b8101908080519060200190929190505050905060008190506000808273ffffffffffffffffffffffffffffffffffffffff1663ef90e1b0886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050604080518083038186803b158015613b5557600080fd5b505afa158015613b69573d6000803e3d6000fd5b505050506040513d6040811015613b7f57600080fd5b810190808051906020019092919080519060200190929190505050809250819350505060008111613c18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f6d656469616e20726174652072657475726e6564203020676f6c64000000000081525060200191505060405180910390fd5b6001600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060048790806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508673ffffffffffffffffffffffffffffffffffffffff167f784c8f4dbf0ffedd6e72c76501c545a70f8b203b30a26ce542bf92ba87c248a460405160405180910390a260019550505050506002548114613d98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b6000803073ffffffffffffffffffffffffffffffffffffffff163190506000613dc56120bc565b9050808211613dd5576000613de9565b613de8818361445290919063ffffffff16565b5b9250505090565b60065481565b606080600c80549050604051908082528060200260200182016040528015613e2d5781602001602082028038833980820191505090505b50905060008090505b600c80549050811015613ea157600d6000600c8381548110613e5457fe5b9060005260206000200154815260200190815260200160002054828281518110613e7a57fe5b602002602001018181525050613e9a600182614aec90919063ffffffff16565b9050613e36565b508091505090565b613eb1612d2c565b613f23576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b613f45613f2e6142e1565b613f37836142c3565b61430790919063ffffffff16565b613f9a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806152006021913960400191505060405180910390fd5b806007819055507ffe69856ffb1b1d6cb00c1d8151726e6e95032b1666282eeb293ecadd58b29a6e816040518082815260200191505060405180910390a150565b613fe3612d2c565b614055576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6001600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508073ffffffffffffffffffffffffffffffffffffffff167f3139419c41cdd7abca84fa19dd21118cd285d3e2ce1a9444e8161ce9fa62fdcd60405160405180910390a250565b6140fb612d2c565b61416d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff16318211156141fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f43616e6e6f7420667265657a65206d6f7265207468616e2062616c616e63650081525060200191505060405180910390fd5b8160118190555062015180428161420d57fe5b04601281905550806013819055505050565b600d6020528060005260406000206000915090505481565b61423f612d2c565b6142b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6142ba81614cc5565b50565b600e5481565b6142cb61512f565b6040518060200160405280838152509050919050565b6142e961512f565b604051806020016040528069d3c21bcecceda1000000815250905090565b6000816000015183600001511115905092915050565b6000614327613d9e565b82111561439c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f457863656564696e6720756e66726f7a656e207265736572766573000000000081525060200191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156143e2573d6000803e3d6000fd5b508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4dd1abe16ad3d4f829372dc77766ca2cce34e205af9b10f8cc1fab370425864f846040518082815260200191505060405180910390a36001905092915050565b600061449483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614ec7565b905092915050565b6144a461512f565b6144ac61512f565b6144bc6144b7612182565b6142c3565b90506144db6144cc6008546142c3565b82614f8790919063ffffffff16565b156144f2576144ea60006142c3565b915050614501565b6144fd6007546142c3565b9150505b90565b600081600001519050919050565b61451a61512f565b614522614f9d565b82111561457a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260368152602001806152216036913960400191505060405180910390fd5b604051806020016040528069d3c21bcecceda100000084028152509050919050565b6145a461512f565b6000836000015114806145bb575060008260000151145b156145d7576040518060200160405280600081525090506149f5565b69d3c21bcecceda1000000826000015114156145f5578290506149f5565b69d3c21bcecceda100000083600001511415614613578190506149f5565b600069d3c21bcecceda100000061462985614fbc565b600001518161463457fe5b049050600061464285614ff3565b600001519050600069d3c21bcecceda100000061465e86614fbc565b600001518161466957fe5b049050600061467786614ff3565b600001519050600082850290506000851461470b578285828161469657fe5b041461470a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b600069d3c21bcecceda100000082029050600082146147ad5769d3c21bcecceda100000082828161473857fe5b04146147ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f6f766572666c6f772078317931202a206669786564312064657465637465640081525060200191505060405180910390fd5b5b809150600084860290506000861461483e57848682816147c957fe5b041461483d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b60008488029050600088146148cc578488828161485757fe5b04146148cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b6148d4615030565b87816148dc57fe5b0496506148e7615030565b85816148ef57fe5b0494506000858802905060008814614980578588828161490b57fe5b041461497f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b61498861512f565b60405180602001604052808781525090506149b181604051806020016040528087815250614e09565b90506149cb81604051806020016040528086815250614e09565b90506149e581604051806020016040528085815250614e09565b9050809a50505050505050505050505b92915050565b600069d3c21bcecceda1000000826000015181614a1457fe5b049050919050565b600080831415614a2f5760009050614a9c565b6000828402905082848281614a4057fe5b0414614a97576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806152786021913960400191505060405180910390fd5b809150505b92915050565b6000614ae483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061503d565b905092915050565b600080828401905083811015614b6a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b614b7c61512f565b600082600001511415614bf7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f63616e277420646976696465206279203000000000000000000000000000000081525060200191505060405180910390fd5b600069d3c21bcecceda10000008460000151029050836000015169d3c21bcecceda10000008281614c2457fe5b0414614c98576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f6f766572666c6f7720617420646976696465000000000000000000000000000081525060200191505060405180910390fd5b604051806020016040528084600001518381614cb057fe5b0481525091505092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415614d4b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806151da6026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b614e1161512f565b6000826000015184600001510190508360000151811015614e9a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f616464206f766572666c6f77206465746563746564000000000000000000000081525060200191505060405180910390fd5b60405180602001604052808281525091505092915050565b60008160000151836000015114905092915050565b6000838311158290614f74576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614f39578082015181840152602081019050614f1e565b50505050905090810190601f168015614f665780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b6000816000015183600001511015905092915050565b60007601357c299a88ea76a58924d52ce4f26a85af186c2b9e74905090565b614fc461512f565b604051806020016040528069d3c21bcecceda100000080856000015181614fe757fe5b04028152509050919050565b614ffb61512f565b604051806020016040528069d3c21bcecceda10000008085600001518161501e57fe5b04028460000151038152509050919050565b600064e8d4a51000905090565b600080831182906150e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156150ae578082015181840152602081019050615093565b50505050905090810190601f1680156150db5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816150f557fe5b049050809150509392505050565b81548183558181111561512a57818360005260206000209182019101615129919061518f565b5b505050565b6040518060200160405280600081525090565b82805482825590600052602060002090810192821561517e579160200282015b8281111561517d578251825591602001919060010190615162565b5b50905061518b91906151b4565b5090565b6151b191905b808211156151ad576000816000905550600101615195565b5090565b90565b6151d691905b808211156151d25760008160009055506001016151ba565b5090565b9056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373746f62696e207461782063616e6e6f74206265206c6172676572207468616e203163616e277420637265617465206669786964697479206e756d626572206c6172676572207468616e206d61784e65774669786564282953756d206f6620617373657420616c6c6f636174696f6e206d7573742062652031536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77696e64657820696e746f2072657365727665206c697374206e6f74206d617070656420746f20616464726573737370656e64696e6720726174696f2063616e6e6f74206265206c6172676572207468616e2031696e64657820696e746f20746f6b656e73206c697374206e6f74206d617070656420746f20746f6b656e63616e206f6e6c79207472616e7366657220746f206f746865722072657365727665206164647265737373656e646572206e6f7420616c6c6f77656420746f207472616e7366657220526573657276652066756e6473a165627a7a723058206b5cc933ad945f41cfe633d1b66a697352e16d012acfd631c195b33817d381420029