add semicolons

add semicolons

pragma solidity ^0.4.11;
import "./StandardToken.sol";
import "./PLCRVoting.sol";

/*
=======
 TO DO
=======

implement events
refactor & wrap check & transfer

*/

contract Registry {

    /*
     * Storage
     */

    //Registry storage
    StandardToken public token;
    PLCRVoting public voting;
    mapping(bytes32 => Publisher) public whitelist; //domainHash => Publisher struct
    mapping(bytes32 => Application) public appPool; //holds applications for both domain and parameter appPool
    mapping(bytes32 => Params) public paramSnapshots;
    mapping(uint => VoteInfo) public pollInfo; // holds information on individual polls
    mapping(address => mapping(uint => bool)) public voterInfo; // holds information on voters' token claims
    string domain;
    //Parameter storage
    mapping(bytes32 => uint) public Parameters;
    mapping(uint => bytes32) public idToHash;
    string parameter;
    uint value;

    struct Publisher {
        address owner;
        uint expTime;
        uint deposit;

        uint nextExpTime; //
        uint prevDeposit; // total withdrawable amount
        uint nextDeposit; //
        bool renewal;
    }

    struct Application {
        address owner;
        bool challenged;
        uint challengeTime; //End of challenge period
        address challenger;

        string parameter;
        uint value;
    }

    struct Params {
        // parameters concerning the whitelist and application pool
        uint minDeposit;
        uint challengeLen;
        uint registryLen;

        // parameters to be passed into the voting contract
        uint commitVoteLen;
        uint revealVoteLen;
        uint majority;

        // parameter representing the scale of how token rewards are distributed
        uint dispensationPct;
    }

    struct VoteInfo {
        // if the vote has been processed
        bool processed;
        // amount of leftover tokens available for winning party to claim
        // (a byproduct of needing to floor the distributed tokens to voters)
        uint256 remainder;
        address claimer;
    }

    // constant used to help represent doubles as ints
    uint256 constant private MULTIPLIER = 10 ** 18;

    /*
     * Constructor
     */
    /// @param _minDeposit      application & challenger deposit amounts
    /// @param _challengeLen    duration of the challenge period
    /// @param _registryLen     duration of a registration’s validity
    /// @param _commitVoteLen   duration of the commit period in token votes
    /// @param _revealVoteLen   duration of reveal period in token votes
    /// @param _dispensationPct percentage of forfeited deposit distributed to winning party; uint between 0 and 100
    /// @param _majority        percentage of votes that constitutes the majority; uint between 0 and 100

    function Registry(address _token,
       uint _minDeposit,
       uint _challengeLen,
       uint _registryLen,
       uint _commitVoteLen,
       uint _revealVoteLen,
       uint _dispensationPct,
       uint _majority) {

       token = StandardToken(_token);
       // initialize values
       Parameters[sha3("minDeposit")]        = _minDeposit;
       Parameters[sha3("challengeLen")]      = _challengeLen;
       Parameters[sha3("registryLen")]       = _registryLen;
       Parameters[sha3("commitVoteLen")]     = _commitVoteLen;
       Parameters[sha3("revealVoteLen")]     = _revealVoteLen;
       Parameters[sha3("dispensationPct")]   = _dispensationPct;
       Parameters[sha3("majority")]          = _majority;
    }

    // called by an applicant to apply (moves them into the application pool on success)
    function apply(string _domain) public {
        bytes32 domainHash = sha3(_domain);
        // must be a new member of the whitelist
        require(whitelist[domainHash].owner == 0);
        // initialize with the current values of all parameters
        initializeSnapshot(domainHash);
        initApplication(domainHash, msg.sender);
        appPool[domainHash].domain = _domain;
    }

    // helper function to apply() and proposeUpdate()
    // initialize general application
    function initApplication(bytes32 _hash, address _applicant) private {
        // applicant must pay the current value of minDeposit
        uint deposit = paramSnapshots[_hash].minDeposit;
        // check to prevent repeat applications
        require(appPool[_hash].owner == 0);
        // check that registry can take sufficient amount of tokens from the applicant
        require(token.allowance(_applicant, this) >= deposit);
        token.transferFrom(_applicant, this, deposit);
        appPool[_hash].challengeTime = now + paramSnapshots[_hash].challengeLen;
        appPool[_hash].owner = _applicant;
    }

    function renew (string _domain) {
        bytes32 domainHash = sha3(_domain);
        // check if no active renewal
        require(hasRenewal(domainHash) == false);
        require(msg.sender == whitelist[domainHash].owner); // checks that you are the owner of the domain
        require(appPool[domainHash].owner == 0); // no double renewal
        uint deposit = get('minDeposit');
        //Check if existing deposit is sufficient
        if (whitelist[domainHash].deposit + whitelist[domainHash].prevDeposit >= deposit){
            // only take from deposit
            if (whitelist[domainHash].deposit >= deposit)
            {
                uint difference = whitelist[domainHash].deposit - deposit;
                whitelist[domainHash].deposit = difference;
            }
            // take whole deposit and part of prevDeposit
            else
            {
                // take all of locked deposit and a portion of unlocked deposit
                uint difference = deposit - whitelist[domainHash].deposit;
                uint difference2 = whitelist[domainHash].prevDeposit - difference;
                whitelist[domainHash].prevDeposit = difference2;
            }
        }
        //if insufficient # of tokens, then must send in the difference
        else {
            uint difference = deposit-(whitelist[domainHash].deposit + whitelist.[domainHash].prevDeposit);
            require(token.allowance(msg.sender, this) >= difference);
            token.transferFrom(msg.sender, this, difference);
            whitelist[domainHash].deposit = 0;
            whitelist[domainHash].prevDeposit = 0;
        }
        //apply
        initializeSnapshot(_domain);
        appPool[domainHash].challengeTime = now + paramSnapshots[_hash].challengeLen;
        appPool[domainHash].owner = msg.sender;
        whitelist[domainHash].renewal = true;
    }

    function claimDeposit(string _domain, uint _amount) public {
        bytes32 domainHash = sha3(_domain);
        require(msg.sender == whitelist[domainHash].owner);
        uint difference = whitelist[domainHash].prevDeposit - _amount;
        require(difference >= 0);
        token.transfer(msg.sender, _amount);
        whitelist[domainHash].prevDeposit = difference;
    }

    // called by domain owner to activate renewal period and allow additional renewals
    function activateRenewal(string _domain) public {
        bytes32 _hash = sha3(_domain);
        if (hasRenewal(_hash) && whitelist[_hash].expTime <= now)
        {
            whitelist[_hash].expTime = whitelist[_hash].nextExpTime;
            whitelist[_hash].prevDeposit += whitelist[_hash].deposit;
            whitelist[_hash].deposit = whitelist[_hash].nextDeposit;
            whitelist[_hash].renewal = false;
        }
    }

    // called by any adtoken holder to challenge an application to the whitelist
    // initialize vote to accept/reject a domain to the registry
    function challengeApplication(string _domain) public returns(pollID) {
        bytes32 domainHash = sha3(_domain);
        challenge(domainHash, msg.sender);
        // start a vote
        uint pollID = callVote(_domain
        ,paramSnapshots[domainHash].majority
        ,paramSnapshots[domainHash].commitVoteLen
        ,paramSnapshots[domainHash].revealVoteLen);
        idToHash[pollID] = domainHash;
        return pollID;
    }

    // helper function to challengeApplication() and challengeProposal()
    function challenge(bytes32 _hash, address _challenger) private {
        // check that registry can take sufficient amount of tokens from the challenger
        uint deposit = paramSnapshots[_hash].minDeposit;
        require(token.allowance(_challenger, this) >= deposit);
        token.transferFrom(_challenger, this, deposit);

        // prevent someone from challenging an unintialized application, rechallenging,
        // or challenging after the challenge period has ended
        require(appPool[_hash].owner != 0);
        require(appPool[_hash].challenged == false);
        require(appPool[_hash].challengeTime > now);

        // update the application's status
        appPool[_hash].challenged = true;
        appPool[_hash].challenger = _challenger;
    }

    // helper function to the challenge() function. Initializes a vote through the voting contract
    // returns a poll id
    function callVote(string _proposalString,
        uint _majority,
        uint _commitVoteLen,
        uint _revealVoteLen
        ) private returns (uint) {
        // event that vote has started
        uint pollID = voting.startPoll( _proposalString, _majority, _commitVoteLen,  _revealVoteLen);
        return pollID;
    }

    // a one-time function for each completed vote
    // if domain won: domain is moved to the whitelist and applicant is rewarded tokens, return true
    // if domain lost: challenger is rewarded tokens, return false
    function processResult(uint _pollID) returns(bool)
    {
        bytes32 domainHash = idToHash[_pollID];
        require(isDomainApp(domainHash));  // processing parameter hash this way is unintended behavior
        require(pollInfo[_pollID].processed == false);
        // ensures the result cannot be processed again
        pollInfo[_pollID].processed = true;

        if (voting.isPassed(_pollID)) {
            // add to registry
            add(domainHash, appPool[domainHash].owner);
            pollInfo[_pollID].claimer = appPool[domainHash].owner;
            // give tokens to applicant based on dist and total tokens
            giveWinnerReward(domainHash, appPool[domainHash].owner);
            // uninitialize application
            delete appPool[domainHash].owner;
            return true;
        }
        else {
            pollInfo[_pollID].claimer = appPool[domainHash].challenger;
            giveWinnerReward(domainHash, appPool[domainHash].challenger);
            token.transfer(appPool[domainHash].challenger, paramSnapshots[domainHash].minDeposit);
            delete appPool[domainHash].owner;
            return false;
        }
    }

    // internal function to give applicant/challenger reward
    // if dispensationPct does not divide minDeposit evenly, gives then the extra token
    function giveWinnerReward(_hash, _address) private {
        uint256 minDeposit = paramSnapshots[_hash].minDeposit;
        uint256 dispensationPct = paramSnapshots[_hash].dispensationPct;
        uint256 rewardTokens = minDeposit * (dispensationPct) / 100;
        if ((minDeposit * dispensationPct) % 100 != 0) {
            rewardTokens++;
        }
        token.transfer(_address, rewardTokens);
    }

    // called by each voter to claim their reward for each completed vote
    function claimReward(uint _pollID, uint _salt) {
        // checks if a voter has claimed tokens
        require(voterInfo[msg.sender][_pollID] == false);
        uint reward = giveTokens(_pollID, _salt, msg.sender);
        // ensures a voter cannot claim tokens again
        token.transfer(msg.sender, reward);
        voterInfo[msg.sender][_pollID] = true;
    }

    // number of tokens person used to vote / total number of tokens for winning side
    // scale using distribution number, give the tokens
    function giveTokens(uint _pollID, uint _salt, address _voter) private returns(uint) {
        bytes32 hash = idToHash[_pollID];
        uint256 minDeposit = paramSnapshots[hash].minDeposit;
        uint256 dispensationPct = paramSnapshots[hash].dispensationPct;
        uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_pollID);
        uint256 voterTokens = voting.getNumPassingTokens(_pollID, _salt, _voter);

        uint256 rewardTokens = minDeposit * (100 - dispensationPct) / 100;
        uint256 numerator = voterTokens * rewardTokens * MULTIPLIER;
        uint256 denominator = totalTokens * MULTIPLIER;
        uint256 remainder = numerator % denominator;

        // save remainder tokens in the form of decimal numbers with 18 places represented
        // as a uint256
        pollInfo[_pollID].remainder += remainder;

        return numerator / denominator;
    }

    function claimExtraReward(uint _pollID) {
        uint256 reward = pollInfo[_pollID].remainder / MULTIPLIER;
        pollInfo[_pollID].remainder = pollInfo[_pollID].remainder - reward * MULTIPLIER;
        token.transfer(pollInfo[_pollID].claimer, reward);
    }

    // called to move an applying domain to the whitelist
    // iff the domain's challenge period has passed without a challenge
    function moveToRegistry(string _domain) public {
        bytes32 domainHash = sha3(_domain);
        require(appPool[domainHash].challengeTime < now);
        require(appPool[domainHash].challenged == false);
        // prevents moving a domain to the registry without ever applying
        require(appPool[domainHash].owner != 0);
        // prevent applicant from moving to registry multiple times
        add(domainHash, appPool[domainHash].owner);
        delete appPool[domainHash].owner;
    }

    // ISSUE WITH OVERLAP

    // private function to add a domain name to the whitelist
    function add(bytes32 _domainHash, address _owner) private {
        uint expiration = paramSnapshots[_domainHash].registryLen;
        if (whitelist[_domainHash].renewal = true)
        {
            whitelist[_domainHash].nextExpTime = whitelist[_domainHash].expTime + expiration;
            whitelist[_domainHash].nextDeposit = paramSnapshots[_domainHash].minDeposit;
        }
        else
        {
            whitelist[_domainHash].expTime = now + expiration;
            whitelist[_domainHash].deposit = paramSnapshots[_domainHash].minDeposit;
        }
        whitelist[_domainHash].owner = _owner;
    }

    /*
     * Helper Functions
     */

    // STATIC

    // returns true if a renewal has been initialized
    function hasRenewal(bytes32 _hash) private constant returns (bool) {
        return whitelist[_hash].renewal;
    }

    //returns true if Application is for domain and not parameter
    function isDomainApp(bytes32 _hash) private constant returns(bool){
        return appPool[_hash].parameter == "";  // checks if param string is initialized
    }

    // checks if a domain name is in the whitelist and unexpired
    function isVerified(string _domain) public constant returns (bool) {
        bytes32 domainHash = sha3(_domain);
        return whitelist[domainHash].expTime > now;
    }

    // DYNAMIC

    // private function to initialize a snapshot of parameters for each application
    function initializeSnapshot(bytes32 _hash) private {
        initializeSnapshotParam(_hash);  // maybe put the two together
        paramSnapshots[_hash].registryLen = get("registryLen");
    }

