ETH Price: $3,332.35 (-0.33%)

Token

IdleEth (Goo)
 

Overview

Max Total Supply

581,002,479,590,583,204 Goo

Holders

5,316

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 0 Decimals)

Balance
154,476,883,779,250 Goo

Value
$0.00
0x0a3239799518e7f7f339867a4739282014b97dcf
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Goo

Compiler Version
v0.4.21+commit.dfe3193c

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2018-04-13
*/

pragma solidity ^0.4.0;

interface ERC20 {
    function totalSupply() public constant returns (uint);
    function balanceOf(address tokenOwner) public constant returns (uint balance);
    function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
    function transfer(address to, uint tokens) public returns (bool success);
    function approve(address spender, uint tokens) public returns (bool success);
    function transferFrom(address from, address to, uint tokens) public returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}

// GOO - Crypto Idle Game
// https://ethergoo.io

contract Goo is ERC20 {
    
    string public constant name  = "IdleEth";
    string public constant symbol = "Goo";
    uint8 public constant decimals = 0;
    uint256 private roughSupply;
    uint256 public totalGooProduction;
    address public owner; // Minor management of game
    bool public gameStarted;
    
    uint256 public researchDivPercent = 8;
    uint256 public gooDepositDivPercent = 2;
    
    uint256 public totalEtherGooResearchPool; // Eth dividends to be split between players' goo production
    uint256[] private totalGooProductionSnapshots; // The total goo production for each prior day past
    uint256[] private totalGooDepositSnapshots;  // The total goo deposited for each prior day past
    uint256[] private allocatedGooResearchSnapshots; // Div pot #1 (research eth allocated to each prior day past)
    uint256[] private allocatedGooDepositSnapshots;  // Div pot #2 (deposit eth allocated to each prior day past)
    uint256 public nextSnapshotTime;
    
    // Balances for each player
    mapping(address => uint256) private ethBalance;
    mapping(address => uint256) private gooBalance;
    mapping(address => mapping(uint256 => uint256)) private gooProductionSnapshots; // Store player's goo production for given day (snapshot)
    mapping(address => mapping(uint256 => uint256)) private gooDepositSnapshots;    // Store player's goo deposited for given day (snapshot)
    mapping(address => mapping(uint256 => bool)) private gooProductionZeroedSnapshots; // This isn't great but we need know difference between 0 production and an unused/inactive day.
    
    mapping(address => uint256) private lastGooSaveTime; // Seconds (last time player claimed their produced goo)
    mapping(address => uint256) public lastGooProductionUpdate; // Days (last snapshot player updated their production)
    mapping(address => uint256) private lastGooResearchFundClaim; // Days (snapshot number)
    mapping(address => uint256) private lastGooDepositFundClaim; // Days (snapshot number)
    mapping(address => uint256) private battleCooldown; // If user attacks they cannot attack again for short time
    
    // Stuff owned by each player
    mapping(address => mapping(uint256 => uint256)) private unitsOwned;
    mapping(address => mapping(uint256 => bool)) private upgradesOwned;
    mapping(uint256 => address) private rareItemOwner;
    mapping(uint256 => uint256) private rareItemPrice;
    
    // Rares & Upgrades (Increase unit's production / attack etc.)
    mapping(address => mapping(uint256 => uint256)) private unitGooProductionIncreases; // Adds to the goo per second
    mapping(address => mapping(uint256 => uint256)) private unitGooProductionMultiplier; // Multiplies the goo per second
    mapping(address => mapping(uint256 => uint256)) private unitAttackIncreases;
    mapping(address => mapping(uint256 => uint256)) private unitAttackMultiplier;
    mapping(address => mapping(uint256 => uint256)) private unitDefenseIncreases;
    mapping(address => mapping(uint256 => uint256)) private unitDefenseMultiplier;
    mapping(address => mapping(uint256 => uint256)) private unitGooStealingIncreases;
    mapping(address => mapping(uint256 => uint256)) private unitGooStealingMultiplier;
    mapping(address => mapping(uint256 => uint256)) private unitMaxCap;
    
    // Mapping of approved ERC20 transfers (by player)
    mapping(address => mapping(address => uint256)) private allowed;
    mapping(address => bool) private protectedAddresses; // For npc exchanges (requires 0 goo production)
    
    // Raffle structures
    struct TicketPurchases {
        TicketPurchase[] ticketsBought;
        uint256 numPurchases; // Allows us to reset without clearing TicketPurchase[] (avoids potential for gas limit)
        uint256 raffleId;
    }
    
    // Allows us to query winner without looping (avoiding potential for gas limit)
    struct TicketPurchase {
        uint256 startId;
        uint256 endId;
    }
    
    // Raffle tickets
    mapping(address => TicketPurchases) private rareItemTicketsBoughtByPlayer;
    mapping(uint256 => address[]) private itemRafflePlayers;
    
    // Duplicating for the two raffles is not ideal
    mapping(address => TicketPurchases) private rareUnitTicketsBoughtByPlayer;
    mapping(uint256 => address[]) private unitRafflePlayers;

    // Item raffle info
    uint256 private constant RAFFLE_TICKET_BASE_GOO_PRICE = 1000;
    uint256 private itemRaffleEndTime;
    uint256 private itemRaffleRareId;
    uint256 private itemRaffleTicketsBought;
    address private itemRaffleWinner; // Address of winner
    bool private itemRaffleWinningTicketSelected;
    uint256 private itemRaffleTicketThatWon;
    
     // Unit raffle info
    uint256 private unitRaffleEndTime;
    uint256 private unitRaffleId;     // Raffle Id
    uint256 private unitRaffleRareId; // Unit Id
    uint256 private unitRaffleTicketsBought;
    address private unitRaffleWinner; // Address of winner
    bool private unitRaffleWinningTicketSelected;
    uint256 private unitRaffleTicketThatWon;
    
    // Minor game events
    event UnitBought(address player, uint256 unitId, uint256 amount);
    event UnitSold(address player, uint256 unitId, uint256 amount);
    event PlayerAttacked(address attacker, address target, bool success, uint256 gooStolen);
    
    event ReferalGain(address player, address referal, uint256 amount);
    event UpgradeMigration(address player, uint256 upgradeId, uint256 txProof);
    
    GooGameConfig schema = GooGameConfig(0xf925a82b8c26520170c8d51b65a7def6364877b3);
    
    // Constructor
    function Goo() public payable {
        owner = msg.sender;
    }
    
    function() payable {
        // Fallback will donate to pot
        totalEtherGooResearchPool += msg.value;
    }
    
    function beginGame(uint256 firstDivsTime) external payable {
        require(msg.sender == owner);
        require(!gameStarted);
        
        gameStarted = true; // GO-OOOO!
        nextSnapshotTime = firstDivsTime;
        totalGooDepositSnapshots.push(0); // Add initial-zero snapshot
        totalEtherGooResearchPool = msg.value; // Seed pot
    }
    
    // Incase community prefers goo deposit payments over production %, can be tweaked for balance
    function tweakDailyDividends(uint256 newResearchPercent, uint256 newGooDepositPercent) external {
        require(msg.sender == owner);
        require(newResearchPercent > 0 && newResearchPercent <= 10);
        require(newGooDepositPercent > 0 && newGooDepositPercent <= 10);
        
        researchDivPercent = newResearchPercent;
        gooDepositDivPercent = newGooDepositPercent;
    }
    
    function totalSupply() public constant returns(uint256) {
        return roughSupply; // Stored goo (rough supply as it ignores earned/unclaimed goo)
    }
    
    function balanceOf(address player) public constant returns(uint256) {
        return gooBalance[player] + balanceOfUnclaimedGoo(player);
    }
    
    function balanceOfUnclaimedGoo(address player) internal constant returns (uint256) {
        uint256 lastSave = lastGooSaveTime[player];
        if (lastSave > 0 && lastSave < block.timestamp) {
            return (getGooProduction(player) * (block.timestamp - lastSave)) / 100;
        }
        return 0;
    }
    
    function etherBalanceOf(address player) public constant returns(uint256) {
        return ethBalance[player];
    }
    
    function transfer(address recipient, uint256 amount) public returns (bool) {
        updatePlayersGoo(msg.sender);
        require(amount <= gooBalance[msg.sender]);
        
        gooBalance[msg.sender] -= amount;
        gooBalance[recipient] += amount;
        
        emit Transfer(msg.sender, recipient, amount);
        return true;
    }
    
    function transferFrom(address player, address recipient, uint256 amount) public returns (bool) {
        updatePlayersGoo(player);
        require(amount <= allowed[player][msg.sender] && amount <= gooBalance[player]);
        
        gooBalance[player] -= amount;
        gooBalance[recipient] += amount;
        allowed[player][msg.sender] -= amount;
        
        emit Transfer(player, recipient, amount);
        return true;
    }
    
    function approve(address approvee, uint256 amount) public returns (bool){
        allowed[msg.sender][approvee] = amount;
        emit Approval(msg.sender, approvee, amount);
        return true;
    }
    
    function allowance(address player, address approvee) public constant returns(uint256){
        return allowed[player][approvee];
    }
    
    function getGooProduction(address player) public constant returns (uint256){
        return gooProductionSnapshots[player][lastGooProductionUpdate[player]];
    }
    
    function updatePlayersGoo(address player) internal {
        uint256 gooGain = balanceOfUnclaimedGoo(player);
        lastGooSaveTime[player] = block.timestamp;
        roughSupply += gooGain;
        gooBalance[player] += gooGain;
    }
    
    function updatePlayersGooFromPurchase(address player, uint256 purchaseCost) internal {
        uint256 unclaimedGoo = balanceOfUnclaimedGoo(player);
        
        if (purchaseCost > unclaimedGoo) {
            uint256 gooDecrease = purchaseCost - unclaimedGoo;
            require(gooBalance[player] >= gooDecrease);
            roughSupply -= gooDecrease;
            gooBalance[player] -= gooDecrease;
        } else {
            uint256 gooGain = unclaimedGoo - purchaseCost;
            roughSupply += gooGain;
            gooBalance[player] += gooGain;
        }
        
        lastGooSaveTime[player] = block.timestamp;
    }
    
    function increasePlayersGooProduction(address player, uint256 increase) internal {
        gooProductionSnapshots[player][allocatedGooResearchSnapshots.length] = getGooProduction(player) + increase;
        lastGooProductionUpdate[player] = allocatedGooResearchSnapshots.length;
        totalGooProduction += increase;
    }
    
    function reducePlayersGooProduction(address player, uint256 decrease) internal {
        uint256 previousProduction = getGooProduction(player);
        uint256 newProduction = SafeMath.sub(previousProduction, decrease);
        
        if (newProduction == 0) { // Special case which tangles with "inactive day" snapshots (claiming divs)
            gooProductionZeroedSnapshots[player][allocatedGooResearchSnapshots.length] = true;
            delete gooProductionSnapshots[player][allocatedGooResearchSnapshots.length]; // 0
        } else {
            gooProductionSnapshots[player][allocatedGooResearchSnapshots.length] = newProduction;
        }
        
        lastGooProductionUpdate[player] = allocatedGooResearchSnapshots.length;
        totalGooProduction -= decrease;
    }
    
    
    function buyBasicUnit(uint256 unitId, uint256 amount) external {
        uint256 schemaUnitId;
        uint256 gooProduction;
        uint256 gooCost;
        uint256 ethCost;
        uint256 existing = unitsOwned[msg.sender][unitId];
        (schemaUnitId, gooProduction, gooCost, ethCost) = schema.getUnitInfo(unitId, existing, amount);
        
        require(gameStarted);
        require(schemaUnitId > 0); // Valid unit
        require(ethCost == 0); // Free unit
        
        uint256 newTotal = SafeMath.add(existing, amount);
        if (newTotal > 99) { // Default unit limit
            require(newTotal <= unitMaxCap[msg.sender][unitId]); // Housing upgrades (allow more units)
        }
        
        // Update players goo
        updatePlayersGooFromPurchase(msg.sender, gooCost);
        
        if (gooProduction > 0) {
            increasePlayersGooProduction(msg.sender, getUnitsProduction(msg.sender, unitId, amount));
        }
        
        unitsOwned[msg.sender][unitId] = newTotal;
        emit UnitBought(msg.sender, unitId, amount);
    }
    
    
    function buyEthUnit(uint256 unitId, uint256 amount) external payable {
        uint256 schemaUnitId;
        uint256 gooProduction;
        uint256 gooCost;
        uint256 ethCost;
        uint256 existing = unitsOwned[msg.sender][unitId];
        (schemaUnitId, gooProduction, gooCost, ethCost) = schema.getUnitInfo(unitId, existing, amount);
        
        require(gameStarted);
        require(schemaUnitId > 0);
        require(ethBalance[msg.sender] + msg.value >= ethCost);

        if (ethCost > msg.value) {
            ethBalance[msg.sender] -= (ethCost - msg.value);
        }
        
        uint256 devFund = ethCost / 50; // 2% fee on purchases (marketing, gameplay & maintenance)
        uint256 dividends = (ethCost - devFund) / 4; // 25% goes to pool (75% retained for sale value)
        totalEtherGooResearchPool += dividends;
        ethBalance[owner] += devFund;
        
        
        uint256 newTotal = SafeMath.add(existing, amount);
        if (newTotal > 99) { // Default unit limit
            require(newTotal <= unitMaxCap[msg.sender][unitId]); // Housing upgrades (allow more units)
        }
        
        // Update players goo
        updatePlayersGooFromPurchase(msg.sender, gooCost);
        
        if (gooProduction > 0) {
            increasePlayersGooProduction(msg.sender, getUnitsProduction(msg.sender, unitId, amount));
        }
        
        unitsOwned[msg.sender][unitId] += amount;
        emit UnitBought(msg.sender, unitId, amount);
    }
    
    
    function sellUnit(uint256 unitId, uint256 amount) external {
        uint256 existing = unitsOwned[msg.sender][unitId];
        require(existing >= amount && amount > 0);
        existing -= amount;
        unitsOwned[msg.sender][unitId] = existing;
        
        uint256 schemaUnitId;
        uint256 gooProduction;
        uint256 gooCost;
        uint256 ethCost;
        (schemaUnitId, gooProduction, gooCost, ethCost) = schema.getUnitInfo(unitId, existing, amount);
        require(schema.unitSellable(unitId));
        
        uint256 gooChange = balanceOfUnclaimedGoo(msg.sender) + ((gooCost * 3) / 4); // Claim unsaved goo whilst here
        lastGooSaveTime[msg.sender] = block.timestamp;
        roughSupply += gooChange;
        gooBalance[msg.sender] += gooChange;
        
        if (gooProduction > 0) {
            reducePlayersGooProduction(msg.sender, getUnitsProduction(msg.sender, unitId, amount));
        }
        
        if (ethCost > 0) { // Premium units sell for 75% of buy cost
            ethBalance[msg.sender] += (ethCost * 3) / 4;
        }
        
        emit UnitSold(msg.sender, unitId, amount);
    }
    
    
    function buyUpgrade(uint256 upgradeId) external payable {
        uint256 gooCost;
        uint256 ethCost;
        uint256 upgradeClass;
        uint256 unitId;
        uint256 upgradeValue;
        uint256 prerequisiteUpgrade;
        (gooCost, ethCost, upgradeClass, unitId, upgradeValue, prerequisiteUpgrade) = schema.getUpgradeInfo(upgradeId);
        
        require(gameStarted);
        require(unitId > 0); // Valid upgrade
        require(!upgradesOwned[msg.sender][upgradeId]); // Haven't already purchased
        
        if (prerequisiteUpgrade > 0) {
            require(upgradesOwned[msg.sender][prerequisiteUpgrade]);
        }
        
        if (ethCost > 0) {
            require(ethBalance[msg.sender] + msg.value >= ethCost);
             if (ethCost > msg.value) { // They can use their balance instead
                ethBalance[msg.sender] -= (ethCost - msg.value);
            }
        
            uint256 devFund = ethCost / 50; // 2% fee on purchases (marketing, gameplay & maintenance)
            totalEtherGooResearchPool += (ethCost - devFund); // Rest goes to div pool (Can't sell upgrades)
            ethBalance[owner] += devFund;
        }
        
        // Update players goo
        updatePlayersGooFromPurchase(msg.sender, gooCost);

        upgradeUnitMultipliers(msg.sender, upgradeClass, unitId, upgradeValue);
        upgradesOwned[msg.sender][upgradeId] = true;
    }
    
    function upgradeUnitMultipliers(address player, uint256 upgradeClass, uint256 unitId, uint256 upgradeValue) internal {
        uint256 productionGain;
        if (upgradeClass == 0) {
            unitGooProductionIncreases[player][unitId] += upgradeValue;
            productionGain = unitsOwned[player][unitId] * upgradeValue * (10 + unitGooProductionMultiplier[player][unitId]);
            increasePlayersGooProduction(player, productionGain);
        } else if (upgradeClass == 1) {
            unitGooProductionMultiplier[player][unitId] += upgradeValue;
            productionGain = unitsOwned[player][unitId] * upgradeValue * (schema.unitGooProduction(unitId) + unitGooProductionIncreases[player][unitId]);
            increasePlayersGooProduction(player, productionGain);
        } else if (upgradeClass == 2) {
            unitAttackIncreases[player][unitId] += upgradeValue;
        } else if (upgradeClass == 3) {
            unitAttackMultiplier[player][unitId] += upgradeValue;
        } else if (upgradeClass == 4) {
            unitDefenseIncreases[player][unitId] += upgradeValue;
        } else if (upgradeClass == 5) {
            unitDefenseMultiplier[player][unitId] += upgradeValue;
        } else if (upgradeClass == 6) {
            unitGooStealingIncreases[player][unitId] += upgradeValue;
        } else if (upgradeClass == 7) {
            unitGooStealingMultiplier[player][unitId] += upgradeValue;
        } else if (upgradeClass == 8) {
            unitMaxCap[player][unitId] = upgradeValue; // Housing upgrade (new capacity)
        }
    }
    
    function removeUnitMultipliers(address player, uint256 upgradeClass, uint256 unitId, uint256 upgradeValue) internal {
        uint256 productionLoss;
        if (upgradeClass == 0) {
            unitGooProductionIncreases[player][unitId] -= upgradeValue;
            productionLoss = unitsOwned[player][unitId] * upgradeValue * (10 + unitGooProductionMultiplier[player][unitId]);
            reducePlayersGooProduction(player, productionLoss);
        } else if (upgradeClass == 1) {
            unitGooProductionMultiplier[player][unitId] -= upgradeValue;
            productionLoss = unitsOwned[player][unitId] * upgradeValue * (schema.unitGooProduction(unitId) + unitGooProductionIncreases[player][unitId]);
            reducePlayersGooProduction(player, productionLoss);
        } else if (upgradeClass == 2) {
            unitAttackIncreases[player][unitId] -= upgradeValue;
        } else if (upgradeClass == 3) {
            unitAttackMultiplier[player][unitId] -= upgradeValue;
        } else if (upgradeClass == 4) {
            unitDefenseIncreases[player][unitId] -= upgradeValue;
        } else if (upgradeClass == 5) {
            unitDefenseMultiplier[player][unitId] -= upgradeValue;
        } else if (upgradeClass == 6) {
            unitGooStealingIncreases[player][unitId] -= upgradeValue;
        } else if (upgradeClass == 7) {
            unitGooStealingMultiplier[player][unitId] -= upgradeValue;
        }
    }
    
    function buyRareItem(uint256 rareId) external payable {
        uint256 upgradeClass;
        uint256 unitId;
        uint256 upgradeValue;
        (upgradeClass, unitId, upgradeValue) = schema.getRareInfo(rareId);

        address previousOwner = rareItemOwner[rareId];
        require(previousOwner != 0);
        require(unitId > 0);
        
        // We have to claim buyer's goo before updating their production values
        updatePlayersGoo(msg.sender);
        upgradeUnitMultipliers(msg.sender, upgradeClass, unitId, upgradeValue);
        
        // We have to claim seller's goo before reducing their production values
        updatePlayersGoo(previousOwner);
        removeUnitMultipliers(previousOwner, upgradeClass, unitId, upgradeValue);
        
        uint256 ethCost = rareItemPrice[rareId];
        require(ethBalance[msg.sender] + msg.value >= ethCost);
        
        // Splitbid/Overbid
        if (ethCost > msg.value) {
            // Earlier require() said they can still afford it (so use their ingame balance)
            ethBalance[msg.sender] -= (ethCost - msg.value);
        } else if (msg.value > ethCost) {
            // Store overbid in their balance
            ethBalance[msg.sender] += msg.value - ethCost;
        }
        
        // Distribute ethCost
        uint256 devFund = ethCost / 50; // 2% fee on purchases (marketing, gameplay & maintenance)
        uint256 dividends = ethCost / 20; // 5% goes to pool (~93% goes to player)
        totalEtherGooResearchPool += dividends;
        ethBalance[owner] += devFund;
        
        // Transfer / update rare item
        rareItemOwner[rareId] = msg.sender;
        rareItemPrice[rareId] = (ethCost * 5) / 4; // 25% price flip increase
        ethBalance[previousOwner] += ethCost - (dividends + devFund);
    }
    
    function withdrawEther(uint256 amount) external {
        require(amount <= ethBalance[msg.sender]);
        ethBalance[msg.sender] -= amount;
        msg.sender.transfer(amount);
    }
    
    function fundGooResearch(uint256 amount) external {
        updatePlayersGooFromPurchase(msg.sender, amount);
        gooDepositSnapshots[msg.sender][totalGooDepositSnapshots.length - 1] += amount;
        totalGooDepositSnapshots[totalGooDepositSnapshots.length - 1] += amount;
    }
    
    function claimResearchDividends(address referer, uint256 startSnapshot, uint256 endSnapShot) external {
        require(startSnapshot <= endSnapShot);
        require(startSnapshot >= lastGooResearchFundClaim[msg.sender]);
        require(endSnapShot < allocatedGooResearchSnapshots.length);
        
        uint256 researchShare;
        uint256 previousProduction = gooProductionSnapshots[msg.sender][lastGooResearchFundClaim[msg.sender] - 1]; // Underflow won't be a problem as gooProductionSnapshots[][0xffffffffff] = 0;
        for (uint256 i = startSnapshot; i <= endSnapShot; i++) {
            
            // Slightly complex things by accounting for days/snapshots when user made no tx's
            uint256 productionDuringSnapshot = gooProductionSnapshots[msg.sender][i];
            bool soldAllProduction = gooProductionZeroedSnapshots[msg.sender][i];
            if (productionDuringSnapshot == 0 && !soldAllProduction) {
                productionDuringSnapshot = previousProduction;
            } else {
               previousProduction = productionDuringSnapshot;
            }
            
            researchShare += (allocatedGooResearchSnapshots[i] * productionDuringSnapshot) / totalGooProductionSnapshots[i];
        }
        
        
        if (gooProductionSnapshots[msg.sender][endSnapShot] == 0 && !gooProductionZeroedSnapshots[msg.sender][endSnapShot] && previousProduction > 0) {
            gooProductionSnapshots[msg.sender][endSnapShot] = previousProduction; // Checkpoint for next claim
        }
        
        lastGooResearchFundClaim[msg.sender] = endSnapShot + 1;
        
        uint256 referalDivs;
        if (referer != address(0) && referer != msg.sender) {
            referalDivs = researchShare / 100; // 1%
            ethBalance[referer] += referalDivs;
            emit ReferalGain(referer, msg.sender, referalDivs);
        }
        
        ethBalance[msg.sender] += researchShare - referalDivs;
    }
    
    
    function claimGooDepositDividends(address referer, uint256 startSnapshot, uint256 endSnapShot) external {
        require(startSnapshot <= endSnapShot);
        require(startSnapshot >= lastGooDepositFundClaim[msg.sender]);
        require(endSnapShot < allocatedGooDepositSnapshots.length);
        
        uint256 depositShare;
        for (uint256 i = startSnapshot; i <= endSnapShot; i++) {
            depositShare += (allocatedGooDepositSnapshots[i] * gooDepositSnapshots[msg.sender][i]) / totalGooDepositSnapshots[i];
        }
        
        lastGooDepositFundClaim[msg.sender] = endSnapShot + 1;
        
        uint256 referalDivs;
        if (referer != address(0) && referer != msg.sender) {
            referalDivs = depositShare / 100; // 1%
            ethBalance[referer] += referalDivs;
            emit ReferalGain(referer, msg.sender, referalDivs);
        }
        
        ethBalance[msg.sender] += depositShare - referalDivs;
    }
    
    
    // Allocate pot #1 divs for the day (00:00 cron job)
    function snapshotDailyGooResearchFunding() external {
        require(msg.sender == owner);
        
        uint256 todaysGooResearchFund = (totalEtherGooResearchPool * researchDivPercent) / 100; // 8% of pool daily
        totalEtherGooResearchPool -= todaysGooResearchFund;
        
        totalGooProductionSnapshots.push(totalGooProduction);
        allocatedGooResearchSnapshots.push(todaysGooResearchFund);
        nextSnapshotTime = block.timestamp + 24 hours;
    }
    
    // Allocate pot #2 divs for the day (12:00 cron job)
    function snapshotDailyGooDepositFunding() external {
        require(msg.sender == owner);
        
        uint256 todaysGooDepositFund = (totalEtherGooResearchPool * gooDepositDivPercent) / 100; // 2% of pool daily
        totalEtherGooResearchPool -= todaysGooDepositFund;
        totalGooDepositSnapshots.push(0); // Reset for to store next day's deposits
        allocatedGooDepositSnapshots.push(todaysGooDepositFund); // Store to payout divs for previous day deposits
    }
    
    
    // Raffle for rare items
    function buyItemRaffleTicket(uint256 amount) external {
        require(itemRaffleEndTime >= block.timestamp);
        require(amount > 0);
        
        uint256 ticketsCost = SafeMath.mul(RAFFLE_TICKET_BASE_GOO_PRICE, amount);
        require(balanceOf(msg.sender) >= ticketsCost);
        
        // Update players goo
        updatePlayersGooFromPurchase(msg.sender, ticketsCost);
        
        // Handle new tickets
        TicketPurchases storage purchases = rareItemTicketsBoughtByPlayer[msg.sender];
        
        // If we need to reset tickets from a previous raffle
        if (purchases.raffleId != itemRaffleRareId) {
            purchases.numPurchases = 0;
            purchases.raffleId = itemRaffleRareId;
            itemRafflePlayers[itemRaffleRareId].push(msg.sender); // Add user to raffle
        }
        
        // Store new ticket purchase
        if (purchases.numPurchases == purchases.ticketsBought.length) {
            purchases.ticketsBought.length += 1;
        }
        purchases.ticketsBought[purchases.numPurchases++] = TicketPurchase(itemRaffleTicketsBought, itemRaffleTicketsBought + (amount - 1)); // (eg: buy 10, get id's 0-9)
        
        // Finally update ticket total
        itemRaffleTicketsBought += amount;
    }
    
    // Raffle for rare units
    function buyUnitRaffleTicket(uint256 amount) external {
        require(unitRaffleEndTime >= block.timestamp);
        require(amount > 0);
        
        uint256 ticketsCost = SafeMath.mul(RAFFLE_TICKET_BASE_GOO_PRICE, amount);
        require(balanceOf(msg.sender) >= ticketsCost);
        
        // Update players goo
        updatePlayersGooFromPurchase(msg.sender, ticketsCost);
        
        // Handle new tickets
        TicketPurchases storage purchases = rareUnitTicketsBoughtByPlayer[msg.sender];
        
        // If we need to reset tickets from a previous raffle
        if (purchases.raffleId != unitRaffleId) {
            purchases.numPurchases = 0;
            purchases.raffleId = unitRaffleId;
            unitRafflePlayers[unitRaffleId].push(msg.sender); // Add user to raffle
        }
        
        // Store new ticket purchase
        if (purchases.numPurchases == purchases.ticketsBought.length) {
            purchases.ticketsBought.length += 1;
        }
        purchases.ticketsBought[purchases.numPurchases++] = TicketPurchase(unitRaffleTicketsBought, unitRaffleTicketsBought + (amount - 1)); // (eg: buy 10, get id's 0-9)
        
        // Finally update ticket total
        unitRaffleTicketsBought += amount;
    }
    
    function startItemRaffle(uint256 endTime, uint256 rareId) external {
        require(msg.sender == owner);
        require(schema.validRareId(rareId));
        require(rareItemOwner[rareId] == 0);
        require(block.timestamp < endTime);
        
        if (itemRaffleRareId != 0) { // Sanity to assure raffle has ended before next one starts
            require(itemRaffleWinner != 0);
        }
        
        // Reset previous raffle info
        itemRaffleWinningTicketSelected = false;
        itemRaffleTicketThatWon = 0;
        itemRaffleWinner = 0;
        itemRaffleTicketsBought = 0;
        
        // Set current raffle info
        itemRaffleEndTime = endTime;
        itemRaffleRareId = rareId;
    }
    
    function startUnitRaffle(uint256 endTime, uint256 unitId) external {
        require(msg.sender == owner);
        require(block.timestamp < endTime);
        
        if (unitRaffleRareId != 0) { // Sanity to assure raffle has ended before next one starts
            require(unitRaffleWinner != 0);
        }
        
        // Reset previous raffle info
        unitRaffleWinningTicketSelected = false;
        unitRaffleTicketThatWon = 0;
        unitRaffleWinner = 0;
        unitRaffleTicketsBought = 0;
        
        // Set current raffle info
        unitRaffleEndTime = endTime;
        unitRaffleRareId = unitId;
        unitRaffleId++; // Can't use unitRaffleRareId (as rare units are not unique)
    }
    
    function awardItemRafflePrize(address checkWinner, uint256 checkIndex) external {
        require(itemRaffleEndTime < block.timestamp);
        require(itemRaffleWinner == 0);
        require(rareItemOwner[itemRaffleRareId] == 0);
        
        if (!itemRaffleWinningTicketSelected) {
            drawRandomItemWinner(); // Ideally do it in one call (gas limit cautious)
        }
        
        // Reduce gas by (optionally) offering an address to _check_ for winner
        if (checkWinner != 0) {
            TicketPurchases storage tickets = rareItemTicketsBoughtByPlayer[checkWinner];
            if (tickets.numPurchases > 0 && checkIndex < tickets.numPurchases && tickets.raffleId == itemRaffleRareId) {
                TicketPurchase storage checkTicket = tickets.ticketsBought[checkIndex];
                if (itemRaffleTicketThatWon >= checkTicket.startId && itemRaffleTicketThatWon <= checkTicket.endId) {
                    assignItemRafflePrize(checkWinner); // WINNER!
                    return;
                }
            }
        }
        
        // Otherwise just naively try to find the winner (will work until mass amounts of players)
        for (uint256 i = 0; i < itemRafflePlayers[itemRaffleRareId].length; i++) {
            address player = itemRafflePlayers[itemRaffleRareId][i];
            TicketPurchases storage playersTickets = rareItemTicketsBoughtByPlayer[player];
            
            uint256 endIndex = playersTickets.numPurchases - 1;
            // Minor optimization to avoid checking every single player
            if (itemRaffleTicketThatWon >= playersTickets.ticketsBought[0].startId && itemRaffleTicketThatWon <= playersTickets.ticketsBought[endIndex].endId) {
                for (uint256 j = 0; j < playersTickets.numPurchases; j++) {
                    TicketPurchase storage playerTicket = playersTickets.ticketsBought[j];
                    if (itemRaffleTicketThatWon >= playerTicket.startId && itemRaffleTicketThatWon <= playerTicket.endId) {
                        assignItemRafflePrize(player); // WINNER!
                        return;
                    }
                }
            }
        }
    }
    
    function awardUnitRafflePrize(address checkWinner, uint256 checkIndex) external {
        require(unitRaffleEndTime < block.timestamp);
        require(unitRaffleWinner == 0);
        
        if (!unitRaffleWinningTicketSelected) {
            drawRandomUnitWinner(); // Ideally do it in one call (gas limit cautious)
        }
        
        // Reduce gas by (optionally) offering an address to _check_ for winner
        if (checkWinner != 0) {
            TicketPurchases storage tickets = rareUnitTicketsBoughtByPlayer[checkWinner];
            if (tickets.numPurchases > 0 && checkIndex < tickets.numPurchases && tickets.raffleId == unitRaffleId) {
                TicketPurchase storage checkTicket = tickets.ticketsBought[checkIndex];
                if (unitRaffleTicketThatWon >= checkTicket.startId && unitRaffleTicketThatWon <= checkTicket.endId) {
                    assignUnitRafflePrize(checkWinner); // WINNER!
                    return;
                }
            }
        }
        
        // Otherwise just naively try to find the winner (will work until mass amounts of players)
        for (uint256 i = 0; i < unitRafflePlayers[unitRaffleId].length; i++) {
            address player = unitRafflePlayers[unitRaffleId][i];
            TicketPurchases storage playersTickets = rareUnitTicketsBoughtByPlayer[player];
            
            uint256 endIndex = playersTickets.numPurchases - 1;
            // Minor optimization to avoid checking every single player
            if (unitRaffleTicketThatWon >= playersTickets.ticketsBought[0].startId && unitRaffleTicketThatWon <= playersTickets.ticketsBought[endIndex].endId) {
                for (uint256 j = 0; j < playersTickets.numPurchases; j++) {
                    TicketPurchase storage playerTicket = playersTickets.ticketsBought[j];
                    if (unitRaffleTicketThatWon >= playerTicket.startId && unitRaffleTicketThatWon <= playerTicket.endId) {
                        assignUnitRafflePrize(player); // WINNER!
                        return;
                    }
                }
            }
        }
    }
    
    function assignItemRafflePrize(address winner) internal {
        itemRaffleWinner = winner;
        rareItemOwner[itemRaffleRareId] = winner;
        rareItemPrice[itemRaffleRareId] = (schema.rareStartPrice(itemRaffleRareId) * 21) / 20; // Buy price slightly higher (Div pool cut)
        
        updatePlayersGoo(winner);
        uint256 upgradeClass;
        uint256 unitId;
        uint256 upgradeValue;
        (upgradeClass, unitId, upgradeValue) = schema.getRareInfo(itemRaffleRareId);
        upgradeUnitMultipliers(winner, upgradeClass, unitId, upgradeValue);
    }
    
    function assignUnitRafflePrize(address winner) internal {
        unitRaffleWinner = winner;
        updatePlayersGoo(winner);
        increasePlayersGooProduction(winner, getUnitsProduction(winner, unitRaffleRareId, 1));
        unitsOwned[winner][unitRaffleRareId] += 1;
    }
    
    // Random enough for small contests (Owner only to prevent trial & error execution)
    function drawRandomItemWinner() public {
        require(msg.sender == owner);
        require(itemRaffleEndTime < block.timestamp);
        require(!itemRaffleWinningTicketSelected);
        
        uint256 seed = itemRaffleTicketsBought + block.timestamp;
        itemRaffleTicketThatWon = addmod(uint256(block.blockhash(block.number-1)), seed, itemRaffleTicketsBought);
        itemRaffleWinningTicketSelected = true;
    }
    
    function drawRandomUnitWinner() public {
        require(msg.sender == owner);
        require(unitRaffleEndTime < block.timestamp);
        require(!unitRaffleWinningTicketSelected);
        
        uint256 seed = unitRaffleTicketsBought + block.timestamp;
        unitRaffleTicketThatWon = addmod(uint256(block.blockhash(block.number-1)), seed, unitRaffleTicketsBought);
        unitRaffleWinningTicketSelected = true;
    }
    
    // Gives players the upgrades they 'previously paid for' (i.e. will be one of same unit/type/value of their v1 purchase)
    // Tx of their (prior) purchase is provided so can be validated by anyone for 0 abuse
    function migrateV1Upgrades(address[] playerToCredit, uint256[] upgradeIds, uint256[] txProof) external {
        require(msg.sender == owner);
        require(!gameStarted); // Pre-game migration
        
        for (uint256 i = 0; i < txProof.length; i++) {
            address player = playerToCredit[i];
            uint256 upgradeId = upgradeIds[i];
            
            uint256 unitId = schema.upgradeUnitId(upgradeId);
            if (unitId > 0 && !upgradesOwned[player][upgradeId]) { // Upgrade valid (and haven't already migrated)
                uint256 upgradeClass = schema.upgradeClass(upgradeId);
                uint256 upgradeValue = schema.upgradeValue(upgradeId);
        
                upgradeUnitMultipliers(player, upgradeClass, unitId, upgradeValue);
                upgradesOwned[player][upgradeId] = true;
                emit UpgradeMigration(player, upgradeId, txProof[i]);
            }
        }
    }
    
    function protectAddress(address exchange, bool shouldProtect) external {
        require(msg.sender == owner);
        if (shouldProtect) {
            require(getGooProduction(exchange) == 0); // Can't protect actual players
        }
        protectedAddresses[exchange] = shouldProtect;
    }
    
    function attackPlayer(address target) external {
        require(battleCooldown[msg.sender] < block.timestamp);
        require(target != msg.sender);
        require(!protectedAddresses[target]); // Target not whitelisted (i.e. exchange wallets)
        
        uint256 attackingPower;
        uint256 defendingPower;
        uint256 stealingPower;
        (attackingPower, defendingPower, stealingPower) = getPlayersBattlePower(msg.sender, target);
        
        if (battleCooldown[target] > block.timestamp) { // When on battle cooldown you're vulnerable (starting value is 50% normal power)
            defendingPower = schema.getWeakenedDefensePower(defendingPower);
        }
        
        if (attackingPower > defendingPower) {
            battleCooldown[msg.sender] = block.timestamp + 30 minutes;
            if (balanceOf(target) > stealingPower) {
                // Save all their unclaimed goo, then steal attacker's max capacity (at same time)
                uint256 unclaimedGoo = balanceOfUnclaimedGoo(target);
                if (stealingPower > unclaimedGoo) {
                    uint256 gooDecrease = stealingPower - unclaimedGoo;
                    gooBalance[target] -= gooDecrease;
                    roughSupply -= gooDecrease;
                } else {
                    uint256 gooGain = unclaimedGoo - stealingPower;
                    gooBalance[target] += gooGain;
                    roughSupply += gooGain;
                }
                gooBalance[msg.sender] += stealingPower;
                emit PlayerAttacked(msg.sender, target, true, stealingPower);
            } else {
                emit PlayerAttacked(msg.sender, target, true, balanceOf(target));
                gooBalance[msg.sender] += balanceOf(target);
                gooBalance[target] = 0;
            }
            
            lastGooSaveTime[target] = block.timestamp;
            // We don't need to claim/save msg.sender's goo (as production delta is unchanged)
        } else {
            battleCooldown[msg.sender] = block.timestamp + 10 minutes;
            emit PlayerAttacked(msg.sender, target, false, 0);
        }
    }
    
    function getPlayersBattlePower(address attacker, address defender) internal constant returns (uint256, uint256, uint256) {
        uint256 startId;
        uint256 endId;
        (startId, endId) = schema.battleUnitIdRange();
        
        uint256 attackingPower;
        uint256 defendingPower;
        uint256 stealingPower;

        // Not ideal but will only be a small number of units (and saves gas when buying units)
        while (startId <= endId) {
            attackingPower += getUnitsAttack(attacker, startId, unitsOwned[attacker][startId]);
            stealingPower += getUnitsStealingCapacity(attacker, startId, unitsOwned[attacker][startId]);
            
            defendingPower += getUnitsDefense(defender, startId, unitsOwned[defender][startId]);
            startId++;
        }
        
        return (attackingPower, defendingPower, stealingPower);
    }
    
    function getPlayersBattleStats(address player) external constant returns (uint256, uint256, uint256, uint256) {
        uint256 startId;
        uint256 endId;
        (startId, endId) = schema.battleUnitIdRange();
        
        uint256 attackingPower;
        uint256 defendingPower;
        uint256 stealingPower;

        // Not ideal but will only be a small number of units (and saves gas when buying units)
        while (startId <= endId) {
            attackingPower += getUnitsAttack(player, startId, unitsOwned[player][startId]);
            stealingPower += getUnitsStealingCapacity(player, startId, unitsOwned[player][startId]);
            defendingPower += getUnitsDefense(player, startId, unitsOwned[player][startId]);
            startId++;
        }
        
        if (battleCooldown[player] > block.timestamp) { // When on battle cooldown you're vulnerable (starting value is 50% normal power)
            defendingPower = schema.getWeakenedDefensePower(defendingPower);
        }
        
        return (attackingPower, defendingPower, stealingPower, battleCooldown[player]);
    }
    
    function getUnitsProduction(address player, uint256 unitId, uint256 amount) internal constant returns (uint256) {
        return (amount * (schema.unitGooProduction(unitId) + unitGooProductionIncreases[player][unitId]) * (10 + unitGooProductionMultiplier[player][unitId]));
    }
    
    function getUnitsAttack(address player, uint256 unitId, uint256 amount) internal constant returns (uint256) {
        return (amount * (schema.unitAttack(unitId) + unitAttackIncreases[player][unitId]) * (10 + unitAttackMultiplier[player][unitId])) / 10;
    }
    
    function getUnitsDefense(address player, uint256 unitId, uint256 amount) internal constant returns (uint256) {
        return (amount * (schema.unitDefense(unitId) + unitDefenseIncreases[player][unitId]) * (10 + unitDefenseMultiplier[player][unitId])) / 10;
    }
    
    function getUnitsStealingCapacity(address player, uint256 unitId, uint256 amount) internal constant returns (uint256) {
        return (amount * (schema.unitStealingCapacity(unitId) + unitGooStealingIncreases[player][unitId]) * (10 + unitGooStealingMultiplier[player][unitId])) / 10;
    }
    
    
    // To display on website
    function getGameInfo() external constant returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256[], bool[]){
        uint256[] memory units = new uint256[](schema.currentNumberOfUnits());
        bool[] memory upgrades = new bool[](schema.currentNumberOfUpgrades());
        
        uint256 startId;
        uint256 endId;
        (startId, endId) = schema.productionUnitIdRange();
        
        uint256 i;
        while (startId <= endId) {
            units[i] = unitsOwned[msg.sender][startId];
            i++;
            startId++;
        }
        
        (startId, endId) = schema.battleUnitIdRange();
        while (startId <= endId) {
            units[i] = unitsOwned[msg.sender][startId];
            i++;
            startId++;
        }
        
        // Reset for upgrades
        i = 0;
        (startId, endId) = schema.upgradeIdRange();
        while (startId <= endId) {
            upgrades[i] = upgradesOwned[msg.sender][startId];
            i++;
            startId++;
        }
        
        return (block.timestamp, totalEtherGooResearchPool, totalGooProduction, totalGooDepositSnapshots[totalGooDepositSnapshots.length - 1],  gooDepositSnapshots[msg.sender][totalGooDepositSnapshots.length - 1],
        nextSnapshotTime, balanceOf(msg.sender), ethBalance[msg.sender], getGooProduction(msg.sender), units, upgrades);
    }
    
    // To display on website
    function getRareItemInfo() external constant returns (address[], uint256[]) {
        address[] memory itemOwners = new address[](schema.currentNumberOfRares());
        uint256[] memory itemPrices = new uint256[](schema.currentNumberOfRares());
        
        uint256 startId;
        uint256 endId;
        (startId, endId) = schema.rareIdRange();
        
        uint256 i;
        while (startId <= endId) {
            itemOwners[i] = rareItemOwner[startId];
            itemPrices[i] = rareItemPrice[startId];
            
            i++;
            startId++;
        }
        
        return (itemOwners, itemPrices);
    }
    
    // To display on website
    function viewUnclaimedResearchDividends() external constant returns (uint256, uint256, uint256) {
        uint256 startSnapshot = lastGooResearchFundClaim[msg.sender];
        uint256 latestSnapshot = allocatedGooResearchSnapshots.length - 1; // No snapshots to begin with
        
        uint256 researchShare;
        uint256 previousProduction = gooProductionSnapshots[msg.sender][lastGooResearchFundClaim[msg.sender] - 1]; // Underflow won't be a problem as gooProductionSnapshots[][0xfffffffffffff] = 0;
        for (uint256 i = startSnapshot; i <= latestSnapshot; i++) {
            
            // Slightly complex things by accounting for days/snapshots when user made no tx's
            uint256 productionDuringSnapshot = gooProductionSnapshots[msg.sender][i];
            bool soldAllProduction = gooProductionZeroedSnapshots[msg.sender][i];
            if (productionDuringSnapshot == 0 && !soldAllProduction) {
                productionDuringSnapshot = previousProduction;
            } else {
               previousProduction = productionDuringSnapshot;
            }
            
            researchShare += (allocatedGooResearchSnapshots[i] * productionDuringSnapshot) / totalGooProductionSnapshots[i];
        }
        return (researchShare, startSnapshot, latestSnapshot);
    }
    
    // To display on website
    function viewUnclaimedDepositDividends() external constant returns (uint256, uint256, uint256) {
        uint256 startSnapshot = lastGooDepositFundClaim[msg.sender];
        uint256 latestSnapshot = allocatedGooDepositSnapshots.length - 1; // No snapshots to begin with
        
        uint256 depositShare;
        for (uint256 i = startSnapshot; i <= latestSnapshot; i++) {
            depositShare += (allocatedGooDepositSnapshots[i] * gooDepositSnapshots[msg.sender][i]) / totalGooDepositSnapshots[i];
        }
        return (depositShare, startSnapshot, latestSnapshot);
    }
    
    
    // To allow clients to verify contestants
    function getItemRafflePlayers(uint256 raffleId) external constant returns (address[]) {
        return (itemRafflePlayers[raffleId]);
    }
    
    // To allow clients to verify contestants
    function getUnitRafflePlayers(uint256 raffleId) external constant returns (address[]) {
        return (unitRafflePlayers[raffleId]);
    }
    
    // To allow clients to verify contestants
    function getPlayersItemTickets(address player) external constant returns (uint256[], uint256[]) {
        TicketPurchases storage playersTickets = rareItemTicketsBoughtByPlayer[player];
        
        if (playersTickets.raffleId == itemRaffleRareId) {
            uint256[] memory startIds = new uint256[](playersTickets.numPurchases);
            uint256[] memory endIds = new uint256[](playersTickets.numPurchases);
            
            for (uint256 i = 0; i < playersTickets.numPurchases; i++) {
                startIds[i] = playersTickets.ticketsBought[i].startId;
                endIds[i] = playersTickets.ticketsBought[i].endId;
            }
        }
        
        return (startIds, endIds);
    }
    
    // To allow clients to verify contestants
    function getPlayersUnitTickets(address player) external constant returns (uint256[], uint256[]) {
        TicketPurchases storage playersTickets = rareUnitTicketsBoughtByPlayer[player];
        
        if (playersTickets.raffleId == unitRaffleId) {
            uint256[] memory startIds = new uint256[](playersTickets.numPurchases);
            uint256[] memory endIds = new uint256[](playersTickets.numPurchases);
            
            for (uint256 i = 0; i < playersTickets.numPurchases; i++) {
                startIds[i] = playersTickets.ticketsBought[i].startId;
                endIds[i] = playersTickets.ticketsBought[i].endId;
            }
        }
        
        return (startIds, endIds);
    }
    
    // To display on website
    function getLatestItemRaffleInfo() external constant returns (uint256, uint256, uint256, address, uint256) {
        return (itemRaffleEndTime, itemRaffleRareId, itemRaffleTicketsBought, itemRaffleWinner, itemRaffleTicketThatWon);
    }
    
    // To display on website
    function getLatestUnitRaffleInfo() external constant returns (uint256, uint256, uint256, address, uint256) {
        return (unitRaffleEndTime, unitRaffleRareId, unitRaffleTicketsBought, unitRaffleWinner, unitRaffleTicketThatWon);
    }
    
    
    // New units may be added in future, but check it matches existing schema so no-one can abuse selling.
    function updateGooConfig(address newSchemaAddress) external {
        require(msg.sender == owner);
        
        GooGameConfig newSchema = GooGameConfig(newSchemaAddress);
        
        requireExistingUnitsSame(newSchema);
        requireExistingUpgradesSame(newSchema);
        
        // Finally update config
        schema = GooGameConfig(newSchema);
    }
    
    function requireExistingUnitsSame(GooGameConfig newSchema) internal constant {
        // Requires units eth costs match up or fail execution
        
        uint256 startId;
        uint256 endId;
        (startId, endId) = schema.productionUnitIdRange();
        while (startId <= endId) {
            require(schema.unitEthCost(startId) == newSchema.unitEthCost(startId));
            require(schema.unitGooProduction(startId) == newSchema.unitGooProduction(startId));
            startId++;
        }
        
        (startId, endId) = schema.battleUnitIdRange();
        while (startId <= endId) {
            require(schema.unitEthCost(startId) == newSchema.unitEthCost(startId));
            require(schema.unitAttack(startId) == newSchema.unitAttack(startId));
            require(schema.unitDefense(startId) == newSchema.unitDefense(startId));
            require(schema.unitStealingCapacity(startId) == newSchema.unitStealingCapacity(startId));
            startId++;
        }
    }
    
    function requireExistingUpgradesSame(GooGameConfig newSchema) internal constant {
        uint256 startId;
        uint256 endId;
        
        // Requires ALL upgrade stats match up or fail execution
        (startId, endId) = schema.upgradeIdRange();
        while (startId <= endId) {
            require(schema.upgradeGooCost(startId) == newSchema.upgradeGooCost(startId));
            require(schema.upgradeEthCost(startId) == newSchema.upgradeEthCost(startId));
            require(schema.upgradeClass(startId) == newSchema.upgradeClass(startId));
            require(schema.upgradeUnitId(startId) == newSchema.upgradeUnitId(startId));
            require(schema.upgradeValue(startId) == newSchema.upgradeValue(startId));
            startId++;
        }
        
        // Requires ALL rare stats match up or fail execution
        (startId, endId) = schema.rareIdRange();
        while (startId <= endId) {
            uint256 oldClass;
            uint256 oldUnitId;
            uint256 oldValue;
            
            uint256 newClass;
            uint256 newUnitId;
            uint256 newValue;
            (oldClass, oldUnitId, oldValue) = schema.getRareInfo(startId);
            (newClass, newUnitId, newValue) = newSchema.getRareInfo(startId);
            
            require(oldClass == newClass);
            require(oldUnitId == newUnitId);
            require(oldValue == newValue);
            startId++;
        }
    }
}


