contract CryptoCongress is StandardToken, SafeMath, usingOraclize {
        mapping(bytes => uint256) initialAllotments;
        mapping(bytes32 => bytes) validQueryIds; // Keeps track of Oraclize queries. 
        
        string public constant name = "CryptoCongress";
        string public constant symbol = "CC";
        uint256 public constant decimals = 18;
        string public constant requiredPrefix = "CryptoCongress ";
        string public constant a = "html(https://twitter.com/";
        string public constant b = "/status/";
        string public constant c = ").xpath(//*[contains(@class, 'TweetTextSize--jumbo')]/text())";

        address public ethFundDeposit; 
      
        // Crowdsale parameters
        uint256 public fundingStartBlock;
        uint256 public totalSupply = 0;
        uint256 public totalSupplyFromCrowdsale = 0;

        uint256 public constant tokenExchangeRate = 50; // 50 CC tokens per 1 ETH purchased at crowdsale
        uint256 public constant tokenCreationCap =  131583 * (10**3) * 10**decimals;  // 131,583,000 tokens
        
        event InitialAllotmentRecorded(string username, uint256 initialAllotment);
        
        // Oraclize events
        event newOraclizeQuery(string url);
        event newOraclizeCallback(string result, bytes proof);

        event InitialAllotmentClaimed(bytes username);
        event Proposal(string ID, string description, string data);
        event Vote(string proposalID, string vote, string data);
        
        // Constructor
        function CryptoCongress (
            address _ethFundDeposit,
            uint256 _fundingStartBlock,
            uint256 _fundingEndBlock) payable
        {                 
          ethFundDeposit = _ethFundDeposit;
          fundingStartBlock = _fundingStartBlock;
          fundingEndBlock = _fundingEndBlock;

          // Allows us to prove correct return from Oraclize
          oraclize_setProof(proofType_TLSNotary);
        }

        function createInitialAllotment(
            string username, 
            uint256 initialAllotment) 
        {
          require (msg.sender == ethFundDeposit);
          require (block.number < fundingStartBlock); 
          initialAllotments[bytes(username)] = initialAllotment;
          InitialAllotmentRecorded(username, initialAllotment);
        }

        function claimInitialAllotment(string twitterStatusID, string username) payable {
          bytes memory usernameAsBytes = bytes(username);
          require (usernameAsBytes.length < 16);
          require (msg.value > 4000000000000000); // accounts for oraclize fee
          require (block.number > fundingStartBlock);
          require (block.number < fundingEndBlock);
          require (initialAllotments[usernameAsBytes] > 0); // Check there are tokens to claim.
          
          string memory url = usingOraclize.strConcat(a,username,b,twitterStatusID,c);
         
          newOraclizeQuery(url);
          bytes32 queryId = oraclize_query("URL",url);
          validQueryIds[queryId] = usernameAsBytes;
        
        }

        function __callback(bytes32 myid, string result, bytes proof) {
            // Must be oraclize
            require (msg.sender == oraclize_cbAddress()); 
            newOraclizeCallback(result, proof);
          
            // // Require that the username not have claimed token allotment already
            require (initialAllotments[validQueryIds[myid]] > 0);  

            // Extra safety below; it should still satisfy basic requirements
            require (block.number > fundingStartBlock);
            require (block.number < fundingEndBlock);
          
            bytes memory resultBytes = bytes(result);
            
            // // Claiming tweet must be exactly 57 bytes
            // // 15 byte "CryptoCongress + 42 byte address"
            require (resultBytes.length == 57);
            
            // // First 16 bytes must be "CryptoCongress " (ending whitespace included)
            // // In hex = 0x 43 72 79 70 74 6f 43 6f 6e 67 72 65 73 73 20
            require (resultBytes[0] == 0x43);
            require (resultBytes[1] == 0x72); 
            require (resultBytes[2] == 0x79);
            require (resultBytes[3] == 0x70);
            require (resultBytes[4] == 0x74);
            require (resultBytes[5] == 0x6f);
            require (resultBytes[6] == 0x43);
            require (resultBytes[7] == 0x6f);
            require (resultBytes[8] == 0x6e);
            require (resultBytes[9] == 0x67);
            require (resultBytes[10] == 0x72);
            require (resultBytes[11] == 0x65);
            require (resultBytes[12] == 0x73);
            require (resultBytes[13] == 0x73);
            require (resultBytes[14] == 0x20);
  
            // // Next 20 characters are the address
            // // Must start with 0x
            require (resultBytes[15] == 0x30);
            require (resultBytes[16] == 0x78);
            
            // Convert bytes to an address
            uint160 iaddr = 0;
            uint160 b1;
            uint160 b2;
            
            for (uint i=0; i<40; i+=2){
                iaddr *= 256;
                b1 = uint160(resultBytes[i+17]);
                b2 = uint160(resultBytes[i+18]);
                if ((b1 >= 97)&&(b1 <= 102)) b1 -= 87;
                else if ((b1 >= 65)&&(b1 <= 70)) b1 -= 55;
                else if ((b1 >= 48)&&(b1 <= 57)) b1 -= 48;
                if ((b2 >= 97)&&(b2 <= 102)) b2 -= 87;
                else if ((b2 >= 65)&&(b2 <= 70)) b2 -= 55;
                else if ((b2 >= 48)&&(b2 <= 57)) b2 -= 48;
                iaddr += (b1*16+b2);
            }
            
            address addr = address(iaddr);
        
            uint256 tokenAllotment = initialAllotments[validQueryIds[myid]];
            uint256 checkedSupply = safeAdd(totalSupply, tokenAllotment);
            require (tokenCreationCap > checkedSupply); // extra safe
            totalSupply = checkedSupply;

            initialAllotments[validQueryIds[myid]] = 0;
            balances[addr] += tokenAllotment;  // SafeAdd not needed; bad semantics to use here

            // Logs token creation by username (bytes)
            InitialAllotmentClaimed(validQueryIds[myid]); // Log the bytes of the username who claimed funds 
            delete validQueryIds[myid];
            
            // Logs token creation by address for ERC20 front end compatibility
            Transfer(0x0,addr,tokenAllotment);

        }

        // Accepts ether and creates new CC tokens.
        // Enforces that no more than 1/3rd of tokens are be created by sale.
        function buyTokens(address beneficiary) public payable {
          require(beneficiary != address(0)); 
          require(msg.value != 0);
          require (block.number > fundingStartBlock);
          require (block.number < fundingEndBlock);

          uint256 tokens = safeMult(msg.value, tokenExchangeRate); 
          
          uint256 checkedTotalSupply = safeAdd(totalSupply, tokens); 
          uint256 checkedCrowdsaleSupply = safeAdd(totalSupplyFromCrowdsale, tokens);

          // (1) Enforces we don't go over total supply with potential sale. 
          require (tokenCreationCap > checkedTotalSupply);  
          
          // (2) Enforces that no more than 1/3rd of tokens are to be created by potential sale.
          require (safeMult(checkedCrowdsaleSupply, 3) < totalSupply);
       
          totalSupply = checkedTotalSupply;
          totalSupplyFromCrowdsale = checkedCrowdsaleSupply;
          
          balances[msg.sender] += tokens;  // safeAdd not needed
          
          // Logs token creation for ERC20 front end compatibility
          // All crowdsale purchases will enter via fallback function
          Transfer(0x0, beneficiary, tokens);  
        
        }

        // Secure withdraw
        function secureTransfer(uint256 amount) external {
          require (msg.sender == ethFundDeposit); 
          assert (ethFundDeposit.send(amount));  
        }

        // 20,000 tokens required to Propose
        function propose(string _ID, string _description, string _data) {
          require(bytes(_ID).length < 281 && bytes(_description).length < 281 && bytes(_data).length < 281);
          require (balances[msg.sender] > 20000000000000000000000);
          Proposal(_ID, _description, _data);
        }

        // 5,000 tokens required to Vote
        function vote(string _proposalID, string _vote, string _data) {
          require(bytes(_proposalID).length < 281 && bytes(_vote).length < 281 && bytes(_data).length < 281);
          require (balances[msg.sender] > 5000000000000000000000);
          Vote(_proposalID, _vote, _data);
        }

        // Payable fallback to ensure privacy.
        function () payable {
            buyTokens(msg.sender);
        }

    }
function vote(string _proposalID, string _vote, string _data) {
  require(bytes(_proposalID).length < 281 && bytes(_vote).length < 281 && bytes(_data).length < 281);
  require (balances[msg.sender] > 5000000000000000000000);
  Vote(_proposalID, _vote, _data);
}

// 5,000 tokens required to Vote