/*****************************************************************************/

    //called by a user who wishes to change a parameter
    //initializes a proposal to change a parameter
    function proposeUpdate(string _parameter, uint _value) public {
        require(_parameter != "");
        bytes32 parameterHash = sha3(_parameter, _value);
        // initialize application with a with the current values of all parameters
        initializeSnapshotParam(parameterHash);
        initApplication(parameterHash, msg.sender);
        appPool[parameterHash].parameter = _parameter;
        appPool[parameterHash].value = _value;
    }

    //called by user who wishes to reject a proposal
    //initializes a vote to accept/reject the param change proposal
    function challengeProposal(string _parameter, uint _value) public {
        bytes32 parameterHash = sha3(_parameter, _value);
        challenge(parameterHash, msg.sender);
        // start a vote
        uint pollID = callVote(_parameter
        ,paramSnapshots[parameterHash].majority
        ,paramSnapshots[parameterHash].commitVoteLen
        ,paramSnapshots[parameterHash].revealVoteLen);
        idToHash[pollID] = parameterHash;
    }

    // called to change parameter
    // iff the proposal's challenge period has passed without a challenge
    function setParams(string _parameter, uint _value) public {
        bytes32 parameterHash = sha3(_parameter, _value);
        require(appPool[parameterHash].challengeTime < now);
        require(appPool[parameterHash].challenged == false);
        // prevents moving a domain to the registry without ever applying
        require(appPool[parameterHash].owner != 0);
        // prevent applicant from moving to registry multiple times
        Parameters[sha3(_parameter)] = _value;
        delete appPool[parameterHash].owner;
    }

    // a one-time function for each completed vote
    // if proposal won: new parameter value is set, and applicant is rewarded tokens, return true
    // if prospsal lost: challenger is rewarded tokens, return false
    function processProposal(uint _pollID) returns(bool)
    {
        require(pollInfo[_pollID].processed == false);
        bytes32 parameterHash = idToHash[_pollID];
        parameter = appPool[parameterHash].parameter;
        value = appPool[parameterHash].value;
        delete appPool[parameterHash].owner;

        if (voting.isPassed(_pollID)) {
            pollInfo[_pollID].claimer = appPool[parameterHash].owner;
            // setting the value of parameter
            Parameters[sha3(parameter)] = value;
            // give tokens to applicant based on dist and total tokens IMPLEMENT
            giveWinnerReward(parameterHash, appPool[parameterHash].owner);
            token.transfer(appPool[parameterHash].owner, paramSnapshots[parameterHash].minDeposit);
            return true;
        }
        else {
            pollInfo[_pollID].claimer = appPool[parameterHash].challenger;
            // give tokens to challenger based on dist and total tokens
            giveWinnerReward(parameterHash, appPool[parameterHash].challenger);
            token.transfer(appPool[parameterHash].challenger, paramSnapshots[parameterHash].minDeposit);
            return false;
        }
        // ensures the result cannot be processed again
        pollInfo[_pollID].processed = true;
    }

     // private function to initialize a snapshot of parameters for each proposal
     function initializeSnapshotParam(bytes32 _hash) private {
        paramSnapshots[_hash].minDeposit = get("minDeposit");
        paramSnapshots[_hash].challengeLen = get("challengeLen");
        paramSnapshots[_hash].commitVoteLen = get("commitVoteLen");
        paramSnapshots[_hash].revealVoteLen = get("revealVoteLen");
        paramSnapshots[_hash].majority = get("majority");
        paramSnapshots[_hash].dispensationPct = get("dispensationPct");
    }

    // interface for retrieving config parameter from hashmapping
    /// @param _keyword key for hashmap (only useful when keyword matches variable name)
    function get(string _keyword) public constant returns (uint) {
       return Parameters[sha3(_keyword)];
    }

/*****************************************************************************/

    // Helper Functions

}

pragma solidity ^0.4.11;
import "./StandardToken.sol";
import "./PLCRVoting.sol";

/*
=======
 TO DO
=======

implement events
refactor & wrap check & transfer

*/