contract GooGameConfig {
    
    mapping(uint256 => Unit) private unitInfo;
    mapping(uint256 => Upgrade) private upgradeInfo;
    mapping(uint256 => Rare) private rareInfo;
    
    uint256 public constant currentNumberOfUnits = 15;
    uint256 public constant currentNumberOfUpgrades = 210;
    uint256 public constant currentNumberOfRares = 2;
    
    address public owner;
    
    struct Unit {
        uint256 unitId;
        uint256 baseGooCost;
        uint256 gooCostIncreaseHalf; // Halfed to make maths slightly less (cancels a 2 out)
        uint256 ethCost;
        uint256 baseGooProduction;
        
        uint256 attackValue;
        uint256 defenseValue;
        uint256 gooStealingCapacity;
        bool unitSellable; // Rare units (from raffle) not sellable
    }
    
    struct Upgrade {
        uint256 upgradeId;
        uint256 gooCost;
        uint256 ethCost;
        uint256 upgradeClass;
        uint256 unitId;
        uint256 upgradeValue;
        uint256 prerequisiteUpgrade;
    }
    
    struct Rare {
        uint256 rareId;
        uint256 ethCost;
        uint256 rareClass;
        uint256 unitId;
        uint256 rareValue;
    }
    
    function GooGameConfig() public {
        owner = msg.sender;
        
        rareInfo[1] = Rare(1, 0.5 ether, 1, 1, 40); // 40 = +400%
        rareInfo[2] = Rare(2, 0.5 ether, 0, 2, 35); // +35
        
        unitInfo[1] = Unit(1, 0, 10, 0, 2, 0, 0, 0, true);
        unitInfo[2] = Unit(2, 100, 50, 0, 5, 0, 0, 0, true);
        unitInfo[3] = Unit(3, 0, 0, 0.01 ether, 100, 0, 0, 0, true);
        unitInfo[4] = Unit(4, 200, 100, 0, 10, 0, 0, 0, true);
        unitInfo[5] = Unit(5, 500, 250, 0, 20, 0, 0, 0, true);
        unitInfo[6] = Unit(6, 1000, 500, 0, 40, 0, 0, 0, true);
        unitInfo[7] = Unit(7, 0, 1000, 0.05 ether, 500, 0, 0, 0, true);
        unitInfo[8] = Unit(8, 1500, 750, 0, 60, 0, 0, 0, true);
        unitInfo[9] = Unit(9, 0, 0, 10 ether, 6000, 0, 0, 0, false); // First secret rare unit from raffle (unsellable)
        
        unitInfo[40] = Unit(40, 50, 25, 0, 0, 10, 10, 10000, true);
        unitInfo[41] = Unit(41, 100, 50, 0, 0, 1, 25, 500, true);
        unitInfo[42] = Unit(42, 0, 0, 0.01 ether, 0, 200, 10, 50000, true);
        unitInfo[43] = Unit(43, 250, 125, 0, 0, 25, 1, 15000, true);
        unitInfo[44] = Unit(44, 500, 250, 0, 0, 20, 40, 5000, true);
        unitInfo[45] = Unit(45, 0, 2500, 0.02 ether, 0, 0, 0, 100000, true);
    }
    
    address allowedConfig;
    function setConfigSetupContract(address schema) external {
        require(msg.sender == owner);
        allowedConfig = schema;
    }
    
    function addUpgrade(uint256 id, uint256 goo, uint256 eth, uint256 class, uint256 unit, uint256 value, uint256 prereq) external {
        require(msg.sender == allowedConfig);
        upgradeInfo[id] = Upgrade(id, goo, eth, class, unit, value, prereq);
    }
    
    function getGooCostForUnit(uint256 unitId, uint256 existing, uint256 amount) public constant returns (uint256) {
        Unit storage unit = unitInfo[unitId];
        if (amount == 1) { // 1
            if (existing == 0) {
                return unit.baseGooCost;
            } else {
                return unit.baseGooCost + (existing * unit.gooCostIncreaseHalf * 2);
            }
        } else if (amount > 1) {
            uint256 existingCost;
            if (existing > 0) { // Gated by unit limit
                existingCost = (unit.baseGooCost * existing) + (existing * (existing - 1) * unit.gooCostIncreaseHalf);
            }
            
            existing = SafeMath.add(existing, amount);
            return SafeMath.add(SafeMath.mul(unit.baseGooCost, existing), SafeMath.mul(SafeMath.mul(existing, (existing - 1)), unit.gooCostIncreaseHalf)) - existingCost;
        }
    }
    
    function getWeakenedDefensePower(uint256 defendingPower) external constant returns (uint256) {
        return defendingPower / 2;
    }
    
    function validRareId(uint256 rareId) external constant returns (bool) {
        return (rareId > 0 && rareId < 3);
    }
    
    function unitSellable(uint256 unitId) external constant returns (bool) {
        return unitInfo[unitId].unitSellable;
    }
    
    function unitEthCost(uint256 unitId) external constant returns (uint256) {
        return unitInfo[unitId].ethCost;
    }
    
    function unitGooProduction(uint256 unitId) external constant returns (uint256) {
        return unitInfo[unitId].baseGooProduction;
    }
    
    function unitAttack(uint256 unitId) external constant returns (uint256) {
        return unitInfo[unitId].attackValue;
    }
    
    function unitDefense(uint256 unitId) external constant returns (uint256) {
        return unitInfo[unitId].defenseValue;
    }
    
    function unitStealingCapacity(uint256 unitId) external constant returns (uint256) {
        return unitInfo[unitId].gooStealingCapacity;
    }
    
    function rareStartPrice(uint256 rareId) external constant returns (uint256) {
        return rareInfo[rareId].ethCost;
    }
    
    function upgradeGooCost(uint256 upgradeId) external constant returns (uint256) {
        return upgradeInfo[upgradeId].gooCost;
    }
    
    function upgradeEthCost(uint256 upgradeId) external constant returns (uint256) {
        return upgradeInfo[upgradeId].ethCost;
    }
    
    function upgradeClass(uint256 upgradeId) external constant returns (uint256) {
        return upgradeInfo[upgradeId].upgradeClass;
    }
    
    function upgradeUnitId(uint256 upgradeId) external constant returns (uint256) {
        return upgradeInfo[upgradeId].unitId;
    }
    
    function upgradeValue(uint256 upgradeId) external constant returns (uint256) {
        return upgradeInfo[upgradeId].upgradeValue;
    }
    
    function productionUnitIdRange() external constant returns (uint256, uint256) {
        return (1, 9);
    }
    
    function battleUnitIdRange() external constant returns (uint256, uint256) {
        return (40, 45);
    }
    
    function upgradeIdRange() external constant returns (uint256, uint256) {
        return (1, 210);
    }
    
    function rareIdRange() external constant returns (uint256, uint256) {
        return (1, 2);
    }
    
    function getUpgradeInfo(uint256 upgradeId) external constant returns (uint256, uint256, uint256, uint256, uint256, uint256) {
        return (upgradeInfo[upgradeId].gooCost, upgradeInfo[upgradeId].ethCost, upgradeInfo[upgradeId].upgradeClass,
        upgradeInfo[upgradeId].unitId, upgradeInfo[upgradeId].upgradeValue, upgradeInfo[upgradeId].prerequisiteUpgrade);
    }
    
    function getRareInfo(uint256 rareId) external constant returns (uint256, uint256, uint256) {
        return (rareInfo[rareId].rareClass, rareInfo[rareId].unitId, rareInfo[rareId].rareValue);
    }
    
    function getUnitInfo(uint256 unitId, uint256 existing, uint256 amount) external constant returns (uint256, uint256, uint256, uint256) {
        return (unitInfo[unitId].unitId, unitInfo[unitId].baseGooProduction, getGooCostForUnit(unitId, existing, amount), SafeMath.mul(unitInfo[unitId].ethCost, amount));
    }
    
}


