pragma solidity 0.4.25;


    
    

    

    contract OraclizeI {
        address public cbAddress;
        function query(uint _timestamp, string _datasource, string _arg) external payable returns (bytes32 _id);
        function query_withGasLimit(uint _timestamp, string _datasource, string _arg, uint _gaslimit) external payable returns (bytes32 _id);
        function query2(uint _timestamp, string _datasource, string _arg1, string _arg2) public payable returns (bytes32 _id);
        function query2_withGasLimit(uint _timestamp, string _datasource, string _arg1, string _arg2, uint _gaslimit) external payable returns (bytes32 _id);
        function queryN(uint _timestamp, string _datasource, bytes _argN) public payable returns (bytes32 _id);
        function queryN_withGasLimit(uint _timestamp, string _datasource, bytes _argN, uint _gaslimit) external payable returns (bytes32 _id);
        function getPrice(string _datasource) public returns (uint _dsprice);
        function getPrice(string _datasource, uint gaslimit) public returns (uint _dsprice);
        function setProofType(byte _proofType) external;
        function setCustomGasPrice(uint _gasPrice) external;
        function randomDS_getSessionPubKeyHash() external constant returns(bytes32);
    }

    contract OraclizeAddrResolverI {
        function getAddress() public returns (address _addr);
    }

    

    library Buffer {
        struct buffer {
            bytes buf;
            uint capacity;
        }

        function init(buffer memory buf, uint _capacity) internal pure {
            uint capacity = _capacity;
            if(capacity % 32 != 0) capacity += 32 - (capacity % 32);
            
            buf.capacity = capacity;
            assembly {
                let ptr := mload(0x40)
                mstore(buf, ptr)
                mstore(ptr, 0)
                mstore(0x40, add(ptr, capacity))
            }
        }

        function resize(buffer memory buf, uint capacity) private pure {
            bytes memory oldbuf = buf.buf;
            init(buf, capacity);
            append(buf, oldbuf);
        }

        function max(uint a, uint b) private pure returns(uint) {
            if(a > b) {
                return a;
            }
            return b;
        }

        
        function append(buffer memory buf, bytes data) internal pure returns(buffer memory) {
            if(data.length + buf.buf.length > buf.capacity) {
                resize(buf, max(buf.capacity, data.length) * 2);
            }

            uint dest;
            uint src;
            uint len = data.length;
            assembly {
                
                let bufptr := mload(buf)
                
                let buflen := mload(bufptr)
                
                dest := add(add(bufptr, buflen), 32)
                
                mstore(bufptr, add(buflen, mload(data)))
                src := add(data, 32)
            }

            
            for(; len >= 32; len -= 32) {
                assembly {
                    mstore(dest, mload(src))
                }
                dest += 32;
                src += 32;
            }

            
            uint mask = 256 ** (32 - len) - 1;
            assembly {
                let srcpart := and(mload(src), not(mask))
                let destpart := and(mload(dest), mask)
                mstore(dest, or(destpart, srcpart))
            }

            return buf;
        }

        
        function append(buffer memory buf, uint8 data) internal pure {
            if(buf.buf.length + 1 > buf.capacity) {
                resize(buf, buf.capacity * 2);
            }

            assembly {
                
                let bufptr := mload(buf)
                
                let buflen := mload(bufptr)
                
                let dest := add(add(bufptr, buflen), 32)
                mstore8(dest, data)
                
                mstore(bufptr, add(buflen, 1))
            }
        }

        
        function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
            if(len + buf.buf.length > buf.capacity) {
                resize(buf, max(buf.capacity, len) * 2);
            }

            uint mask = 256 ** len - 1;
            assembly {
                
                let bufptr := mload(buf)
                
                let buflen := mload(bufptr)
                
                let dest := add(add(bufptr, buflen), len)
                mstore(dest, or(and(mload(dest), not(mask)), data))
                
                mstore(bufptr, add(buflen, len))
            }
            return buf;
        }
    }

    library CBOR {
        using Buffer for Buffer.buffer;

        uint8 private constant MAJOR_TYPE_INT = 0;
        uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1;
        uint8 private constant MAJOR_TYPE_BYTES = 2;
        uint8 private constant MAJOR_TYPE_STRING = 3;
        uint8 private constant MAJOR_TYPE_ARRAY = 4;
        uint8 private constant MAJOR_TYPE_MAP = 5;
        uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7;

        function encodeType(Buffer.buffer memory buf, uint8 major, uint value) private pure {
            if(value <= 23) {
                buf.append(uint8((major << 5) | value));
            } else if(value <= 0xFF) {
                buf.append(uint8((major << 5) | 24));
                buf.appendInt(value, 1);
            } else if(value <= 0xFFFF) {
                buf.append(uint8((major << 5) | 25));
                buf.appendInt(value, 2);
            } else if(value <= 0xFFFFFFFF) {
                buf.append(uint8((major << 5) | 26));
                buf.appendInt(value, 4);
            } else if(value <= 0xFFFFFFFFFFFFFFFF) {
                buf.append(uint8((major << 5) | 27));
                buf.appendInt(value, 8);
            }
        }

        function encodeIndefiniteLengthType(Buffer.buffer memory buf, uint8 major) private pure {
            buf.append(uint8((major << 5) | 31));
        }

        function encodeUInt(Buffer.buffer memory buf, uint value) internal pure {
            encodeType(buf, MAJOR_TYPE_INT, value);
        }

        function encodeInt(Buffer.buffer memory buf, int value) internal pure {
            if(value >= 0) {
                encodeType(buf, MAJOR_TYPE_INT, uint(value));
            } else {
                encodeType(buf, MAJOR_TYPE_NEGATIVE_INT, uint(-1 - value));
            }
        }

        function encodeBytes(Buffer.buffer memory buf, bytes value) internal pure {
            encodeType(buf, MAJOR_TYPE_BYTES, value.length);
            buf.append(value);
        }

        function encodeString(Buffer.buffer memory buf, string value) internal pure {
            encodeType(buf, MAJOR_TYPE_STRING, bytes(value).length);
            buf.append(bytes(value));
        }

        function startArray(Buffer.buffer memory buf) internal pure {
            encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY);
        }

        function startMap(Buffer.buffer memory buf) internal pure {
            encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP);
        }

        function endSequence(Buffer.buffer memory buf) internal pure {
            encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE);
        }
    }

    

    contract usingOraclize {
        uint constant day = 60*60*24;
        uint constant week = 60*60*24*7;
        uint constant month = 60*60*24*30;
        byte constant proofType_NONE = 0x00;
        byte constant proofType_TLSNotary = 0x10;
        byte constant proofType_Ledger = 0x30;
        byte constant proofType_Android = 0x40;
        byte constant proofType_Native = 0xF0;
        byte constant proofStorage_IPFS = 0x01;
        uint8 constant networkID_auto = 0;
        uint8 constant networkID_mainnet = 1;
        uint8 constant networkID_testnet = 2;
        uint8 constant networkID_morden = 2;
        uint8 constant networkID_consensys = 161;

        OraclizeAddrResolverI OAR;

        OraclizeI oraclize;
        modifier oraclizeAPI {
            if((address(OAR)==0)||(getCodeSize(address(OAR))==0))
                oraclize_setNetwork(networkID_auto);

            if(address(oraclize) != OAR.getAddress())
                oraclize = OraclizeI(OAR.getAddress());

            _;
        }
        modifier coupon(string code){
            oraclize = OraclizeI(OAR.getAddress());
            _;
        }

        function oraclize_setNetwork(uint8 networkID) internal returns(bool){
        return oraclize_setNetwork();
        networkID; 
        }
        function oraclize_setNetwork() internal returns(bool){
            if (getCodeSize(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed)>0){ 
                OAR = OraclizeAddrResolverI(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed);
                oraclize_setNetworkName("eth_mainnet");
                return true;
            }
            if (getCodeSize(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1)>0){ 
                OAR = OraclizeAddrResolverI(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1);
                oraclize_setNetworkName("eth_ropsten3");
                return true;
            }
            if (getCodeSize(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e)>0){ 
                OAR = OraclizeAddrResolverI(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e);
                oraclize_setNetworkName("eth_kovan");
                return true;
            }
            if (getCodeSize(0x146500cfd35B22E4A392Fe0aDc06De1a1368Ed48)>0){ 
                OAR = OraclizeAddrResolverI(0x146500cfd35B22E4A392Fe0aDc06De1a1368Ed48);
                oraclize_setNetworkName("eth_rinkeby");
                return true;
            }
            if (getCodeSize(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475)>0){ 
                OAR = OraclizeAddrResolverI(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475);
                return true;
            }
            if (getCodeSize(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF)>0){ 
                OAR = OraclizeAddrResolverI(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF);
                return true;
            }
            if (getCodeSize(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA)>0){ 
                OAR = OraclizeAddrResolverI(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA);
                return true;
            }
            return false;
        }

        function __callback(bytes32 myid, string result) public {
            __callback(myid, result, new bytes(0));
        }
        function __callback(bytes32 myid, string result, bytes proof) public {
        return;
        
        
        
        myid; result; proof; 
        oraclize = OraclizeI(0); 
        }

        function oraclize_getPrice(string datasource) oraclizeAPI internal returns (uint){
            return oraclize.getPrice(datasource);
        }

        function oraclize_getPrice(string datasource, uint gaslimit) oraclizeAPI internal returns (uint){
            return oraclize.getPrice(datasource, gaslimit);
        }


        function oraclize_query(string datasource, string arg) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; 
            return oraclize.query.value(price)(0, datasource, arg);
        }
        function oraclize_query(uint timestamp, string datasource, string arg) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; 
            return oraclize.query.value(price)(timestamp, datasource, arg);
        }
        function oraclize_query(uint timestamp, string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; 
            return oraclize.query_withGasLimit.value(price)(timestamp, datasource, arg, gaslimit);
        }
        function oraclize_query(string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; 
            return oraclize.query_withGasLimit.value(price)(0, datasource, arg, gaslimit);
        }
        function oraclize_query(string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; 
            return oraclize.query2.value(price)(0, datasource, arg1, arg2);
        }
        function oraclize_query(uint timestamp, string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; 
            return oraclize.query2.value(price)(timestamp, datasource, arg1, arg2);
        }
        function oraclize_query(uint timestamp, string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; 
            return oraclize.query2_withGasLimit.value(price)(timestamp, datasource, arg1, arg2, gaslimit);
        }
        function oraclize_query(string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; 
            return oraclize.query2_withGasLimit.value(price)(0, datasource, arg1, arg2, gaslimit);
        }
        function oraclize_query(string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; 
            bytes memory args = stra2cbor(argN);
            return oraclize.queryN.value(price)(0, datasource, args);
        }
        function oraclize_query(uint timestamp, string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; 
            bytes memory args = stra2cbor(argN);
            return oraclize.queryN.value(price)(timestamp, datasource, args);
        }
        function oraclize_query(uint timestamp, string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; 
            bytes memory args = stra2cbor(argN);
            return oraclize.queryN_withGasLimit.value(price)(timestamp, datasource, args, gaslimit);
        }
        function oraclize_query(string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; 
            bytes memory args = stra2cbor(argN);
            return oraclize.queryN_withGasLimit.value(price)(0, datasource, args, gaslimit);
        }
        function oraclize_query(string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](1);
            dynargs[0] = args[0];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](1);
            dynargs[0] = args[0];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](1);
            dynargs[0] = args[0];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](1);
            dynargs[0] = args[0];
            return oraclize_query(datasource, dynargs, gaslimit);
        }

        function oraclize_query(string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(datasource, dynargs, gaslimit);
        }

        function oraclize_query(string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            string[] memory dynargs = new string[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[] argN) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; 
            bytes memory args = ba2cbor(argN);
            return oraclize.queryN.value(price)(0, datasource, args);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[] argN) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource);
            if (price > 1 ether + tx.gasprice*200000) return 0; 
            bytes memory args = ba2cbor(argN);
            return oraclize.queryN.value(price)(timestamp, datasource, args);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; 
            bytes memory args = ba2cbor(argN);
            return oraclize.queryN_withGasLimit.value(price)(timestamp, datasource, args, gaslimit);
        }
        function oraclize_query(string datasource, bytes[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
            uint price = oraclize.getPrice(datasource, gaslimit);
            if (price > 1 ether + tx.gasprice*gaslimit) return 0; 
            bytes memory args = ba2cbor(argN);
            return oraclize.queryN_withGasLimit.value(price)(0, datasource, args, gaslimit);
        }
        function oraclize_query(string datasource, bytes[1] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](1);
            dynargs[0] = args[0];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[1] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](1);
            dynargs[0] = args[0];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](1);
            dynargs[0] = args[0];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](1);
            dynargs[0] = args[0];
            return oraclize_query(datasource, dynargs, gaslimit);
        }

        function oraclize_query(string datasource, bytes[2] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[2] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](2);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[3] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[3] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](3);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            return oraclize_query(datasource, dynargs, gaslimit);
        }

        function oraclize_query(string datasource, bytes[4] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[4] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](4);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            return oraclize_query(datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[5] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[5] args) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(timestamp, datasource, dynargs);
        }
        function oraclize_query(uint timestamp, string datasource, bytes[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(timestamp, datasource, dynargs, gaslimit);
        }
        function oraclize_query(string datasource, bytes[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
            bytes[] memory dynargs = new bytes[](5);
            dynargs[0] = args[0];
            dynargs[1] = args[1];
            dynargs[2] = args[2];
            dynargs[3] = args[3];
            dynargs[4] = args[4];
            return oraclize_query(datasource, dynargs, gaslimit);
        }

        function oraclize_cbAddress() oraclizeAPI internal returns (address){
            return oraclize.cbAddress();
        }
        function oraclize_setProof(byte proofP) oraclizeAPI internal {
            return oraclize.setProofType(proofP);
        }
        function oraclize_setCustomGasPrice(uint gasPrice) oraclizeAPI internal {
            return oraclize.setCustomGasPrice(gasPrice);
        }

        function oraclize_randomDS_getSessionPubKeyHash() oraclizeAPI internal returns (bytes32){
            return oraclize.randomDS_getSessionPubKeyHash();
        }

        function getCodeSize(address _addr) view internal returns(uint _size) {
            assembly {
                _size := extcodesize(_addr)
            }
        }

        function parseAddr(string _a) internal pure returns (address){
            bytes memory tmp = bytes(_a);
            uint160 iaddr = 0;
            uint160 b1;
            uint160 b2;
            for (uint i=2; i<2+2*20; i+=2){
                iaddr *= 256;
                b1 = uint160(tmp[i]);
                b2 = uint160(tmp[i+1]);
                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);
            }
            return address(iaddr);
        }

        function strCompare(string _a, string _b) internal pure returns (int) {
            bytes memory a = bytes(_a);
            bytes memory b = bytes(_b);
            uint minLength = a.length;
            if (b.length < minLength) minLength = b.length;
            for (uint i = 0; i < minLength; i ++)
                if (a[i] < b[i])
                    return -1;
                else if (a[i] > b[i])
                    return 1;
            if (a.length < b.length)
                return -1;
            else if (a.length > b.length)
                return 1;
            else
                return 0;
        }

        function indexOf(string _haystack, string _needle) internal pure returns (int) {
            bytes memory h = bytes(_haystack);
            bytes memory n = bytes(_needle);
            if(h.length < 1 || n.length < 1 || (n.length > h.length))
                return -1;
            else if(h.length > (2**128 -1))
                return -1;
            else
            {
                uint subindex = 0;
                for (uint i = 0; i < h.length; i ++)
                {
                    if (h[i] == n[0])
                    {
                        subindex = 1;
                        while(subindex < n.length && (i + subindex) < h.length && h[i + subindex] == n[subindex])
                        {
                            subindex++;
                        }
                        if(subindex == n.length)
                            return int(i);
                    }
                }
                return -1;
            }
        }

        function strConcat(string _a, string _b, string _c, string _d, string _e) internal pure returns (string) {
            bytes memory _ba = bytes(_a);
            bytes memory _bb = bytes(_b);
            bytes memory _bc = bytes(_c);
            bytes memory _bd = bytes(_d);
            bytes memory _be = bytes(_e);
            string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
            bytes memory babcde = bytes(abcde);
            uint k = 0;
            for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
            for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
            for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
            for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
            for (i = 0; i < _be.length; i++) babcde[k++] = _be[i];
            return string(babcde);
        }

        function strConcat(string _a, string _b, string _c, string _d) internal pure returns (string) {
            return strConcat(_a, _b, _c, _d, "");
        }

        function strConcat(string _a, string _b, string _c) internal pure returns (string) {
            return strConcat(_a, _b, _c, "", "");
        }

        function strConcat(string _a, string _b) internal pure returns (string) {
            return strConcat(_a, _b, "", "", "");
        }

        
        function parseInt(string _a) internal pure returns (uint) {
            return parseInt(_a, 0);
        }

        
        function parseInt(string _a, uint _b) internal pure returns (uint) {
            bytes memory bresult = bytes(_a);
            uint mint = 0;
            bool decimals = false;
            for (uint i=0; i<bresult.length; i++){
                if ((bresult[i] >= 48)&&(bresult[i] <= 57)){
                    if (decimals){
                    if (_b == 0) break;
                        else _b--;
                    }
                    mint *= 10;
                    mint += uint(bresult[i]) - 48;
                } else if (bresult[i] == 46) decimals = true;
            }
            if (_b > 0) mint *= 10**_b;
            return mint;
        }

        function uint2str(uint i) internal pure returns (string){
            if (i == 0) return "0";
            uint j = i;
            uint len;
            while (j != 0){
                len++;
                j /= 10;
            }
            bytes memory bstr = new bytes(len);
            uint k = len - 1;
            while (i != 0){
                bstr[k--] = byte(48 + i % 10);
                i /= 10;
            }
            return string(bstr);
        }

        using CBOR for Buffer.buffer;
        function stra2cbor(string[] arr) internal pure returns (bytes) {
            safeMemoryCleaner();
            Buffer.buffer memory buf;
            Buffer.init(buf, 1024);
            buf.startArray();
            for (uint i = 0; i < arr.length; i++) {
                buf.encodeString(arr[i]);
            }
            buf.endSequence();
            return buf.buf;
        }

        function ba2cbor(bytes[] arr) internal pure returns (bytes) {
            safeMemoryCleaner();
            Buffer.buffer memory buf;
            Buffer.init(buf, 1024);
            buf.startArray();
            for (uint i = 0; i < arr.length; i++) {
                buf.encodeBytes(arr[i]);
            }
            buf.endSequence();
            return buf.buf;
        }

        string oraclize_network_name;
        function oraclize_setNetworkName(string _network_name) internal {
            oraclize_network_name = _network_name;
        }

        function oraclize_getNetworkName() internal view returns (string) {
            return oraclize_network_name;
        }

        function oraclize_newRandomDSQuery(uint _delay, uint _nbytes, uint _customGasLimit) internal returns (bytes32){
            require((_nbytes > 0) && (_nbytes <= 32));
            
            _delay *= 10;
            bytes memory nbytes = new bytes(1);
            nbytes[0] = byte(_nbytes);
            bytes memory unonce = new bytes(32);
            bytes memory sessionKeyHash = new bytes(32);
            bytes32 sessionKeyHash_bytes32 = oraclize_randomDS_getSessionPubKeyHash();
            assembly {
                mstore(unonce, 0x20)
                
                
                
                mstore(add(unonce, 0x20), xor(blockhash(sub(number, 1)), xor(coinbase, timestamp)))
                mstore(sessionKeyHash, 0x20)
                mstore(add(sessionKeyHash, 0x20), sessionKeyHash_bytes32)
            }
            bytes memory delay = new bytes(32);
            assembly {
                mstore(add(delay, 0x20), _delay)
            }

            bytes memory delay_bytes8 = new bytes(8);
            copyBytes(delay, 24, 8, delay_bytes8, 0);

            bytes[4] memory args = [unonce, nbytes, sessionKeyHash, delay];
            bytes32 queryId = oraclize_query("random", args, _customGasLimit);

            bytes memory delay_bytes8_left = new bytes(8);

            assembly {
                let x := mload(add(delay_bytes8, 0x20))
                mstore8(add(delay_bytes8_left, 0x27), div(x, 0x100000000000000000000000000000000000000000000000000000000000000))
                mstore8(add(delay_bytes8_left, 0x26), div(x, 0x1000000000000000000000000000000000000000000000000000000000000))
                mstore8(add(delay_bytes8_left, 0x25), div(x, 0x10000000000000000000000000000000000000000000000000000000000))
                mstore8(add(delay_bytes8_left, 0x24), div(x, 0x100000000000000000000000000000000000000000000000000000000))
                mstore8(add(delay_bytes8_left, 0x23), div(x, 0x1000000000000000000000000000000000000000000000000000000))
                mstore8(add(delay_bytes8_left, 0x22), div(x, 0x10000000000000000000000000000000000000000000000000000))
                mstore8(add(delay_bytes8_left, 0x21), div(x, 0x100000000000000000000000000000000000000000000000000))
                mstore8(add(delay_bytes8_left, 0x20), div(x, 0x1000000000000000000000000000000000000000000000000))

            }

            oraclize_randomDS_setCommitment(queryId, keccak256(abi.encodePacked(delay_bytes8_left, args[1], sha256(args[0]), args[2])));
            return queryId;
        }

        function oraclize_randomDS_setCommitment(bytes32 queryId, bytes32 commitment) internal {
            oraclize_randomDS_args[queryId] = commitment;
        }

        mapping(bytes32=>bytes32) oraclize_randomDS_args;
        mapping(bytes32=>bool) oraclize_randomDS_sessionKeysHashVerified;

        function verifySig(bytes32 tosignh, bytes dersig, bytes pubkey) internal returns (bool){
            bool sigok;
            address signer;

            bytes32 sigr;
            bytes32 sigs;

            bytes memory sigr_ = new bytes(32);
            uint offset = 4+(uint(dersig[3]) - 0x20);
            sigr_ = copyBytes(dersig, offset, 32, sigr_, 0);
            bytes memory sigs_ = new bytes(32);
            offset += 32 + 2;
            sigs_ = copyBytes(dersig, offset+(uint(dersig[offset-1]) - 0x20), 32, sigs_, 0);

            assembly {
                sigr := mload(add(sigr_, 32))
                sigs := mload(add(sigs_, 32))
            }


            (sigok, signer) = safer_ecrecover(tosignh, 27, sigr, sigs);
            if (address(keccak256(pubkey)) == signer) return true;
            else {
                (sigok, signer) = safer_ecrecover(tosignh, 28, sigr, sigs);
                return (address(keccak256(pubkey)) == signer);
            }
        }

        function oraclize_randomDS_proofVerify__sessionKeyValidity(bytes proof, uint sig2offset) internal returns (bool) {
            bool sigok;

            
            bytes memory sig2 = new bytes(uint(proof[sig2offset+1])+2);
            copyBytes(proof, sig2offset, sig2.length, sig2, 0);

            bytes memory appkey1_pubkey = new bytes(64);
            copyBytes(proof, 3+1, 64, appkey1_pubkey, 0);

            bytes memory tosign2 = new bytes(1+65+32);
            tosign2[0] = byte(1); 
            copyBytes(proof, sig2offset-65, 65, tosign2, 1);
            bytes memory CODEHASH = hex"fd94fa71bc0ba10d39d464d0d8f465efeef0a2764e3887fcc9df41ded20f505c";
            copyBytes(CODEHASH, 0, 32, tosign2, 1+65);
            sigok = verifySig(sha256(tosign2), sig2, appkey1_pubkey);

            if (sigok == false) return false;


            
            bytes memory LEDGERKEY = hex"7fb956469c5c9b89840d55b43537e66a98dd4811ea0a27224272c2e5622911e8537a2f8e86a46baec82864e98dd01e9ccc2f8bc5dfc9cbe5a91a290498dd96e4";

            bytes memory tosign3 = new bytes(1+65);
            tosign3[0] = 0xFE;
            copyBytes(proof, 3, 65, tosign3, 1);

            bytes memory sig3 = new bytes(uint(proof[3+65+1])+2);
            copyBytes(proof, 3+65, sig3.length, sig3, 0);

            sigok = verifySig(sha256(tosign3), sig3, LEDGERKEY);

            return sigok;
        }

        modifier oraclize_randomDS_proofVerify(bytes32 _queryId, string _result, bytes _proof) {
            
            require((_proof[0] == "L") && (_proof[1] == "P") && (_proof[2] == 1));

            bool proofVerified = oraclize_randomDS_proofVerify__main(_proof, _queryId, bytes(_result), oraclize_getNetworkName());
            require(proofVerified);

            _;
        }

        function oraclize_randomDS_proofVerify__returnCode(bytes32 _queryId, string _result, bytes _proof) internal returns (uint8){
            
            if ((_proof[0] != "L")||(_proof[1] != "P")||(_proof[2] != 1)) return 1;

            bool proofVerified = oraclize_randomDS_proofVerify__main(_proof, _queryId, bytes(_result), oraclize_getNetworkName());
            if (proofVerified == false) return 2;

            return 0;
        }

        function matchBytes32Prefix(bytes32 content, bytes prefix, uint n_random_bytes) internal pure returns (bool){
            bool match_ = true;

            require(prefix.length == n_random_bytes);

            for (uint256 i=0; i< n_random_bytes; i++) {
                if (content[i] != prefix[i]) match_ = false;
            }

            return match_;
        }

        function oraclize_randomDS_proofVerify__main(bytes proof, bytes32 queryId, bytes result, string context_name) internal returns (bool){

            
            uint ledgerProofLength = 3+65+(uint(proof[3+65+1])+2)+32;
            bytes memory keyhash = new bytes(32);
            copyBytes(proof, ledgerProofLength, 32, keyhash, 0);
            if (!(keccak256(keyhash) == keccak256(abi.encodePacked(sha256(abi.encodePacked(context_name, queryId)))))) return false;

            bytes memory sig1 = new bytes(uint(proof[ledgerProofLength+(32+8+1+32)+1])+2);
            copyBytes(proof, ledgerProofLength+(32+8+1+32), sig1.length, sig1, 0);

            
            if (!matchBytes32Prefix(sha256(sig1), result, uint(proof[ledgerProofLength+32+8]))) return false;

            
            
            bytes memory commitmentSlice1 = new bytes(8+1+32);
            copyBytes(proof, ledgerProofLength+32, 8+1+32, commitmentSlice1, 0);

            bytes memory sessionPubkey = new bytes(64);
            uint sig2offset = ledgerProofLength+32+(8+1+32)+sig1.length+65;
            copyBytes(proof, sig2offset-64, 64, sessionPubkey, 0);

            bytes32 sessionPubkeyHash = sha256(sessionPubkey);
            if (oraclize_randomDS_args[queryId] == keccak256(abi.encodePacked(commitmentSlice1, sessionPubkeyHash))){ 
                delete oraclize_randomDS_args[queryId];
            } else return false;


            
            bytes memory tosign1 = new bytes(32+8+1+32);
            copyBytes(proof, ledgerProofLength, 32+8+1+32, tosign1, 0);
            if (!verifySig(sha256(tosign1), sig1, sessionPubkey)) return false;

            
            if (oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash] == false){
                oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash] = oraclize_randomDS_proofVerify__sessionKeyValidity(proof, sig2offset);
            }

            return oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash];
        }

        
        function copyBytes(bytes from, uint fromOffset, uint length, bytes to, uint toOffset) internal pure returns (bytes) {
            uint minLength = length + toOffset;

            
            require(to.length >= minLength); 

            
            uint i = 32 + fromOffset;
            uint j = 32 + toOffset;

            while (i < (32 + fromOffset + length)) {
                assembly {
                    let tmp := mload(add(from, i))
                    mstore(add(to, j), tmp)
                }
                i += 32;
                j += 32;
            }

            return to;
        }

        
        
        function safer_ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal returns (bool, address) {
            
            
            
            
            

            
            bool ret;
            address addr;

            assembly {
                let size := mload(0x40)
                mstore(size, hash)
                mstore(add(size, 32), v)
                mstore(add(size, 64), r)
                mstore(add(size, 96), s)

                
                
                ret := call(3000, 1, 0, size, 128, size, 32)
                addr := mload(size)
            }

            return (ret, addr);
        }

        
        function ecrecovery(bytes32 hash, bytes sig) internal returns (bool, address) {
            bytes32 r;
            bytes32 s;
            uint8 v;

            if (sig.length != 65)
            return (false, 0);

            
            
            
            assembly {
                r := mload(add(sig, 32))
                s := mload(add(sig, 64))

                
                
                
                v := byte(0, mload(add(sig, 96)))

                
                
                
                
            }

            
            
            
            
            
            if (v < 27)
            v += 27;

            if (v != 27 && v != 28)
                return (false, 0);

            return safer_ecrecover(hash, v, r, s);
        }

        function safeMemoryCleaner() internal pure {
            assembly {
                let fmem := mload(0x40)
                codecopy(fmem, codesize, sub(msize, fmem))
            }
        }

    }