contract Registry {

    /*
     * Storage
     */

    //Registry storage
    StandardToken public token;
    PLCRVoting public voting;
    mapping(bytes32 => Publisher) public whitelist; //domainHash => Publisher struct
    mapping(bytes32 => Application) public appPool; //holds applications for both domain and parameter appPool
    mapping(bytes32 => Params) public paramSnapshots;
    mapping(uint => VoteInfo) public pollInfo; // holds information on individual polls
    mapping(address => mapping(uint => bool)) public voterInfo; // holds information on voters' token claims
    string domain;
    //Parameter storage
    mapping(bytes32 => uint) public Parameters;
    mapping(uint => bytes32) public idToHash;
    string parameter;
    uint value;

    struct Publisher {
        address owner;
        uint expTime;
        uint deposit;

        uint nextExpTime //
        uint prevDeposit // total withdrawable amount
        uint nextDeposit //
        bool renewal;
    }

    struct Application {
        address owner;
        bool challenged;
        uint challengeTime; //End of challenge period
        address challenger;

        string parameter;
        uint value;
    }

    struct Params {
        // parameters concerning the whitelist and application pool
        uint minDeposit;
        uint challengeLen;
        uint registryLen;

        // parameters to be passed into the voting contract
        uint commitVoteLen;
        uint revealVoteLen;
        uint majority;

        // parameter representing the scale of how token rewards are distributed
        uint dispensationPct;
    }

    struct VoteInfo {
        // if the vote has been processed
        bool processed;
        // amount of leftover tokens available for winning party to claim
        // (a byproduct of needing to floor the distributed tokens to voters)
        uint256 remainder;
        address claimer;
    }

    // constant used to help represent doubles as ints
    uint256 constant private MULTIPLIER = 10 ** 18;

    /*
     * Constructor
     */
    /// @param _minDeposit      application & challenger deposit amounts
    /// @param _challengeLen    duration of the challenge period
    /// @param _registryLen     duration of a registration’s validity
    /// @param _commitVoteLen   duration of the commit period in token votes
    /// @param _revealVoteLen   duration of reveal period in token votes
    /// @param _dispensationPct percentage of forfeited deposit distributed to winning party; uint between 0 and 100
    /// @param _majority        percentage of votes that constitutes the majority; uint between 0 and 100

    function Registry(address _token,
       uint _minDeposit,
       uint _challengeLen,
       uint _registryLen,
       uint _commitVoteLen,
       uint _revealVoteLen,
       uint _dispensationPct,
       uint _majority) {

       token = StandardToken(_token);
       // initialize values
       Parameters[sha3("minDeposit")]        = _minDeposit;
       Parameters[sha3("challengeLen")]      = _challengeLen;
       Parameters[sha3("registryLen")]       = _registryLen;
       Parameters[sha3("commitVoteLen")]     = _commitVoteLen;
       Parameters[sha3("revealVoteLen")]     = _revealVoteLen;
       Parameters[sha3("dispensationPct")]   = _dispensationPct;
       Parameters[sha3("majority")]          = _majority;
    }

    // called by an applicant to apply (moves them into the application pool on success)
    function apply(string _domain) public {
        bytes32 domainHash = sha3(_domain);
        // must be a new member of the whitelist
        require(whitelist[domainHash].owner == 0);
        // initialize with the current values of all parameters
        initializeSnapshot(domainHash);
        initApplication(domainHash, msg.sender);
        appPool[domainHash].domain = _domain;
    }

    // helper function to apply() and proposeUpdate()
    // initialize general application
    function initApplication(bytes32 _hash, address _applicant) private {
        // applicant must pay the current value of minDeposit
        uint deposit = paramSnapshots[_hash].minDeposit;
        // check to prevent repeat applications
        require(appPool[_hash].owner == 0);
        // check that registry can take sufficient amount of tokens from the applicant
        require(token.allowance(_applicant, this) >= deposit);
        token.transferFrom(_applicant, this, deposit);
        appPool[_hash].challengeTime = now + paramSnapshots[_hash].challengeLen;
        appPool[_hash].owner = _applicant;
    }

    function renew (string _domain) {
        bytes32 domainHash = sha3(_domain);
        // check if no active renewal
        require(hasRenewal(domainHash) == false);
        require(msg.sender == whitelist[domainHash].owner); // checks that you are the owner of the domain
        require(appPool[domainHash].owner == 0); // no double renewal
        uint deposit = get('minDeposit');
        //Check if existing deposit is sufficient
        if (whitelist[domainHash].deposit + whitelist[domainHash].prevDeposit >= deposit){
            // only take from deposit
            if (whitelist[domainHash].deposit >= deposit)
            {
                uint difference = whitelist[domainHash].deposit - deposit;
                whitelist[domainHash].deposit = difference;
            }
            // take whole deposit and part of prevDeposit
            else
            {
                // take all of locked deposit and a portion of unlocked deposit
                uint difference = deposit - whitelist[domainHash].deposit;
                uint difference2 = whitelist[domainHash].prevDeposit - difference;
                whitelist[domainHash].prevDeposit = difference2;
            }
        }
        //if insufficient # of tokens, then must send in the difference
        else {
            uint difference = deposit-(whitelist[domainHash].deposit + whitelist.[domainHash].prevDeposit);
            require(token.allowance(msg.sender, this) >= difference);
            token.transferFrom(msg.sender, this, difference);
            whitelist[domainHash].deposit = 0;
            whitelist[domainHash].prevDeposit = 0;
        }
        //apply
        initializeSnapshot(_domain);
        appPool[domainHash].challengeTime = now + paramSnapshots[_hash].challengeLen;
        appPool[domainHash].owner = msg.sender;
        whitelist[domainHash].renewal = true;
    }

    function claimDeposit(string _domain, uint _amount) public {
        bytes32 domainHash = sha3(_domain);
        require(msg.sender == whitelist[domainHash].owner);
        uint difference = whitelist[domainHash].prevDeposit - _amount;
        require(difference >= 0);
        token.transfer(msg.sender, _amount);
        whitelist[domainHash].prevDeposit = difference;
    }

    // called by domain owner to activate renewal period and allow additional renewals
    function activateRenewal(string _domain) public {
        bytes32 _hash = sha3(_domain);
        if (hasRenewal(_hash) && whitelist[_hash].expTime <= now)
        {
            whitelist[_hash].expTime = whitelist[_hash].nextExpTime;
            whitelist[_hash].prevDeposit += whitelist[_hash].deposit;
            whitelist[_hash].deposit = whitelist[_hash].nextDeposit;
            whitelist[_hash].renewal = false;
        }
    }

    // called by any adtoken holder to challenge an application to the whitelist
    // initialize vote to accept/reject a domain to the registry
    function challengeApplication(string _domain) public returns(pollID) {
        bytes32 domainHash = sha3(_domain);
        challenge(domainHash, msg.sender);
        // start a vote
        uint pollID = callVote(_domain
        ,paramSnapshots[domainHash].majority
        ,paramSnapshots[domainHash].commitVoteLen
        ,paramSnapshots[domainHash].revealVoteLen);
        idToHash[pollID] = domainHash;
        return pollID;
    }

    // helper function to challengeApplication() and challengeProposal()
    function challenge(bytes32 _hash, address _challenger) private {
        // check that registry can take sufficient amount of tokens from the challenger
        uint deposit = paramSnapshots[_hash].minDeposit;
        require(token.allowance(_challenger, this) >= deposit);
        token.transferFrom(_challenger, this, deposit);

        // prevent someone from challenging an unintialized application, rechallenging,
        // or challenging after the challenge period has ended
        require(appPool[_hash].owner != 0);
        require(appPool[_hash].challenged == false);
        require(appPool[_hash].challengeTime > now);

        // update the application's status
        appPool[_hash].challenged = true;
        appPool[_hash].challenger = _challenger;
    }

    // helper function to the challenge() function. Initializes a vote through the voting contract
    // returns a poll id
    function callVote(string _proposalString,
        uint _majority,
        uint _commitVoteLen,
        uint _revealVoteLen
        ) private returns (uint) {
        // event that vote has started
        uint pollID = voting.startPoll( _proposalString, _majority, _commitVoteLen,  _revealVoteLen);
        return pollID;
    }

    // a one-time function for each completed vote
    // if domain won: domain is moved to the whitelist and applicant is rewarded tokens, return true
    // if domain lost: challenger is rewarded tokens, return false
    function processResult(uint _pollID) returns(bool)
    {
        bytes32 domainHash = idToHash[_pollID];
        require(isDomainApp(domainHash));  // processing parameter hash this way is unintended behavior
        require(pollInfo[_pollID].processed == false);
        // ensures the result cannot be processed again
        pollInfo[_pollID].processed = true;

        if (voting.isPassed(_pollID)) {
            // add to registry
            add(domainHash, appPool[domainHash].owner);
            pollInfo[_pollID].claimer = appPool[domainHash].owner;
            // give tokens to applicant based on dist and total tokens
            giveWinnerReward(domainHash, appPool[domainHash].owner);
            // uninitialize application
            delete appPool[domainHash].owner;
            return true;
        }
        else {
            pollInfo[_pollID].claimer = appPool[domainHash].challenger;
            giveWinnerReward(domainHash, appPool[domainHash].challenger);
            token.transfer(appPool[domainHash].challenger, paramSnapshots[domainHash].minDeposit);
            delete appPool[domainHash].owner;
            return false;
        }
    }

    // internal function to give applicant/challenger reward
    // if dispensationPct does not divide minDeposit evenly, gives then the extra token
    function giveWinnerReward(_hash, _address) private {
        uint256 minDeposit = paramSnapshots[_hash].minDeposit;
        uint256 dispensationPct = paramSnapshots[_hash].dispensationPct;
        uint256 rewardTokens = minDeposit * (dispensationPct) / 100;
        if ((minDeposit * dispensationPct) % 100 != 0) {
            rewardTokens++;
        }
        token.transfer(_address, rewardTokens);
    }

    // called by each voter to claim their reward for each completed vote
    function claimReward(uint _pollID, uint _salt) {
        // checks if a voter has claimed tokens
        require(voterInfo[msg.sender][_pollID] == false);
        uint reward = giveTokens(_pollID, _salt, msg.sender);
        // ensures a voter cannot claim tokens again
        token.transfer(msg.sender, reward);
        voterInfo[msg.sender][_pollID] = true;
    }

    // number of tokens person used to vote / total number of tokens for winning side
    // scale using distribution number, give the tokens
    function giveTokens(uint _pollID, uint _salt, address _voter) private returns(uint) {
        bytes32 hash = idToHash[_pollID];
        uint256 minDeposit = paramSnapshots[hash].minDeposit;
        uint256 dispensationPct = paramSnapshots[hash].dispensationPct;
        uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_pollID);
        uint256 voterTokens = voting.getNumPassingTokens(_pollID, _salt, _voter);

        uint256 rewardTokens = minDeposit * (100 - dispensationPct) / 100;
        uint256 numerator = voterTokens * rewardTokens * MULTIPLIER;
        uint256 denominator = totalTokens * MULTIPLIER;
        uint256 remainder = numerator % denominator;

        // save remainder tokens in the form of decimal numbers with 18 places represented
        // as a uint256
        pollInfo[_pollID].remainder += remainder;

        return numerator / denominator;
    }

    function claimExtraReward(uint _pollID) {
        uint256 reward = pollInfo[_pollID].remainder / MULTIPLIER;
        pollInfo[_pollID].remainder = pollInfo[_pollID].remainder - reward * MULTIPLIER;
        token.transfer(pollInfo[_pollID].claimer, reward);
    }

    // called to move an applying domain to the whitelist
    // iff the domain's challenge period has passed without a challenge
    function moveToRegistry(string _domain) public {
        bytes32 domainHash = sha3(_domain);
        require(appPool[domainHash].challengeTime < now);
        require(appPool[domainHash].challenged == false);
        // prevents moving a domain to the registry without ever applying
        require(appPool[domainHash].owner != 0);
        // prevent applicant from moving to registry multiple times
        add(domainHash, appPool[domainHash].owner);
        delete appPool[domainHash].owner;
    }

    // ISSUE WITH OVERLAP

    // private function to add a domain name to the whitelist
    function add(bytes32 _domainHash, address _owner) private {
        uint expiration = paramSnapshots[_domainHash].registryLen;
        if (whitelist[_domainHash].renewal = true)
        {
            whitelist[_domainHash].nextExpTime = whitelist[_domainHash].expTime + expiration;
            whitelist[_domainHash].nextDeposit = paramSnapshots[_domainHash].minDeposit;
        }
        else
        {
            whitelist[_domainHash].expTime = now + expiration;
            whitelist[_domainHash].deposit = paramSnapshots[_domainHash].minDeposit;
        }
        whitelist[_domainHash].owner = _owner;
    }

    /*
     * Helper Functions
     */

    // STATIC

    // returns true if a renewal has been initialized
    function hasRenewal(bytes32 _hash) private constant returns (bool) {
        return whitelist[_hash].renewal;
    }

    //returns true if Application is for domain and not parameter
    function isDomainApp(bytes32 _hash) private constant returns(bool){
        return appPool[_hash].parameter == "";  // checks if param string is initialized
    }

    // checks if a domain name is in the whitelist and unexpired
    function isVerified(string _domain) public constant returns (bool) {
        bytes32 domainHash = sha3(_domain);
        return whitelist[domainHash].expTime > now;
    }

    // DYNAMIC

    // private function to initialize a snapshot of parameters for each application
    function initializeSnapshot(bytes32 _hash) private {
        initializeSnapshotParam(_hash);  // maybe put the two together
        paramSnapshots[_hash].registryLen = get("registryLen");
    }

