function contribute() 
        public 
        payable
        checkAllowed 
    {
        require(msg.value > 0);   

        uint256 contributionLimit = getContributionLimit(msg.sender);
        require(contributionLimit > 0);

        
        uint256 totalContribution = contributions[msg.sender].add(msg.value);
        uint256 excess = 0;

        
        if (weiContributed.add(msg.value) > contributionCap) {
            
            excess = weiContributed.add(msg.value).sub(contributionCap);
            totalContribution = totalContribution.sub(excess);
        }

        
        if (totalContribution > contributionLimit) {
            excess = excess.add(totalContribution).sub(contributionLimit);
            contributions[msg.sender] = contributionLimit;
        } else {
            contributions[msg.sender] = totalContribution;
        }

        
        
        require(excess <= msg.value);

        weiContributed = weiContributed.add(msg.value).sub(excess);

        if (excess > 0) {
            msg.sender.transfer(excess);
        }

        wallet.transfer(this.balance);

        assert(contributions[msg.sender] <= contributionLimit);
        LogContribution(msg.sender, msg.value, excess);
    }