function internalContribution(address _contributor, uint256 _wei) internal {
        updateState();
        require(currentState == State.InCrowdsale);

        ICUStrategy pricing = ICUStrategy(pricingStrategy);
        uint256 usdAmount = pricing.getUSDAmount(_wei);
        require(!isHardCapAchieved(usdAmount.sub(1)));

        uint256 tokensAvailable = allocator.tokensAvailable();
        uint256 collectedWei = contributionForwarder.weiCollected();
        uint256 tierIndex = pricing.getTierIndex();
        uint256 tokens;
        uint256 tokensExcludingBonus;
        uint256 bonus;

        (tokens, tokensExcludingBonus, bonus) = pricing.getTokens(
            _contributor, tokensAvailable, tokensSold, _wei, collectedWei
        );

        require(tokens > 0);
        tokensSold = tokensSold.add(tokens);
        allocator.allocate(_contributor, tokensExcludingBonus);

        if (isSoftCapAchieved(usdAmount)) {
            if (msg.value > 0) {
                contributionForwarder.forward.value(address(this).balance)();
            }
        } else {
            
            if (contributorsWei[_contributor] == 0) {
                contributors.push(_contributor);
            }
            contributorsWei[_contributor] = contributorsWei[_contributor].add(msg.value);
        }

        usdCollected = usdCollected.add(usdAmount);

        if (availableBonusAmount > 0) {
            if (availableBonusAmount >= bonus) {
                availableBonusAmount -= bonus;
            } else {
                bonus = availableBonusAmount;
                availableBonusAmount = 0;
            }
            contributorBonuses[_contributor] = contributorBonuses[_contributor].add(bonus);
        } else {
            bonus = 0;
        }

        crowdsaleAgent.onContribution(pricing, tierIndex, tokensExcludingBonus, bonus);
        emit Contribution(_contributor, _wei, tokensExcludingBonus, bonus);
    }