/*****************************************************************************/

    //called by a user who wishes to change a parameter
    //initializes a proposal to change a parameter
    function proposeUpdate(string _parameter, uint _value) public {
        require(_parameter != "");
        bytes32 parameterHash = sha3(_parameter, _value);
        // initialize application with a with the current values of all parameters
        initializeSnapshotParam(parameterHash);
        initApplication(parameterHash, msg.sender);
        appPool[parameterHash].parameter = _parameter;
        appPool[parameterHash].value = _value;
    }

    //called by user who wishes to reject a proposal
    //initializes a vote to accept/reject the param change proposal
    function challengeProposal(string _parameter, uint _value) public {
        bytes32 parameterHash = sha3(_parameter, _value);
        challenge(parameterHash, msg.sender);
        // start a vote
        uint pollID = callVote(_parameter
        ,paramSnapshots[parameterHash].majority
        ,paramSnapshots[parameterHash].commitVoteLen
        ,paramSnapshots[parameterHash].revealVoteLen);
        idToHash[pollID] = parameterHash;
    }

    // called to change parameter
    // iff the proposal's challenge period has passed without a challenge
    function setParams(string _parameter, uint _value) public {
        bytes32 parameterHash = sha3(_parameter, _value);
        require(appPool[parameterHash].challengeTime < now);
        require(appPool[parameterHash].challenged == false);
        // prevents moving a domain to the registry without ever applying
        require(appPool[parameterHash].owner != 0);
        // prevent applicant from moving to registry multiple times
        Parameters[sha3(_parameter)] = _value;
        delete appPool[parameterHash].owner;
    }

    // a one-time function for each completed vote
    // if proposal won: new parameter value is set, and applicant is rewarded tokens, return true
    // if prospsal lost: challenger is rewarded tokens, return false
    function processProposal(uint _pollID) returns(bool)
    {
        require(pollInfo[_pollID].processed == false);
        bytes32 parameterHash = idToHash[_pollID];
        parameter = appPool[parameterHash].parameter;
        value = appPool[parameterHash].value;
        delete appPool[parameterHash].owner;

        if (voting.isPassed(_pollID)) {
            pollInfo[_pollID].claimer = appPool[parameterHash].owner;
            // setting the value of parameter
            Parameters[sha3(parameter)] = value;
            // give tokens to applicant based on dist and total tokens IMPLEMENT
            giveWinnerReward(parameterHash, appPool[parameterHash].owner);
            token.transfer(appPool[parameterHash].owner, paramSnapshots[parameterHash].minDeposit);
            return true;
        }
        else {
            pollInfo[_pollID].claimer = appPool[parameterHash].challenger;
            // give tokens to challenger based on dist and total tokens
            giveWinnerReward(parameterHash, appPool[parameterHash].challenger);
            token.transfer(appPool[parameterHash].challenger, paramSnapshots[parameterHash].minDeposit);
            return false;
        }
        // ensures the result cannot be processed again
        pollInfo[_pollID].processed = true;
    }

     // private function to initialize a snapshot of parameters for each proposal
     function initializeSnapshotParam(bytes32 _hash) private {
        paramSnapshots[_hash].minDeposit = get("minDeposit");
        paramSnapshots[_hash].challengeLen = get("challengeLen");
        paramSnapshots[_hash].commitVoteLen = get("commitVoteLen");
        paramSnapshots[_hash].revealVoteLen = get("revealVoteLen");
        paramSnapshots[_hash].majority = get("majority");
        paramSnapshots[_hash].dispensationPct = get("dispensationPct");
    }

    // interface for retrieving config parameter from hashmapping
    /// @param _keyword key for hashmap (only useful when keyword matches variable name)
    function get(string _keyword) public constant returns (uint) {
       return Parameters[sha3(_keyword)];
    }

/*****************************************************************************/

    // Helper Functions

}


Use jobExists() modifier for verify() in JobsManager

pragma solidity ^0.4.17;

import "../ManagerProxyTarget.sol";
import "./IJobsManager.sol";
import "./libraries/JobLib.sol";
import "../token/ILivepeerToken.sol";
import "../token/IMinter.sol";
import "../bonding/IBondingManager.sol";
import "../rounds/IRoundsManager.sol";
import "../verification/IVerifiable.sol";
import "../verification/IVerifier.sol";
import "../libraries/MathUtils.sol";

import "zeppelin-solidity/contracts/math/SafeMath.sol";