library SafeMath {

  /**
  * @dev Multiplies two numbers, throws on overflow.
  */
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }

  /**
  * @dev Integer division of two numbers, truncating the quotient.
  */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  /**
  * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  /**
  * @dev Adds two numbers, throws on overflow.
  */
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

Contract Security Audit

Contract ABI

[{"constant":true,"inputs":[{"name":"player","type":"address"}],"name":"getPlayersItemTickets","outputs":[{"name":"","type":"uint256[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"approvee","type":"address"},{"name":"amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"playerToCredit","type":"address[]"},{"name":"upgradeIds","type":"uint256[]"},{"name":"txProof","type":"uint256[]"}],"name":"migrateV1Upgrades","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"viewUnclaimedDepositDividends","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getGameInfo","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256[]"},{"name":"","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"player","type":"address"}],"name":"etherBalanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"endTime","type":"uint256"},{"name":"unitId","type":"uint256"}],"name":"startUnitRaffle","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"player","type":"address"}],"name":"getGooProduction","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"drawRandomUnitWinner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"player","type":"address"},{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"firstDivsTime","type":"uint256"}],"name":"beginGame","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"unitId","type":"uint256"},{"name":"amount","type":"uint256"}],"name":"buyBasicUnit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"lastGooProductionUpdate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalEtherGooResearchPool","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"withdrawEther","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"drawRandomItemWinner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"gooDepositDivPercent","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"viewUnclaimedResearchDividends","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newResearchPercent","type":"uint256"},{"name":"newGooDepositPercent","type":"uint256"}],"name":"tweakDailyDividends","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"target","type":"address"}],"name":"attackPlayer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"gameStarted","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"buyUnitRaffleTicket","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getLatestItemRaffleInfo","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"address"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"player","type":"address"}],"name":"getPlayersUnitTickets","outputs":[{"name":"","type":"uint256[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"raffleId","type":"uint256"}],"name":"getItemRafflePlayers","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"player","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"exchange","type":"address"},{"name":"shouldProtect","type":"bool"}],"name":"protectAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"checkWinner","type":"address"},{"name":"checkIndex","type":"uint256"}],"name":"awardItemRafflePrize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"endTime","type":"uint256"},{"name":"rareId","type":"uint256"}],"name":"startItemRaffle","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"unitId","type":"uint256"},{"name":"amount","type":"uint256"}],"name":"sellUnit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newSchemaAddress","type":"address"}],"name":"updateGooConfig","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalGooProduction","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"player","type":"address"}],"name":"getPlayersBattleStats","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"referer","type":"address"},{"name":"startSnapshot","type":"uint256"},{"name":"endSnapShot","type":"uint256"}],"name":"claimGooDepositDividends","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"referer","type":"address"},{"name":"startSnapshot","type":"uint256"},{"name":"endSnapShot","type":"uint256"}],"name":"claimResearchDividends","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"checkWinner","type":"address"},{"name":"checkIndex","type":"uint256"}],"name":"awardUnitRafflePrize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"researchDivPercent","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"rareId","type":"uint256"}],"name":"buyRareItem","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"fundGooResearch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"upgradeId","type":"uint256"}],"name":"buyUpgrade","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getLatestUnitRaffleInfo","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"address"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"nextSnapshotTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRareItemInfo","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"buyItemRaffleTicket","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"snapshotDailyGooResearchFunding","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"raffleId","type":"uint256"}],"name":"getUnitRafflePlayers","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"unitId","type":"uint256"},{"name":"amount","type":"uint256"}],"name":"buyEthUnit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"player","type":"address"},{"name":"approvee","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"snapshotDailyGooDepositFunding","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":true,"stateMutability":"payable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"player","type":"address"},{"indexed":false,"name":"unitId","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"UnitBought","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"player","type":"address"},{"indexed":false,"name":"unitId","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"UnitSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"attacker","type":"address"},{"indexed":false,"name":"target","type":"address"},{"indexed":false,"name":"success","type":"bool"},{"indexed":false,"name":"gooStolen","type":"uint256"}],"name":"PlayerAttacked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"player","type":"address"},{"indexed":false,"name":"referal","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"ReferalGain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"player","type":"address"},{"indexed":false,"name":"upgradeId","type":"uint256"},{"indexed":false,"name":"txProof","type":"uint256"}],"name":"UpgradeMigration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"tokens","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"tokenOwner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"tokens","type":"uint256"}],"name":"Approval","type":"event"}]

