function issueTokens(address _beneficiary, uint _contribution) external onlyBackend onlyValidPhase onlyUnpaused {
        
        if (crowdsalePhase == CrowdsalePhase.PhaseOne) {
            require(totalCentsGathered.add(_contribution) <= phaseOneCap);
        } else {
            require(totalCentsGathered.add(_contribution) <= hardCap);
        }

        uint remainingContribution = _contribution;

        
        
        do {
            
            uint centsLeftInPhase = calculateCentsLeftInPhase(remainingContribution);
            uint contributionPart = min(remainingContribution, centsLeftInPhase);

            
            uint tokensToMint = tokenRate.mul(contributionPart);
            mintAndUpdate(_beneficiary, tokensToMint);
            TokensAllocated(_beneficiary, contributionPart, tokensToMint);

            
            uint tierBonus = calculateTierBonus(contributionPart);
            if (tierBonus > 0) {
                mintAndUpdate(_beneficiary, tierBonus);
                BonusIssued(_beneficiary, tierBonus);
            }

            
            if ((bonusPhase != BonusPhase.None) && (contributionPart == centsLeftInPhase)) {
                advanceBonusPhase();
            }

            
            totalCentsGathered = totalCentsGathered.add(contributionPart);
            remainingContribution = remainingContribution.sub(contributionPart);

            
        } while (remainingContribution > 0);

        
        uint sizeBonus = calculateSizeBonus(_contribution);
        if (sizeBonus > 0) {
            mintAndUpdate(_beneficiary, sizeBonus);
            BonusIssued(_beneficiary, sizeBonus);
        }
    }