contract JobsManager is ManagerProxyTarget, IVerifiable, IJobsManager {
    using SafeMath for uint256;

    // % of segments to be verified. 1 / verificationRate == % to be verified
    uint64 public verificationRate;

    // Time after a transcoder calls claimWork() that it has to complete verification of claimed work
    uint256 public verificationPeriod;

    // Time after a claim's verification period during which anyone can slash the transcoder for missing a required verification
    uint256 public slashingPeriod;

    // % of stake slashed for failed verification
    uint256 public failedVerificationSlashAmount;

    // % of stake slashed for missed verification
    uint256 public missedVerificationSlashAmount;

    // % of stake slashed for double claiming a segment
    uint256 public doubleClaimSegmentSlashAmount;

    // % of of slashed amount awarded to finder
    uint256 public finderFee;

    struct Broadcaster {
        uint256 deposit;         // Deposited tokens for jobs
        uint256 withdrawBlock;   // Block at which a deposit can be withdrawn
    }

    // Mapping broadcaster address => broadcaster info
    mapping (address => Broadcaster) public broadcasters;

    // Represents a transcode job
    struct Job {
        uint256 jobId;                        // Unique identifer for job
        string streamId;                      // Unique identifier for stream.
        string transcodingOptions;            // Options used for transcoding
        uint256 maxPricePerSegment;           // Max price (in LPT base units) per segment of a stream
        address broadcasterAddress;           // Address of broadcaster that requestes a transcoding job
        address transcoderAddress;            // Address of transcoder selected for the job
        uint256 creationRound;                // Round that a job is created
        uint256 creationBlock;                // Block that a job is created
        uint256 endBlock;                     // Block at which the job is ended and considered inactive
        Claim[] claims;                       // Claims submitted for this job
        uint256 escrow;                       // Claim fees before verification and slashing periods are complete
    }

    // States of a job
    enum JobStatus { Inactive, Active }

    // Represents a transcode claim
    struct Claim {
        uint256 claimId;                                   // Unique identifier for claim
        uint256[2] segmentRange;                           // Range of segments claimed
        bytes32 claimRoot;                                 // Merkle root of segment transcode proof data
        uint256 claimBlock;                                // Block number that claim was submitted
        uint256 endVerificationBlock;                      // End of verification period for this claim
        uint256 endSlashingBlock;                          // End of slashing period for this claim
        mapping (uint256 => bool) segmentVerifications;    // Mapping segment number => whether segment was submitted for verification
        ClaimStatus status;                                // Status of claim (pending, slashed, complete)
    }

    // States of a transcode claim
    enum ClaimStatus { Pending, Slashed, Complete }

    // Transcode jobs
    mapping (uint256 => Job) public jobs;
    // Number of jobs created. Also used for sequential identifiers
    uint256 public numJobs;

    // Check if sender is Verifier
    modifier onlyVerifier() {
        require(msg.sender == controller.getContract(keccak256("Verifier")));
        _;
    }

    // Check if job exists
    modifier jobExists(uint256 _jobId) {
        require(_jobId < numJobs);
        _;
    }

    // Check if sender provided enough payment for verification
    modifier sufficientPayment() {
        require(msg.value >= verifier().getPrice());
        _;
    }

    function JobsManager(address _controller) public Manager(_controller) {}

    /*
     * @dev Set verification rate. Only callable by the controller owner
     * @param _verificationRate Verification rate such that 1 / verificationRate of segments are challenged
     */
    function setVerificationRate(uint64 _verificationRate) external onlyControllerOwner {
        // verificationRate cannot be 0
        require(_verificationRate > 0);

        verificationRate = _verificationRate;

        ParameterUpdate("verificationRate");
    }

    /*
     * @dev Set verification period. Only callable by the controller owner
     * @param _verificationPeriod Number of blocks to complete verification of claimed work
     */
    function setVerificationPeriod(uint256 _verificationPeriod) external onlyControllerOwner {
        // Verification period + slashing period currently cannot be longer than 256 blocks
        // because contracts can only access the last 256 blocks from
        // the current block
        require(_verificationPeriod + slashingPeriod <= 256);

        verificationPeriod = _verificationPeriod;

        ParameterUpdate("verificationPeriod");
    }

    /*
     * @dev Set slashing period. Only callable by the controller owner
     * @param _slashingPeriod Number of blocks after the verification period to submit slashing proofs
     */
    function setSlashingPeriod(uint256 _slashingPeriod) external onlyControllerOwner {
        // Verification period + slashing period currently cannot be longer than 256 blocks
        // because contracts can only access the last 256 blocks from
        // the current block
        require(verificationPeriod + _slashingPeriod <= 256);

        slashingPeriod = _slashingPeriod;

        ParameterUpdate("slashingPeriod");
    }

    /*
     * @dev Set failed verification slash amount. Only callable by the controller owner
     * @param _failedVerificationSlashAmount % of stake slashed for failed verification
     */
    function setFailedVerificationSlashAmount(uint256 _failedVerificationSlashAmount) external onlyControllerOwner {
        // Must be a valid percentage
        require(MathUtils.validPerc(_failedVerificationSlashAmount));

        failedVerificationSlashAmount = _failedVerificationSlashAmount;

        ParameterUpdate("failedVerificationSlashAmount");
    }

    /*
     * @dev Set missed verification slash amount. Only callable by the controller owner
     * @param _missedVerificationSlashAmount % of stake slashed for missed verification
     */
    function setMissedVerificationSlashAmount(uint256 _missedVerificationSlashAmount) external onlyControllerOwner {
        // Must be a valid percentage
        require(MathUtils.validPerc(_missedVerificationSlashAmount));

        missedVerificationSlashAmount = _missedVerificationSlashAmount;

        ParameterUpdate("missedVerificationSlashAmount");
    }

    /*
     * @dev Set double claim slash amount. Only callable by the controller owner
     * @param _doubleClaimSegmentSlashAmount % of stake slashed for double claiming a segment
     */
    function setDoubleClaimSegmentSlashAmount(uint256 _doubleClaimSegmentSlashAmount) external onlyControllerOwner {
        // Must be a valid percentage
        require(MathUtils.validPerc(_doubleClaimSegmentSlashAmount));

        doubleClaimSegmentSlashAmount = _doubleClaimSegmentSlashAmount;

        ParameterUpdate("doubleClaimSegmentSlashAmount");
    }

    /*
     * @dev Set finder fee. Only callable by the controller owner
     * @param _finderFee % of slashed amount awarded to finder
     */
    function setFinderFee(uint256 _finderFee) external onlyControllerOwner {
        // Must be a valid percentage
        require(MathUtils.validPerc(_finderFee));

        finderFee = _finderFee;
    }

    /*
     * @dev Deposit ETH for jobs
     */
    function deposit() external payable whenSystemNotPaused {
        broadcasters[msg.sender].deposit = broadcasters[msg.sender].deposit.add(msg.value);
        // Transfer ETH for deposit to Minter
        minter().depositETH.value(msg.value)();

        Deposit(msg.sender, msg.value);
    }

    /*
     * @dev Withdraw deposited funds
     */
    function withdraw() external whenSystemNotPaused {
        // Can only withdraw at or after the broadcster's withdraw block
        require(broadcasters[msg.sender].withdrawBlock <= roundsManager().blockNum());

        uint256 amount = broadcasters[msg.sender].deposit;
        delete broadcasters[msg.sender];
        minter().withdrawETH(msg.sender, amount);

        Withdraw(msg.sender);
    }

    /*
     * @dev Submit a transcoding job
     * @param _streamId Unique stream identifier
     * @param _transcodingOptions Output bitrates, formats, encodings
     * @param _maxPricePerSegment Max price (in LPT base units) to pay for transcoding a segment of a stream
     * @param _endBlock Block at which this job becomes inactive
     */
    function job(string _streamId, string _transcodingOptions, uint256 _maxPricePerSegment, uint256 _endBlock)
        external
        whenSystemNotPaused
    {
        uint256 blockNum = roundsManager().blockNum();

        // End block must be in the future
        require(_endBlock > blockNum);

        Job storage job = jobs[numJobs];
        job.jobId = numJobs;
        job.streamId = _streamId;
        job.transcodingOptions = _transcodingOptions;
        job.maxPricePerSegment = _maxPricePerSegment;
        job.broadcasterAddress = msg.sender;
        job.creationRound = roundsManager().currentRound();
        job.creationBlock = blockNum;
        job.endBlock = _endBlock;

        NewJob(
            msg.sender,
            numJobs,
            _streamId,
            _transcodingOptions,
            _maxPricePerSegment,
            blockNum
        );

        // Increment number of created jobs
        numJobs = numJobs.add(1);

        if (_endBlock > broadcasters[msg.sender].withdrawBlock) {
            // Set new withdraw block if job end block is greater than current
            // broadcaster withdraw block
            broadcasters[msg.sender].withdrawBlock = _endBlock;
        }
    }

    /*
     * @dev Submit claim for a range of segments
     * @param _jobId Job identifier
     * @param _segmentRange Range of claimed segments
     * @param _claimRoot Merkle root of transcoded segment proof data for claimed segments
     */
    function claimWork(uint256 _jobId, uint256[2] _segmentRange, bytes32 _claimRoot)
        external
        whenSystemNotPaused
        jobExists(_jobId)
    {
        Job storage job = jobs[_jobId];

        // Job cannot be inactive
        require(jobStatus(_jobId) != JobStatus.Inactive);
        // Segment range must be valid
        require(_segmentRange[1] >= _segmentRange[0]);
        // Caller must be registered transcoder
        require(bondingManager().isRegisteredTranscoder(msg.sender));

        uint256 blockNum = roundsManager().blockNum();

        if (job.transcoderAddress != address(0)) {
            // If transcoder already assigned, check if sender is
            // the assigned transcoder
            require(job.transcoderAddress == msg.sender);
        } else {
            // If transcoder is not already assigned, check if sender should be assigned
            // roundsManager.blockHash() will ensure that the job creation block has been mined and it has not
            // been more than 256 blocks since the creation block
            require(bondingManager().electActiveTranscoder(job.maxPricePerSegment, roundsManager().blockHash(job.creationBlock), job.creationRound) == msg.sender);

            job.transcoderAddress = msg.sender;
        }

        // Move fees from broadcaster deposit to escrow
        uint256 fees = JobLib.calcFees(_segmentRange[1].sub(_segmentRange[0]).add(1), job.transcodingOptions, job.maxPricePerSegment);
        broadcasters[job.broadcasterAddress].deposit = broadcasters[job.broadcasterAddress].deposit.sub(fees);
        job.escrow = job.escrow.add(fees);

        uint256 endVerificationBlock = blockNum.add(verificationPeriod);
        uint256 endSlashingBlock = endVerificationBlock.add(slashingPeriod);

        job.claims.push(
            Claim({
                claimId: job.claims.length,
                segmentRange: _segmentRange,
                claimRoot: _claimRoot,
                claimBlock: blockNum,
                endVerificationBlock: endVerificationBlock,
                endSlashingBlock: endSlashingBlock,
                status: ClaimStatus.Pending
           })
        );

        NewClaim(job.transcoderAddress, _jobId, job.claims.length - 1);
    }

    /*
     * @dev Submit transcode receipt and invoke transcoding verification
     * @param _jobId Job identifier
     * @param _segmentNumber Segment sequence number in stream
     * @param _dataStorageHash Content-addressed storage hash of segment data
     * @param _dataHashes Hash of segment data and hash of transcoded segment data
     * @param _broadcasterSig Broadcaster's signature over segment hash
     * @param _proof Merkle proof for transcode receipt
     */
    function verify(
        uint256 _jobId,
        uint256 _claimId,
        uint256 _segmentNumber,
        string _dataStorageHash,
        bytes32[2] _dataHashes,
        bytes _broadcasterSig,
        bytes _proof
    )
        external
        payable
        whenSystemNotPaused
        sufficientPayment
        jobExists(_jobId)
    {
        Job storage job = jobs[_jobId];
        Claim storage claim = job.claims[_claimId];

        // Job cannot be inactive
        require(jobStatus(_jobId) != JobStatus.Inactive);
        // Sender must be elected transcoder
        require(job.transcoderAddress == msg.sender);

        uint256 challengeBlock = claim.claimBlock + 1;
        // Segment must be eligible for verification
        // roundsManager().blockHash() ensures that the challenge block is within the last 256 blocks from the current block
        require(JobLib.shouldVerifySegment(_segmentNumber, claim.segmentRange, challengeBlock, roundsManager().blockHash(challengeBlock), verificationRate));
        // Segment must be signed by broadcaster
        require(
            JobLib.validateBroadcasterSig(
                job.streamId,
                _segmentNumber,
                _dataHashes[0],
                _broadcasterSig,
                job.broadcasterAddress
            )
        );
        // Receipt must be valid
        require(
            JobLib.validateReceipt(
                job.streamId,
                _segmentNumber,
                _dataHashes[0],
                _dataHashes[1],
                _broadcasterSig,
                _proof,
                claim.claimRoot
           )
        );

        // Mark segment as submitted for verification
        claim.segmentVerifications[_segmentNumber] = true;

        // Invoke transcoding verification. This is async and will result in a callback to receiveVerification() which is implemented by this contract
        invokeVerification(_jobId, _claimId, _segmentNumber, _dataStorageHash, _dataHashes);

        Verify(msg.sender, _jobId, _claimId, _segmentNumber);
    }

    /*
     * @dev Invoke transcoding verification by calling the Verifier contract
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     * @param _segmentNumber Segment sequence number in stream
     * @param _dataStorageHash Content addressable storage hash of segment data
     * @param _dataHashes Hash of segment data and hash of transcoded segment data
     */
    function invokeVerification(
        uint256 _jobId,
        uint256 _claimId,
        uint256 _segmentNumber,
        string _dataStorageHash,
        bytes32[2] _dataHashes
    )
        internal
    {
        IVerifier verifierContract = verifier();

        uint256 price = verifierContract.getPrice();

        // Send payment to verifier if price is greater than zero
        if (price > 0) {
            verifierContract.verify.value(price)(
                _jobId,
                _claimId,
                _segmentNumber,
                jobs[_jobId].transcodingOptions,
                _dataStorageHash,
                _dataHashes
            );
        } else {
            verifierContract.verify(
                _jobId,
                _claimId,
                _segmentNumber,
                jobs[_jobId].transcodingOptions,
                _dataStorageHash,
                _dataHashes
            );
        }
    }

    /*
     * @dev Callback function that receives the results of transcoding verification
     * @param _jobId Job identifier
     * @param _segmentNumber Segment being verified for job
     * @param _result Boolean result of whether verification succeeded or not
     */
    function receiveVerification(uint256 _jobId, uint256 _claimId, uint256 _segmentNumber, bool _result)
        external
        whenSystemNotPaused
        onlyVerifier
    {
        address transcoder = jobs[_jobId].transcoderAddress;

        if (!_result) {
            refundBroadcaster(_jobId);
            // Protocol slashes transcoder for failing verification (no finder)
            bondingManager().slashTranscoder(transcoder, address(0), failedVerificationSlashAmount, 0);

            FailedVerification(transcoder, _jobId, _claimId, _segmentNumber);
        } else {
            PassedVerification(transcoder, _jobId, _claimId, _segmentNumber);
        }
    }

    /*
     * @dev Distribute fees for multiple claims
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     */
    function batchDistributeFees(uint256 _jobId, uint256[] _claimIds)
        external
        whenSystemNotPaused
    {
        for (uint256 i = 0; i < _claimIds.length; i++) {
            distributeFees(_jobId, _claimIds[i]);
        }
    }

    /*
     * @dev Slash transcoder for missing verification
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     * @param _segmentNumber Segment that was not verified
     */
    function missedVerificationSlash(uint256 _jobId, uint256 _claimId, uint256 _segmentNumber)
        external
        whenSystemNotPaused
        jobExists(_jobId)
    {
        Job storage job = jobs[_jobId];
        Claim storage claim = job.claims[_claimId];

        uint256 blockNum = roundsManager().blockNum();
        uint256 challengeBlock = claim.claimBlock + 1;
        // Must be after verification period
        require(blockNum >= claim.endVerificationBlock);
        // Must be before end of slashing period
        require(blockNum < claim.endSlashingBlock);
        // Claim must be pending
        require(claim.status == ClaimStatus.Pending);
        // Segment must be eligible for verification
        // roundsManager().blockHash() ensures that the challenge block is within the last 256 blocks from the current block
        require(JobLib.shouldVerifySegment(_segmentNumber, claim.segmentRange, challengeBlock, roundsManager().blockHash(challengeBlock), verificationRate));
        // Transcoder must have missed verification for the segment
        require(!claim.segmentVerifications[_segmentNumber]);

        refundBroadcaster(_jobId);

        // Slash transcoder and provide finder params
        bondingManager().slashTranscoder(job.transcoderAddress, msg.sender, missedVerificationSlashAmount, finderFee);

        // Set claim as slashed
        claim.status = ClaimStatus.Slashed;
    }

    /*
     * @dev Slash transcoder for claiming a segment twice
     * @param _jobId Job identifier
     * @param _claimId1 Claim 1 identifier
     * @param _claimId2 Claim 2 identifier
     * @param _segmentNumber Segment that was claimed twice
     */
    function doubleClaimSegmentSlash(
        uint256 _jobId,
        uint256 _claimId1,
        uint256 _claimId2,
        uint256 _segmentNumber
    )
        external
        whenSystemNotPaused
        jobExists(_jobId)
    {
        Job storage job = jobs[_jobId];
        Claim storage claim1 = job.claims[_claimId1];
        Claim storage claim2 = job.claims[_claimId2];

        // Claim 1 must not be slashed
        require(claim1.status != ClaimStatus.Slashed);
        // Claim 2 must not be slashed
        require(claim2.status != ClaimStatus.Slashed);
        // Segment must be in claim 1 segment range
        require(_segmentNumber >= claim1.segmentRange[0] && _segmentNumber <= claim1.segmentRange[1]);
        // Segment must be in claim 2 segment range
        require(_segmentNumber >= claim2.segmentRange[0] && _segmentNumber <= claim2.segmentRange[1]);

        // Slash transcoder and provide finder params
        bondingManager().slashTranscoder(job.transcoderAddress, msg.sender, doubleClaimSegmentSlashAmount, finderFee);

        refundBroadcaster(_jobId);

        // Set claim 1 as slashed
        claim1.status = ClaimStatus.Slashed;
        // Set claim 2 as slashed
        claim2.status = ClaimStatus.Slashed;
    }

    /*
     * @dev Distribute fees for a particular claim
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     */
    function distributeFees(uint256 _jobId, uint256 _claimId)
        public
        whenSystemNotPaused
        jobExists(_jobId)
    {
        Job storage job = jobs[_jobId];
        Claim storage claim = job.claims[_claimId];

        // Sender must be elected transcoder for job
        require(job.transcoderAddress == msg.sender);
        // Claim must not be complete
        require(claim.status == ClaimStatus.Pending);
        // Slashing period must be over for claim
        require(claim.endSlashingBlock <= roundsManager().blockNum());

        uint256 fees = JobLib.calcFees(claim.segmentRange[1].sub(claim.segmentRange[0]).add(1), job.transcodingOptions, job.maxPricePerSegment);
        // Deduct fees from escrow
        job.escrow = job.escrow.sub(fees);
        // Add fees to transcoder's fee pool
        bondingManager().updateTranscoderWithFees(msg.sender, fees, job.creationRound);

        // Set claim as complete
        claim.status = ClaimStatus.Complete;

        DistributeFees(msg.sender, _jobId, _claimId, fees);
    }

    /*
     * @dev Compute status of job
     * @param _jobId Job identifier
     */
    function jobStatus(uint256 _jobId) public view returns (JobStatus) {
        if (jobs[_jobId].endBlock <= roundsManager().blockNum()) {
            // A job is inactive if the current block is greater than or equal to the job's end block
            return JobStatus.Inactive;
        } else {
            // A job is active if the current block is less than the job's end block
            return JobStatus.Active;
        }
    }

    /*
     * @dev Return job info
     * @param _jobId Job identifier
     */
    function getJob(
        uint256 _jobId
    )
        public
        view
        returns (string streamId, string transcodingOptions, uint256 maxPricePerSegment, address broadcasterAddress, address transcoderAddress, uint256 creationRound, uint256 creationBlock, uint256 endBlock, uint256 escrow, uint256 totalClaims)
    {
        Job storage job = jobs[_jobId];

        streamId = job.streamId;
        transcodingOptions = job.transcodingOptions;
        maxPricePerSegment = job.maxPricePerSegment;
        broadcasterAddress = job.broadcasterAddress;
        transcoderAddress = job.transcoderAddress;
        creationRound = job.creationRound;
        creationBlock = job.creationBlock;
        endBlock = job.endBlock;
        escrow = job.escrow;
        totalClaims = job.claims.length;
    }

    /*
     * @dev Return claim info
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     */
    function getClaim(
        uint256 _jobId,
        uint256 _claimId
    )
        public
        view
        returns (uint256[2] segmentRange, bytes32 claimRoot, uint256 claimBlock, uint256 endVerificationBlock, uint256 endSlashingBlock, ClaimStatus status)
    {
        Claim storage claim = jobs[_jobId].claims[_claimId];

        segmentRange = claim.segmentRange;
        claimRoot = claim.claimRoot;
        claimBlock = claim.claimBlock;
        endVerificationBlock = claim.endVerificationBlock;
        endSlashingBlock = claim.endSlashingBlock;
        status = claim.status;
    }

    /*
     * @dev Return whether a segment was verified for a claim
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     * @param _segmentNumber Segment number
     */
    function isClaimSegmentVerified(
        uint256 _jobId,
        uint256 _claimId,
        uint256 _segmentNumber
    )
        public
        view
        returns (bool)
    {
        return jobs[_jobId].claims[_claimId].segmentVerifications[_segmentNumber];
    }

    /*
     * @dev Refund broadcaster for a job
     * @param _jobId Job identifier
     */
    function refundBroadcaster(uint256 _jobId) internal {
        Job storage job = jobs[_jobId];

        // Return all escrowed fees for a job
        uint256 fees = job.escrow;
        job.escrow = job.escrow.sub(fees);
        broadcasters[job.broadcasterAddress].deposit = broadcasters[job.broadcasterAddress].deposit.add(fees);
        // Set end block of job to current block - job becomes inactive
        job.endBlock = roundsManager().blockNum();
    }

    /*
     * @dev Returns LivepeerToken
     */
    function livepeerToken() internal view returns (ILivepeerToken) {
        return ILivepeerToken(controller.getContract(keccak256("LivepeerToken")));
    }

    /*
     * @dev Returns Minter
     */
    function minter() internal view returns (IMinter) {
        return IMinter(controller.getContract(keccak256("Minter")));
    }

    /*
     * @dev Returns BondingManager
     */
    function bondingManager() internal view returns (IBondingManager) {
        return IBondingManager(controller.getContract(keccak256("BondingManager")));
    }

    /*
     * @dev Returns RoundsManager
     */
    function roundsManager() internal view returns (IRoundsManager) {
        return IRoundsManager(controller.getContract(keccak256("RoundsManager")));
    }

    /*
     * @dev Returns Verifier
     */
    function verifier() internal view returns (IVerifier) {
        return IVerifier(controller.getContract(keccak256("Verifier")));
    }
}