60606040526008600355600260048190556033805473f925a82b8c26520170c8d51b65a7def6364877b3600160a060020a031991821617909155815416600160a060020a033316179055615754806100586000396000f3006060604052600436106102795763ffffffff60e060020a60003504166302b68bbf811461028357806306fdde031461033b578063095ea7b3146103c55780630b407022146103fb57806313aa7b6f146104335780631746bd1b1461046a578063179fc99f1461055557806318160ddd1461058657806318d801681461059957806319e9e5de146105b257806322bfba59146105d157806323b872dd146105e457806325a7650a1461060c5780632bfd2e06146106175780633081fe3f14610630578063313ce5671461064f57806338198c65146106785780633bed33ce1461068b5780634a1d08af146106a15780634a617fba146106b45780634efdd4f9146106c757806353dd8881146106da5780635dc22cce146106f35780635e123ce41461071257806360f61a4c1461072557806364f54a171461073b5780636a7d1a7e146107885780636c20d755146107a757806370a082311461081057806370bc52fb1461082f57806370d9f7dc14610853578063716e560414610875578063751fef651461088e5780637c85a757146108a75780637ef58e73146108c657806380fa7902146108d95780638d4777c8146109235780638da5cb5b146109485780638fafb286146109775780639323eaad1461099c57806393d7c6bf146109be57806395d89b41146109d15780639e30dd5f146109e4578063a21f74b8146109ef578063a5a2cb1914610a05578063a7b7f1d414610a10578063a89cdad914610a23578063a9059cbb14610a36578063b1d6600314610a58578063b912950e14610a6b578063c38f074114610a81578063c9c286c614610a94578063d8737d8a14610aaa578063dd62ed3e14610ab8578063f2f921e614610add575b6005805434019055005b341561028e57600080fd5b6102a2600160a060020a0360043516610af0565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156102e65780820151838201526020016102ce565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561032557808201518382015260200161030d565b5050505090500194505050505060405180910390f35b341561034657600080fd5b61034e610c16565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561038a578082015183820152602001610372565b50505050905090810190601f1680156103b75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156103d057600080fd5b6103e7600160a060020a0360043516602435610c4d565b604051901515815260200160405180910390f35b341561040657600080fd5b6104316024600480358281019290820135918135808301929082013591604435918201910135610cb9565b005b341561043e57600080fd5b610446610f59565b60405180848152602001838152602001828152602001935050505060405180910390f35b341561047557600080fd5b61047d610ffe565b604051808c81526020018b81526020018a81526020018981526020018881526020018781526020018681526020018581526020018481526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156104f75780820151838201526020016104df565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561053657808201518382015260200161051e565b505050509050019d505050505050505050505050505060405180910390f35b341561056057600080fd5b610574600160a060020a03600435166113e6565b60405190815260200160405180910390f35b341561059157600080fd5b610574611401565b34156105a457600080fd5b610431600435602435611408565b34156105bd57600080fd5b610574600160a060020a036004351661148e565b34156105dc57600080fd5b6104316114bb565b34156105ef57600080fd5b6103e7600160a060020a0360043581169060243516604435611542565b610431600435611634565b341561062257600080fd5b6104316004356024356116b4565b341561063b57600080fd5b610574600160a060020a0360043516611894565b341561065a57600080fd5b6106626118a6565b60405160ff909116815260200160405180910390f35b341561068357600080fd5b6105746118ab565b341561069657600080fd5b6104316004356118b1565b34156106ac57600080fd5b610431611921565b34156106bf57600080fd5b6105746119a8565b34156106d257600080fd5b6104466119ae565b34156106e557600080fd5b610431600435602435611ab0565b34156106fe57600080fd5b610431600160a060020a0360043516611b0e565b341561071d57600080fd5b6103e7611e84565b341561073057600080fd5b610431600435611e94565b341561074657600080fd5b61074e611fec565b6040519485526020850193909352604080850192909252600160a060020a03166060840152608083019190915260a0909101905180910390f35b341561079357600080fd5b6102a2600160a060020a036004351661200c565b34156107b257600080fd5b6107bd600435612126565b60405160208082528190810183818151815260200191508051906020019060200280838360005b838110156107fc5780820151838201526020016107e4565b505050509050019250505060405180910390f35b341561081b57600080fd5b610574600160a060020a03600435166121a1565b341561083a57600080fd5b610431600160a060020a036004351660243515156121cd565b341561085e57600080fd5b610431600160a060020a036004351660243561222c565b341561088057600080fd5b610431600435602435612480565b341561089957600080fd5b610431600435602435612588565b34156108b257600080fd5b610431600160a060020a03600435166127e0565b34156108d157600080fd5b610574612842565b34156108e457600080fd5b6108f8600160a060020a0360043516612848565b6040518085815260200184815260200183815260200182815260200194505050505060405180910390f35b341561092e57600080fd5b610431600160a060020a0360043516602435604435612a26565b341561095357600080fd5b61095b612bcd565b604051600160a060020a03909116815260200160405180910390f35b341561098257600080fd5b610431600160a060020a0360043516602435604435612bdc565b34156109a757600080fd5b610431600160a060020a0360043516602435612e85565b34156109c957600080fd5b6105746130a3565b34156109dc57600080fd5b61034e6130a9565b6104316004356130e0565b34156109fa57600080fd5b6104316004356132e3565b610431600435613344565b3415610a1b57600080fd5b61074e61354e565b3415610a2e57600080fd5b61057461356e565b3415610a4157600080fd5b6103e7600160a060020a0360043516602435613574565b3415610a6357600080fd5b6102a2613612565b3415610a7657600080fd5b610431600435613807565b3415610a8c57600080fd5b61043161395f565b3415610a9f57600080fd5b6107bd6004356139e9565b610431600435602435613a62565b3415610ac357600080fd5b610574600160a060020a0360043581169060243516613cca565b3415610ae857600080fd5b610431613cf5565b610af8615688565b610b00615688565b6000610b0a615688565b610b12615688565b600160a060020a038616600090815260246020526040812060295460028201549195501415610c0a578360010154604051805910610b4d5750595b908082528060200260200182016040525092508360010154604051805910610b725750595b90808252806020026020018201604052509150600090505b8360010154811015610c0a578354849082908110610ba457fe5b906000526020600020906002020160000154838281518110610bc257fe5b602090810290910101528354849082908110610bda57fe5b906000526020600020906002020160010154828281518110610bf857fe5b60209081029091010152600101610b8a565b50909590945092505050565b60408051908101604052600781527f49646c6545746800000000000000000000000000000000000000000000000000602082015281565b600160a060020a03338116600081815260226020908152604080832094871680845294909152808220859055909291907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259085905190815260200160405180910390a350600192915050565b6002546000908190819081908190819033600160a060020a03908116911614610ce157600080fd5b60025460a060020a900460ff1615610cf857600080fd5b600095505b86861015610f4b578b8b87818110610d1157fe5b90506020020135600160a060020a031694508989878181101515610d3157fe5b60335460209091029290920135955050600160a060020a03166372fecf848560405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610d8657600080fd5b5af11515610d9357600080fd5b5050506040518051935050600083118015610dd25750600160a060020a038516600090815260166020908152604080832087845290915290205460ff16155b15610f4057603354600160a060020a031663309ba1208560405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610e1f57600080fd5b5af11515610e2c57600080fd5b5050506040518051603354909350600160a060020a03169050630caeb3508560405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610e8157600080fd5b5af11515610e8e57600080fd5b505050604051805190509050610ea685838584613d69565b600160a060020a03851660009081526016602090815260408083208784529091529020805460ff191660011790557fb84e528e18e54dd4bb87635427809661099f52b6fb31e5c969e6f07c9a19913c85858a8a8a818110610f0357fe5b905060200201356040518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a15b600190950194610cfd565b505050505050505050505050565b600160a060020a033316600090815260136020526040812054600954829182916000190182825b828111610ff3576007805482908110610f9557fe5b6000918252602080832090910154600160a060020a0333168352600e825260408084208585529092529120546009805484908110610fcf57fe5b90600052602060002090015402811515610fe557fe5b049190910190600101610f80565b509591945092509050565b6000806000806000806000806000611014615688565b61101c615688565b611024615688565b61102c615688565b60335460009081908190600160a060020a0316638975e45f6040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561107257600080fd5b5af1151561107f57600080fd5b505050604051805190506040518059106110965750595b9080825280602002602001820160405250603354909550600160a060020a031663f10a98486040518163ffffffff1660e060020a028152600401602060405180830381600087803b15156110e957600080fd5b5af115156110f657600080fd5b5050506040518051905060405180591061110d5750595b9080825280602002602001820160405250603354909450600160a060020a03166328bdbdca6040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561115f57600080fd5b5af1151561116c57600080fd5b5050506040518051906020018051919450909250505b8183116111cf57600160a060020a03331660009081526015602090815260408083208684529091529020548582815181106111b957fe5b6020908102909101015260019283019201611182565b603354600160a060020a0316636026bb866040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561120d57600080fd5b5af1151561121a57600080fd5b5050506040518051906020018051919450909250505b81831161127d57600160a060020a033316600090815260156020908152604080832086845290915290205485828151811061126757fe5b6020908102909101015260019283019201611230565b50603354600090600160a060020a031663709e6ed46040518163ffffffff1660e060020a0281526004016040805180830381600087803b15156112bf57600080fd5b5af115156112cc57600080fd5b5050506040518051906020018051919450909250505b81831161133757600160a060020a033316600090815260166020908152604080832086845290915290205460ff1684828151811061131c57fe5b911515602092830290910190910152600192830192016112e2565b600554600154600780544293929190600019810190811061135457fe5b6000918252602080832090910154600160a060020a03339081168452600e835260408085206007546000190186529093529190922054600a549091611398906121a1565b33600160a060020a0381166000908152600b6020526040902054906113bc9061148e565b8d8d9f509f509f509f509f509f509f509f509f509f509f505050505050909192939495969798999a565b600160a060020a03166000908152600b602052604090205490565b6000545b90565b60025433600160a060020a0390811691161461142357600080fd5b4282901061143057600080fd5b602f541561144f57603154600160a060020a0316151561144f57600080fd5b603180546000603281905574ffffffffffffffffffffffffffffffffffffffffff19909116909155603055602d91909155602f55602e80546001019055565b600160a060020a03166000908152600d602090815260408083206011835281842054845290915290205490565b60025460009033600160a060020a039081169116146114d957600080fd5b602d544290106114e857600080fd5b60315460a060020a900460ff16156114ff57600080fd5b506030544281019080151561151057fe5b8160001943014008603255506031805474ff0000000000000000000000000000000000000000191660a060020a179055565b600061154d84614030565b600160a060020a0380851660009081526022602090815260408083203390941683529290522054821180159061159b5750600160a060020a0384166000908152600c60205260409020548211155b15156115a657600080fd5b600160a060020a038085166000818152600c6020908152604080832080548890039055878516808452818420805489019055848452602283528184203390961684529490915290819020805486900390557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9085905190815260200160405180910390a35060019392505050565b60025433600160a060020a0390811691161461164f57600080fd5b60025460a060020a900460ff161561166657600080fd5b6002805474ff0000000000000000000000000000000000000000191660a060020a179055600a81905560078054600181016116a1838261569a565b5060009182526020822001555034600555565b600160a060020a03338116600090815260156020908152604080832086845290915280822054603354929384938493849392849216906306011b14908a9085908b905160e060020a63ffffffff8616028152600481019390935260248301919091526044820152606401608060405180830381600087803b151561173757600080fd5b5af1151561174457600080fd5b5050506040518051906020018051906020018051906020018051600254949a509298509096509094505060a060020a900460ff16151561178357600080fd5b6000861161179057600080fd5b821561179b57600080fd5b6117a58288614072565b905060638111156117e057600160a060020a03331660009081526021602090815260408083208b84529091529020548111156117e057600080fd5b6117ea338561408c565b60008511156118075761180733611802338b8b614143565b6141eb565b33600160a060020a03811660009081526015602090815260408083208c8452909152908190208390557fb6d35f558a34938047f09ebf800fa2e15ec407c357a8eab97a5dd67b4d015b5b91908a908a90518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a15050505050505050565b60116020526000908152604090205481565b600081565b60055481565b600160a060020a0333166000908152600b60205260409020548111156118d657600080fd5b600160a060020a0333166000818152600b6020526040908190208054849003905582156108fc0290839051600060405180830381858888f19350505050151561191e57600080fd5b50565b60025460009033600160a060020a0390811691161461193f57600080fd5b60285442901061194e57600080fd5b602b5460a060020a900460ff161561196557600080fd5b50602a544281019080151561197657fe5b8160001943014008602c5550602b805474ff0000000000000000000000000000000000000000191660a060020a179055565b60045481565b600160a060020a033316600090815260126020908152604080832054600854600d8452828520600019808401875294529184205484938493019083908382805b858311611a9f575050600160a060020a0333166000818152600d60209081526040808320858452825280832054938352600f825280832085845290915290205460ff1681158015611a3d575080155b15611a4a57839150611a4e565b8193505b6006805484908110611a5c57fe5b90600052602060002090015482600885815481101515611a7857fe5b90600052602060002090015402811515611a8e57fe5b0494909401936001909201916119ee565b509298949750929550929350505050565b60025433600160a060020a03908116911614611acb57600080fd5b600082118015611adc5750600a8211155b1515611ae757600080fd5b600081118015611af85750600a8111155b1515611b0357600080fd5b600391909155600455565b600160a060020a03331660009081526014602052604081205481908190819081908190429010611b3d57600080fd5b33600160a060020a031687600160a060020a031614151515611b5e57600080fd5b600160a060020a03871660009081526023602052604090205460ff1615611b8457600080fd5b611b8e338861423f565b600160a060020a038a16600090815260146020526040902054929850909650945042901115611c1857603354600160a060020a03166394b67b1c8660405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515611bff57600080fd5b5af11515611c0c57600080fd5b50505060405180519550505b84861115611dfe57600160a060020a03331660009081526014602052604090206107084201905583611c49886121a1565b1115611d4557611c5887614370565b925082841115611c9557600160a060020a0387166000908152600c6020526040812080548587039081900390915581548190039091559150611cc1565b50600160a060020a0386166000908152600c602052604081208054858503908101909155815481019091555b33600160a060020a0381166000908152600c6020526040908190208054870190557fb06cb54b17603e70140ce0216d86cef7e3e645e5a77c76f0cd1e4afe1b5b9e3f91908990600190889051600160a060020a03948516815292909316602083015215156040808301919091526060820192909252608001905180910390a1611dde565b7fb06cb54b17603e70140ce0216d86cef7e3e645e5a77c76f0cd1e4afe1b5b9e3f33886001611d738b6121a1565b604051600160a060020a03948516815292909316602083015215156040808301919091526060820192909252608001905180910390a1611db2876121a1565b600160a060020a033381166000908152600c602052604080822080549094019093559089168152908120555b600160a060020a0387166000908152601060205260409020429055611e7b565b33600160a060020a038116600090815260146020526040808220426102580190557fb06cb54b17603e70140ce0216d86cef7e3e645e5a77c76f0cd1e4afe1b5b9e3f92918a91819051600160a060020a03948516815292909316602083015215156040808301919091526060820192909252608001905180910390a15b50505050505050565b60025460a060020a900460ff1681565b60008042602d5410151515611ea857600080fd5b60008311611eb557600080fd5b611ec16103e8846143c7565b915081611ecd336121a1565b1015611ed857600080fd5b611ee2338361408c565b50600160a060020a0333166000908152602660205260409020602e54600282015414611f6b5760006001808301829055602e5460028401819055825260276020526040909120805490918101611f38838261569a565b506000918252602090912001805473ffffffffffffffffffffffffffffffffffffffff191633600160a060020a03161790555b805460018201541415611f89578054600101611f8782826156be565b505b60408051908101604052603054808252840160001901602082015260018281018054918201905582548391908110611fbd57fe5b906000526020600020906002020160008201518155602082015160019091015550506030805490920190915550565b602854602954602a54602b54602c54600160a060020a0390911691929394565b612014615688565b61201c615688565b6000612026615688565b61202e615688565b600160a060020a0386166000908152602660205260408120602e5460028201549195501415610c0a5783600101546040518059106120695750595b90808252806020026020018201604052509250836001015460405180591061208e5750595b90808252806020026020018201604052509150600090505b8360010154811015610c0a5783548490829081106120c057fe5b9060005260206000209060020201600001548382815181106120de57fe5b6020908102909101015283548490829081106120f657fe5b90600052602060002090600202016001015482828151811061211457fe5b602090810290910101526001016120a6565b61212e615688565b6025600083815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561219557602002820191906000526020600020905b8154600160a060020a03168152600190910190602001808311612177575b50505050509050919050565b60006121ac82614370565b600160a060020a0383166000908152600c6020526040902054019050919050565b60025433600160a060020a039081169116146121e857600080fd5b8015612201576121f78261148e565b1561220157600080fd5b600160a060020a03919091166000908152602360205260409020805460ff1916911515919091179055565b6000806000806000806000804260285410151561224857600080fd5b602b54600160a060020a03161561225e57600080fd5b602954600090815260176020526040902054600160a060020a03161561228357600080fd5b602b5460a060020a900460ff16151561229e5761229e611921565b600160a060020a038a161561234057600160a060020a038a16600090815260246020526040812060018101549099501180156122dd5750876001015489105b80156122ee57506029548860020154145b1561234057875488908a90811061230157fe5b906000526020600020906002020196508660000154602c541015801561232d57508660010154602c5411155b156123405761233b8a6143f2565b612474565b600095505b60295460009081526025602052604090205486101561247457602954600090815260256020526040902080548790811061237b57fe5b6000918252602080832090910154600160a060020a03168083526024909152604082206001810154815492985090965060001901945085919081106123bc57fe5b906000526020600020906002020160000154602c5410158015612400575083548490849081106123e857fe5b906000526020600020906002020160010154602c5411155b1561246957600091505b836001015482101561246957835484908390811061242457fe5b906000526020600020906002020190508060000154602c541015801561245057508060010154602c5411155b1561245e5761233b856143f2565b60019091019061240a565b600190950194612345565b50505050505050505050565b60025433600160a060020a0390811691161461249b57600080fd5b603354600160a060020a03166297b6078260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156124e257600080fd5b5af115156124ef57600080fd5b50505060405180519050151561250457600080fd5b600081815260176020526040902054600160a060020a03161561252657600080fd5b4282901061253357600080fd5b6029541561255257602b54600160a060020a0316151561255257600080fd5b602b80546000602c81905574ffffffffffffffffffffffffffffffffffffffffff19909116909155602a55602891909155602955565b600160a060020a033316600090815260156020908152604080832085845290915281205490808080808686108015906125c15750600087115b15156125cc57600080fd5b600160a060020a0333811660009081526015602090815260408083208c8452909152908190209789900397889055603354909116906306011b14908a9089908b905160e060020a63ffffffff8616028152600481019390935260248301919091526044820152606401608060405180830381600087803b151561264e57600080fd5b5af1151561265b57600080fd5b505050604051805190602001805190602001805190602001805160335494995092975090955090935050600160a060020a03166341e34be98960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156126ca57600080fd5b5af115156126d757600080fd5b5050506040518051905015156126ec57600080fd5b600460038402046126fc33614370565b33600160a060020a031660009081526010602090815260408083204290558254939094019283018255600c9052918220805482019055915084111561274f5761274f3361274a338b8b614143565b614556565b600082111561277d57600160a060020a0333166000908152600b602052604090208054600460038502040190555b7f9c8076df639d56f1ef3ca3d4d8dc6ed089f8c4756bc5bf5d574f1cec4ef13c543389896040518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a15050505050505050565b60025460009033600160a060020a039081169116146127fe57600080fd5b50806128098161461a565b61281281614bc0565b6033805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039290921691909117905550565b60015481565b6000806000806000806000806000603360009054906101000a9004600160a060020a0316600160a060020a0316636026bb866040518163ffffffff1660e060020a0281526004016040805180830381600087803b15156128a757600080fd5b5af115156128b457600080fd5b5050506040518051906020018051919650909450505b83851161297957600160a060020a038a166000908152601560209081526040808320888452909152902054612902908b9087906151b7565b600160a060020a038b166000908152601560209081526040808320898452909152902054930192612936908b908790615269565b600160a060020a038b16600090815260156020908152604080832089845290915290205491019061296a908b9087906152ec565b600190950194909101906128ca565b600160a060020a038a16600090815260146020526040902054429011156129fb57603354600160a060020a03166394b67b1c8360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156129e257600080fd5b5af115156129ef57600080fd5b50505060405180519250505b600160a060020a03999099166000908152601460205260409020549199909897509095509350505050565b6000808083851115612a3757600080fd5b600160a060020a033316600090815260136020526040902054851015612a5c57600080fd5b6009548410612a6a57600080fd5b8491505b838211612ae4576007805483908110612a8357fe5b6000918252602080832090910154600160a060020a0333168352600e825260408084208685529092529120546009805485908110612abd57fe5b90600052602060002090015402811515612ad357fe5b049290920191600190910190612a6e565b600160a060020a033381166000908152601360205260409020600186019055861615801590612b25575033600160a060020a031686600160a060020a031614155b15612ba55750600160a060020a0385166000908152600b602052604090819020805460648504908101909155907f676f0fffb2fbfbfc8daa0d0f7d89788003ac6a87c448c7fb792ceb5b8e00e0dd9087903390849051600160a060020a039384168152919092166020820152604080820192909252606001905180910390a15b600160a060020a0333166000908152600b602052604090208054919093030190915550505050565b600254600160a060020a031681565b6000808080808086881115612bf057600080fd5b600160a060020a033316600090815260126020526040902054881015612c1557600080fd5b6008548710612c2357600080fd5b600160a060020a0333166000908152600d60209081526040808320601283528184205460001901845290915290205494508793505b868411612d0c57600160a060020a0333166000818152600d60209081526040808320888452825280832054938352600f825280832088845290915290205490935060ff16915082158015612caa575081155b15612cb757849250612cbb565b8294505b6006805485908110612cc957fe5b90600052602060002090015483600886815481101515612ce557fe5b90600052602060002090015402811515612cfb57fe5b049590950194600190930192612c58565b600160a060020a0333166000908152600d602090815260408083208a8452909152902054158015612d615750600160a060020a0333166000908152600f602090815260408083208a845290915290205460ff16155b8015612d6d5750600085115b15612d9957600160a060020a0333166000908152600d602090815260408083208a845290915290208590555b600160a060020a033381166000908152601260205260409020600189019055891615801590612dda575033600160a060020a031689600160a060020a031614155b15612e5a5750600160a060020a0388166000908152600b602052604090819020805460648804908101909155907f676f0fffb2fbfbfc8daa0d0f7d89788003ac6a87c448c7fb792ceb5b8e00e0dd908a903390849051600160a060020a039384168152919092166020820152604080820192909252606001905180910390a15b600160a060020a0333166000908152600b602052604090208054919096030190945550505050505050565b60008060008060008060008042602d54101515612ea157600080fd5b603154600160a060020a031615612eb757600080fd5b60315460a060020a900460ff161515612ed257612ed26114bb565b600160a060020a038a1615612f6f57600160a060020a038a1660009081526026602052604081206001810154909950118015612f115750876001015489105b8015612f225750602e548860020154145b15612f6f57875488908a908110612f3557fe5b90600052602060002090600202019650866000015460325410158015612f615750866001015460325411155b15612f6f5761233b8a615371565b600095505b602e5460009081526027602052604090205486101561247457602e546000908152602760205260409020805487908110612faa57fe5b6000918252602080832090910154600160a060020a0316808352602690915260408220600181015481549298509096506000190194508591908110612feb57fe5b9060005260206000209060020201600001546032541015801561302f5750835484908490811061301757fe5b90600052602060002090600202016001015460325411155b1561309857600091505b836001015482101561309857835484908390811061305357fe5b9060005260206000209060020201905080600001546032541015801561307f5750806001015460325411155b1561308d5761233b85615371565b600190910190613039565b600190950194612f74565b60035481565b60408051908101604052600381527f476f6f0000000000000000000000000000000000000000000000000000000000602082015281565b603354600090819081908190819081908190600160a060020a031663275babee8960405160e060020a63ffffffff84160281526004810191909152602401606060405180830381600087803b151561313757600080fd5b5af1151561314457600080fd5b505050604051805190602001805190602001805160008c815260176020526040902054939a5091985090965050600160a060020a0316935083151561318857600080fd5b6000861161319557600080fd5b61319e33614030565b6131aa33888888613d69565b6131b384614030565b6131bf848888886153e1565b600088815260186020908152604080832054600160a060020a0333168452600b909252909120549093503401839010156131f857600080fd5b3483111561322657600160a060020a0333166000908152600b60205260409020805434850390039055613250565b8234111561325057600160a060020a0333166000908152600b602052604090208054348590030190555b505060058054601483049081018255600254600160a060020a039081166000908152600b60208181526040808420805460328a049081019091559c845260178252808420805433871673ffffffffffffffffffffffffffffffffffffffff199091161790556018825280842060049789029790970490965596909216815294529220805492909601900301909355505050565b6132ed338261408c565b600160a060020a0333166000908152600e6020908152604080832060078054600019908101865291909352922080548401905580548392810190811061332f57fe5b60009182526020909120018054909101905550565b603354600090819081908190819081908190600160a060020a03166328a42e9d8960405160e060020a63ffffffff8416028152600481019190915260240160c060405180830381600087803b151561339b57600080fd5b5af115156133a857600080fd5b5050506040518051906020018051906020018051906020018051906020018051906020018051600254969d50949b5092995090975095509093505060a060020a900460ff1615156133f857600080fd5b6000841161340557600080fd5b600160a060020a03331660009081526016602090815260408083208b845290915290205460ff161561343657600080fd5b600082111561347157600160a060020a033316600090815260166020908152604080832085845290915290205460ff16151561347157600080fd5b60008611156134ff57600160a060020a0333166000908152600b60205260409020543401869010156134a257600080fd5b348611156134cc57600160a060020a0333166000908152600b602052604090208054348803900390555b506005805460328704808803909101909155600254600160a060020a03166000908152600b602052604090208054820190555b613509338861408c565b61351533868686613d69565b505050600160a060020a033316600090815260166020908152604080832097835296905294909420805460ff1916600117905550505050565b602d54602f54603054603154603254600160a060020a0390911691929394565b600a5481565b600061357f33614030565b600160a060020a0333166000908152600c60205260409020548211156135a457600080fd5b600160a060020a033381166000818152600c60205260408082208054879003905592861680825290839020805486019055917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9085905190815260200160405180910390a350600192915050565b61361a615688565b613622615688565b61362a615688565b613632615688565b60335460009081908190600160a060020a031663a528cb4f6040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561367857600080fd5b5af1151561368557600080fd5b5050506040518051905060405180591061369c5750595b9080825280602002602001820160405250603354909550600160a060020a031663a528cb4f6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15156136ef57600080fd5b5af115156136fc57600080fd5b505050604051805190506040518059106137135750595b9080825280602002602001820160405250603354909450600160a060020a0316634ecdf1656040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561376557600080fd5b5af1151561377257600080fd5b5050506040518051906020018051919450909250505b8183116137fa57600083815260176020526040902054600160a060020a03168582815181106137b357fe5b600160a060020a0390921660209283029091018201526000848152601890915260409020548482815181106137e457fe5b6020908102909101015260019283019201613788565b5092959194509092505050565b600080426028541015151561381b57600080fd5b6000831161382857600080fd5b6138346103e8846143c7565b915081613840336121a1565b101561384b57600080fd5b613855338361408c565b50600160a060020a03331660009081526024602052604090206029546002820154146138de5760006001808301829055602954600284018190558252602560205260409091208054909181016138ab838261569a565b506000918252602090912001805473ffffffffffffffffffffffffffffffffffffffff191633600160a060020a03161790555b8054600182015414156138fc5780546001016138fa82826156be565b505b60408051908101604052602a5480825284016000190160208201526001828101805491820190558254839190811061393057fe5b90600052602060002090600202016000820151815560208201516001909101555050602a805490920190915550565b60025460009033600160a060020a0390811691161461397d57600080fd5b506003546005805460649281029290920491829003905560068054600181016139a6838261569a565b9160005260206000209001600060015490919091505550600880548060010182816139d1919061569a565b50600091825260209091200155620151804201600a55565b6139f1615688565b6027600083815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561219557602002820191906000526020600020908154600160a060020a031681526001909101906020018083116121775750505050509050919050565b600160a060020a0333811660009081526015602090815260408083208684529091528082205460335492938493849384939284928392839291909116906306011b14908c9087908d905160e060020a63ffffffff8616028152600481019390935260248301919091526044820152606401608060405180830381600087803b1515613aec57600080fd5b5af11515613af957600080fd5b5050506040518051906020018051906020018051906020018051600254949c50929a509098509096505060a060020a900460ff161515613b3857600080fd5b60008811613b4557600080fd5b600160a060020a0333166000908152600b6020526040902054340185901015613b6d57600080fd5b34851115613b9757600160a060020a0333166000908152600b602052604090208054348703900390555b603285049250600483860360058054929091049182019055600254600160a060020a03166000908152600b602052604090208054850190559150613bdb848a614072565b90506063811115613c1657600160a060020a03331660009081526021602090815260408083208d8452909152902054811115613c1657600080fd5b613c20338761408c565b6000871115613c3857613c3833611802338d8d614143565b33600160a060020a03811660009081526015602090815260408083208e84529091529081902080548c0190557fb6d35f558a34938047f09ebf800fa2e15ec407c357a8eab97a5dd67b4d015b5b91908c908c90518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a150505050505050505050565b600160a060020a03918216600090815260226020908152604080832093909416825291909152205490565b60025460009033600160a060020a03908116911614613d1357600080fd5b50600454600580546064928102929092049182900390556007805460018101613d3c838261569a565b5060009182526020822001556009805460018101613d5a838261569a565b50600091825260209091200155565b6000831515613dd95750600160a060020a03841660008181526019602090815260408083208684528252808320805486019055838352601a8252808320868452825280832054938352601582528083208684529091529020548202600a90910102613dd485826141eb565b614029565b8360011415613eb157600160a060020a038086166000818152601a602090815260408083208884528252808320805488019055928252601981528282208783529052819020546033549092169063c46e3e859086905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515613e6257600080fd5b5af11515613e6f57600080fd5b5050506040518051600160a060020a038816600090815260156020908152604080832089845290915290205485029201919091029150613dd4905085826141eb565b8360021415613ee857600160a060020a0385166000908152601b602090815260408083208684529091529020805483019055614029565b8360031415613f1f57600160a060020a0385166000908152601c602090815260408083208684529091529020805483019055614029565b8360041415613f5657600160a060020a0385166000908152601d602090815260408083208684529091529020805483019055614029565b8360051415613f8d57600160a060020a0385166000908152601e602090815260408083208684529091529020805483019055614029565b8360061415613fc457600160a060020a0385166000908152601f602090815260408083208684529091529020805483019055614029565b8360071415613ff957600160a060020a0385166000908152602080805260408083208684529091529020805483019055614029565b836008141561402957600160a060020a038516600090815260216020908152604080832086845290915290208290555b5050505050565b600061403b82614370565b600160a060020a039092166000908152601060209081526040808320429055825485018355600c9091529020805490920190915550565b60008282018381101561408157fe5b8091505b5092915050565b600080600061409a85614370565b9250828411156140f957600160a060020a0385166000908152600c60205260409020548385039250829010156140cf57600080fd5b600080548390038155600160a060020a0386168152600c6020526040902080548390039055614123565b50600080548484039081018255600160a060020a0386168252600c60205260409091208054820190555b50505050600160a060020a03166000908152601060205260409020429055565b600160a060020a038084166000818152601a6020908152604080832087845282528083205493835260198252808320878452909152808220546033549294600a909401939092169063c46e3e859087905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156141c757600080fd5b5af115156141d457600080fd5b505050604051805190500183020290509392505050565b806141f58361148e565b600160a060020a039093166000818152600d602090815260408083206008805485529083528184209590970190945594549181526011909452922091909155600180549091019055565b6033546000908190819081908190819081908190600160a060020a0316636026bb866040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561428e57600080fd5b5af1151561429b57600080fd5b5050506040518051906020018051919650909450505b83851161436057600160a060020a038a1660009081526015602090815260408083208884529091529020546142e9908b9087906151b7565b600160a060020a038b16600090815260156020908152604080832089845290915290205493019261431d908b908790615269565b600160a060020a038a166000908152601560209081526040808320898452909152902054910190614351908a9087906152ec565b600190950194909101906142b1565b9199909850909650945050505050565b600160a060020a038116600090815260106020526040812054818111801561439757504281105b156143bc5760648142036143aa8561148e565b028115156143b457fe5b0491506143c1565b600091505b50919050565b6000808315156143da5760009150614085565b508282028284828115156143ea57fe5b041461408157fe5b602b8054600160a060020a0380841673ffffffffffffffffffffffffffffffffffffffff199283168117909355602980546000908152601760205260408082208054909516909517909355603354905492938493849360149316916357f1f6ca91905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561448857600080fd5b5af1151561449557600080fd5b505050604051805190506015028115156144ab57fe5b602954600090815260186020526040902091900490556144ca84614030565b603354602954600160a060020a039091169063275babee9060405160e060020a63ffffffff84160281526004810191909152602401606060405180830381600087803b151561451857600080fd5b5af1151561452557600080fd5b5050506040518051906020018051906020018051929550909350909150614550905084848484613d69565b50505050565b6000806145628461148e565b915061456e8284615676565b90508015156145c357600160a060020a0384166000818152600f60209081526040808320600880548552908352818420805460ff19166001179055938352600d825280832093548352929052908120556145ec565b600160a060020a0384166000908152600d60209081526040808320600854845290915290208190555b5050600854600160a060020a0390921660009081526011602052604090209190915560018054919091039055565b6033546000908190600160a060020a03166328bdbdca6040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561465d57600080fd5b5af1151561466a57600080fd5b5050506040518051906020018051919350909150505b8082116148245782600160a060020a031663ee9cebde8360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156146cd57600080fd5b5af115156146da57600080fd5b5050506040518051603354909150600160a060020a031663ee9cebde8460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561472d57600080fd5b5af1151561473a57600080fd5b5050506040518051905014151561475057600080fd5b82600160a060020a031663c46e3e858360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561479657600080fd5b5af115156147a357600080fd5b5050506040518051603354909150600160a060020a031663c46e3e858460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156147f657600080fd5b5af1151561480357600080fd5b5050506040518051905014151561481957600080fd5b600190910190614680565b603354600160a060020a0316636026bb866040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561486257600080fd5b5af1151561486f57600080fd5b5050506040518051906020018051919350909150505b808211614bbb5782600160a060020a031663ee9cebde8360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156148d257600080fd5b5af115156148df57600080fd5b5050506040518051603354909150600160a060020a031663ee9cebde8460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561493257600080fd5b5af1151561493f57600080fd5b5050506040518051905014151561495557600080fd5b82600160a060020a03166369632f568360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561499b57600080fd5b5af115156149a857600080fd5b5050506040518051603354909150600160a060020a03166369632f568460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156149fb57600080fd5b5af11515614a0857600080fd5b50505060405180519050141515614a1e57600080fd5b82600160a060020a03166321446cfe8360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614a6457600080fd5b5af11515614a7157600080fd5b5050506040518051603354909150600160a060020a03166321446cfe8460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614ac457600080fd5b5af11515614ad157600080fd5b50505060405180519050141515614ae757600080fd5b82600160a060020a0316636101a1f78360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614b2d57600080fd5b5af11515614b3a57600080fd5b5050506040518051603354909150600160a060020a0316636101a1f78460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614b8d57600080fd5b5af11515614b9a57600080fd5b50505060405180519050141515614bb057600080fd5b600190910190614885565b505050565b6033546000908190819081908190819081908190600160a060020a031663709e6ed46040518163ffffffff1660e060020a0281526004016040805180830381600087803b1515614c0f57600080fd5b5af11515614c1c57600080fd5b5050506040518051906020018051919950909750505b8688116150315788600160a060020a0316637e0be7e38960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614c7f57600080fd5b5af11515614c8c57600080fd5b5050506040518051603354909150600160a060020a0316637e0be7e38a60405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614cdf57600080fd5b5af11515614cec57600080fd5b50505060405180519050141515614d0257600080fd5b88600160a060020a031663f48aa0448960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614d4857600080fd5b5af11515614d5557600080fd5b5050506040518051603354909150600160a060020a031663f48aa0448a60405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614da857600080fd5b5af11515614db557600080fd5b50505060405180519050141515614dcb57600080fd5b88600160a060020a031663309ba1208960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614e1157600080fd5b5af11515614e1e57600080fd5b5050506040518051603354909150600160a060020a031663309ba1208a60405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614e7157600080fd5b5af11515614e7e57600080fd5b50505060405180519050141515614e9457600080fd5b88600160a060020a03166372fecf848960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614eda57600080fd5b5af11515614ee757600080fd5b5050506040518051603354909150600160a060020a03166372fecf848a60405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614f3a57600080fd5b5af11515614f4757600080fd5b50505060405180519050141515614f5d57600080fd5b88600160a060020a0316630caeb3508960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614fa357600080fd5b5af11515614fb057600080fd5b5050506040518051603354909150600160a060020a0316630caeb3508a60405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561500357600080fd5b5af1151561501057600080fd5b5050506040518051905014151561502657600080fd5b600190970196614c32565b603354600160a060020a0316634ecdf1656040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561506f57600080fd5b5af1151561507c57600080fd5b5050506040518051906020018051919950909750505b8688116151ac57603354600160a060020a031663275babee8960405160e060020a63ffffffff84160281526004810191909152602401606060405180830381600087803b15156150e157600080fd5b5af115156150ee57600080fd5b505050604051805190602001805190602001805192985090965090945050600160a060020a03891663275babee8960405160e060020a63ffffffff84160281526004810191909152602401606060405180830381600087803b151561515257600080fd5b5af1151561515f57600080fd5b50505060405180519060200180519060200180519295509093509091505085831461518957600080fd5b84821461519557600080fd5b8381146151a157600080fd5b600190970196615092565b505050505050505050565b600160a060020a038084166000818152601c60209081526040808320878452825280832054938352601b8252808320878452909152808220546033549294600a9485019391929116906369632f569088905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561523c57600080fd5b5af1151561524957600080fd5b505050604051805190500184020281151561526057fe5b04949350505050565b600160a060020a03808416600081815260208080526040808320878452825280832054938352601f8252808320878452909152808220546033549294600a948501939192911690636101a1f79088905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561523c57600080fd5b600160a060020a038084166000818152601e60209081526040808320878452825280832054938352601d8252808320878452909152808220546033549294600a9485019391929116906321446cfe9088905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561523c57600080fd5b6031805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790556153a281614030565b6153b48161180283602f546001614143565b600160a060020a03166000908152601560209081526040808320602f548452909152902080546001019055565b600083151561544d5750600160a060020a0384166000818152601960209081526040808320868452825280832080548690039055838352601a8252808320868452825280832054938352601582528083208684529091529020548202600a90910102613dd48582614556565b836001141561552657600160a060020a038086166000818152601a60209081526040808320888452825280832080548890039055928252601981528282208783529052819020546033549092169063c46e3e859086905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156154d757600080fd5b5af115156154e457600080fd5b5050506040518051600160a060020a038816600090815260156020908152604080832089845290915290205485029201919091029150613dd490508582614556565b836002141561555e57600160a060020a0385166000908152601b60209081526040808320868452909152902080548390039055614029565b836003141561559657600160a060020a0385166000908152601c60209081526040808320868452909152902080548390039055614029565b83600414156155ce57600160a060020a0385166000908152601d60209081526040808320868452909152902080548390039055614029565b836005141561560657600160a060020a0385166000908152601e60209081526040808320868452909152902080548390039055614029565b836006141561563e57600160a060020a0385166000908152601f60209081526040808320868452909152902080548390039055614029565b836007141561402957600160a060020a0385166000908152602080805260408083208684529091529020805483900390555050505050565b60008282111561568257fe5b50900390565b60206040519081016040526000815290565b815481835581811511614bbb57600083815260209020614bbb9181019083016156ea565b815481835581811511614bbb57600202816002028360005260206000209182019101614bbb9190615708565b61140591905b8082111561570457600081556001016156f0565b5090565b61140591905b80821115615704576000808255600182015560020161570e5600a165627a7a723058208057da4d208b614eacaa1130285e8cb6b121808fad9dad42962a710dfd2634ac0029

