## Full example

    pragma solidity >=0.4.22 <0.7.0;

    /// @title Voting with delegation.
    contract Ballot {
    	// This declares a new complex type which will
    	// be used for variables later.
    	// It will represent a single voter.
    	struct Voter {
    		uint weight; // weight is accumulated by delegation
    		bool voted;  // if true, that person already voted
    		address delegate; // person delegated to
    		uint vote;   // index of the voted proposal
    	}

    	// This is a type for a single proposal.
    	struct Proposal {
    		bytes32 name;   // short name (up to 32 bytes)
    		uint voteCount; // number of accumulated votes
    	}

    	address public chairperson;

    	// This declares a state variable that
    	// stores a `Voter` struct for each possible address.
    	mapping(address => Voter) public voters;

    	// A dynamically-sized array of `Proposal` structs.
    	Proposal[] public proposals;

    	/// Create a new ballot to choose one of `proposalNames`.
    	constructor(bytes32[] memory proposalNames) public {
    		chairperson = msg.sender;
    		voters[chairperson].weight = 1;

    		// For each of the provided proposal names,
    		// create a new proposal object and add it
    		// to the end of the array.
    		for (uint i = 0; i < proposalNames.length; i++) {
    			// `Proposal({...})` creates a temporary
    			// Proposal object and `proposals.push(...)`
    			// appends it to the end of `proposals`.
    			proposals.push(Proposal({
    					name: proposalNames[i],
    					voteCount: 0
    			}));
    		}
    	}

    	// Give `voter` the right to vote on this ballot.
    	// May only be called by `chairperson`.
    	function giveRightToVote(address voter) public {
    		// If the first argument of `require` evaluates
    		// to `false`, execution terminates and all
    		// changes to the state and to Ether balances
    		// are reverted.
    		// This used to consume all gas in old EVM versions, but
    		// not anymore.
    		// It is often a good idea to use `require` to check if
    		// functions are called correctly.
    		// As a second argument, you can also provide an
    		// explanation about what went wrong.
    		require(
    			msg.sender == chairperson,
    			"Only chairperson can give right to vote."
    		);
    		require(
    			!voters[voter].voted,
    			"The voter already voted."
    		);
    		require(voters[voter].weight == 0);
    		voters[voter].weight = 1;
    	}

    	/// Delegate your vote to the voter `to`.
    	function delegate(address to) public {
    		// assigns reference
    		Voter storage sender = voters[msg.sender];
    		require(!sender.voted, "You already voted.");

    		require(to != msg.sender, "Self-delegation is disallowed.");

    		// Forward the delegation as long as
    		// `to` also delegated.
    		// In general, such loops are very dangerous,
    		// because if they run too long, they might
    		// need more gas than is available in a block.
    		// In this case, the delegation will not be executed,
    		// but in other situations, such loops might
    		// cause a contract to get "stuck" completely.
    		while (voters[to].delegate != address(0)) {
    			to = voters[to].delegate;

    			// We found a loop in the delegation, not allowed.
    			require(to != msg.sender, "Found loop in delegation.");
    		}

    		// Since `sender` is a reference, this
    		// modifies `voters[msg.sender].voted`
    		sender.voted = true;
    		sender.delegate = to;
    		Voter storage delegate_ = voters[to];
    		if (delegate_.voted) {
    			// If the delegate already voted,
    			// directly add to the number of votes
    			proposals[delegate_.vote].voteCount += sender.weight;
    		} else {
    			// If the delegate did not vote yet,
    			// add to her weight.
    			delegate_.weight += sender.weight;
    		}
    	}

    	/// Give your vote (including votes delegated to you)
    	/// to proposal `proposals[proposal].name`.
    	function vote(uint proposal) public {
    		Voter storage sender = voters[msg.sender];
    		require(sender.weight != 0, "Has no right to vote");
    		require(!sender.voted, "Already voted.");
    		sender.voted = true;
    		sender.vote = proposal;

    		// If `proposal` is out of the range of the array,
    		// this will throw automatically and revert all
    		// changes.
    		proposals[proposal].voteCount += sender.weight;
    	}

    	/// @dev Computes the winning proposal taking all
    	/// previous votes into account.
    	function winningProposal() public view
    			returns (uint winningProposal_)
    	{
    		uint winningVoteCount = 0;
    		for (uint p = 0; p < proposals.length; p++) {
    			if (proposals[p].voteCount > winningVoteCount) {
    				winningVoteCount = proposals[p].voteCount;
    				winningProposal_ = p;
    			}
    		}
    	}

    	// Calls winningProposal() function to get the index
    	// of the winner contained in the proposals array and then
    	// returns the name of the winner
    	function winnerName() public view
    			returns (bytes32 winnerName_)
    	{
    		winnerName_ = proposals[winningProposal()].name;
    	}
    }