function buyTokens(address beneficiary) public whenNotPaused payable {
        require(startTime <= now && now <= endTime);

        uint weiAmount = msg.value;

        require(weiAmount >= minInvest);

        uint tokenAmountEnable = tokensLimit.sub(tokensSold);

        require(tokenAmountEnable > 0);

        uint tokenAmount = weiAmount / price * 1 ether;

        if (tokenAmount > tokenAmountEnable) {
            tokenAmount = tokenAmountEnable;
            weiAmount = tokenAmount * price / 1 ether;
            msg.sender.transfer(msg.value.sub(weiAmount));


            if (msg.data.length > 0) {
                Promo storage promo = promoMap[sha3(msg.data)];
                if (promo.enable && promo.dealerPercentETH > 0) {
                    uint dealerEthAmount = weiAmount * promo.dealerPercentETH / 10000;
                    promo.dealer.transfer(dealerEthAmount);
                    weiAmount = weiAmount.sub(dealerEthAmount);

                    promo.dealerEthAmount += dealerEthAmount;
                }
            }
        }
        else {
            uint countBonusAmount = tokenAmount * getCountBonus(weiAmount) / 1000;
            uint timeBonusAmount = tokenAmount * getTimeBonus(now) / 1000;

            if (msg.data.length > 0) {
                bytes32 promoPublicKey = sha3(msg.data);
                promo = promoMap[promoPublicKey];
                if (promo.enable) {
                    
                    promo.buyCount++;
                    promo.investorTokenAmount += tokenAmount;
                    promo.investorEthAmount += weiAmount;
                    
                    if (promo.dealerPercentToken > 0) {
                        uint dealerTokenAmount = tokenAmount * promo.dealerPercentToken / 10000;
                        sendTokens(promo.dealer, dealerTokenAmount);
                        promo.dealerTokenAmount += dealerTokenAmount;
                    }

                    if (promo.dealerPercentETH > 0) {
                        dealerEthAmount = weiAmount * promo.dealerPercentETH / 10000;
                        promo.dealer.transfer(dealerEthAmount);
                        weiAmount = weiAmount.sub(dealerEthAmount);
                        promo.dealerEthAmount += dealerEthAmount;
                    }

                        
                    if (promo.investorPercentToken > 0) {
                        uint promoBonusAmount = tokenAmount * promo.investorPercentToken / 10000;
                        tokenAmount += promoBonusAmount;
                    }

                }
            }

            tokenAmount += countBonusAmount + timeBonusAmount;

            if (tokenAmount > tokenAmountEnable) {
                tokenAmount = tokenAmountEnable;
            }
        }


        if (purchaseTokens[beneficiary] == 0) investorCount++;

        purchaseTokens[beneficiary] = purchaseTokens[beneficiary].add(tokenAmount);

        sendTokens(beneficiary, tokenAmount);

        weiRaised = weiRaised.add(weiAmount);

        TokenPurchase(msg.sender, beneficiary, weiAmount, tokenAmount);
    }