Move adds on total earlier to enable the use of unchecked (#3527)

Co-authored-by: Francisco <4223852eec80914c4c190cdc031e06592b151a67@gmail.com>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (finance/PaymentSplitter.sol)

pragma solidity ^0.8.0;

import "../token/ERC20/utils/SafeERC20.sol";
import "../utils/Address.sol";
import "../utils/Context.sol";

/**
 * @title PaymentSplitter
 * @dev This contract allows to split Ether payments among a group of accounts. The sender does not need to be aware
 * that the Ether will be split in this way, since it is handled transparently by the contract.
 *
 * The split can be in equal parts or in any other arbitrary proportion. The way this is specified is by assigning each
 * account to a number of shares. Of all the Ether that this contract receives, each account will then be able to claim
 * an amount proportional to the percentage of total shares they were assigned. The distribution of shares is set at the
 * time of contract deployment and can't be updated thereafter.
 *
 * `PaymentSplitter` follows a _pull payment_ model. This means that payments are not automatically forwarded to the
 * accounts but kept in this contract, and the actual transfer is triggered as a separate step by calling the {release}
 * function.
 *
 * NOTE: This contract assumes that ERC20 tokens will behave similarly to native tokens (Ether). Rebasing tokens, and
 * tokens that apply fees during transfers, are likely to not be supported as expected. If in doubt, we encourage you
 * to run tests before sending real value to this contract.
 */
contract PaymentSplitter is Context {
    event PayeeAdded(address account, uint256 shares);
    event PaymentReleased(address to, uint256 amount);
    event ERC20PaymentReleased(IERC20 indexed token, address to, uint256 amount);
    event PaymentReceived(address from, uint256 amount);

    uint256 private _totalShares;
    uint256 private _totalReleased;

    mapping(address => uint256) private _shares;
    mapping(address => uint256) private _released;
    address[] private _payees;

    mapping(IERC20 => uint256) private _erc20TotalReleased;
    mapping(IERC20 => mapping(address => uint256)) private _erc20Released;

    /**
     * @dev Creates an instance of `PaymentSplitter` where each account in `payees` is assigned the number of shares at
     * the matching position in the `shares` array.
     *
     * All addresses in `payees` must be non-zero. Both arrays must have the same non-zero length, and there must be no
     * duplicates in `payees`.
     */
    constructor(address[] memory payees, uint256[] memory shares_) payable {
        require(payees.length == shares_.length, "PaymentSplitter: payees and shares length mismatch");
        require(payees.length > 0, "PaymentSplitter: no payees");

        for (uint256 i = 0; i < payees.length; i++) {
            _addPayee(payees[i], shares_[i]);
        }
    }

    /**
     * @dev The Ether received will be logged with {PaymentReceived} events. Note that these events are not fully
     * reliable: it's possible for a contract to receive Ether without triggering this function. This only affects the
     * reliability of the events, and not the actual splitting of Ether.
     *
     * To learn more about this see the Solidity documentation for
     * https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function[fallback
     * functions].
     */
    receive() external payable virtual {
        emit PaymentReceived(_msgSender(), msg.value);
    }

    /**
     * @dev Getter for the total shares held by payees.
     */
    function totalShares() public view returns (uint256) {
        return _totalShares;
    }

    /**
     * @dev Getter for the total amount of Ether already released.
     */
    function totalReleased() public view returns (uint256) {
        return _totalReleased;
    }

    /**
     * @dev Getter for the total amount of `token` already released. `token` should be the address of an IERC20
     * contract.
     */
    function totalReleased(IERC20 token) public view returns (uint256) {
        return _erc20TotalReleased[token];
    }

    /**
     * @dev Getter for the amount of shares held by an account.
     */
    function shares(address account) public view returns (uint256) {
        return _shares[account];
    }

    /**
     * @dev Getter for the amount of Ether already released to a payee.
     */
    function released(address account) public view returns (uint256) {
        return _released[account];
    }

    /**
     * @dev Getter for the amount of `token` tokens already released to a payee. `token` should be the address of an
     * IERC20 contract.
     */
    function released(IERC20 token, address account) public view returns (uint256) {
        return _erc20Released[token][account];
    }

    /**
     * @dev Getter for the address of the payee number `index`.
     */
    function payee(uint256 index) public view returns (address) {
        return _payees[index];
    }

    /**
     * @dev Getter for the amount of payee's releasable Ether.
     */
    function releasable(address account) public view returns (uint256) {
        uint256 totalReceived = address(this).balance + totalReleased();
        return _pendingPayment(account, totalReceived, released(account));
    }

    /**
     * @dev Getter for the amount of payee's releasable `token` tokens. `token` should be the address of an
     * IERC20 contract.
     */
    function releasable(IERC20 token, address account) public view returns (uint256) {
        uint256 totalReceived = token.balanceOf(address(this)) + totalReleased(token);
        return _pendingPayment(account, totalReceived, released(token, account));
    }

    /**
     * @dev Triggers a transfer to `account` of the amount of Ether they are owed, according to their percentage of the
     * total shares and their previous withdrawals.
     */
    function release(address payable account) public virtual {
        require(_shares[account] > 0, "PaymentSplitter: account has no shares");

        uint256 payment = releasable(account);

        require(payment != 0, "PaymentSplitter: account is not due payment");

        // _totalReleased is the sum of all values in _released.
        // If "_totalReleased += payment" does not overflow, then "_released[account] += payment" cannot overflow.
        _totalReleased += payment;
        unchecked {
            _released[account] += payment;
        }

        Address.sendValue(account, payment);
        emit PaymentReleased(account, payment);
    }

    /**
     * @dev Triggers a transfer to `account` of the amount of `token` tokens they are owed, according to their
     * percentage of the total shares and their previous withdrawals. `token` must be the address of an IERC20
     * contract.
     */
    function release(IERC20 token, address account) public virtual {
        require(_shares[account] > 0, "PaymentSplitter: account has no shares");

        uint256 payment = releasable(token, account);

        require(payment != 0, "PaymentSplitter: account is not due payment");

        // _erc20TotalReleased[token] is the sum of all values in _erc20Released[token].
        // If "_erc20TotalReleased[token] += payment" does not overflow, then "_erc20Released[token][account] += payment"
        // cannot overflow.
        _erc20TotalReleased[token] += payment;
        unchecked {
            _erc20Released[token][account] += payment;
        }

        SafeERC20.safeTransfer(token, account, payment);
        emit ERC20PaymentReleased(token, account, payment);
    }

    /**
     * @dev internal logic for computing the pending payment of an `account` given the token historical balances and
     * already released amounts.
     */
    function _pendingPayment(
        address account,
        uint256 totalReceived,
        uint256 alreadyReleased
    ) private view returns (uint256) {
        return (totalReceived * _shares[account]) / _totalShares - alreadyReleased;
    }

    /**
     * @dev Add a new payee to the contract.
     * @param account The address of the payee to add.
     * @param shares_ The number of shares owned by the payee.
     */
    function _addPayee(address account, uint256 shares_) private {
        require(account != address(0), "PaymentSplitter: account is the zero address");
        require(shares_ > 0, "PaymentSplitter: shares are 0");
        require(_shares[account] == 0, "PaymentSplitter: account already has shares");

        _payees.push(account);
        _shares[account] = shares_;
        _totalShares = _totalShares + shares_;
        emit PayeeAdded(account, shares_);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (finance/PaymentSplitter.sol)

pragma solidity ^0.8.0;

import "../token/ERC20/utils/SafeERC20.sol";
import "../utils/Address.sol";
import "../utils/Context.sol";

/**
 * @title PaymentSplitter
 * @dev This contract allows to split Ether payments among a group of accounts. The sender does not need to be aware
 * that the Ether will be split in this way, since it is handled transparently by the contract.
 *
 * The split can be in equal parts or in any other arbitrary proportion. The way this is specified is by assigning each
 * account to a number of shares. Of all the Ether that this contract receives, each account will then be able to claim
 * an amount proportional to the percentage of total shares they were assigned. The distribution of shares is set at the
 * time of contract deployment and can't be updated thereafter.
 *
 * `PaymentSplitter` follows a _pull payment_ model. This means that payments are not automatically forwarded to the
 * accounts but kept in this contract, and the actual transfer is triggered as a separate step by calling the {release}
 * function.
 *
 * NOTE: This contract assumes that ERC20 tokens will behave similarly to native tokens (Ether). Rebasing tokens, and
 * tokens that apply fees during transfers, are likely to not be supported as expected. If in doubt, we encourage you
 * to run tests before sending real value to this contract.
 */
contract PaymentSplitter is Context {
    event PayeeAdded(address account, uint256 shares);
    event PaymentReleased(address to, uint256 amount);
    event ERC20PaymentReleased(IERC20 indexed token, address to, uint256 amount);
    event PaymentReceived(address from, uint256 amount);

    uint256 private _totalShares;
    uint256 private _totalReleased;

    mapping(address => uint256) private _shares;
    mapping(address => uint256) private _released;
    address[] private _payees;

    mapping(IERC20 => uint256) private _erc20TotalReleased;
    mapping(IERC20 => mapping(address => uint256)) private _erc20Released;

    /**
     * @dev Creates an instance of `PaymentSplitter` where each account in `payees` is assigned the number of shares at
     * the matching position in the `shares` array.
     *
     * All addresses in `payees` must be non-zero. Both arrays must have the same non-zero length, and there must be no
     * duplicates in `payees`.
     */
    constructor(address[] memory payees, uint256[] memory shares_) payable {
        require(payees.length == shares_.length, "PaymentSplitter: payees and shares length mismatch");
        require(payees.length > 0, "PaymentSplitter: no payees");

        for (uint256 i = 0; i < payees.length; i++) {
            _addPayee(payees[i], shares_[i]);
        }
    }

    /**
     * @dev The Ether received will be logged with {PaymentReceived} events. Note that these events are not fully
     * reliable: it's possible for a contract to receive Ether without triggering this function. This only affects the
     * reliability of the events, and not the actual splitting of Ether.
     *
     * To learn more about this see the Solidity documentation for
     * https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function[fallback
     * functions].
     */
    receive() external payable virtual {
        emit PaymentReceived(_msgSender(), msg.value);
    }

    /**
     * @dev Getter for the total shares held by payees.
     */
    function totalShares() public view returns (uint256) {
        return _totalShares;
    }

    /**
     * @dev Getter for the total amount of Ether already released.
     */
    function totalReleased() public view returns (uint256) {
        return _totalReleased;
    }

    /**
     * @dev Getter for the total amount of `token` already released. `token` should be the address of an IERC20
     * contract.
     */
    function totalReleased(IERC20 token) public view returns (uint256) {
        return _erc20TotalReleased[token];
    }

    /**
     * @dev Getter for the amount of shares held by an account.
     */
    function shares(address account) public view returns (uint256) {
        return _shares[account];
    }

    /**
     * @dev Getter for the amount of Ether already released to a payee.
     */
    function released(address account) public view returns (uint256) {
        return _released[account];
    }

    /**
     * @dev Getter for the amount of `token` tokens already released to a payee. `token` should be the address of an
     * IERC20 contract.
     */
    function released(IERC20 token, address account) public view returns (uint256) {
        return _erc20Released[token][account];
    }

    /**
     * @dev Getter for the address of the payee number `index`.
     */
    function payee(uint256 index) public view returns (address) {
        return _payees[index];
    }

    /**
     * @dev Getter for the amount of payee's releasable Ether.
     */
    function releasable(address account) public view returns (uint256) {
        uint256 totalReceived = address(this).balance + totalReleased();
        return _pendingPayment(account, totalReceived, released(account));
    }

    /**
     * @dev Getter for the amount of payee's releasable `token` tokens. `token` should be the address of an
     * IERC20 contract.
     */
    function releasable(IERC20 token, address account) public view returns (uint256) {
        uint256 totalReceived = token.balanceOf(address(this)) + totalReleased(token);
        return _pendingPayment(account, totalReceived, released(token, account));
    }

    /**
     * @dev Triggers a transfer to `account` of the amount of Ether they are owed, according to their percentage of the
     * total shares and their previous withdrawals.
     */
    function release(address payable account) public virtual {
        require(_shares[account] > 0, "PaymentSplitter: account has no shares");

        uint256 payment = releasable(account);

        require(payment != 0, "PaymentSplitter: account is not due payment");

        _released[account] += payment;
        _totalReleased += payment;

        Address.sendValue(account, payment);
        emit PaymentReleased(account, payment);
    }

    /**
     * @dev Triggers a transfer to `account` of the amount of `token` tokens they are owed, according to their
     * percentage of the total shares and their previous withdrawals. `token` must be the address of an IERC20
     * contract.
     */
    function release(IERC20 token, address account) public virtual {
        require(_shares[account] > 0, "PaymentSplitter: account has no shares");

        uint256 payment = releasable(token, account);

        require(payment != 0, "PaymentSplitter: account is not due payment");

        _erc20Released[token][account] += payment;
        _erc20TotalReleased[token] += payment;

        SafeERC20.safeTransfer(token, account, payment);
        emit ERC20PaymentReleased(token, account, payment);
    }

    /**
     * @dev internal logic for computing the pending payment of an `account` given the token historical balances and
     * already released amounts.
     */
    function _pendingPayment(
        address account,
        uint256 totalReceived,
        uint256 alreadyReleased
    ) private view returns (uint256) {
        return (totalReceived * _shares[account]) / _totalShares - alreadyReleased;
    }

    /**
     * @dev Add a new payee to the contract.
     * @param account The address of the payee to add.
     * @param shares_ The number of shares owned by the payee.
     */
    function _addPayee(address account, uint256 shares_) private {
        require(account != address(0), "PaymentSplitter: account is the zero address");
        require(shares_ > 0, "PaymentSplitter: shares are 0");
        require(_shares[account] == 0, "PaymentSplitter: account already has shares");

        _payees.push(account);
        _shares[account] = shares_;
        _totalShares = _totalShares + shares_;
        emit PayeeAdded(account, shares_);
    }
}


fix import path

fix import path

pragma solidity 0.4.24;

import "./RoleCreator.sol";
import "../../interaction/interface/IAuthorization.sol";
import "../lib/ContractCheck.sol";
import "../lib/AddressArray.sol";
import "../../interaction/interface/IRoleAuth.sol";

/// @title Authorization about role and account
/// @author ["Cryptape Technologies <contact@cryptape.com>"]
/// @notice The address: 0xffffffffffffffffffffffffffffffffff02000d
///         The interface can be called: Only query type
contract RoleAuth is IRoleAuth, ReservedAddrPublic {

    IAuthorization auth = IAuthorization(authorizationAddr);

    mapping(address => address[]) internal accounts;
    mapping(address => address[]) internal roles;

    event RoleSetted(address indexed _account, address indexed _role);
    event RoleCanceled(address indexed _account, address indexed _role);
    event RoleCleared(address indexed _account);

    modifier onlyRoleManagement {
        require(roleManagementAddr == msg.sender, "permission denied.");
        _;
    }

    /// @notice Set the role to the account
    /// @param _account The account to be setted
    /// @param _role The role to be setted
    /// @return true if successed, otherwise false
    function setRole(address _account, address _role)
        external
        onlyRoleManagement
        returns (bool)
    {

        if (!AddressArray.exist(_role, roles[_account])) {
            roles[_account].push(_role);
            // Set role permissions to account.
            require(_setRolePermissions(_account, _role), "setRolePermissions failed.");
        }
        if (!AddressArray.exist(_account, accounts[_role]))
            accounts[_role].push(_account);

        emit RoleSetted(_account, _role);
        return true;
    }

    /// @notice Cancel the account's role
    /// @param _account The account to be canceled
    /// @param _role The role to be canceled
    /// @return true if successed, otherwise false
    function cancelRole(address _account, address _role)
        external
        onlyRoleManagement
        returns (bool)
    {
        return _cancelRole(_account, _role);
    }

    /// @notice Clear all the accounts that have the role
    /// @param _role The role to be canceled
    /// @return true if successed, otherwise false
    function clearAuthOfRole(address _role)
        external
        onlyRoleManagement
        returns (bool)
    {
        for (uint i = 0; i < accounts[_role].length; i++)
            require(
                _cancelRole(accounts[_role][i], _role),
                "cancelRole failed."
            );

        return true;
    }

    /// @notice Set all the accounts that have the permissions
    /// @param _role The role to be canceled
    /// @return true if successed, otherwise false
    function setPermissionsOfRole(address _role, address[] _permissions)
        external
        onlyRoleManagement
        returns (bool)
    {
        for (uint i = 0; i < accounts[_role].length; i++)
            require(
                _setPermissions(accounts[_role][i], _permissions),
                "setPermissions failed."
            );

        return true;
    }

    /// @notice Cancel all the accounts that have the permissions
    /// @param _role The role to be canceled
    /// @return true if successed, otherwise false
    function cancelPermissionsOfRole(address _role, address[] _permissions)
        external
        onlyRoleManagement
        returns (bool)
    {
        for (uint i = 0; i < accounts[_role].length; i++)
            require(
                _cancelPermissions(accounts[_role][i], _permissions),
                "cancelPermissions failed."
            );

        return true;
    }

    /// @notice Clear the account's role
    /// @param _account The account to be cleared
    /// @return true if successed, otherwise false
    function clearRole(address _account)
        external
        onlyRoleManagement
        returns (bool)
    {
        // Clear account and roles
        for (uint i = 0; i < roles[_account].length; i++) {
            // Clear account auth
            require(
                _cancelRolePermissions(_account, roles[_account][i]),
                "cancelRolePermissions failed."
            );
            // Clear _account in all roles array.
            assert(
                AddressArray.remove(_account, accounts[roles[_account][i]])
            );
        }

        // Clear all roles associate with _account
        delete roles[_account];
        emit RoleCleared(_account);

        return true;
    }

    /// @notice Query the roles of the account
    /// @param _account The account to be queried
    /// @return The roles of the account
    function queryRoles(address _account)
        public
        view
        returns (address[])
    {
        return roles[_account];
    }

    /// @notice Query the accounts that have the role
    /// @param _role The role to be queried
    /// @return The accounts that have the role
    function queryAccounts(address _role)
        public
        view
        returns (address[])
    {
        return accounts[_role];
    }

    /// @notice Private: cancelRole
    function _cancelRole(address _account, address _role)
        private
        returns (bool)
    {
        assert(AddressArray.remove(_account, accounts[_role]));
        assert(AddressArray.remove(_role, roles[_account]));

        // Cancel role permissions of account.
        require(
            _cancelRolePermissions(_account, _role),
            "cancelRolePermissions failed."
        );

        emit RoleCanceled(_account, _role);
        return true;
    }

    /// @notice Private: cancel role of account
    function _cancelRolePermissions(address _account, address _role)
        private
        returns (bool)
    {
        address[] memory permissions = _queryPermissions(_role);
        require(
            _cancelPermissions(_account, permissions),
            "cancelPermissions failed."
        );
        return true;
    }

    /// @notice Private: cancel permissions of account
    function _cancelPermissions(address _account, address[] _permissions)
        private
        returns (bool)
    {
        for (uint i = 0; i<_permissions.length; i++) {
            // Cancel this permission when account has not it in any of his other roles
            if (!_hasPermission(_account, _permissions[i]))
                require(auth.cancelAuth(_account, _permissions[i]), "cancelAuth failed.");
        }

        return true;
    }

    /// @notice Private: account has permission in one of his roles
    function _hasPermission(address _account, address _permission)
        private
        view
        returns (bool)
    {
        for (uint i = 0; i < roles[_account].length; i++) {
            Role roleContract = Role(roles[_account][i]);
            if (roleContract.inPermissions(_permission))
                return true;
        }
    }
    /// @notice Private: set all role permissions of account
    function _setRolePermissions(address _account, address _role)
        private
        returns (bool)
    {
        address[] memory permissions = _queryPermissions(_role);
        require(
            _setPermissions(_account, permissions),
            "setPermissions failed."
        );
        return true;
    }

    /// @notice Private: set permissions of account
    function _setPermissions(address _account, address[] _permissions)
        private
        returns (bool)
    {
        for (uint i = 0; i<_permissions.length; i++)
            require(
                auth.setAuth(_account, _permissions[i]),
                "setAuth failed."
            );

        return true;
    }

    /// @notice Private: Query the permissions of the role
    function _queryPermissions(address _role)
        private
        view
        returns (address[] permissions)
    {
        require(
            ContractCheck.isContract(_role),
            "not a valid contract address."
        );
        Role roleContract = Role(_role);
        permissions = roleContract.queryPermissions();
    }
}

pragma solidity 0.4.24;

import "./RoleCreator.sol";
import "../../interaction/interface/IAuthorization.sol";
import "../lib/ContractCheck.sol";
import "../lib/AddressArray.sol";
import "../interaction/interface/IRoleAuth.sol";

/// @title Authorization about role and account
/// @author ["Cryptape Technologies <contact@cryptape.com>"]
/// @notice The address: 0xffffffffffffffffffffffffffffffffff02000d
///         The interface can be called: Only query type
contract RoleAuth is IRoleAuth, ReservedAddrPublic {

    IAuthorization auth = IAuthorization(authorizationAddr);

    mapping(address => address[]) internal accounts;
    mapping(address => address[]) internal roles;

    event RoleSetted(address indexed _account, address indexed _role);
    event RoleCanceled(address indexed _account, address indexed _role);
    event RoleCleared(address indexed _account);

    modifier onlyRoleManagement {
        require(roleManagementAddr == msg.sender, "permission denied.");
        _;
    }

    /// @notice Set the role to the account
    /// @param _account The account to be setted
    /// @param _role The role to be setted
    /// @return true if successed, otherwise false
    function setRole(address _account, address _role)
        external
        onlyRoleManagement
        returns (bool)
    {

        if (!AddressArray.exist(_role, roles[_account])) {
            roles[_account].push(_role);
            // Set role permissions to account.
            require(_setRolePermissions(_account, _role), "setRolePermissions failed.");
        }
        if (!AddressArray.exist(_account, accounts[_role]))
            accounts[_role].push(_account);

        emit RoleSetted(_account, _role);
        return true;
    }

    /// @notice Cancel the account's role
    /// @param _account The account to be canceled
    /// @param _role The role to be canceled
    /// @return true if successed, otherwise false
    function cancelRole(address _account, address _role)
        external
        onlyRoleManagement
        returns (bool)
    {
        return _cancelRole(_account, _role);
    }

    /// @notice Clear all the accounts that have the role
    /// @param _role The role to be canceled
    /// @return true if successed, otherwise false
    function clearAuthOfRole(address _role)
        external
        onlyRoleManagement
        returns (bool)
    {
        for (uint i = 0; i < accounts[_role].length; i++)
            require(
                _cancelRole(accounts[_role][i], _role),
                "cancelRole failed."
            );

        return true;
    }

    /// @notice Set all the accounts that have the permissions
    /// @param _role The role to be canceled
    /// @return true if successed, otherwise false
    function setPermissionsOfRole(address _role, address[] _permissions)
        external
        onlyRoleManagement
        returns (bool)
    {
        for (uint i = 0; i < accounts[_role].length; i++)
            require(
                _setPermissions(accounts[_role][i], _permissions),
                "setPermissions failed."
            );

        return true;
    }

    /// @notice Cancel all the accounts that have the permissions
    /// @param _role The role to be canceled
    /// @return true if successed, otherwise false
    function cancelPermissionsOfRole(address _role, address[] _permissions)
        external
        onlyRoleManagement
        returns (bool)
    {
        for (uint i = 0; i < accounts[_role].length; i++)
            require(
                _cancelPermissions(accounts[_role][i], _permissions),
                "cancelPermissions failed."
            );

        return true;
    }

    /// @notice Clear the account's role
    /// @param _account The account to be cleared
    /// @return true if successed, otherwise false
    function clearRole(address _account)
        external
        onlyRoleManagement
        returns (bool)
    {
        // Clear account and roles
        for (uint i = 0; i < roles[_account].length; i++) {
            // Clear account auth
            require(
                _cancelRolePermissions(_account, roles[_account][i]),
                "cancelRolePermissions failed."
            );
            // Clear _account in all roles array.
            assert(
                AddressArray.remove(_account, accounts[roles[_account][i]])
            );
        }

        // Clear all roles associate with _account
        delete roles[_account];
        emit RoleCleared(_account);

        return true;
    }

    /// @notice Query the roles of the account
    /// @param _account The account to be queried
    /// @return The roles of the account
    function queryRoles(address _account)
        public
        view
        returns (address[])
    {
        return roles[_account];
    }

    /// @notice Query the accounts that have the role
    /// @param _role The role to be queried
    /// @return The accounts that have the role
    function queryAccounts(address _role)
        public
        view
        returns (address[])
    {
        return accounts[_role];
    }

    /// @notice Private: cancelRole
    function _cancelRole(address _account, address _role)
        private
        returns (bool)
    {
        assert(AddressArray.remove(_account, accounts[_role]));
        assert(AddressArray.remove(_role, roles[_account]));

        // Cancel role permissions of account.
        require(
            _cancelRolePermissions(_account, _role),
            "cancelRolePermissions failed."
        );

        emit RoleCanceled(_account, _role);
        return true;
    }

    /// @notice Private: cancel role of account
    function _cancelRolePermissions(address _account, address _role)
        private
        returns (bool)
    {
        address[] memory permissions = _queryPermissions(_role);
        require(
            _cancelPermissions(_account, permissions),
            "cancelPermissions failed."
        );
        return true;
    }

    /// @notice Private: cancel permissions of account
    function _cancelPermissions(address _account, address[] _permissions)
        private
        returns (bool)
    {
        for (uint i = 0; i<_permissions.length; i++) {
            // Cancel this permission when account has not it in any of his other roles
            if (!_hasPermission(_account, _permissions[i]))
                require(auth.cancelAuth(_account, _permissions[i]), "cancelAuth failed.");
        }

        return true;
    }

    /// @notice Private: account has permission in one of his roles
    function _hasPermission(address _account, address _permission)
        private
        view
        returns (bool)
    {
        for (uint i = 0; i < roles[_account].length; i++) {
            Role roleContract = Role(roles[_account][i]);
            if (roleContract.inPermissions(_permission))
                return true;
        }
    }
    /// @notice Private: set all role permissions of account
    function _setRolePermissions(address _account, address _role)
        private
        returns (bool)
    {
        address[] memory permissions = _queryPermissions(_role);
        require(
            _setPermissions(_account, permissions),
            "setPermissions failed."
        );
        return true;
    }

    /// @notice Private: set permissions of account
    function _setPermissions(address _account, address[] _permissions)
        private
        returns (bool)
    {
        for (uint i = 0; i<_permissions.length; i++)
            require(
                auth.setAuth(_account, _permissions[i]),
                "setAuth failed."
            );

        return true;
    }

    /// @notice Private: Query the permissions of the role
    function _queryPermissions(address _role)
        private
        view
        returns (address[] permissions)
    {
        require(
            ContractCheck.isContract(_role),
            "not a valid contract address."
        );
        Role roleContract = Role(_role);
        permissions = roleContract.queryPermissions();
    }
}


fixed wrong call order in Ownable.transferOwnership

pragma solidity ^0.4.11;

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
  address public owner;

  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  function Ownable() {
    owner = msg.sender;
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) onlyOwner {
    require(newOwner != address(0));
    OwnershipTransferred(owner, newOwner);
    owner = newOwner;
  }

}

pragma solidity ^0.4.11;

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
  address public owner;

  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  function Ownable() {
    owner = msg.sender;
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) onlyOwner {
    require(newOwner != address(0));
    owner = newOwner;
    OwnershipTransferred(owner, newOwner);
  }

}


TicTacToeRules.sol is almost done

TicTacToeRules.sol is almost done

Only thing left to do is cover the exposures

import "Rules.sol";
import "TicTacToeAdjudicator.sol";

/* Grid is as follows:
 *  0 | 1 | 2
 *  ---------
 *  3 | 4 | 5
 *  ---------
 *  6 | 7 | 8
 */
contract TicTacToeRules is Rules {

    constant uint NONE = 0;
    constant uint X = 1;
    constant uint O = 4;

    address addressX;
    address addressO;
    uint timeout;

    function TicTacToeRules(address _addressX, address _addressO, uint _timeout) {
        addressX = _addressX;
        addressO = _addressO;
        timeout = _timeout;
    }

    function createAdjudicator() internal returns (Adjudicator adjudicator) {
        adjudicator = new TicTacToeAdjudicator(addressX, addressO, timeout);
        delete addressX;
        delete addressO;
        delete timeout;
    }

    function gridToIndex(uint x, uint y) constant internal returns (uint) {
        return x + GRID_SIZE*y;
    }

    function sendState(
        bytes state,
        uint nonce,
        uint8 v1,
        bytes32 r1,
        bytes32 s1,
        uint8 v2,
        bytes32 r2,
        bytes32 s2
    ) external returns (bool) {
        uint8[] v = new uint8[](2);
        bytes32[] r = new bytes32[](2);
        bytes32[] s = new bytes32[](2);

        v[0] = v1;
        v[1] = v2;
        r[0] = r1;
        r[1] = r2;
        s[0] = s1;
        s[1] = s2;

        return adjudicator.close(2, state, nonce, v, r, s);
    }

    function sendBoard(
        bytes9 board,
        uint nonce,
        uint8 v1,
        bytes32 r1,
        bytes32 s1,
        uint8 v2,
        bytes32 r2,
        bytes32 s2
    ) external returns (bool) {
        uint x;
        uint y;
        uint8[] v = new uint8[](2);
        bytes32[] r = new bytes32[](2);
        bytes32[] s = new bytes32[](2);

        v[0] = v1;
        v[1] = v2;
        r[0] = r1;
        r[1] = r2;
        s[0] = s1;
        s[1] = s2;

        //checking |
        for (x = 0; x < 3; x++) {
            sum = 0;
            for (y = 0; y < 3; y++) {
                sum += uint(state[gridToIndex(x, y)]);
            }
            if (sum == X * 3) {
                adjudicator.close(0, nonce, byte(1), new uint8[](2), new bytes32[](2), new bytes32[](2));
                return true;
            } else if (sum == O * 3) {
                adjudicator.close(0, nonce, byte(2), new uint8[](2), new bytes32[](2), new bytes32[](2));
                return true;
            }
        }

        //checking -
        for (y = 0; y < 3; y++) {
            sum = 0;
            for (x = 0; x < 3; x++) {
                sum += uint(state[gridToIndex(x, y)]);
            }
            if (sum == X * 3) {
                adjudicator.close(0, nonce, byte(1), new uint8[](2), new bytes32[](2), new bytes32[](2));
                return true;
            } else if (sum == O * 3) {
                adjudicator.close(0, nonce, byte(2), new uint8[](2), new bytes32[](2), new bytes32[](2));
                return true;
            }
        }

        //checking \
        sum = 0;
        for (x = 0; x < 3; x++) {
            sum += uint(state[gridToIndex(x, x)]);
        }
        if (sum == X * 3) {
            adjudicator.close(0, nonce, byte(1), new uint8[](2), new bytes32[](2), new bytes32[](2));
            return true;
        } else if (sum == O * 3) {
            adjudicator.close(0, nonce, byte(2), new uint8[](2), new bytes32[](2), new bytes32[](2));
            return true;
        }

        //checking /
        sum = 0;
        for (x = 0; x < 3; x++) {
            sum += uint(state[gridToIndex(x, 3-1 - x)]);
        }
        if (sum == X * 3) {
            adjudicator.close(0, nonce, byte(1), new uint8[](2), new bytes32[](2), new bytes32[](2));
            return true;
        } else if (sum == O * 3) {
            adjudicator.close(0, nonce, byte(2), new uint8[](2), new bytes32[](2), new bytes32[](2));
            return true;
        }

        //checking if there's a tie
        x = 0;
        y = 0;
        for (i = 0; i < 3 * 3; i++) {
            if (state[i] == byte(X)) {
                x++;
            } else if (state[i] == byte(Y)) {
                y++;
            }
        }

        // what happens if someone isn't being honest??
        if (x + y == 9) {
            adjudicator.close(0, nonce, byte(0), new uint8[](2), new bytes32[](2), new bytes32[](2));
        }
    }
}

import "Rules.sol";
import "TicTacToeAdjudicator.sol";

contract TicTacToeRules is Rules {

    address address1;
    address address2;
    uint timeout;

    function TicTacToeRules(address _address1, address _address2, uint _timeout) {
        address1 = _address1;
        address2 = _address2;
        timeout = _timeout;
    }

    function createAdjudicator() internal returns (Adjudicator adjudicator) {
        adjudicator = new TicTacToeAdjudicator(address1, address2, timeout);
        delete address1;
        delete address2;
        delete timeout;
    }
}


Added replay attack prevention for TicTacToeRules

import "Rules.sol";
import "TicTacToeAdjudicator.sol";

/* Board state values are as follows:
 *  0 | 1 | 2
 *  ---------
 *  3 | 4 | 5
 *  ---------
 *  6 | 7 | 8
 *
 * 9: 4 if last player was O, 1 if the last player was X
 */
contract TicTacToeRules is Rules {

    uint constant BLANK = 0;
    uint constant X = 1;
    uint constant O = 4;

    address addressX;
    address addressO;
    uint timeout;

    /**
     * Creates a new TicTacToeRules
     * _addressX: the address of X
     * _addressO: the address of O
     * _timeout: the timeout before state can be closed
     */
    function TicTacToeRules(address _addressX, address _addressO, uint _timeout) {
        addressX = _addressX;
        addressO = _addressO;
        timeout = _timeout;
    }

    function createAdjudicator() internal returns (Adjudicator newAdjudicator) {
        newAdjudicator = new TicTacToeAdjudicator(addressX, addressO, timeout);
        delete timeout;
    }

    // Converts a grid coordinate to an index value
    function gridToIndex(uint x, uint y) constant internal returns (uint) {
        return x + 3*y;
    }

    /**
     * Send a state directly to the underlying state channel.
     * Allows for transactions to be closed without any adjudication fees.
     *
     * state: the state that will be sent
     * nonce: the nonce that will be sent
     * the rest are signature values for X and O, respectively
     * returns: true if state sent sucessfully, otherwise false
     */
    function sendState(
        bytes state,
        uint nonce,
        uint8 vX,
        bytes32 rX,
        bytes32 sX,
        uint8 vO,
        bytes32 rO,
        bytes32 sO
    ) external returns (bool) {
        uint8[] memory v = new uint8[](2);
        bytes32[] memory r = new bytes32[](2);
        bytes32[] memory s = new bytes32[](2);

        v[0] = vX;
        v[1] = vO;
        r[0] = rX;
        r[1] = rO;
        s[0] = sX;
        s[1] = sO;

        return adjudicator.close(2, state, nonce, this, v, r, s);
    }

    /**
     * Sends a unilateral ruling (0 signatures required) to underlying adjudicator.
     *
     * uintState: the state which will be sent
     * nonce: the nonce which will be sent
     * returns: true if the state was sent successfully, otherwise false
     */
    function unilateralRuling(uint8 uintState, uint nonce) internal returns (bool) {
        bytes memory state = new bytes(1);
        state[0] = byte(uintState);
        adjudicator.close(0, state, nonce, this, new uint8[](1), new bytes32[](1), new bytes32[](1));
    }

    /**
     * Sends a board to be adjudicated upon.
     *
     * board: the board to be adjudicated upon
     * nonce: the nonce that will be used
     * v, r, s: X's signature if last player was X, O's signature if last player was O
     * returns: true if adjudication was sucessful, otherwise false
     */
    function sendBoard(
        bytes10 board,
        uint nonce,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (bool) {
        uint x;
        uint y;
        uint i;
        uint8 uintState = uint(board[9]) == X ? 0x28 : 0x14;// by default, the person who didn't play will lose all deposits

        if (
            !((uint(board[9]) == X && addressX == ecrecover(sha3(board, nonce, this), v, r, s))
            || (uint(board[9]) == O && addressO == ecrecover(sha3(board, nonce, this), v, r, s)))
        ) {
            return false;
        }

        // do something about what happens if you send old boards???

        // checking wins
        // checking |
        for (x = 0; x < 3; x++) {
            i = 0;
            for (y = 0; y < 3; y++) {
                i += uint(board[gridToIndex(x, y)]);
            }
            if (i == X * 3) {
                return unilateralRuling(uintState | 0x01 , nonce);// give X the bet winnings
            } else if (i == O * 3) {
                return unilateralRuling(uintState | 0x02, nonce);// give O the bet winnings
            }
        }

        // checking -
        for (y = 0; y < 3; y++) {
            i = 0;
            for (x = 0; x < 3; x++) {
                i += uint(board[gridToIndex(x, y)]);
            }
            if (i == X * 3) {
                return unilateralRuling(uintState | 0x01, nonce);
            } else if (i == O * 3) {
                return unilateralRuling(uintState | 0x02, nonce);
            }
        }

        // checking \
        i = 0;
        for (x = 0; x < 3; x++) {
            i += uint(board[gridToIndex(x, x)]);
        }
        if (i == X * 3) {
            return unilateralRuling(uintState | 0x01, nonce);
        } else if (i == O * 3) {
            return unilateralRuling(uintState | 0x02, nonce);
        }

        // checking /
        i = 0;
        for (x = 0; x < 3; x++) {
            i += uint(board[gridToIndex(x, 2 - x)]);
        }
        if (i == X * 3) {
            return unilateralRuling(uintState | 0x01, nonce);
        } else if (i == O * 3) {
            return unilateralRuling(uintState | 0x02, nonce);
        }

        // check if tie
        for (i = 0; i < 9; i++) {
            if (uint(board[i]) == BLANK) {
                // last player wins
                return unilateralRuling(uintState | uint(board[9]) == X ? 0x01 : 0x02, nonce);// bets sent to last player
            }
        }
        // it is a tie
        return unilateralRuling(uintState, nonce);// if tie, bets returned
    }

    /**
     * Punishes a sender for sending an errornous board.
     *
     * oldBoard: the old board to be compared against
     * oldNonce: the old nonce to verify the old board
     * oldV, oldR, oldS: the signature for oldBoard, from the last player
     * newBoard: the new board which has an error
     * newNonce: the new nonce of newBoard
     * newV, newR, newS: the signatures for newBoard, from the last player
     */
    function badBoardSent(
        bytes10 oldBoard,
        uint oldNonce,
        uint8 oldV,
        bytes32 oldR,
        bytes32 oldS,
        bytes10 newBoard,
        uint newNonce,
        uint8 newV,
        bytes32 newR,
        bytes32 newS
    ) external returns (bool) {
        // verify the integrity of oldBoard
        if (
            !((uint(oldBoard[9]) == X && addressX == ecrecover(sha3(oldBoard, oldNonce, this), oldV, oldR, oldS))
            || (uint(oldBoard[9]) == O && addressO == ecrecover(sha3(oldBoard, oldNonce, this), oldV, oldR, oldS)))
        ) {
            return false;
        }

        // verify the integrity of newBoard
        if (
            !((uint(newBoard[9]) == X && addressX == ecrecover(sha3(newBoard, newNonce, this), newV, newR, newS))
            || (uint(newBoard[9]) == O && addressO == ecrecover(sha3(newBoard, newNonce, this), newV, newR, newS)))
        ) {
            return false;
        }

        bool notChanged = true;
        for (uint i = 0; i < 9; i++) {
            if (oldBoard[i] == newBoard[i]) {
                break;
            }
            if ((uint(newBoard[i]) == X || uint(newBoard[i]) == O) && (uint(oldBoard[i]) == BLANK) && notChanged && (newBoard[i] == newBoard[9])) {
                notChanged = false;
                break;
            }
            // shenanigans
            return unilateralRuling(uint(newBoard[9]) == X ? 0x56 : 0x69, newNonce);
        }
        if (notChanged) {
            // shenanigans
            return unilateralRuling(uint(newBoard[9]) == X ? 0x56 : 0x69, newNonce);
        } else {
            // nothing fishy
            return false;
        }
    }

    /**
     * Lets the contract know that you have not disconnected.
     * Will modify the state such that the disconnect deposits will be
     * refunded and both party's adjudication deposits will be lost.
     *
     * returns: true if sucessful, otherwise false
     */
    function checkIn() external returns (bool) {
        uint8 uintState = uint8(adjudicator.getStateAt(0));
        if (uintState & 0x40 != 0x00 || uintState & 0x0C != 0x00) {
            return false;
        }
        return unilateralRuling(uintState & 0xCF | 0x0C, adjudicator.getNonce());
    }
}

import "Rules.sol";
import "TicTacToeAdjudicator.sol";

/* Board state values are as follows:
 *  0 | 1 | 2
 *  ---------
 *  3 | 4 | 5
 *  ---------
 *  6 | 7 | 8
 *
 * 9: 4 if last player was O, 1 if the last player was X
 */
contract TicTacToeRules is Rules {

    uint constant BLANK = 0;
    uint constant X = 1;
    uint constant O = 4;

    address addressX;
    address addressO;
    uint timeout;

    /**
     * Creates a new TicTacToeRules
     * _addressX: the address of X
     * _addressO: the address of O
     * _timeout: the timeout before state can be closed
     */
    function TicTacToeRules(address _addressX, address _addressO, uint _timeout) {
        addressX = _addressX;
        addressO = _addressO;
        timeout = _timeout;
    }

    function createAdjudicator() internal returns (Adjudicator newAdjudicator) {
        newAdjudicator = new TicTacToeAdjudicator(addressX, addressO, timeout);
        delete timeout;
    }

    // Converts a grid coordinate to an index value
    function gridToIndex(uint x, uint y) constant internal returns (uint) {
        return x + 3*y;
    }

    /**
     * Send a state directly to the underlying state channel.
     * Allows for transactions to be closed without any adjudication fees.
     *
     * state: the state that will be sent
     * nonce: the nonce that will be sent
     * the rest are signature values for X and O, respectively
     * returns: true if state sent sucessfully, otherwise false
     */
    function sendState(
        bytes state,
        uint nonce,
        uint8 vX,
        bytes32 rX,
        bytes32 sX,
        uint8 vO,
        bytes32 rO,
        bytes32 sO
    ) external returns (bool) {
        uint8[] memory v = new uint8[](2);
        bytes32[] memory r = new bytes32[](2);
        bytes32[] memory s = new bytes32[](2);

        v[0] = vX;
        v[1] = vO;
        r[0] = rX;
        r[1] = rO;
        s[0] = sX;
        s[1] = sO;

        return adjudicator.close(2, state, nonce, this, v, r, s);
    }

    /**
     * Sends a unilateral ruling (0 signatures required) to underlying adjudicator.
     *
     * uintState: the state which will be sent
     * nonce: the nonce which will be sent
     * returns: true if the state was sent successfully, otherwise false
     */
    function unilateralRuling(uint8 uintState, uint nonce) internal returns (bool) {
        bytes memory state = new bytes(1);
        state[0] = byte(uintState);
        adjudicator.close(0, state, nonce, this, new uint8[](1), new bytes32[](1), new bytes32[](1));
    }

    /**
     * Sends a board to be adjudicated upon.
     *
     * board: the board to be adjudicated upon
     * nonce: the nonce that will be used
     * v, r, s: X's signature if last player was X, O's signature if last player was O
     * returns: true if adjudication was sucessful, otherwise false
     */
    function sendBoard(
        bytes10 board,
        uint nonce,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (bool) {
        uint x;
        uint y;
        uint i;
        uint8 uintState = uint(board[9]) == X ? 0x28 : 0x14;// by default, the person who didn't play will lose all deposits

        if (
            !((uint(board[9]) == X && addressX == ecrecover(sha3(board, nonce), v, r, s))
            || (uint(board[9]) == O && addressO == ecrecover(sha3(board, nonce), v, r, s)))
        ) {
            return false;
        }

        // do something about what happens if you send old boards???

        // checking wins
        // checking |
        for (x = 0; x < 3; x++) {
            i = 0;
            for (y = 0; y < 3; y++) {
                i += uint(board[gridToIndex(x, y)]);
            }
            if (i == X * 3) {
                return unilateralRuling(uintState | 0x01 , nonce);// give X the bet winnings
            } else if (i == O * 3) {
                return unilateralRuling(uintState | 0x02, nonce);// give O the bet winnings
            }
        }

        // checking -
        for (y = 0; y < 3; y++) {
            i = 0;
            for (x = 0; x < 3; x++) {
                i += uint(board[gridToIndex(x, y)]);
            }
            if (i == X * 3) {
                return unilateralRuling(uintState | 0x01, nonce);
            } else if (i == O * 3) {
                return unilateralRuling(uintState | 0x02, nonce);
            }
        }

        // checking \
        i = 0;
        for (x = 0; x < 3; x++) {
            i += uint(board[gridToIndex(x, x)]);
        }
        if (i == X * 3) {
            return unilateralRuling(uintState | 0x01, nonce);
        } else if (i == O * 3) {
            return unilateralRuling(uintState | 0x02, nonce);
        }

        // checking /
        i = 0;
        for (x = 0; x < 3; x++) {
            i += uint(board[gridToIndex(x, 2 - x)]);
        }
        if (i == X * 3) {
            return unilateralRuling(uintState | 0x01, nonce);
        } else if (i == O * 3) {
            return unilateralRuling(uintState | 0x02, nonce);
        }

        // check if tie
        for (i = 0; i < 9; i++) {
            if (uint(board[i]) == BLANK) {
                // last player wins
                return unilateralRuling(uintState | uint(board[9]) == X ? 0x01 : 0x02, nonce);// bets sent to last player
            }
        }
        // it is a tie
        return unilateralRuling(uintState, nonce);// if tie, bets returned
    }

    /**
     * Punishes a sender for sending an errornous board.
     *
     * oldBoard: the old board to be compared against
     * oldNonce: the old nonce to verify the old board
     * oldV, oldR, oldS: the signature for oldBoard, from the last player
     * newBoard: the new board which has an error
     * newNonce: the new nonce of newBoard
     * newV, newR, newS: the signatures for newBoard, from the last player
     */
    function badBoardSent(
        bytes10 oldBoard,
        uint oldNonce,
        uint8 oldV,
        bytes32 oldR,
        bytes32 oldS,
        bytes10 newBoard,
        uint newNonce,
        uint8 newV,
        bytes32 newR,
        bytes32 newS
    ) external returns (bool) {
        // verify the integrity of oldBoard
        if (
            !((uint(oldBoard[9]) == X && addressX == ecrecover(sha3(oldBoard, oldNonce), oldV, oldR, oldS))
            || (uint(oldBoard[9]) == O && addressO == ecrecover(sha3(oldBoard, oldNonce), oldV, oldR, oldS)))
        ) {
            return false;
        }

        // verify the integrity of newBoard
        if (
            !((uint(newBoard[9]) == X && addressX == ecrecover(sha3(newBoard, newNonce), newV, newR, newS))
            || (uint(newBoard[9]) == O && addressO == ecrecover(sha3(newBoard, newNonce), newV, newR, newS)))
        ) {
            return false;
        }

        bool notChanged = true;
        for (uint i = 0; i < 9; i++) {
            if (oldBoard[i] == newBoard[i]) {
                break;
            }
            if ((uint(newBoard[i]) == X || uint(newBoard[i]) == O) && (uint(oldBoard[i]) == BLANK) && notChanged && (newBoard[i] == newBoard[9])) {
                notChanged = false;
                break;
            }
            // shenanigans
            return unilateralRuling(uint(newBoard[9]) == X ? 0x56 : 0x69, newNonce);
        }
        if (notChanged) {
            // shenanigans
            return unilateralRuling(uint(newBoard[9]) == X ? 0x56 : 0x69, newNonce);
        } else {
            // nothing fishy
            return false;
        }
    }

    /**
     * Lets the contract know that you have not disconnected.
     * Will modify the state such that the disconnect deposits will be
     * refunded and both party's adjudication deposits will be lost.
     *
     * returns: true if sucessful, otherwise false
     */
    function checkIn() external returns (bool) {
        uint8 uintState = uint8(adjudicator.getStateAt(0));
        if (uintState & 0x40 != 0x00 || uintState & 0x0C != 0x00) {
            return false;
        }
        return unilateralRuling(uintState & 0xCF | 0x0C, adjudicator.getNonce());
    }
}


add setIndex event

add setIndex event

pragma solidity ^0.4.11;

import "./UserRegistry.sol";
import "./ConceptRegistry.sol";
import "./Assessment.sol";
import "./Math.sol";

//@purpose: To store concept data and create and manage assessments and members
contract Concept {
    address[] public parents; //The concepts that this concept is child to (ie: Calculus is child to Math)
    bytes data;
    address userRegistry;
    address conceptRegistry;
    uint public maxWeight;
    uint public lifetime;
    mapping (address => bool) public assessmentExists;

    uint[] propagationRates;

    address[] public members;
    mapping (address => MemberData) memberData;

    struct MemberData {
        address recentAssessment;
        bool isMember;
        mapping(address => uint) approval;
        ComponentWeight[] weights;
        mapping(address => uint) componentWeightIndex;
    }

    struct ComponentWeight {
        uint weight;
        uint date;
    }

    modifier onlyUserRegistry() {
        require(msg.sender == userRegistry);
        _;
    }

    modifier onlyConceptRegistry() {
        require(msg.sender == conceptRegistry);
        _;
    }

    modifier onlyConcept() {
        require(ConceptRegistry(conceptRegistry).conceptExists(msg.sender));
        _;
    }

    /*
      @type: event
      @name: CompletedAssessment
      @purpose: To build a database of completed assessments
    */
    event CompletedAssessment (
                               address _assessee,
                               int _score,
                               address _assessment
                               );

    event setAssessorIndex (address member, uint index);

    function Concept(address[] _parents, uint[] _propagationRates, uint _lifetime, bytes _data) {
        for(uint i = 0; i < _propagationRates.length; i++) {
            require(_propagationRates[i] <= 1000);
        }
        propagationRates = _propagationRates;
        parents = _parents;
        data = _data;
        conceptRegistry = msg.sender;
        lifetime = _lifetime;
        userRegistry = ConceptRegistry(conceptRegistry).userRegistry();
    }

    function getMemberLength() constant returns(uint) {
        return members.length;
    }

    function getParentsLength() constant returns(uint) {
        return parents.length;
    }

    /*
      @purpose: To add the firstUser to Mew
    */
    function addInitialMember(address _user, uint _weight) {
        if (ConceptRegistry(conceptRegistry).distributorAddress() == msg.sender)
            {
                this.addWeight(_user, _weight);
            }
    }

    function addParent(address _parent) onlyConceptRegistry() {
        parents.push(_parent);
    }

    function setAvailability(uint _index) {
        if(members[_index] == msg.sender) {
            memberData[msg.sender].isMember = false;
            setAssessorIndex(members[members.length -1], _index);
            members[_index] = members[members.length - 1];
            members.length = members.length - 1;
        }

        else {
            if(getWeight(msg.sender) > 0 && !memberData[msg.sender].isMember){
                members.push(msg.sender);
                memberData[msg.sender].isMember = true;
            }
        }
    }

    //@purpose: returns a random member of the Concept. Users with high weights are more likely to be called
    function getRandomMember(uint seed) returns(address) {
        uint index = Math.getRandom(seed, members.length - 1);
        address randomMember = members[index];
        uint weight = getWeight(randomMember);
        if (weight > 0) {
            if ( weight > now % maxWeight) {
                return randomMember;
            }
            else {
                return address(0x0);
            }
        }
        else {
            //remove from list
            memberData[randomMember].isMember = false;
            setAssessorIndex(members[members.length -1], index);
            members[index] = members[members.length - 1];
            members.length = members.length - 1;
            return getRandomMember(seed*2);
        }
    }

    function getWeight(address _assessee) returns(uint){
        uint weight = 0;
        for (uint i=0; i < memberData[_assessee].weights.length; i++){
            if (memberData[_assessee].weights[i].date + lifetime > now){
                uint timefactor = (memberData[_assessee].weights[i].weight * 100 years) / lifetime;
                weight += (memberData[_assessee].weights[i].weight * 100 years - timefactor * (now - memberData[_assessee].weights[i].date));
            }
        }
        return weight / 100 years;
    }

    /*
      @purpose: To make a new assessment
      @param: uint cost = the cost per assessor
      @param: uint size = the number of assessors
    */
    function makeAssessment(uint cost, uint size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (size >= 5 && this.subtractBalance(msg.sender, cost*size)) {
            Assessment newAssessment = new Assessment(msg.sender, userRegistry, conceptRegistry, size, cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;
            if (Concept(ConceptRegistry(conceptRegistry).mewAddress()).getMemberLength()<size*20) {
                newAssessment.setAssessorPoolFromMew(); // simply use all members of mew (Bootstrap phase)
            }
            else{
                newAssessment.setAssessorPool(block.number, address(this), size*20); //assemble the assessorPool by relevance
            }

            return true;
        }
        else {
            return false;
        }
    }

    /*
      @purpose: To approve addresses to create assessments for users on this concept
      @param: _from = the address approved to create assessments
      @param: _amount = the maximum value of Tokens they are allowed to spend
    */
    function approve(address _from, uint _amount) returns(bool) {
        memberData[msg.sender].approval[_from] = _amount;
        return true;
    }

    //@purpose: allow approved address to create assessments for users on this concept
    function makeAssessmentFrom(address _assessee, uint _cost, uint _size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (memberData[_assessee].approval[msg.sender] >= _cost * _size &&
           _size >= 5 &&
           this.subtractBalance(_assessee, _cost*_size)) {
            Assessment newAssessment = new Assessment(_assessee, userRegistry, conceptRegistry, _size, _cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;

            if (Concept(ConceptRegistry(conceptRegistry).mewAddress()).getMemberLength()<_size*20) {
                newAssessment.setAssessorPoolFromMew(); // simply use all members of mew (Bootstrap phase)
            }
            else {
                newAssessment.setAssessorPool(block.number, address(this), _size*20); //assemble the assessorPool by relevance
            }
            memberData[_assessee].approval[msg.sender] -= _cost*_size;
            return true;
        }
        else {
            return false;
        }
    }

    /*
      @purpose: To add a member to a concept and to recursively add  a member to parent concept, thereby halving the added weight with each generation and changing the maxWeight of each concept if necessary
      @param: address assessee = the address of the assessee
      @param: uint weight = the weight for the member
      @returns: nothing
    */
    function addMember(address _assessee, uint _weight) {
        if (assessmentExists[msg.sender]) {
            memberData[_assessee].recentAssessment = msg.sender;
            memberData[_assessee].isMember = true;
            this.addWeight(_assessee, _weight);
        }
    }
    function addWeight(address _assessee, uint _weight) onlyConcept() {
        if (!memberData[_assessee].isMember) {
            members.push(_assessee);
            memberData[_assessee].isMember = true;
        }

        uint idx = memberData[_assessee].componentWeightIndex[msg.sender];
        if (idx > 0) {
            memberData[_assessee].weights[idx-1] = ComponentWeight(_weight, now);
        } else {
            memberData[_assessee].weights.push(ComponentWeight(_weight, now));
            memberData[_assessee].componentWeightIndex[msg.sender] = memberData[_assessee].weights.length;
        }

        if (_weight > maxWeight) {
            maxWeight = _weight;
        }

        for(uint i = 0; i < parents.length; i++) {
            if((_weight*propagationRates[i])/1000 > 0) {
                Concept(parents[i]).addWeight(_assessee, (_weight*propagationRates[i])/1000);
            }
        }
    }

    function subtractBalance(address _from, uint _amount) returns(bool) {
        if (assessmentExists[msg.sender] || msg.sender == address(this)) {
            return UserRegistry(userRegistry).subtractBalance(_from, _amount);
        }
        return false;
    }

    function addBalance(address _to, uint _amount)  returns(bool) {
        if (assessmentExists[msg.sender]) {
            return UserRegistry(userRegistry).addBalance(_to, _amount);
        }
    }
}

pragma solidity ^0.4.11;

import "./UserRegistry.sol";
import "./ConceptRegistry.sol";
import "./Assessment.sol";
import "./Math.sol";

//@purpose: To store concept data and create and manage assessments and members
contract Concept {
    address[] public parents; //The concepts that this concept is child to (ie: Calculus is child to Math)
    bytes data;
    address userRegistry;
    address conceptRegistry;
    uint public maxWeight;
    uint public lifetime;
    mapping (address => bool) public assessmentExists;

    uint[] propagationRates;

    address[] public members;
    mapping (address => MemberData) memberData;

    struct MemberData {
        address recentAssessment;
        bool isMember;
        mapping(address => uint) approval;
        ComponentWeight[] weights;
        mapping(address => uint) componentWeightIndex;
    }

    struct ComponentWeight {
        uint weight;
        uint date;
    }

    modifier onlyUserRegistry() {
        require(msg.sender == userRegistry);
        _;
    }

    modifier onlyConceptRegistry() {
        require(msg.sender == conceptRegistry);
        _;
    }

    modifier onlyConcept() {
        require(ConceptRegistry(conceptRegistry).conceptExists(msg.sender));
        _;
    }

    /*
      @type: event
      @name: CompletedAssessment
      @purpose: To build a database of completed assessments
    */
    event CompletedAssessment (
                               address _assessee,
                               int _score,
                               address _assessment
                               );

    function Concept(address[] _parents, uint[] _propagationRates, uint _lifetime, bytes _data) {
        for(uint i = 0; i < _propagationRates.length; i++) {
            require(_propagationRates[i] <= 1000);
        }
        propagationRates = _propagationRates;
        parents = _parents;
        data = _data;
        conceptRegistry = msg.sender;
        lifetime = _lifetime;
        userRegistry = ConceptRegistry(conceptRegistry).userRegistry();
    }

    function getMemberLength() constant returns(uint) {
        return members.length;
    }

    function getParentsLength() constant returns(uint) {
        return parents.length;
    }

    /*
      @purpose: To add the firstUser to Mew
    */
    function addInitialMember(address _user, uint _weight) {
        if (ConceptRegistry(conceptRegistry).distributorAddress() == msg.sender)
            {
                this.addWeight(_user, _weight);
            }
    }

    function addParent(address _parent) onlyConceptRegistry() {
        parents.push(_parent);
    }

    function setAvailability(uint _index) {
        if(members[_index] == msg.sender) {
            memberData[msg.sender].isMember = false;
            members[_index] = members[members.length - 1];
            members.length = members.length - 1;
        }

        else {
            if(getWeight(msg.sender) > 0 && !memberData[msg.sender].isMember){
                members.push(msg.sender);
                memberData[msg.sender].isMember = true;
            }
        }
    }

    //@purpose: returns a random member of the Concept. Users with high weights are more likely to be called
    function getRandomMember(uint seed) returns(address) {
        uint index = Math.getRandom(seed, members.length - 1);
        address randomMember = members[index];
        uint weight = getWeight(randomMember);
        if (weight > 0) {
            if ( weight > now % maxWeight) {
                return randomMember;
            }
            else {
                return address(0x0);
            }
        }
        else {
            //remove from list
            memberData[randomMember].isMember = false;
            members[index] = members[members.length - 1];
            members.length = members.length - 1;
            return getRandomMember(seed*2);
        }
    }

    function getWeight(address _assessee) returns(uint){
        uint weight = 0;
        for (uint i=0; i < memberData[_assessee].weights.length; i++){
            if (memberData[_assessee].weights[i].date + lifetime > now){
                uint timefactor = (memberData[_assessee].weights[i].weight * 100 years) / lifetime;
                weight += (memberData[_assessee].weights[i].weight * 100 years - timefactor * (now - memberData[_assessee].weights[i].date));
            }
        }
        return weight / 100 years;
    }

    /*
      @purpose: To make a new assessment
      @param: uint cost = the cost per assessor
      @param: uint size = the number of assessors
    */
    function makeAssessment(uint cost, uint size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (size >= 5 && this.subtractBalance(msg.sender, cost*size)) {
            Assessment newAssessment = new Assessment(msg.sender, userRegistry, conceptRegistry, size, cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;
            if (Concept(ConceptRegistry(conceptRegistry).mewAddress()).getMemberLength()<size*20) {
                newAssessment.setAssessorPoolFromMew(); // simply use all members of mew (Bootstrap phase)
            }
            else{
                newAssessment.setAssessorPool(block.number, address(this), size*20); //assemble the assessorPool by relevance
            }

            return true;
        }
        else {
            return false;
        }
    }

    /*
      @purpose: To approve addresses to create assessments for users on this concept
      @param: _from = the address approved to create assessments
      @param: _amount = the maximum value of Tokens they are allowed to spend
    */
    function approve(address _from, uint _amount) returns(bool) {
        memberData[msg.sender].approval[_from] = _amount;
        return true;
    }

    //@purpose: allow approved address to create assessments for users on this concept
    function makeAssessmentFrom(address _assessee, uint _cost, uint _size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (memberData[_assessee].approval[msg.sender] >= _cost * _size &&
           _size >= 5 &&
           this.subtractBalance(_assessee, _cost*_size)) {
            Assessment newAssessment = new Assessment(_assessee, userRegistry, conceptRegistry, _size, _cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;

            if (Concept(ConceptRegistry(conceptRegistry).mewAddress()).getMemberLength()<_size*20) {
                newAssessment.setAssessorPoolFromMew(); // simply use all members of mew (Bootstrap phase)
            }
            else {
                newAssessment.setAssessorPool(block.number, address(this), _size*20); //assemble the assessorPool by relevance
            }
            memberData[_assessee].approval[msg.sender] -= _cost*_size;
            return true;
        }
        else {
            return false;
        }
    }

    /*
      @purpose: To add a member to a concept and to recursively add  a member to parent concept, thereby halving the added weight with each generation and changing the maxWeight of each concept if necessary
      @param: address assessee = the address of the assessee
      @param: uint weight = the weight for the member
      @returns: nothing
    */
    function addMember(address _assessee, uint _weight) {
        if (assessmentExists[msg.sender]) {
            memberData[_assessee].recentAssessment = msg.sender;
            memberData[_assessee].isMember = true;
            this.addWeight(_assessee, _weight);
        }
    }
    function addWeight(address _assessee, uint _weight) onlyConcept() {
        if (!memberData[_assessee].isMember) {
            members.push(_assessee);
            memberData[_assessee].isMember = true;
        }

        uint idx = memberData[_assessee].componentWeightIndex[msg.sender];
        if (idx > 0) {
            memberData[_assessee].weights[idx-1] = ComponentWeight(_weight, now);
        } else {
            memberData[_assessee].weights.push(ComponentWeight(_weight, now));
            memberData[_assessee].componentWeightIndex[msg.sender] = memberData[_assessee].weights.length;
        }

        if (_weight > maxWeight) {
            maxWeight = _weight;
        }

        for(uint i = 0; i < parents.length; i++) {
            if((_weight*propagationRates[i])/1000 > 0) {
                Concept(parents[i]).addWeight(_assessee, (_weight*propagationRates[i])/1000);
            }
        }
    }

    function subtractBalance(address _from, uint _amount) returns(bool) {
        if (assessmentExists[msg.sender] || msg.sender == address(this)) {
            return UserRegistry(userRegistry).subtractBalance(_from, _amount);
        }
        return false;
    }

    function addBalance(address _to, uint _amount)  returns(bool) {
        if (assessmentExists[msg.sender]) {
            return UserRegistry(userRegistry).addBalance(_to, _amount);
        }
    }
}


add struct to store assessment history

add struct to store assessment history

pragma solidity ^0.4.0;

import "./UserRegistry.sol";
import "./ConceptRegistry.sol";
import "./Assessment.sol";
import "./Math.sol";

//@purpose: To store concept data and create and manage assessments and members
contract Concept {
    address[] public parents; //The concepts that this concept is child to (ie: Calculus is child to Math)
    bytes data;
    address userRegistry;
    address conceptRegistry;
    uint public maxWeight;
    address[] public members;
    mapping (address => bool) public assessmentExists;
    mapping (address => Member) public membersData;
    mapping (address => mapping (address => uint)) public approval;

    struct Member {
        Score[] assessments;
        uint weight;
    }

    struct Score {
        uint score;
        uint time;
    }

    modifier onlyUserRegistry() {
        if (msg.sender != userRegistry)
            {
                throw;
            }
        _;
    }

    modifier onlyConceptRegistry() {
        if (msg.sender != conceptRegistry) {
            throw;
        }
        _;
    }

    modifier onlyConcept() {
        if (!ConceptRegistry(conceptRegistry).conceptExists(msg.sender)) {
            throw;
        }
        _;
    }

    /*
      @type: event
      @name: CompletedAssessment
      @purpose: To build a database of completed assessments
    */
    event CompletedAssessment (
                               address _assessee,
                               int _score,
                               address _assessment
                               );

    function Concept(address[] _parents, bytes _data) {
        parents = _parents;
        data = _data;
        conceptRegistry = msg.sender;
        userRegistry = ConceptRegistry(conceptRegistry).userRegistry();
    }

    function getMemberLength() constant returns(uint) {
        return members.length;
    }

    function getParentsLength() constant returns(uint) {
        return parents.length;
    }

    /*
      @purpose: To add the firstUser to Mew
    */
    function addInitialMember(address _user, uint _weight) {
        if (ConceptRegistry(conceptRegistry).distributorAddress() == msg.sender)
            {
                this.addMember(_user, _weight);
            }
    }

    function addParent(address _parent) onlyConceptRegistry() {
        parents.push(_parent);
    }

    //@purpose: returns a random member of the Concept. Users with high weights are more likely to be called
    function getRandomMember(uint seed) returns(address) {
        address randomUser = members[Math.getRandom(seed, members.length-1)];
        if (UserRegistry(userRegistry).availability(randomUser) && membersData[randomUser].weight > now % maxWeight) {
            return randomUser;
        }
        return address(0x0);
    }
    /*
      @purpose: To make a new assessment
      @param: uint cost = the cost per assessor
      @param: uint size = the number of assessors
    */
    function makeAssessment(uint cost, uint size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (size >= 5 && this.subtractBalance(msg.sender, cost*size)) {
            Assessment newAssessment = new Assessment(msg.sender, userRegistry, conceptRegistry, size, cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;
            if (Concept(ConceptRegistry(conceptRegistry).mewAddress()).getMemberLength()<size*20) {
                newAssessment.setAssessorPoolFromMew(); // simply use all members of mew (Bootstrap phase)
            }
            else{
                newAssessment.setAssessorPool(block.number, address(this), size*20); //assemble the assessorPool by relevance
            }

            return true;
        }
        else {
            return false;
        }
    }

    /*
      @purpose: To approve addresses to create assessments for users on this concept
      @param: _from = the address approved to create assessments
      @param: _amount = the maximum value of Tokens they are allowed to spend
    */
    function approve(address _from, uint _amount) returns(bool) {
        approval[msg.sender][_from] = _amount;
        return true;
    }

    //@purpose: allow approved address to create assessments for users on this concept
    function makeAssessmentFrom(address _assessee, uint _cost, uint _size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (approval[_assessee][msg.sender] >= _cost * _size &&
           _size >= 5 &&
           this.subtractBalance(_assessee, _cost*_size)) {
            Assessment newAssessment = new Assessment(_assessee, userRegistry, conceptRegistry, _size, _cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;
            newAssessment.setAssessorPool(block.number, address(this), _size*20);
            approval[_assessee][msg.sender] -= _cost*_size;
            return true;
        }
        else {
            return false;
        }
    }
    /*
      @purpose: To finish the assessment process
      @param: int score = the assessee's score
      @param: address assessee = the address of the assessee
      @param: address assessment = the address of the assessment
      @returns: nothing
    */
    function finishAssessment(int score, address assessee, address assessment) {
        if (assessmentExists[msg.sender]) {
            if (score > 0) {
                uint weight = Assessment(assessment).size()*uint(score);
                this.addMember(assessee, weight);
            }
            currentScores[assessee] = score; //Maps the assessee to their score
            UserRegistry(userRegistry).notification(assessee, 7); //Assessment on Concept finished
        }
    }
    /*
      @purpose: To add a member to a concept and recursively add a member to parent concept, halving the added weight with each generation and chinging the macWeight for a concept if neccisairy
      @param: address assessee = the address of the assessee
      @param: uint weight = the weight for the member
      @returns: nothing
    */
    function addMember(address assessee, uint weight) onlyConcept() {
        members.push(assessee);
        weights[assessee] += weight;
        if (weight > maxWeight) {
            maxWeight = weight;
        }
        if (weight/2 > 0) {
            for(uint i = 0; i < parents.length; i++) {
                Concept(parents[i]).addMember(assessee, weight/2); //recursively adds member to all parent concepts but with half the weight
            }
        }
    }

    function subtractBalance(address _from, uint _amount) returns(bool) {
        if (assessmentExists[msg.sender] || msg.sender == address(this)) {
            return UserRegistry(userRegistry).subtractBalance(_from, _amount);
        }
        return false;
    }

    function addBalance(address _to, uint _amount)  returns(bool) {
        if (assessmentExists[msg.sender]) {
            return UserRegistry(userRegistry).addBalance(_to, _amount);
        }
    }
}

pragma solidity ^0.4.0;

import "./UserRegistry.sol";
import "./ConceptRegistry.sol";
import "./Assessment.sol";
import "./Math.sol";

//@purpose: To store concept data and create and manage assessments and members
contract Concept {
    address[] public parents; //The concepts that this concept is child to (ie: Calculus is child to Math)
    bytes data;
    address userRegistry;
    address conceptRegistry;
    uint public maxWeight;
    address[] public members;
    mapping (address => int) public currentScores;
    mapping (address => bool) public assessmentExists;
    mapping (address => uint) public weights;
    mapping (address => mapping (address => uint)) public approval;

    modifier onlyUserRegistry() {
        if (msg.sender != userRegistry)
            {
                throw;
            }
        _;
    }

    modifier onlyConceptRegistry() {
        if (msg.sender != conceptRegistry) {
            throw;
        }
        _;
    }

    modifier onlyConcept() {
        if (!ConceptRegistry(conceptRegistry).conceptExists(msg.sender)) {
            throw;
        }
        _;
    }

    /*
      @type: event
      @name: CompletedAssessment
      @purpose: To build a database of completed assessments
    */
    event CompletedAssessment (
                               address _assessee,
                               int _score,
                               address _assessment
                               );

    function Concept(address[] _parents, bytes _data) {
        parents = _parents;
        data = _data;
        conceptRegistry = msg.sender;
        userRegistry = ConceptRegistry(conceptRegistry).userRegistry();
    }

    function getMemberLength() constant returns(uint) {
        return members.length;
    }

    function getParentsLength() constant returns(uint) {
        return parents.length;
    }

    /*
      @purpose: To add the firstUser to Mew
    */
    function addInitialMember(address _user, uint _weight) {
        if (ConceptRegistry(conceptRegistry).distributorAddress() == msg.sender)
            {
                this.addMember(_user, _weight);
            }
    }

    function addParent(address _parent) onlyConceptRegistry() {
        parents.push(_parent);
    }

    //@purpose: returns a random member of the Concept. Users with high weights are more likely to be called
    function getRandomMember(uint seed) returns(address) {
        address randomUser = members[Math.getRandom(seed, members.length-1)];
        if (UserRegistry(userRegistry).availability(randomUser) && weights[randomUser] > now % maxWeight) {
            return randomUser;
        }
        return address(0x0);
    }
    /*
      @purpose: To make a new assessment
      @param: uint cost = the cost per assessor
      @param: uint size = the number of assessors
    */
    function makeAssessment(uint cost, uint size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (size >= 5 && this.subtractBalance(msg.sender, cost*size)) {
            Assessment newAssessment = new Assessment(msg.sender, userRegistry, conceptRegistry, size, cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;
            if (Concept(ConceptRegistry(conceptRegistry).mewAddress()).getMemberLength()<size*20) {
                newAssessment.setAssessorPoolFromMew(); // simply use all members of mew (Bootstrap phase)
            }
            else{
                newAssessment.setAssessorPool(block.number, address(this), size*20); //assemble the assessorPool by relevance
            }

            return true;
        }
        else {
            return false;
        }
    }

    /*
      @purpose: To approve addresses to create assessments for users on this concept
      @param: _from = the address approved to create assessments
      @param: _amount = the maximum value of Tokens they are allowed to spend
    */
    function approve(address _from, uint _amount) returns(bool) {
        approval[msg.sender][_from] = _amount;
        return true;
    }

    //@purpose: allow approved address to create assessments for users on this concept
    function makeAssessmentFrom(address _assessee, uint _cost, uint _size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (approval[_assessee][msg.sender] >= _cost * _size &&
           _size >= 5 &&
           this.subtractBalance(_assessee, _cost*_size)) {
            Assessment newAssessment = new Assessment(_assessee, userRegistry, conceptRegistry, _size, _cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;
            newAssessment.setAssessorPool(block.number, address(this), _size*20);
            approval[_assessee][msg.sender] -= _cost*_size;
            return true;
        }
        else {
            return false;
        }
    }
    /*
      @purpose: To finish the assessment process
      @param: int score = the assessee's score
      @param: address assessee = the address of the assessee
      @param: address assessment = the address of the assessment
      @returns: nothing
    */
    function finishAssessment(int score, address assessee, address assessment) {
        if (assessmentExists[msg.sender]) {
            if (score > 0) {
                uint weight = Assessment(assessment).size()*uint(score);
                this.addMember(assessee, weight);
            }
            currentScores[assessee] = score; //Maps the assessee to their score
            UserRegistry(userRegistry).notification(assessee, 7); //Assessment on Concept finished
        }
    }
    /*
      @purpose: To add a member to a concept and recursively add a member to parent concept, halving the added weight with each generation and chinging the macWeight for a concept if neccisairy
      @param: address assessee = the address of the assessee
      @param: uint weight = the weight for the member
      @returns: nothing
    */
    function addMember(address assessee, uint weight) onlyConcept() {
        members.push(assessee);
        weights[assessee] += weight;
        if (weight > maxWeight) {
            maxWeight = weight;
        }
        if (weight/2 > 0) {
            for(uint i = 0; i < parents.length; i++) {
                Concept(parents[i]).addMember(assessee, weight/2); //recursively adds member to all parent concepts but with half the weight
            }
        }
    }

    function subtractBalance(address _from, uint _amount) returns(bool) {
        if (assessmentExists[msg.sender] || msg.sender == address(this)) {
            return UserRegistry(userRegistry).subtractBalance(_from, _amount);
        }
        return false;
    }

    function addBalance(address _to, uint _amount)  returns(bool) {
        if (assessmentExists[msg.sender]) {
            return UserRegistry(userRegistry).addBalance(_to, _amount);
        }
    }
}


use short circuit (#654)

use short circuit (#654)

pragma solidity ^0.4.18;

import "../math/SafeMath.sol";
import "./Crowdsale.sol";

/**
 * @title CappedCrowdsale
 * @dev Extension of Crowdsale with a max amount of funds raised
 */
contract CappedCrowdsale is Crowdsale {
  using SafeMath for uint256;

  uint256 public cap;

  function CappedCrowdsale(uint256 _cap) public {
    require(_cap > 0);
    cap = _cap;
  }

  // overriding Crowdsale#hasEnded to add cap logic
  // @return true if crowdsale event has ended
  function hasEnded() public view returns (bool) {
    bool capReached = weiRaised >= cap;
    return capReached || super.hasEnded();
  }

  // overriding Crowdsale#validPurchase to add extra cap logic
  // @return true if investors can buy at the moment
  function validPurchase() internal view returns (bool) {
    bool withinCap = weiRaised.add(msg.value) <= cap;
    return withinCap && super.validPurchase();
  }

}

pragma solidity ^0.4.18;

import "../math/SafeMath.sol";
import "./Crowdsale.sol";

/**
 * @title CappedCrowdsale
 * @dev Extension of Crowdsale with a max amount of funds raised
 */
contract CappedCrowdsale is Crowdsale {
  using SafeMath for uint256;

  uint256 public cap;

  function CappedCrowdsale(uint256 _cap) public {
    require(_cap > 0);
    cap = _cap;
  }

  // overriding Crowdsale#hasEnded to add cap logic
  // @return true if crowdsale event has ended
  function hasEnded() public view returns (bool) {
    bool capReached = weiRaised >= cap;
    return super.hasEnded() || capReached;
  }

  // overriding Crowdsale#validPurchase to add extra cap logic
  // @return true if investors can buy at the moment
  function validPurchase() internal view returns (bool) {
    bool withinCap = weiRaised.add(msg.value) <= cap;
    return super.validPurchase() && withinCap;
  }

}