pragma solidity ^0.4.17;

import "../ManagerProxyTarget.sol";
import "./IJobsManager.sol";
import "./libraries/JobLib.sol";
import "../token/ILivepeerToken.sol";
import "../token/IMinter.sol";
import "../bonding/IBondingManager.sol";
import "../rounds/IRoundsManager.sol";
import "../verification/IVerifiable.sol";
import "../verification/IVerifier.sol";
import "../libraries/MathUtils.sol";

import "zeppelin-solidity/contracts/math/SafeMath.sol";

contract JobsManager is ManagerProxyTarget, IVerifiable, IJobsManager {
    using SafeMath for uint256;

    // % of segments to be verified. 1 / verificationRate == % to be verified
    uint64 public verificationRate;

    // Time after a transcoder calls claimWork() that it has to complete verification of claimed work
    uint256 public verificationPeriod;

    // Time after a claim's verification period during which anyone can slash the transcoder for missing a required verification
    uint256 public slashingPeriod;

    // % of stake slashed for failed verification
    uint256 public failedVerificationSlashAmount;

    // % of stake slashed for missed verification
    uint256 public missedVerificationSlashAmount;

    // % of stake slashed for double claiming a segment
    uint256 public doubleClaimSegmentSlashAmount;

    // % of of slashed amount awarded to finder
    uint256 public finderFee;

    struct Broadcaster {
        uint256 deposit;         // Deposited tokens for jobs
        uint256 withdrawBlock;   // Block at which a deposit can be withdrawn
    }

    // Mapping broadcaster address => broadcaster info
    mapping (address => Broadcaster) public broadcasters;

    // Represents a transcode job
    struct Job {
        uint256 jobId;                        // Unique identifer for job
        string streamId;                      // Unique identifier for stream.
        string transcodingOptions;            // Options used for transcoding
        uint256 maxPricePerSegment;           // Max price (in LPT base units) per segment of a stream
        address broadcasterAddress;           // Address of broadcaster that requestes a transcoding job
        address transcoderAddress;            // Address of transcoder selected for the job
        uint256 creationRound;                // Round that a job is created
        uint256 creationBlock;                // Block that a job is created
        uint256 endBlock;                     // Block at which the job is ended and considered inactive
        Claim[] claims;                       // Claims submitted for this job
        uint256 escrow;                       // Claim fees before verification and slashing periods are complete
    }

    // States of a job
    enum JobStatus { Inactive, Active }

    // Represents a transcode claim
    struct Claim {
        uint256 claimId;                                   // Unique identifier for claim
        uint256[2] segmentRange;                           // Range of segments claimed
        bytes32 claimRoot;                                 // Merkle root of segment transcode proof data
        uint256 claimBlock;                                // Block number that claim was submitted
        uint256 endVerificationBlock;                      // End of verification period for this claim
        uint256 endSlashingBlock;                          // End of slashing period for this claim
        mapping (uint256 => bool) segmentVerifications;    // Mapping segment number => whether segment was submitted for verification
        ClaimStatus status;                                // Status of claim (pending, slashed, complete)
    }

    // States of a transcode claim
    enum ClaimStatus { Pending, Slashed, Complete }

    // Transcode jobs
    mapping (uint256 => Job) public jobs;
    // Number of jobs created. Also used for sequential identifiers
    uint256 public numJobs;

    // Check if sender is Verifier
    modifier onlyVerifier() {
        require(msg.sender == controller.getContract(keccak256("Verifier")));
        _;
    }

    // Check if job exists
    modifier jobExists(uint256 _jobId) {
        require(_jobId < numJobs);
        _;
    }

    // Check if sender provided enough payment for verification
    modifier sufficientPayment() {
        require(msg.value >= verifier().getPrice());
        _;
    }

    function JobsManager(address _controller) public Manager(_controller) {}

    /*
     * @dev Set verification rate. Only callable by the controller owner
     * @param _verificationRate Verification rate such that 1 / verificationRate of segments are challenged
     */
    function setVerificationRate(uint64 _verificationRate) external onlyControllerOwner {
        // verificationRate cannot be 0
        require(_verificationRate > 0);

        verificationRate = _verificationRate;

        ParameterUpdate("verificationRate");
    }

    /*
     * @dev Set verification period. Only callable by the controller owner
     * @param _verificationPeriod Number of blocks to complete verification of claimed work
     */
    function setVerificationPeriod(uint256 _verificationPeriod) external onlyControllerOwner {
        // Verification period + slashing period currently cannot be longer than 256 blocks
        // because contracts can only access the last 256 blocks from
        // the current block
        require(_verificationPeriod + slashingPeriod <= 256);

        verificationPeriod = _verificationPeriod;

        ParameterUpdate("verificationPeriod");
    }

    /*
     * @dev Set slashing period. Only callable by the controller owner
     * @param _slashingPeriod Number of blocks after the verification period to submit slashing proofs
     */
    function setSlashingPeriod(uint256 _slashingPeriod) external onlyControllerOwner {
        // Verification period + slashing period currently cannot be longer than 256 blocks
        // because contracts can only access the last 256 blocks from
        // the current block
        require(verificationPeriod + _slashingPeriod <= 256);

        slashingPeriod = _slashingPeriod;

        ParameterUpdate("slashingPeriod");
    }

    /*
     * @dev Set failed verification slash amount. Only callable by the controller owner
     * @param _failedVerificationSlashAmount % of stake slashed for failed verification
     */
    function setFailedVerificationSlashAmount(uint256 _failedVerificationSlashAmount) external onlyControllerOwner {
        // Must be a valid percentage
        require(MathUtils.validPerc(_failedVerificationSlashAmount));

        failedVerificationSlashAmount = _failedVerificationSlashAmount;

        ParameterUpdate("failedVerificationSlashAmount");
    }

    /*
     * @dev Set missed verification slash amount. Only callable by the controller owner
     * @param _missedVerificationSlashAmount % of stake slashed for missed verification
     */
    function setMissedVerificationSlashAmount(uint256 _missedVerificationSlashAmount) external onlyControllerOwner {
        // Must be a valid percentage
        require(MathUtils.validPerc(_missedVerificationSlashAmount));

        missedVerificationSlashAmount = _missedVerificationSlashAmount;

        ParameterUpdate("missedVerificationSlashAmount");
    }

    /*
     * @dev Set double claim slash amount. Only callable by the controller owner
     * @param _doubleClaimSegmentSlashAmount % of stake slashed for double claiming a segment
     */
    function setDoubleClaimSegmentSlashAmount(uint256 _doubleClaimSegmentSlashAmount) external onlyControllerOwner {
        // Must be a valid percentage
        require(MathUtils.validPerc(_doubleClaimSegmentSlashAmount));

        doubleClaimSegmentSlashAmount = _doubleClaimSegmentSlashAmount;

        ParameterUpdate("doubleClaimSegmentSlashAmount");
    }

    /*
     * @dev Set finder fee. Only callable by the controller owner
     * @param _finderFee % of slashed amount awarded to finder
     */
    function setFinderFee(uint256 _finderFee) external onlyControllerOwner {
        // Must be a valid percentage
        require(MathUtils.validPerc(_finderFee));

        finderFee = _finderFee;
    }

    /*
     * @dev Deposit ETH for jobs
     */
    function deposit() external payable whenSystemNotPaused {
        broadcasters[msg.sender].deposit = broadcasters[msg.sender].deposit.add(msg.value);
        // Transfer ETH for deposit to Minter
        minter().depositETH.value(msg.value)();

        Deposit(msg.sender, msg.value);
    }

    /*
     * @dev Withdraw deposited funds
     */
    function withdraw() external whenSystemNotPaused {
        // Can only withdraw at or after the broadcster's withdraw block
        require(broadcasters[msg.sender].withdrawBlock <= roundsManager().blockNum());

        uint256 amount = broadcasters[msg.sender].deposit;
        delete broadcasters[msg.sender];
        minter().withdrawETH(msg.sender, amount);

        Withdraw(msg.sender);
    }

    /*
     * @dev Submit a transcoding job
     * @param _streamId Unique stream identifier
     * @param _transcodingOptions Output bitrates, formats, encodings
     * @param _maxPricePerSegment Max price (in LPT base units) to pay for transcoding a segment of a stream
     * @param _endBlock Block at which this job becomes inactive
     */
    function job(string _streamId, string _transcodingOptions, uint256 _maxPricePerSegment, uint256 _endBlock)
        external
        whenSystemNotPaused
    {
        uint256 blockNum = roundsManager().blockNum();

        // End block must be in the future
        require(_endBlock > blockNum);

        Job storage job = jobs[numJobs];
        job.jobId = numJobs;
        job.streamId = _streamId;
        job.transcodingOptions = _transcodingOptions;
        job.maxPricePerSegment = _maxPricePerSegment;
        job.broadcasterAddress = msg.sender;
        job.creationRound = roundsManager().currentRound();
        job.creationBlock = blockNum;
        job.endBlock = _endBlock;

        NewJob(
            msg.sender,
            numJobs,
            _streamId,
            _transcodingOptions,
            _maxPricePerSegment,
            blockNum
        );

        // Increment number of created jobs
        numJobs = numJobs.add(1);

        if (_endBlock > broadcasters[msg.sender].withdrawBlock) {
            // Set new withdraw block if job end block is greater than current
            // broadcaster withdraw block
            broadcasters[msg.sender].withdrawBlock = _endBlock;
        }
    }

    /*
     * @dev Submit claim for a range of segments
     * @param _jobId Job identifier
     * @param _segmentRange Range of claimed segments
     * @param _claimRoot Merkle root of transcoded segment proof data for claimed segments
     */
    function claimWork(uint256 _jobId, uint256[2] _segmentRange, bytes32 _claimRoot)
        external
        whenSystemNotPaused
        jobExists(_jobId)
    {
        Job storage job = jobs[_jobId];

        // Job cannot be inactive
        require(jobStatus(_jobId) != JobStatus.Inactive);
        // Segment range must be valid
        require(_segmentRange[1] >= _segmentRange[0]);
        // Caller must be registered transcoder
        require(bondingManager().isRegisteredTranscoder(msg.sender));

        uint256 blockNum = roundsManager().blockNum();

        if (job.transcoderAddress != address(0)) {
            // If transcoder already assigned, check if sender is
            // the assigned transcoder
            require(job.transcoderAddress == msg.sender);
        } else {
            // If transcoder is not already assigned, check if sender should be assigned
            // roundsManager.blockHash() will ensure that the job creation block has been mined and it has not
            // been more than 256 blocks since the creation block
            require(bondingManager().electActiveTranscoder(job.maxPricePerSegment, roundsManager().blockHash(job.creationBlock), job.creationRound) == msg.sender);

            job.transcoderAddress = msg.sender;
        }

        // Move fees from broadcaster deposit to escrow
        uint256 fees = JobLib.calcFees(_segmentRange[1].sub(_segmentRange[0]).add(1), job.transcodingOptions, job.maxPricePerSegment);
        broadcasters[job.broadcasterAddress].deposit = broadcasters[job.broadcasterAddress].deposit.sub(fees);
        job.escrow = job.escrow.add(fees);

        uint256 endVerificationBlock = blockNum.add(verificationPeriod);
        uint256 endSlashingBlock = endVerificationBlock.add(slashingPeriod);

        job.claims.push(
            Claim({
                claimId: job.claims.length,
                segmentRange: _segmentRange,
                claimRoot: _claimRoot,
                claimBlock: blockNum,
                endVerificationBlock: endVerificationBlock,
                endSlashingBlock: endSlashingBlock,
                status: ClaimStatus.Pending
           })
        );

        NewClaim(job.transcoderAddress, _jobId, job.claims.length - 1);
    }

    /*
     * @dev Submit transcode receipt and invoke transcoding verification
     * @param _jobId Job identifier
     * @param _segmentNumber Segment sequence number in stream
     * @param _dataStorageHash Content-addressed storage hash of segment data
     * @param _dataHashes Hash of segment data and hash of transcoded segment data
     * @param _broadcasterSig Broadcaster's signature over segment hash
     * @param _proof Merkle proof for transcode receipt
     */
    function verify(
        uint256 _jobId,
        uint256 _claimId,
        uint256 _segmentNumber,
        string _dataStorageHash,
        bytes32[2] _dataHashes,
        bytes _broadcasterSig,
        bytes _proof
    )
        external
        payable
        whenSystemNotPaused
        sufficientPayment
    {
        require(_jobId < numJobs);

        Job storage job = jobs[_jobId];
        Claim storage claim = job.claims[_claimId];

        // Job cannot be inactive
        require(jobStatus(_jobId) != JobStatus.Inactive);
        // Sender must be elected transcoder
        require(job.transcoderAddress == msg.sender);

        uint256 challengeBlock = claim.claimBlock + 1;
        // Segment must be eligible for verification
        // roundsManager().blockHash() ensures that the challenge block is within the last 256 blocks from the current block
        require(JobLib.shouldVerifySegment(_segmentNumber, claim.segmentRange, challengeBlock, roundsManager().blockHash(challengeBlock), verificationRate));
        // Segment must be signed by broadcaster
        require(
            JobLib.validateBroadcasterSig(
                job.streamId,
                _segmentNumber,
                _dataHashes[0],
                _broadcasterSig,
                job.broadcasterAddress
            )
        );
        // Receipt must be valid
        require(
            JobLib.validateReceipt(
                job.streamId,
                _segmentNumber,
                _dataHashes[0],
                _dataHashes[1],
                _broadcasterSig,
                _proof,
                claim.claimRoot
           )
        );

        // Mark segment as submitted for verification
        claim.segmentVerifications[_segmentNumber] = true;

        // Invoke transcoding verification. This is async and will result in a callback to receiveVerification() which is implemented by this contract
        invokeVerification(_jobId, _claimId, _segmentNumber, _dataStorageHash, _dataHashes);

        Verify(msg.sender, _jobId, _claimId, _segmentNumber);
    }

    /*
     * @dev Invoke transcoding verification by calling the Verifier contract
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     * @param _segmentNumber Segment sequence number in stream
     * @param _dataStorageHash Content addressable storage hash of segment data
     * @param _dataHashes Hash of segment data and hash of transcoded segment data
     */
    function invokeVerification(
        uint256 _jobId,
        uint256 _claimId,
        uint256 _segmentNumber,
        string _dataStorageHash,
        bytes32[2] _dataHashes
    )
        internal
    {
        IVerifier verifierContract = verifier();

        uint256 price = verifierContract.getPrice();

        // Send payment to verifier if price is greater than zero
        if (price > 0) {
            verifierContract.verify.value(price)(
                _jobId,
                _claimId,
                _segmentNumber,
                jobs[_jobId].transcodingOptions,
                _dataStorageHash,
                _dataHashes
            );
        } else {
            verifierContract.verify(
                _jobId,
                _claimId,
                _segmentNumber,
                jobs[_jobId].transcodingOptions,
                _dataStorageHash,
                _dataHashes
            );
        }
    }

    /*
     * @dev Callback function that receives the results of transcoding verification
     * @param _jobId Job identifier
     * @param _segmentNumber Segment being verified for job
     * @param _result Boolean result of whether verification succeeded or not
     */
    function receiveVerification(uint256 _jobId, uint256 _claimId, uint256 _segmentNumber, bool _result)
        external
        whenSystemNotPaused
        onlyVerifier
    {
        address transcoder = jobs[_jobId].transcoderAddress;

        if (!_result) {
            refundBroadcaster(_jobId);
            // Protocol slashes transcoder for failing verification (no finder)
            bondingManager().slashTranscoder(transcoder, address(0), failedVerificationSlashAmount, 0);

            FailedVerification(transcoder, _jobId, _claimId, _segmentNumber);
        } else {
            PassedVerification(transcoder, _jobId, _claimId, _segmentNumber);
        }
    }

    /*
     * @dev Distribute fees for multiple claims
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     */
    function batchDistributeFees(uint256 _jobId, uint256[] _claimIds)
        external
        whenSystemNotPaused
    {
        for (uint256 i = 0; i < _claimIds.length; i++) {
            distributeFees(_jobId, _claimIds[i]);
        }
    }

    /*
     * @dev Slash transcoder for missing verification
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     * @param _segmentNumber Segment that was not verified
     */
    function missedVerificationSlash(uint256 _jobId, uint256 _claimId, uint256 _segmentNumber)
        external
        whenSystemNotPaused
        jobExists(_jobId)
    {
        Job storage job = jobs[_jobId];
        Claim storage claim = job.claims[_claimId];

        uint256 blockNum = roundsManager().blockNum();
        uint256 challengeBlock = claim.claimBlock + 1;
        // Must be after verification period
        require(blockNum >= claim.endVerificationBlock);
        // Must be before end of slashing period
        require(blockNum < claim.endSlashingBlock);
        // Claim must be pending
        require(claim.status == ClaimStatus.Pending);
        // Segment must be eligible for verification
        // roundsManager().blockHash() ensures that the challenge block is within the last 256 blocks from the current block
        require(JobLib.shouldVerifySegment(_segmentNumber, claim.segmentRange, challengeBlock, roundsManager().blockHash(challengeBlock), verificationRate));
        // Transcoder must have missed verification for the segment
        require(!claim.segmentVerifications[_segmentNumber]);

        refundBroadcaster(_jobId);

        // Slash transcoder and provide finder params
        bondingManager().slashTranscoder(job.transcoderAddress, msg.sender, missedVerificationSlashAmount, finderFee);

        // Set claim as slashed
        claim.status = ClaimStatus.Slashed;
    }

    /*
     * @dev Slash transcoder for claiming a segment twice
     * @param _jobId Job identifier
     * @param _claimId1 Claim 1 identifier
     * @param _claimId2 Claim 2 identifier
     * @param _segmentNumber Segment that was claimed twice
     */
    function doubleClaimSegmentSlash(
        uint256 _jobId,
        uint256 _claimId1,
        uint256 _claimId2,
        uint256 _segmentNumber
    )
        external
        whenSystemNotPaused
        jobExists(_jobId)
    {
        Job storage job = jobs[_jobId];
        Claim storage claim1 = job.claims[_claimId1];
        Claim storage claim2 = job.claims[_claimId2];

        // Claim 1 must not be slashed
        require(claim1.status != ClaimStatus.Slashed);
        // Claim 2 must not be slashed
        require(claim2.status != ClaimStatus.Slashed);
        // Segment must be in claim 1 segment range
        require(_segmentNumber >= claim1.segmentRange[0] && _segmentNumber <= claim1.segmentRange[1]);
        // Segment must be in claim 2 segment range
        require(_segmentNumber >= claim2.segmentRange[0] && _segmentNumber <= claim2.segmentRange[1]);

        // Slash transcoder and provide finder params
        bondingManager().slashTranscoder(job.transcoderAddress, msg.sender, doubleClaimSegmentSlashAmount, finderFee);

        refundBroadcaster(_jobId);

        // Set claim 1 as slashed
        claim1.status = ClaimStatus.Slashed;
        // Set claim 2 as slashed
        claim2.status = ClaimStatus.Slashed;
    }

    /*
     * @dev Distribute fees for a particular claim
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     */
    function distributeFees(uint256 _jobId, uint256 _claimId)
        public
        whenSystemNotPaused
        jobExists(_jobId)
    {
        Job storage job = jobs[_jobId];
        Claim storage claim = job.claims[_claimId];

        // Sender must be elected transcoder for job
        require(job.transcoderAddress == msg.sender);
        // Claim must not be complete
        require(claim.status == ClaimStatus.Pending);
        // Slashing period must be over for claim
        require(claim.endSlashingBlock <= roundsManager().blockNum());

        uint256 fees = JobLib.calcFees(claim.segmentRange[1].sub(claim.segmentRange[0]).add(1), job.transcodingOptions, job.maxPricePerSegment);
        // Deduct fees from escrow
        job.escrow = job.escrow.sub(fees);
        // Add fees to transcoder's fee pool
        bondingManager().updateTranscoderWithFees(msg.sender, fees, job.creationRound);

        // Set claim as complete
        claim.status = ClaimStatus.Complete;

        DistributeFees(msg.sender, _jobId, _claimId, fees);
    }

    /*
     * @dev Compute status of job
     * @param _jobId Job identifier
     */
    function jobStatus(uint256 _jobId) public view returns (JobStatus) {
        if (jobs[_jobId].endBlock <= roundsManager().blockNum()) {
            // A job is inactive if the current block is greater than or equal to the job's end block
            return JobStatus.Inactive;
        } else {
            // A job is active if the current block is less than the job's end block
            return JobStatus.Active;
        }
    }

    /*
     * @dev Return job info
     * @param _jobId Job identifier
     */
    function getJob(
        uint256 _jobId
    )
        public
        view
        returns (string streamId, string transcodingOptions, uint256 maxPricePerSegment, address broadcasterAddress, address transcoderAddress, uint256 creationRound, uint256 creationBlock, uint256 endBlock, uint256 escrow, uint256 totalClaims)
    {
        Job storage job = jobs[_jobId];

        streamId = job.streamId;
        transcodingOptions = job.transcodingOptions;
        maxPricePerSegment = job.maxPricePerSegment;
        broadcasterAddress = job.broadcasterAddress;
        transcoderAddress = job.transcoderAddress;
        creationRound = job.creationRound;
        creationBlock = job.creationBlock;
        endBlock = job.endBlock;
        escrow = job.escrow;
        totalClaims = job.claims.length;
    }

    /*
     * @dev Return claim info
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     */
    function getClaim(
        uint256 _jobId,
        uint256 _claimId
    )
        public
        view
        returns (uint256[2] segmentRange, bytes32 claimRoot, uint256 claimBlock, uint256 endVerificationBlock, uint256 endSlashingBlock, ClaimStatus status)
    {
        Claim storage claim = jobs[_jobId].claims[_claimId];

        segmentRange = claim.segmentRange;
        claimRoot = claim.claimRoot;
        claimBlock = claim.claimBlock;
        endVerificationBlock = claim.endVerificationBlock;
        endSlashingBlock = claim.endSlashingBlock;
        status = claim.status;
    }

    /*
     * @dev Return whether a segment was verified for a claim
     * @param _jobId Job identifier
     * @param _claimId Claim identifier
     * @param _segmentNumber Segment number
     */
    function isClaimSegmentVerified(
        uint256 _jobId,
        uint256 _claimId,
        uint256 _segmentNumber
    )
        public
        view
        returns (bool)
    {
        return jobs[_jobId].claims[_claimId].segmentVerifications[_segmentNumber];
    }

    /*
     * @dev Refund broadcaster for a job
     * @param _jobId Job identifier
     */
    function refundBroadcaster(uint256 _jobId) internal {
        Job storage job = jobs[_jobId];

        // Return all escrowed fees for a job
        uint256 fees = job.escrow;
        job.escrow = job.escrow.sub(fees);
        broadcasters[job.broadcasterAddress].deposit = broadcasters[job.broadcasterAddress].deposit.add(fees);
        // Set end block of job to current block - job becomes inactive
        job.endBlock = roundsManager().blockNum();
    }

    /*
     * @dev Returns LivepeerToken
     */
    function livepeerToken() internal view returns (ILivepeerToken) {
        return ILivepeerToken(controller.getContract(keccak256("LivepeerToken")));
    }

    /*
     * @dev Returns Minter
     */
    function minter() internal view returns (IMinter) {
        return IMinter(controller.getContract(keccak256("Minter")));
    }

    /*
     * @dev Returns BondingManager
     */
    function bondingManager() internal view returns (IBondingManager) {
        return IBondingManager(controller.getContract(keccak256("BondingManager")));
    }

    /*
     * @dev Returns RoundsManager
     */
    function roundsManager() internal view returns (IRoundsManager) {
        return IRoundsManager(controller.getContract(keccak256("RoundsManager")));
    }

    /*
     * @dev Returns Verifier
     */
    function verifier() internal view returns (IVerifier) {
        return IVerifier(controller.getContract(keccak256("Verifier")));
    }
}