Deployed Bytecode

0x6060604052600436106102795763ffffffff60e060020a60003504166302b68bbf811461028357806306fdde031461033b578063095ea7b3146103c55780630b407022146103fb57806313aa7b6f146104335780631746bd1b1461046a578063179fc99f1461055557806318160ddd1461058657806318d801681461059957806319e9e5de146105b257806322bfba59146105d157806323b872dd146105e457806325a7650a1461060c5780632bfd2e06146106175780633081fe3f14610630578063313ce5671461064f57806338198c65146106785780633bed33ce1461068b5780634a1d08af146106a15780634a617fba146106b45780634efdd4f9146106c757806353dd8881146106da5780635dc22cce146106f35780635e123ce41461071257806360f61a4c1461072557806364f54a171461073b5780636a7d1a7e146107885780636c20d755146107a757806370a082311461081057806370bc52fb1461082f57806370d9f7dc14610853578063716e560414610875578063751fef651461088e5780637c85a757146108a75780637ef58e73146108c657806380fa7902146108d95780638d4777c8146109235780638da5cb5b146109485780638fafb286146109775780639323eaad1461099c57806393d7c6bf146109be57806395d89b41146109d15780639e30dd5f146109e4578063a21f74b8146109ef578063a5a2cb1914610a05578063a7b7f1d414610a10578063a89cdad914610a23578063a9059cbb14610a36578063b1d6600314610a58578063b912950e14610a6b578063c38f074114610a81578063c9c286c614610a94578063d8737d8a14610aaa578063dd62ed3e14610ab8578063f2f921e614610add575b6005805434019055005b341561028e57600080fd5b6102a2600160a060020a0360043516610af0565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156102e65780820151838201526020016102ce565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561032557808201518382015260200161030d565b5050505090500194505050505060405180910390f35b341561034657600080fd5b61034e610c16565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561038a578082015183820152602001610372565b50505050905090810190601f1680156103b75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156103d057600080fd5b6103e7600160a060020a0360043516602435610c4d565b604051901515815260200160405180910390f35b341561040657600080fd5b6104316024600480358281019290820135918135808301929082013591604435918201910135610cb9565b005b341561043e57600080fd5b610446610f59565b60405180848152602001838152602001828152602001935050505060405180910390f35b341561047557600080fd5b61047d610ffe565b604051808c81526020018b81526020018a81526020018981526020018881526020018781526020018681526020018581526020018481526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156104f75780820151838201526020016104df565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561053657808201518382015260200161051e565b505050509050019d505050505050505050505050505060405180910390f35b341561056057600080fd5b610574600160a060020a03600435166113e6565b60405190815260200160405180910390f35b341561059157600080fd5b610574611401565b34156105a457600080fd5b610431600435602435611408565b34156105bd57600080fd5b610574600160a060020a036004351661148e565b34156105dc57600080fd5b6104316114bb565b34156105ef57600080fd5b6103e7600160a060020a0360043581169060243516604435611542565b610431600435611634565b341561062257600080fd5b6104316004356024356116b4565b341561063b57600080fd5b610574600160a060020a0360043516611894565b341561065a57600080fd5b6106626118a6565b60405160ff909116815260200160405180910390f35b341561068357600080fd5b6105746118ab565b341561069657600080fd5b6104316004356118b1565b34156106ac57600080fd5b610431611921565b34156106bf57600080fd5b6105746119a8565b34156106d257600080fd5b6104466119ae565b34156106e557600080fd5b610431600435602435611ab0565b34156106fe57600080fd5b610431600160a060020a0360043516611b0e565b341561071d57600080fd5b6103e7611e84565b341561073057600080fd5b610431600435611e94565b341561074657600080fd5b61074e611fec565b6040519485526020850193909352604080850192909252600160a060020a03166060840152608083019190915260a0909101905180910390f35b341561079357600080fd5b6102a2600160a060020a036004351661200c565b34156107b257600080fd5b6107bd600435612126565b60405160208082528190810183818151815260200191508051906020019060200280838360005b838110156107fc5780820151838201526020016107e4565b505050509050019250505060405180910390f35b341561081b57600080fd5b610574600160a060020a03600435166121a1565b341561083a57600080fd5b610431600160a060020a036004351660243515156121cd565b341561085e57600080fd5b610431600160a060020a036004351660243561222c565b341561088057600080fd5b610431600435602435612480565b341561089957600080fd5b610431600435602435612588565b34156108b257600080fd5b610431600160a060020a03600435166127e0565b34156108d157600080fd5b610574612842565b34156108e457600080fd5b6108f8600160a060020a0360043516612848565b6040518085815260200184815260200183815260200182815260200194505050505060405180910390f35b341561092e57600080fd5b610431600160a060020a0360043516602435604435612a26565b341561095357600080fd5b61095b612bcd565b604051600160a060020a03909116815260200160405180910390f35b341561098257600080fd5b610431600160a060020a0360043516602435604435612bdc565b34156109a757600080fd5b610431600160a060020a0360043516602435612e85565b34156109c957600080fd5b6105746130a3565b34156109dc57600080fd5b61034e6130a9565b6104316004356130e0565b34156109fa57600080fd5b6104316004356132e3565b610431600435613344565b3415610a1b57600080fd5b61074e61354e565b3415610a2e57600080fd5b61057461356e565b3415610a4157600080fd5b6103e7600160a060020a0360043516602435613574565b3415610a6357600080fd5b6102a2613612565b3415610a7657600080fd5b610431600435613807565b3415610a8c57600080fd5b61043161395f565b3415610a9f57600080fd5b6107bd6004356139e9565b610431600435602435613a62565b3415610ac357600080fd5b610574600160a060020a0360043581169060243516613cca565b3415610ae857600080fd5b610431613cf5565b610af8615688565b610b00615688565b6000610b0a615688565b610b12615688565b600160a060020a038616600090815260246020526040812060295460028201549195501415610c0a578360010154604051805910610b4d5750595b908082528060200260200182016040525092508360010154604051805910610b725750595b90808252806020026020018201604052509150600090505b8360010154811015610c0a578354849082908110610ba457fe5b906000526020600020906002020160000154838281518110610bc257fe5b602090810290910101528354849082908110610bda57fe5b906000526020600020906002020160010154828281518110610bf857fe5b60209081029091010152600101610b8a565b50909590945092505050565b60408051908101604052600781527f49646c6545746800000000000000000000000000000000000000000000000000602082015281565b600160a060020a03338116600081815260226020908152604080832094871680845294909152808220859055909291907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259085905190815260200160405180910390a350600192915050565b6002546000908190819081908190819033600160a060020a03908116911614610ce157600080fd5b60025460a060020a900460ff1615610cf857600080fd5b600095505b86861015610f4b578b8b87818110610d1157fe5b90506020020135600160a060020a031694508989878181101515610d3157fe5b60335460209091029290920135955050600160a060020a03166372fecf848560405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610d8657600080fd5b5af11515610d9357600080fd5b5050506040518051935050600083118015610dd25750600160a060020a038516600090815260166020908152604080832087845290915290205460ff16155b15610f4057603354600160a060020a031663309ba1208560405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610e1f57600080fd5b5af11515610e2c57600080fd5b5050506040518051603354909350600160a060020a03169050630caeb3508560405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610e8157600080fd5b5af11515610e8e57600080fd5b505050604051805190509050610ea685838584613d69565b600160a060020a03851660009081526016602090815260408083208784529091529020805460ff191660011790557fb84e528e18e54dd4bb87635427809661099f52b6fb31e5c969e6f07c9a19913c85858a8a8a818110610f0357fe5b905060200201356040518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a15b600190950194610cfd565b505050505050505050505050565b600160a060020a033316600090815260136020526040812054600954829182916000190182825b828111610ff3576007805482908110610f9557fe5b6000918252602080832090910154600160a060020a0333168352600e825260408084208585529092529120546009805484908110610fcf57fe5b90600052602060002090015402811515610fe557fe5b049190910190600101610f80565b509591945092509050565b6000806000806000806000806000611014615688565b61101c615688565b611024615688565b61102c615688565b60335460009081908190600160a060020a0316638975e45f6040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561107257600080fd5b5af1151561107f57600080fd5b505050604051805190506040518059106110965750595b9080825280602002602001820160405250603354909550600160a060020a031663f10a98486040518163ffffffff1660e060020a028152600401602060405180830381600087803b15156110e957600080fd5b5af115156110f657600080fd5b5050506040518051905060405180591061110d5750595b9080825280602002602001820160405250603354909450600160a060020a03166328bdbdca6040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561115f57600080fd5b5af1151561116c57600080fd5b5050506040518051906020018051919450909250505b8183116111cf57600160a060020a03331660009081526015602090815260408083208684529091529020548582815181106111b957fe5b6020908102909101015260019283019201611182565b603354600160a060020a0316636026bb866040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561120d57600080fd5b5af1151561121a57600080fd5b5050506040518051906020018051919450909250505b81831161127d57600160a060020a033316600090815260156020908152604080832086845290915290205485828151811061126757fe5b6020908102909101015260019283019201611230565b50603354600090600160a060020a031663709e6ed46040518163ffffffff1660e060020a0281526004016040805180830381600087803b15156112bf57600080fd5b5af115156112cc57600080fd5b5050506040518051906020018051919450909250505b81831161133757600160a060020a033316600090815260166020908152604080832086845290915290205460ff1684828151811061131c57fe5b911515602092830290910190910152600192830192016112e2565b600554600154600780544293929190600019810190811061135457fe5b6000918252602080832090910154600160a060020a03339081168452600e835260408085206007546000190186529093529190922054600a549091611398906121a1565b33600160a060020a0381166000908152600b6020526040902054906113bc9061148e565b8d8d9f509f509f509f509f509f509f509f509f509f509f505050505050909192939495969798999a565b600160a060020a03166000908152600b602052604090205490565b6000545b90565b60025433600160a060020a0390811691161461142357600080fd5b4282901061143057600080fd5b602f541561144f57603154600160a060020a0316151561144f57600080fd5b603180546000603281905574ffffffffffffffffffffffffffffffffffffffffff19909116909155603055602d91909155602f55602e80546001019055565b600160a060020a03166000908152600d602090815260408083206011835281842054845290915290205490565b60025460009033600160a060020a039081169116146114d957600080fd5b602d544290106114e857600080fd5b60315460a060020a900460ff16156114ff57600080fd5b506030544281019080151561151057fe5b8160001943014008603255506031805474ff0000000000000000000000000000000000000000191660a060020a179055565b600061154d84614030565b600160a060020a0380851660009081526022602090815260408083203390941683529290522054821180159061159b5750600160a060020a0384166000908152600c60205260409020548211155b15156115a657600080fd5b600160a060020a038085166000818152600c6020908152604080832080548890039055878516808452818420805489019055848452602283528184203390961684529490915290819020805486900390557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9085905190815260200160405180910390a35060019392505050565b60025433600160a060020a0390811691161461164f57600080fd5b60025460a060020a900460ff161561166657600080fd5b6002805474ff0000000000000000000000000000000000000000191660a060020a179055600a81905560078054600181016116a1838261569a565b5060009182526020822001555034600555565b600160a060020a03338116600090815260156020908152604080832086845290915280822054603354929384938493849392849216906306011b14908a9085908b905160e060020a63ffffffff8616028152600481019390935260248301919091526044820152606401608060405180830381600087803b151561173757600080fd5b5af1151561174457600080fd5b5050506040518051906020018051906020018051906020018051600254949a509298509096509094505060a060020a900460ff16151561178357600080fd5b6000861161179057600080fd5b821561179b57600080fd5b6117a58288614072565b905060638111156117e057600160a060020a03331660009081526021602090815260408083208b84529091529020548111156117e057600080fd5b6117ea338561408c565b60008511156118075761180733611802338b8b614143565b6141eb565b33600160a060020a03811660009081526015602090815260408083208c8452909152908190208390557fb6d35f558a34938047f09ebf800fa2e15ec407c357a8eab97a5dd67b4d015b5b91908a908a90518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a15050505050505050565b60116020526000908152604090205481565b600081565b60055481565b600160a060020a0333166000908152600b60205260409020548111156118d657600080fd5b600160a060020a0333166000818152600b6020526040908190208054849003905582156108fc0290839051600060405180830381858888f19350505050151561191e57600080fd5b50565b60025460009033600160a060020a0390811691161461193f57600080fd5b60285442901061194e57600080fd5b602b5460a060020a900460ff161561196557600080fd5b50602a544281019080151561197657fe5b8160001943014008602c5550602b805474ff0000000000000000000000000000000000000000191660a060020a179055565b60045481565b600160a060020a033316600090815260126020908152604080832054600854600d8452828520600019808401875294529184205484938493019083908382805b858311611a9f575050600160a060020a0333166000818152600d60209081526040808320858452825280832054938352600f825280832085845290915290205460ff1681158015611a3d575080155b15611a4a57839150611a4e565b8193505b6006805484908110611a5c57fe5b90600052602060002090015482600885815481101515611a7857fe5b90600052602060002090015402811515611a8e57fe5b0494909401936001909201916119ee565b509298949750929550929350505050565b60025433600160a060020a03908116911614611acb57600080fd5b600082118015611adc5750600a8211155b1515611ae757600080fd5b600081118015611af85750600a8111155b1515611b0357600080fd5b600391909155600455565b600160a060020a03331660009081526014602052604081205481908190819081908190429010611b3d57600080fd5b33600160a060020a031687600160a060020a031614151515611b5e57600080fd5b600160a060020a03871660009081526023602052604090205460ff1615611b8457600080fd5b611b8e338861423f565b600160a060020a038a16600090815260146020526040902054929850909650945042901115611c1857603354600160a060020a03166394b67b1c8660405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515611bff57600080fd5b5af11515611c0c57600080fd5b50505060405180519550505b84861115611dfe57600160a060020a03331660009081526014602052604090206107084201905583611c49886121a1565b1115611d4557611c5887614370565b925082841115611c9557600160a060020a0387166000908152600c6020526040812080548587039081900390915581548190039091559150611cc1565b50600160a060020a0386166000908152600c602052604081208054858503908101909155815481019091555b33600160a060020a0381166000908152600c6020526040908190208054870190557fb06cb54b17603e70140ce0216d86cef7e3e645e5a77c76f0cd1e4afe1b5b9e3f91908990600190889051600160a060020a03948516815292909316602083015215156040808301919091526060820192909252608001905180910390a1611dde565b7fb06cb54b17603e70140ce0216d86cef7e3e645e5a77c76f0cd1e4afe1b5b9e3f33886001611d738b6121a1565b604051600160a060020a03948516815292909316602083015215156040808301919091526060820192909252608001905180910390a1611db2876121a1565b600160a060020a033381166000908152600c602052604080822080549094019093559089168152908120555b600160a060020a0387166000908152601060205260409020429055611e7b565b33600160a060020a038116600090815260146020526040808220426102580190557fb06cb54b17603e70140ce0216d86cef7e3e645e5a77c76f0cd1e4afe1b5b9e3f92918a91819051600160a060020a03948516815292909316602083015215156040808301919091526060820192909252608001905180910390a15b50505050505050565b60025460a060020a900460ff1681565b60008042602d5410151515611ea857600080fd5b60008311611eb557600080fd5b611ec16103e8846143c7565b915081611ecd336121a1565b1015611ed857600080fd5b611ee2338361408c565b50600160a060020a0333166000908152602660205260409020602e54600282015414611f6b5760006001808301829055602e5460028401819055825260276020526040909120805490918101611f38838261569a565b506000918252602090912001805473ffffffffffffffffffffffffffffffffffffffff191633600160a060020a03161790555b805460018201541415611f89578054600101611f8782826156be565b505b60408051908101604052603054808252840160001901602082015260018281018054918201905582548391908110611fbd57fe5b906000526020600020906002020160008201518155602082015160019091015550506030805490920190915550565b602854602954602a54602b54602c54600160a060020a0390911691929394565b612014615688565b61201c615688565b6000612026615688565b61202e615688565b600160a060020a0386166000908152602660205260408120602e5460028201549195501415610c0a5783600101546040518059106120695750595b90808252806020026020018201604052509250836001015460405180591061208e5750595b90808252806020026020018201604052509150600090505b8360010154811015610c0a5783548490829081106120c057fe5b9060005260206000209060020201600001548382815181106120de57fe5b6020908102909101015283548490829081106120f657fe5b90600052602060002090600202016001015482828151811061211457fe5b602090810290910101526001016120a6565b61212e615688565b6025600083815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561219557602002820191906000526020600020905b8154600160a060020a03168152600190910190602001808311612177575b50505050509050919050565b60006121ac82614370565b600160a060020a0383166000908152600c6020526040902054019050919050565b60025433600160a060020a039081169116146121e857600080fd5b8015612201576121f78261148e565b1561220157600080fd5b600160a060020a03919091166000908152602360205260409020805460ff1916911515919091179055565b6000806000806000806000804260285410151561224857600080fd5b602b54600160a060020a03161561225e57600080fd5b602954600090815260176020526040902054600160a060020a03161561228357600080fd5b602b5460a060020a900460ff16151561229e5761229e611921565b600160a060020a038a161561234057600160a060020a038a16600090815260246020526040812060018101549099501180156122dd5750876001015489105b80156122ee57506029548860020154145b1561234057875488908a90811061230157fe5b906000526020600020906002020196508660000154602c541015801561232d57508660010154602c5411155b156123405761233b8a6143f2565b612474565b600095505b60295460009081526025602052604090205486101561247457602954600090815260256020526040902080548790811061237b57fe5b6000918252602080832090910154600160a060020a03168083526024909152604082206001810154815492985090965060001901945085919081106123bc57fe5b906000526020600020906002020160000154602c5410158015612400575083548490849081106123e857fe5b906000526020600020906002020160010154602c5411155b1561246957600091505b836001015482101561246957835484908390811061242457fe5b906000526020600020906002020190508060000154602c541015801561245057508060010154602c5411155b1561245e5761233b856143f2565b60019091019061240a565b600190950194612345565b50505050505050505050565b60025433600160a060020a0390811691161461249b57600080fd5b603354600160a060020a03166297b6078260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156124e257600080fd5b5af115156124ef57600080fd5b50505060405180519050151561250457600080fd5b600081815260176020526040902054600160a060020a03161561252657600080fd5b4282901061253357600080fd5b6029541561255257602b54600160a060020a0316151561255257600080fd5b602b80546000602c81905574ffffffffffffffffffffffffffffffffffffffffff19909116909155602a55602891909155602955565b600160a060020a033316600090815260156020908152604080832085845290915281205490808080808686108015906125c15750600087115b15156125cc57600080fd5b600160a060020a0333811660009081526015602090815260408083208c8452909152908190209789900397889055603354909116906306011b14908a9089908b905160e060020a63ffffffff8616028152600481019390935260248301919091526044820152606401608060405180830381600087803b151561264e57600080fd5b5af1151561265b57600080fd5b505050604051805190602001805190602001805190602001805160335494995092975090955090935050600160a060020a03166341e34be98960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156126ca57600080fd5b5af115156126d757600080fd5b5050506040518051905015156126ec57600080fd5b600460038402046126fc33614370565b33600160a060020a031660009081526010602090815260408083204290558254939094019283018255600c9052918220805482019055915084111561274f5761274f3361274a338b8b614143565b614556565b600082111561277d57600160a060020a0333166000908152600b602052604090208054600460038502040190555b7f9c8076df639d56f1ef3ca3d4d8dc6ed089f8c4756bc5bf5d574f1cec4ef13c543389896040518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a15050505050505050565b60025460009033600160a060020a039081169116146127fe57600080fd5b50806128098161461a565b61281281614bc0565b6033805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039290921691909117905550565b60015481565b6000806000806000806000806000603360009054906101000a9004600160a060020a0316600160a060020a0316636026bb866040518163ffffffff1660e060020a0281526004016040805180830381600087803b15156128a757600080fd5b5af115156128b457600080fd5b5050506040518051906020018051919650909450505b83851161297957600160a060020a038a166000908152601560209081526040808320888452909152902054612902908b9087906151b7565b600160a060020a038b166000908152601560209081526040808320898452909152902054930192612936908b908790615269565b600160a060020a038b16600090815260156020908152604080832089845290915290205491019061296a908b9087906152ec565b600190950194909101906128ca565b600160a060020a038a16600090815260146020526040902054429011156129fb57603354600160a060020a03166394b67b1c8360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156129e257600080fd5b5af115156129ef57600080fd5b50505060405180519250505b600160a060020a03999099166000908152601460205260409020549199909897509095509350505050565b6000808083851115612a3757600080fd5b600160a060020a033316600090815260136020526040902054851015612a5c57600080fd5b6009548410612a6a57600080fd5b8491505b838211612ae4576007805483908110612a8357fe5b6000918252602080832090910154600160a060020a0333168352600e825260408084208685529092529120546009805485908110612abd57fe5b90600052602060002090015402811515612ad357fe5b049290920191600190910190612a6e565b600160a060020a033381166000908152601360205260409020600186019055861615801590612b25575033600160a060020a031686600160a060020a031614155b15612ba55750600160a060020a0385166000908152600b602052604090819020805460648504908101909155907f676f0fffb2fbfbfc8daa0d0f7d89788003ac6a87c448c7fb792ceb5b8e00e0dd9087903390849051600160a060020a039384168152919092166020820152604080820192909252606001905180910390a15b600160a060020a0333166000908152600b602052604090208054919093030190915550505050565b600254600160a060020a031681565b6000808080808086881115612bf057600080fd5b600160a060020a033316600090815260126020526040902054881015612c1557600080fd5b6008548710612c2357600080fd5b600160a060020a0333166000908152600d60209081526040808320601283528184205460001901845290915290205494508793505b868411612d0c57600160a060020a0333166000818152600d60209081526040808320888452825280832054938352600f825280832088845290915290205490935060ff16915082158015612caa575081155b15612cb757849250612cbb565b8294505b6006805485908110612cc957fe5b90600052602060002090015483600886815481101515612ce557fe5b90600052602060002090015402811515612cfb57fe5b049590950194600190930192612c58565b600160a060020a0333166000908152600d602090815260408083208a8452909152902054158015612d615750600160a060020a0333166000908152600f602090815260408083208a845290915290205460ff16155b8015612d6d5750600085115b15612d9957600160a060020a0333166000908152600d602090815260408083208a845290915290208590555b600160a060020a033381166000908152601260205260409020600189019055891615801590612dda575033600160a060020a031689600160a060020a031614155b15612e5a5750600160a060020a0388166000908152600b602052604090819020805460648804908101909155907f676f0fffb2fbfbfc8daa0d0f7d89788003ac6a87c448c7fb792ceb5b8e00e0dd908a903390849051600160a060020a039384168152919092166020820152604080820192909252606001905180910390a15b600160a060020a0333166000908152600b602052604090208054919096030190945550505050505050565b60008060008060008060008042602d54101515612ea157600080fd5b603154600160a060020a031615612eb757600080fd5b60315460a060020a900460ff161515612ed257612ed26114bb565b600160a060020a038a1615612f6f57600160a060020a038a1660009081526026602052604081206001810154909950118015612f115750876001015489105b8015612f225750602e548860020154145b15612f6f57875488908a908110612f3557fe5b90600052602060002090600202019650866000015460325410158015612f615750866001015460325411155b15612f6f5761233b8a615371565b600095505b602e5460009081526027602052604090205486101561247457602e546000908152602760205260409020805487908110612faa57fe5b6000918252602080832090910154600160a060020a0316808352602690915260408220600181015481549298509096506000190194508591908110612feb57fe5b9060005260206000209060020201600001546032541015801561302f5750835484908490811061301757fe5b90600052602060002090600202016001015460325411155b1561309857600091505b836001015482101561309857835484908390811061305357fe5b9060005260206000209060020201905080600001546032541015801561307f5750806001015460325411155b1561308d5761233b85615371565b600190910190613039565b600190950194612f74565b60035481565b60408051908101604052600381527f476f6f0000000000000000000000000000000000000000000000000000000000602082015281565b603354600090819081908190819081908190600160a060020a031663275babee8960405160e060020a63ffffffff84160281526004810191909152602401606060405180830381600087803b151561313757600080fd5b5af1151561314457600080fd5b505050604051805190602001805190602001805160008c815260176020526040902054939a5091985090965050600160a060020a0316935083151561318857600080fd5b6000861161319557600080fd5b61319e33614030565b6131aa33888888613d69565b6131b384614030565b6131bf848888886153e1565b600088815260186020908152604080832054600160a060020a0333168452600b909252909120549093503401839010156131f857600080fd5b3483111561322657600160a060020a0333166000908152600b60205260409020805434850390039055613250565b8234111561325057600160a060020a0333166000908152600b602052604090208054348590030190555b505060058054601483049081018255600254600160a060020a039081166000908152600b60208181526040808420805460328a049081019091559c845260178252808420805433871673ffffffffffffffffffffffffffffffffffffffff199091161790556018825280842060049789029790970490965596909216815294529220805492909601900301909355505050565b6132ed338261408c565b600160a060020a0333166000908152600e6020908152604080832060078054600019908101865291909352922080548401905580548392810190811061332f57fe5b60009182526020909120018054909101905550565b603354600090819081908190819081908190600160a060020a03166328a42e9d8960405160e060020a63ffffffff8416028152600481019190915260240160c060405180830381600087803b151561339b57600080fd5b5af115156133a857600080fd5b5050506040518051906020018051906020018051906020018051906020018051906020018051600254969d50949b5092995090975095509093505060a060020a900460ff1615156133f857600080fd5b6000841161340557600080fd5b600160a060020a03331660009081526016602090815260408083208b845290915290205460ff161561343657600080fd5b600082111561347157600160a060020a033316600090815260166020908152604080832085845290915290205460ff16151561347157600080fd5b60008611156134ff57600160a060020a0333166000908152600b60205260409020543401869010156134a257600080fd5b348611156134cc57600160a060020a0333166000908152600b602052604090208054348803900390555b506005805460328704808803909101909155600254600160a060020a03166000908152600b602052604090208054820190555b613509338861408c565b61351533868686613d69565b505050600160a060020a033316600090815260166020908152604080832097835296905294909420805460ff1916600117905550505050565b602d54602f54603054603154603254600160a060020a0390911691929394565b600a5481565b600061357f33614030565b600160a060020a0333166000908152600c60205260409020548211156135a457600080fd5b600160a060020a033381166000818152600c60205260408082208054879003905592861680825290839020805486019055917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9085905190815260200160405180910390a350600192915050565b61361a615688565b613622615688565b61362a615688565b613632615688565b60335460009081908190600160a060020a031663a528cb4f6040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561367857600080fd5b5af1151561368557600080fd5b5050506040518051905060405180591061369c5750595b9080825280602002602001820160405250603354909550600160a060020a031663a528cb4f6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15156136ef57600080fd5b5af115156136fc57600080fd5b505050604051805190506040518059106137135750595b9080825280602002602001820160405250603354909450600160a060020a0316634ecdf1656040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561376557600080fd5b5af1151561377257600080fd5b5050506040518051906020018051919450909250505b8183116137fa57600083815260176020526040902054600160a060020a03168582815181106137b357fe5b600160a060020a0390921660209283029091018201526000848152601890915260409020548482815181106137e457fe5b6020908102909101015260019283019201613788565b5092959194509092505050565b600080426028541015151561381b57600080fd5b6000831161382857600080fd5b6138346103e8846143c7565b915081613840336121a1565b101561384b57600080fd5b613855338361408c565b50600160a060020a03331660009081526024602052604090206029546002820154146138de5760006001808301829055602954600284018190558252602560205260409091208054909181016138ab838261569a565b506000918252602090912001805473ffffffffffffffffffffffffffffffffffffffff191633600160a060020a03161790555b8054600182015414156138fc5780546001016138fa82826156be565b505b60408051908101604052602a5480825284016000190160208201526001828101805491820190558254839190811061393057fe5b90600052602060002090600202016000820151815560208201516001909101555050602a805490920190915550565b60025460009033600160a060020a0390811691161461397d57600080fd5b506003546005805460649281029290920491829003905560068054600181016139a6838261569a565b9160005260206000209001600060015490919091505550600880548060010182816139d1919061569a565b50600091825260209091200155620151804201600a55565b6139f1615688565b6027600083815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561219557602002820191906000526020600020908154600160a060020a031681526001909101906020018083116121775750505050509050919050565b600160a060020a0333811660009081526015602090815260408083208684529091528082205460335492938493849384939284928392839291909116906306011b14908c9087908d905160e060020a63ffffffff8616028152600481019390935260248301919091526044820152606401608060405180830381600087803b1515613aec57600080fd5b5af11515613af957600080fd5b5050506040518051906020018051906020018051906020018051600254949c50929a509098509096505060a060020a900460ff161515613b3857600080fd5b60008811613b4557600080fd5b600160a060020a0333166000908152600b6020526040902054340185901015613b6d57600080fd5b34851115613b9757600160a060020a0333166000908152600b602052604090208054348703900390555b603285049250600483860360058054929091049182019055600254600160a060020a03166000908152600b602052604090208054850190559150613bdb848a614072565b90506063811115613c1657600160a060020a03331660009081526021602090815260408083208d8452909152902054811115613c1657600080fd5b613c20338761408c565b6000871115613c3857613c3833611802338d8d614143565b33600160a060020a03811660009081526015602090815260408083208e84529091529081902080548c0190557fb6d35f558a34938047f09ebf800fa2e15ec407c357a8eab97a5dd67b4d015b5b91908c908c90518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a150505050505050505050565b600160a060020a03918216600090815260226020908152604080832093909416825291909152205490565b60025460009033600160a060020a03908116911614613d1357600080fd5b50600454600580546064928102929092049182900390556007805460018101613d3c838261569a565b5060009182526020822001556009805460018101613d5a838261569a565b50600091825260209091200155565b6000831515613dd95750600160a060020a03841660008181526019602090815260408083208684528252808320805486019055838352601a8252808320868452825280832054938352601582528083208684529091529020548202600a90910102613dd485826141eb565b614029565b8360011415613eb157600160a060020a038086166000818152601a602090815260408083208884528252808320805488019055928252601981528282208783529052819020546033549092169063c46e3e859086905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515613e6257600080fd5b5af11515613e6f57600080fd5b5050506040518051600160a060020a038816600090815260156020908152604080832089845290915290205485029201919091029150613dd4905085826141eb565b8360021415613ee857600160a060020a0385166000908152601b602090815260408083208684529091529020805483019055614029565b8360031415613f1f57600160a060020a0385166000908152601c602090815260408083208684529091529020805483019055614029565b8360041415613f5657600160a060020a0385166000908152601d602090815260408083208684529091529020805483019055614029565b8360051415613f8d57600160a060020a0385166000908152601e602090815260408083208684529091529020805483019055614029565b8360061415613fc457600160a060020a0385166000908152601f602090815260408083208684529091529020805483019055614029565b8360071415613ff957600160a060020a0385166000908152602080805260408083208684529091529020805483019055614029565b836008141561402957600160a060020a038516600090815260216020908152604080832086845290915290208290555b5050505050565b600061403b82614370565b600160a060020a039092166000908152601060209081526040808320429055825485018355600c9091529020805490920190915550565b60008282018381101561408157fe5b8091505b5092915050565b600080600061409a85614370565b9250828411156140f957600160a060020a0385166000908152600c60205260409020548385039250829010156140cf57600080fd5b600080548390038155600160a060020a0386168152600c6020526040902080548390039055614123565b50600080548484039081018255600160a060020a0386168252600c60205260409091208054820190555b50505050600160a060020a03166000908152601060205260409020429055565b600160a060020a038084166000818152601a6020908152604080832087845282528083205493835260198252808320878452909152808220546033549294600a909401939092169063c46e3e859087905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156141c757600080fd5b5af115156141d457600080fd5b505050604051805190500183020290509392505050565b806141f58361148e565b600160a060020a039093166000818152600d602090815260408083206008805485529083528184209590970190945594549181526011909452922091909155600180549091019055565b6033546000908190819081908190819081908190600160a060020a0316636026bb866040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561428e57600080fd5b5af1151561429b57600080fd5b5050506040518051906020018051919650909450505b83851161436057600160a060020a038a1660009081526015602090815260408083208884529091529020546142e9908b9087906151b7565b600160a060020a038b16600090815260156020908152604080832089845290915290205493019261431d908b908790615269565b600160a060020a038a166000908152601560209081526040808320898452909152902054910190614351908a9087906152ec565b600190950194909101906142b1565b9199909850909650945050505050565b600160a060020a038116600090815260106020526040812054818111801561439757504281105b156143bc5760648142036143aa8561148e565b028115156143b457fe5b0491506143c1565b600091505b50919050565b6000808315156143da5760009150614085565b508282028284828115156143ea57fe5b041461408157fe5b602b8054600160a060020a0380841673ffffffffffffffffffffffffffffffffffffffff199283168117909355602980546000908152601760205260408082208054909516909517909355603354905492938493849360149316916357f1f6ca91905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561448857600080fd5b5af1151561449557600080fd5b505050604051805190506015028115156144ab57fe5b602954600090815260186020526040902091900490556144ca84614030565b603354602954600160a060020a039091169063275babee9060405160e060020a63ffffffff84160281526004810191909152602401606060405180830381600087803b151561451857600080fd5b5af1151561452557600080fd5b5050506040518051906020018051906020018051929550909350909150614550905084848484613d69565b50505050565b6000806145628461148e565b915061456e8284615676565b90508015156145c357600160a060020a0384166000818152600f60209081526040808320600880548552908352818420805460ff19166001179055938352600d825280832093548352929052908120556145ec565b600160a060020a0384166000908152600d60209081526040808320600854845290915290208190555b5050600854600160a060020a0390921660009081526011602052604090209190915560018054919091039055565b6033546000908190600160a060020a03166328bdbdca6040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561465d57600080fd5b5af1151561466a57600080fd5b5050506040518051906020018051919350909150505b8082116148245782600160a060020a031663ee9cebde8360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156146cd57600080fd5b5af115156146da57600080fd5b5050506040518051603354909150600160a060020a031663ee9cebde8460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561472d57600080fd5b5af1151561473a57600080fd5b5050506040518051905014151561475057600080fd5b82600160a060020a031663c46e3e858360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561479657600080fd5b5af115156147a357600080fd5b5050506040518051603354909150600160a060020a031663c46e3e858460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156147f657600080fd5b5af1151561480357600080fd5b5050506040518051905014151561481957600080fd5b600190910190614680565b603354600160a060020a0316636026bb866040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561486257600080fd5b5af1151561486f57600080fd5b5050506040518051906020018051919350909150505b808211614bbb5782600160a060020a031663ee9cebde8360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156148d257600080fd5b5af115156148df57600080fd5b5050506040518051603354909150600160a060020a031663ee9cebde8460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561493257600080fd5b5af1151561493f57600080fd5b5050506040518051905014151561495557600080fd5b82600160a060020a03166369632f568360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561499b57600080fd5b5af115156149a857600080fd5b5050506040518051603354909150600160a060020a03166369632f568460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156149fb57600080fd5b5af11515614a0857600080fd5b50505060405180519050141515614a1e57600080fd5b82600160a060020a03166321446cfe8360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614a6457600080fd5b5af11515614a7157600080fd5b5050506040518051603354909150600160a060020a03166321446cfe8460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614ac457600080fd5b5af11515614ad157600080fd5b50505060405180519050141515614ae757600080fd5b82600160a060020a0316636101a1f78360405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614b2d57600080fd5b5af11515614b3a57600080fd5b5050506040518051603354909150600160a060020a0316636101a1f78460405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614b8d57600080fd5b5af11515614b9a57600080fd5b50505060405180519050141515614bb057600080fd5b600190910190614885565b505050565b6033546000908190819081908190819081908190600160a060020a031663709e6ed46040518163ffffffff1660e060020a0281526004016040805180830381600087803b1515614c0f57600080fd5b5af11515614c1c57600080fd5b5050506040518051906020018051919950909750505b8688116150315788600160a060020a0316637e0be7e38960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614c7f57600080fd5b5af11515614c8c57600080fd5b5050506040518051603354909150600160a060020a0316637e0be7e38a60405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614cdf57600080fd5b5af11515614cec57600080fd5b50505060405180519050141515614d0257600080fd5b88600160a060020a031663f48aa0448960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614d4857600080fd5b5af11515614d5557600080fd5b5050506040518051603354909150600160a060020a031663f48aa0448a60405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614da857600080fd5b5af11515614db557600080fd5b50505060405180519050141515614dcb57600080fd5b88600160a060020a031663309ba1208960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614e1157600080fd5b5af11515614e1e57600080fd5b5050506040518051603354909150600160a060020a031663309ba1208a60405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614e7157600080fd5b5af11515614e7e57600080fd5b50505060405180519050141515614e9457600080fd5b88600160a060020a03166372fecf848960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614eda57600080fd5b5af11515614ee757600080fd5b5050506040518051603354909150600160a060020a03166372fecf848a60405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614f3a57600080fd5b5af11515614f4757600080fd5b50505060405180519050141515614f5d57600080fd5b88600160a060020a0316630caeb3508960405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515614fa357600080fd5b5af11515614fb057600080fd5b5050506040518051603354909150600160a060020a0316630caeb3508a60405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561500357600080fd5b5af1151561501057600080fd5b5050506040518051905014151561502657600080fd5b600190970196614c32565b603354600160a060020a0316634ecdf1656040518163ffffffff1660e060020a0281526004016040805180830381600087803b151561506f57600080fd5b5af1151561507c57600080fd5b5050506040518051906020018051919950909750505b8688116151ac57603354600160a060020a031663275babee8960405160e060020a63ffffffff84160281526004810191909152602401606060405180830381600087803b15156150e157600080fd5b5af115156150ee57600080fd5b505050604051805190602001805190602001805192985090965090945050600160a060020a03891663275babee8960405160e060020a63ffffffff84160281526004810191909152602401606060405180830381600087803b151561515257600080fd5b5af1151561515f57600080fd5b50505060405180519060200180519060200180519295509093509091505085831461518957600080fd5b84821461519557600080fd5b8381146151a157600080fd5b600190970196615092565b505050505050505050565b600160a060020a038084166000818152601c60209081526040808320878452825280832054938352601b8252808320878452909152808220546033549294600a9485019391929116906369632f569088905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561523c57600080fd5b5af1151561524957600080fd5b505050604051805190500184020281151561526057fe5b04949350505050565b600160a060020a03808416600081815260208080526040808320878452825280832054938352601f8252808320878452909152808220546033549294600a948501939192911690636101a1f79088905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561523c57600080fd5b600160a060020a038084166000818152601e60209081526040808320878452825280832054938352601d8252808320878452909152808220546033549294600a9485019391929116906321446cfe9088905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561523c57600080fd5b6031805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790556153a281614030565b6153b48161180283602f546001614143565b600160a060020a03166000908152601560209081526040808320602f548452909152902080546001019055565b600083151561544d5750600160a060020a0384166000818152601960209081526040808320868452825280832080548690039055838352601a8252808320868452825280832054938352601582528083208684529091529020548202600a90910102613dd48582614556565b836001141561552657600160a060020a038086166000818152601a60209081526040808320888452825280832080548890039055928252601981528282208783529052819020546033549092169063c46e3e859086905160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156154d757600080fd5b5af115156154e457600080fd5b5050506040518051600160a060020a038816600090815260156020908152604080832089845290915290205485029201919091029150613dd490508582614556565b836002141561555e57600160a060020a0385166000908152601b60209081526040808320868452909152902080548390039055614029565b836003141561559657600160a060020a0385166000908152601c60209081526040808320868452909152902080548390039055614029565b83600414156155ce57600160a060020a0385166000908152601d60209081526040808320868452909152902080548390039055614029565b836005141561560657600160a060020a0385166000908152601e60209081526040808320868452909152902080548390039055614029565b836006141561563e57600160a060020a0385166000908152601f60209081526040808320868452909152902080548390039055614029565b836007141561402957600160a060020a0385166000908152602080805260408083208684529091529020805483900390555050505050565b60008282111561568257fe5b50900390565b60206040519081016040526000815290565b815481835581811511614bbb57600083815260209020614bbb9181019083016156ea565b815481835581811511614bbb57600202816002028360005260206000209182019101614bbb9190615708565b61140591905b8082111561570457600081556001016156f0565b5090565b61140591905b80821115615704576000808255600182015560020161570e5600a165627a7a723058208057da4d208b614eacaa1130285e8cb6b121808fad9dad42962a710dfd2634ac0029

Swarm Source

bzzr://8057da4d208b614eacaa1130285e8cb6b121808fad9dad42962a710dfd2634ac
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.