contract UBets is usingOraclize {
    address public owner;

    struct Game {
        uint bet;
        uint max_players;
        bool finish;
        address[] players;
        uint[] numbers;
        uint[] uniq_numbers;
    }

    uint public min_bet = 0.1 ether;
    uint constant public min_players = 2;
    uint public max_players = 10;
    uint constant public min_number = 0;
    uint constant public max_number = 9;
    uint public oraclize_gas_limit = 350000;

    uint public commision = 10;
    uint public referer_commision = 1;

    Game[] public games;
    mapping(bytes32 => uint) public await_finish;
    mapping(uint => uint) public await_finish_block;
    mapping(address => address) public referers;

    event NewGame(uint indexed game_id, address indexed author, uint bet, uint max_players);
    event Bet(uint indexed game_id, address indexed addr, uint index, uint number);
    event Play(uint indexed game_id, bytes32 indexed id);
    event Winner(uint indexed game_id, address indexed winner, uint index, uint win);
    event RefererPayout(uint indexed game_id, address indexed winner, address indexed referer, uint payout);
    event GameOver(uint indexed game_id, uint[] numbers);
    event Refund(uint indexed game_id, address indexed addr, uint bet);
    event RefundGame(uint indexed game_id);

    modifier onlyOwner() {
        require(msg.sender == owner, "Access denied");
        _;
    }

    constructor() public {
        owner = msg.sender;
        oraclize_setProof(proofType_Ledger);
    }

    function() payable external {
        revert();
    }

    function donate() payable external {
        
    }

    function inArray(uint[] memory arr, uint number) private pure returns(bool) {
        for(uint i = 0; i < arr.length; i++) {
            if(arr[i] == number) return true;
        }
        
        return false;
    }
    
    function __callback(bytes32 id, string res, bytes memory proof) public {
        require(msg.sender == oraclize_cbAddress(), "Permission denied");
        require(oraclize_randomDS_proofVerify__returnCode(id, res, proof) == 0, "No proof random number");
        require(await_finish_block[await_finish[id]] < block.number, "No proof block");

        Game storage game = games[await_finish[id]];

        require(game.bet > 0, "Game not found");
        require(!game.finish, "Game over");

        uint seed = uint(keccak256(abi.encodePacked(res)));

        uint[] memory numbers = new uint[](game.uniq_numbers.length > 1 ? game.uniq_numbers.length - 1 : 1);
        for(uint i = 0; i < numbers.length; i++) {
            numbers[i] = game.uniq_numbers[seed % game.uniq_numbers.length];
            seed = seed / game.uniq_numbers.length;
        }

        _finishGame(await_finish[id], numbers);

        delete await_finish_block[await_finish[id]];
        delete await_finish[id];
    }

    function _joinGame(uint game_id, address player, uint bet, uint number, address referer) private {
        require(games[game_id].bet > 0, "Game not found");

        Game storage game = games[game_id];

        require(!game.finish, "Game over");
        require(bet == game.bet, "Insufficient funds");
        require(game.max_players > game.players.length, "Bets are no longer accepted");
        require(number >= min_number && number <= max_number, "Number does not match the interval");
        require(!(game.max_players == game.players.length - 1 && game.uniq_numbers.length < 2 && inArray(game.uniq_numbers, number)), "Number already exists");

        for(uint i = 0; i < game.numbers.length; i++) {
            if(game.numbers[i] == number && game.players[i] == player) revert("Number already exists");
        }

        game.players.push(player);
        game.numbers.push(number);

        if(!inArray(game.uniq_numbers, number)) {
            game.uniq_numbers.push(number);
        }

        if(referer != address(0) && referers[player] == address(0)) {
            referers[player] = referer;
        }

        emit Bet(game_id, player, game.players.length - 1, number);

        if(game.max_players == game.players.length) {
            _playGame(game_id);
        }
    }

    function _playGame(uint game_id) private {
        require(games[game_id].bet > 0, "Game not found");
        require(!games[game_id].finish, "Game over");
        require(games[game_id].max_players == games[game_id].players.length, "The game has free slots");
        require(oraclize_getPrice("random", oraclize_gas_limit) <= address(this).balance, "Insufficient funds");

        bytes32 id = oraclize_newRandomDSQuery(0, 32, oraclize_gas_limit);
        
        await_finish[id] = game_id;
        await_finish_block[game_id] = block.number;

        emit Play(game_id, id);
    }

    function _finishGame(uint game_id, uint[] memory numbers) private {
        require(games[game_id].bet > 0, "Game not found");

        Game storage game = games[game_id];

        require(!game.finish, "Game over");
        require(game.max_players == game.players.length, "The game has free slots");
        require(numbers.length == (game.uniq_numbers.length > 1 ? game.uniq_numbers.length - 1 : 1), "Incorect winning numbers");
        
        uint bank = game.bet * game.max_players;
        uint bank_use = oraclize_getPrice("random", oraclize_gas_limit);
        uint num_payout = (bank * (100 - commision) / 100) / numbers.length;
        
        for(uint n = 0; n < numbers.length; n++) {
            uint num_w = 0;

            for(uint j = 0; j < game.numbers.length; j++) {
                if(numbers[n] == game.numbers[j]) {
                    num_w++;
                }
            }

            uint payout = num_payout / num_w;

            for(uint p = 0; p < game.players.length; p++) {
                if(numbers[n] == game.numbers[p]) {
                    game.players[p].send(payout);
                    bank_use += payout;

                    emit Winner(game_id, game.players[p], p, payout);

                    if(referers[game.players[p]] != address(0) && referer_commision > 0) {
                        uint referer_payout = payout * referer_commision / 100;

                        referers[game.players[p]].send(referer_payout);
                        bank_use += referer_payout;
                        
                        emit RefererPayout(game_id, game.players[p], referers[game.players[p]], referer_payout);
                    }
                }
            }
        }

        if(bank > bank_use) {
            owner.transfer(bank - bank_use);
        }

        game.finish = true;

        emit GameOver(game_id, numbers);
    }

    function newGame(uint players, uint number, address referer) payable external {
        require(msg.value >= min_bet, "Min bet of 0.1 ether");
        require(players >= min_players && players <= max_players, "Players does not match the interval");
        require(number >= min_number && number <= max_number, "Number does not match the interval");

        address[] memory players_arr;
        uint[] memory numbers_arr;
        uint[] memory uniq_numbers;

        games.push(Game({
            bet: msg.value,
            max_players: players,
            finish: false,
            players: players_arr,
            numbers: numbers_arr,
            uniq_numbers: uniq_numbers
        }));

        emit NewGame(games.length - 1, msg.sender, msg.value, players);

        _joinGame(games.length - 1, msg.sender, msg.value, number, referer);
    }

    function joinGame(uint game_id, uint number, address referer) payable external {
        _joinGame(game_id, msg.sender, msg.value, number, referer);
    }
    
    function refundGame(uint game_id) onlyOwner external {
        require(games[game_id].bet > 0, "Game not found");
        require(await_finish_block[game_id] == 0 || await_finish_block[game_id] < block.number - 1000, "Game not found");

        Game storage game = games[game_id];

        require(!game.finish, "Game over");

        game.finish = true;

        for(uint i = 0; i < game.players.length; i++) {
            game.players[i].send(game.bet);

            emit Refund(game_id, game.players[i], game.bet);
        }

        emit RefundGame(game_id);
    }
 
    function setOraclizeGasLimit(uint value) onlyOwner external {
        require(value >= 21000 && value <= 5000000, "Value does not match the interval");

        oraclize_gas_limit = value;
    }

    function setOraclizeGasPrice(uint value) onlyOwner external {
        require(value >= 1000000000 && value <= 100000000000, "Value does not match the interval");

        oraclize_setCustomGasPrice(value);
    }

    function setOwner(address value) onlyOwner external {
        require(value != address(0), "Zero address");
        
        owner = value;
    }
}