New contract

New contract

contract NewPoll {

  //defines the poll
  struct Poll {
    address owner;
    string title;
    uint votelimit;
    string options;
    uint deadline;
    bool status;
    uint numVotes;
  }

  bytes32[] public votes;
  Poll public p;

  //initiator function that stores the necessary poll information
  function NewPoll(string _options, string _title, uint _votelimit, uint _deadline) {
    p.owner = msg.sender;
    p.options = _options;
    p.title = _title;
    p.votelimit = _votelimit;
    p.deadline = _deadline;
    p.status = true;
    p.numVotes = 0;
  }

  //function for user vote. input is a string choice
  function vote(bytes32 choice) returns (bool) {
    if (msg.sender != p.owner || p.status != true) {
      return false;
    }
    votes[votes.length++] = choice;
    p.numVotes += 1;
    if (p.votelimit > 0) {
        if (p.numVotes >= p.votelimit) {
          endPoll();
        }
    }
    return true;
  }

  //when time or vote limit is reached, set the poll status to false
  function endPoll() returns (bool) {
    if (msg.sender != p.owner) {
      return false;
    }
    p.status = false;
    return true;
  }
}

contract NewPoll {

  //defines the poll
  struct Poll {
    address owner;
    string title;
    uint votelimit;
    string options;
    uint deadline;
    bool status;
    bytes32[] votes;
  }

  //declares the variables
  uint numVotes = 0;
  Poll public p;

  //initiator function that stores the necessary poll information
  function NewPoll(string _options, string _title, uint _votelimit, uint _deadline) {
    p.owner = msg.sender;
    p.options = _options;
    p.title = _title;
    p.votelimit = _votelimit;
    p.deadline = _deadline;
    p.status = true;
  }

  //function for user vote. input is a string choice
  function vote(bytes32 choice) returns (bool) {
    if (msg.sender != p.owner || p.status != true) {
      return false;
    }
    p.votes[numVotes] = choice;
    numVotes++;
    if (p.votelimit > 0) {
        if (numVotes >= p.votelimit) {
          endPoll();
        }
    }
    return true;
  }

  //when time or vote limit is reached, set the poll status to false
  function endPoll() returns (bool) {
    if (msg.sender != p.owner) {
      return false;
    }
    p.status = false;
    return true;
  }
}