// Contract: CryptoSharesFactory
// Target function: function _erc223Call(address _to, uint _value, bytes memory _data) private returns (bool success)
3
        shareholdersLedgerByIdNumber[id].shareholderName = _shareholderName;
        // 4
        shareholdersLedgerByIdNumber[id].shareholderRegistrationNumber = _shareholderRegistrationNumber;
        // 5
        shareholdersLedgerByIdNumber[id].shareholderAddress = _shareholderAddress;
        // 6
        shareholdersLedgerByIdNumber[id].shareholderIsLegalPerson = _isLegalPerson;
        // 7
        shareholdersLedgerByIdNumber[id].linkToSignersAuthorityToRepresentTheShareholder = _linkToSignersAuthorityToRepresentTheShareholder;
        // 8
        shareholdersLedgerByIdNumber[id].balanceOf = balanceOf[msg.sender];

        /* copy struct  */
        shareholdersLedgerByEthAddress[msg.sender] = shareholdersLedgerByIdNumber[id];

        emit shareholderAddedOrUpdated(
            shareholdersLedgerByIdNumber[id].shareholderID,
            shareholdersLedgerByIdNumber[id].shareholderEthereumAddress,
            shareholdersLedgerByIdNumber[id].shareholderIsLegalPerson,
            shareholdersLedgerByIdNumber[id].shareholderName,
            shareholdersLedgerByIdNumber[id].shareholderRegistrationNumber,
            shareholdersLedgerByIdNumber[id].shareholderAddress,
            shareholdersLedgerByIdNumber[id].balanceOf,
            newShareholder
        );

        /*
        * even if shareholder updates data he makes new signature under dispute resolution agreement
        */
        signDisputeResolutionAgreement(
            id,
            shareholdersLedgerByIdNumber[id].shareholderName,
            shareholdersLedgerByIdNumber[id].shareholderRegistrationNumber,
            shareholdersLedgerByIdNumber[id].shareholderAddress
        );

        return true;
    }

    /* ---------------- Dividends --------------- */

    /**
    * Time in seconds between dividends distribution rounds.
    * Next round can be started only if the specified number of seconds has elapsed since the end of the previous round.
    * See: https://en.wikipedia.org/wiki/Dividend#Dividend_frequency
    */
    uint public dividendsPeriod;

    /*
    * @param roundIsRunning Shows if this dividends payouts round is running.
    * @param sumWeiToPayForOneToken Sum in wei to pay for one token in this round.
    * @param sumXEurToPayForOneToken Sum in xEUR to pay for one token in this round.
    * @param allRegisteredShareholders Number of all shareholder registered in whole smart contract.
    * history, at the moment this round was started.
    * @shareholdersCounter Number (id) of shareholder to whom last payment was made.
    * On the start it will be 0, and on the end of the round shareholdersCounter == allRegisteredShareholders.
    * @registeredShares Number of shares that will receive dividends in this round, i.e. number of shares,
    * hold by registered shareholder (that's all shares minus shares 'in transfer')
    * @param roundStartedOnUnixTime Timestamp.
    * @param roundFinishedOnUnixTime Timestamp.
    * @param weiForTxFees Amount in wei deposited for this round to reward those who make transactions to distribute
    * dividends.
    */
    struct DividendsRound {
        bool roundIsRunning; //............0
        uint sumWeiToPayForOneToken; //....1
        uint sumXEurToPayForOneToken; //...2
        uint allRegisteredShareholders; //.3
        uint shareholdersCounter; //.......4
        uint registeredShares; //..........5
        uint roundStartedOnUnixTime; //....6
        uint roundFinishedOnUnixTime; //...7
        uint weiForTxFees; //..............8
    }

    /**
    * 'dividendsRoundsCounter' holds the sequence number of the last (or current) round of dividends payout
    * We record all historical dividends payouts data
    */
    uint public dividendsRoundsCounter;
    mapping(uint => DividendsRound) public dividendsRound;

    /*
    * @param dividendsRound Number of dividends distribution round.
    * @param startedBy ETH address that started round (if time to pay dividends, can be started by any ETH address)
    * @param totalWei Sum in wei that has to be distributed in this round.
    * @param totalXEur Sum in xEUR that has to be distributed in this round.
    * @param sharesToPayDividendsTo The same as 'registeredShares' in struct DividendsRound.
    * @param sumWeiToPayForOneShare Sum in wei to pay for one token in this round.
    * @param sumXEurToPayForOneShare Sum in xEUR to pay for one token in this round.
    */
    event DividendsPaymentsStarted(
        uint indexed dividendsRound, //..0
        address indexed startedBy, //...1
        uint totalWei, //................2
        uint totalXEur, //...............3
        uint sharesToPayDividendsTo, //..4
        uint sumWeiToPayForOneShare, //..5
        uint sumXEurToPayForOneShare //..6
    );

    /**
    * @param dividendsRound Number of dividends distribution round
    */
    event DividendsPaymentsFinished(
        uint indexed dividendsRound
    );

    /**
    * dev: Info about the payment in ETH made to next shareholder
    */
    event DividendsPaymentEther (
        bool indexed success,
        address indexed to,
        uint shareholderID,
        uint shares,
        uint sumWei,
        uint indexed dividendsRound
    );

    /**
    * dev: Info about the payment in xEUR made to next shareholder
    */
    event DividendsPaymentXEuro (
        bool indexed success,
        address indexed to,
        uint shareholderID,
        uint shares,
        uint sumXEuro,
        uint indexed dividendsRound
    );

    /*
    * @notice This function starts dividend payout round, and can be started from ANY address if the time has come.
    */
    function startDividendsPayments() public returns (bool success) {

        require(
            dividendsRound[dividendsRoundsCounter].roundIsRunning == false,
            "Already running"
        );

        // dividendsRound[dividendsRoundsCounter].roundFinishedOnUnixTime is zero for first round
        // so it can be started right after contract deploy
        require(now.sub(dividendsRound[dividendsRoundsCounter].roundFinishedOnUnixTime) > dividendsPeriod,
            "To early to start"
        );

        require(registeredShares > 0,
            "No registered shares to distribute dividends to"
        );

        uint sumWeiToPayForOneToken = address(this).balance / registeredShares;
        uint sumXEurToPayForOneToken = xEuro.balanceOf(address(this)) / registeredShares;

        require(
            sumWeiToPayForOneToken > 0 || sumXEurToPayForOneToken > 0,
            "Nothing to pay"
        );

        // here we start the next dividends payout round:
        dividendsRoundsCounter++;

        dividendsRound[dividendsRoundsCounter].roundIsRunning = true;
        dividendsRound[dividendsRoundsCounter].roundStartedOnUnixTime = now;
        dividendsRound[dividendsRoundsCounter].registeredShares = registeredShares;
        dividendsRound[dividendsRoundsCounter].allRegisteredShareholders = shareholdersCounter;

        dividendsRound[dividendsRoundsCounter].sumWeiToPayForOneToken = sumWeiToPayForOneToken;
        dividendsRound[dividendsRoundsCounter].sumXEurToPayForOneToken = sumXEurToPayForOneToken;

        emit DividendsPaymentsStarted(
            dividendsRoundsCounter,
            msg.sender,
            address(this).balance,
            xEuro.balanceOf(address(this)),
            registeredShares,
            sumWeiToPayForOneToken,
            sumXEurToPayForOneToken
        );

        return true;
    }

    /*
    * @dev Reward for tx distributing dividends was paid
    * @dividendsRoundNumber Number (Id) of dividends round.
    * @dividendsToShareholderNumber Shareholder ID, to whom payment was made by the transaction
    * @dividendsToShareholderAddress Shareholder ETH address, to whom payment was made by the transaction
    * @feePaidTo Address (ETH), who received the reward (this is the address who send tx to pay dividends to above
    * stated shareholder
    * @feeInWei Amount of the reward paid.
    * @paymentSuccesful Shows if fee payment was successful (msg.sender.send == true)
    */
    event FeeForDividendsDistributionTxPaid(
        uint indexed dividendsRoundNumber,
        uint dividendsToShareholderNumber,
        address dividendsToShareholderAddress,
        address indexed feePaidTo,
        uint feeInWei,
        bool feePaymentSuccesful
    );

    /*
    * @notice This function pays dividends due to the next shareholder.
    * dev: This functions is intended to be called by external script (bot), but can be also called manually.
    * External script can be run by any person interested in distributing dividends.
    * Script code is open source and published on smart contract's web site and/or on Github.
    * Technically this functions can be run also manually (acceptable option for small number of shareholders)
    */
    function payDividendsToNext() external returns (bool success) {

        require(
            dividendsRound[dividendsRoundsCounter].roundIsRunning,
            "Dividends payments round is not open"
        );

        dividendsRound[dividendsRoundsCounter].shareholdersCounter = dividendsRound[dividendsRoundsCounter].shareholdersCounter + 1;

        uint nextShareholderToPayDividends = dividendsRound[dividendsRoundsCounter].shareholdersCounter;

        uint sumWeiToPayForOneToken = dividendsRound[dividendsRoundsCounter].sumWeiToPayForOneToken;
        uint sumXEurToPayForOneToken = dividendsRound[dividendsRoundsCounter].sumXEurToPayForOneToken;

        address payable to = shareholdersLedgerByIdNumber[nextShareholderToPayDividends].shareholderEthereumAddress;

        if (balanceOf[to] > 0) {

            if (sumWeiToPayForOneToken > 0) {

                uint sumWeiToPay = sumWeiToPayForOneToken * balanceOf[to];

                // 'send' is the low-level counterpart of 'transfer'.
                // If the execution fails, the current contract will not stop with an exception, but 'send' will return false.
                // https://solidity.readthedocs.io/en/v0.5.10/types.html?highlight=send#members-of-addresses
                // So we use 'send' and not 'transfer' to ensure that execution continues even if sending ether fails.
                bool result = to.send(sumWeiToPay);
                emit DividendsPaymentEther(
                    result,
                    to,
                    nextShareholderToPayDividends,
                    balanceOf[to],
                    sumWeiToPay,
                    dividendsRoundsCounter
                );
            }

            if (sumXEurToPayForOneToken > 0) {
                uint sumXEuroToPay = sumXEurToPayForOneToken * balanceOf[to];
                //  if (sumXEuroToPay <= xEuro.balanceOf(address(this))) {
                bool result = xEuro.transfer(to, sumXEuroToPay);
                emit DividendsPaymentXEuro(
                    result,
                    to,
                    nextShareholderToPayDividends,
                    sumXEuroToPay,
                    nextShareholderToPayDividends,
                    dividendsRoundsCounter
                );
                //  }
            }

        }

        // if the round started shareholdersCounter can not be zero
        // because to start the round we need at least one registered share and thus at least one registered shareholder

        uint feeForTxCaller = dividendsRound[dividendsRoundsCounter].weiForTxFees / shareholdersCounter;

        if (
            feeForTxCaller > 0
            && msg.sender == tx.origin // < msg.sender is not a contract (to prevent reentrancy)
        ) {

            // we use send not transfer (returns false, not fail)
            bool feePaymentSuccessful = msg.sender.send(feeForTxCaller);
            emit FeeForDividendsDistributionTxPaid(
                dividendsRoundsCounter,
                nextShareholderToPayDividends,
                to,
                msg.sender,
                feeForTxCaller,
                feePaymentSuccessful
            );
        }

        // if this is the last registered shareholder for this round
        // then FINISH the round:
        if (nextShareholderToPayDividends == shareholdersCounter) {

            dividendsRound[dividendsRoundsCounter].roundIsRunning = false;
            dividendsRound[dividendsRoundsCounter].roundFinishedOnUnixTime = now;

            emit DividendsPaymentsFinished(
                dividendsRoundsCounter
            );
        }

        return true;
    }

    /*
    * Interested party can provide funds to pay for dividends distribution.
    * @param forDividendsRound Number (Id) of dividends payout round.
    * @param sumInWei Sum in wei received.
    * @param from Address from which sum was received.
    * @param currentSum Current sum of wei to reward accounts sending dividends distributing transactions.
    */
    event FundsToPayForDividendsDistributionReceived(
        uint indexed forDividendsRound,
        uint sumInWei,
        address indexed from,
        uint currentSum
    );

    /*
    * Function to add funds to reward transactions distributing dividends in this round/
    */
    function fundDividendsPayout() public payable returns (bool success){

        /* We allow this only for running round */
        require(
            dividendsRound[dividendsRoundsCounter].roundIsRunning,
            "Dividends payout is not running"
        );

        dividendsRound[dividendsRoundsCounter].weiForTxFees = dividendsRound[dividendsRoundsCounter].weiForTxFees + msg.value;

        emit FundsToPayForDividendsDistributionReceived(
            dividendsRoundsCounter,
            msg.value,
            msg.sender,
            dividendsRound[dividendsRoundsCounter].weiForTxFees // totalSum
        );

        return true;
    }

    /*
    * @dev startDividendsPayments() and fundDividendsPayout() combined for convenience
    */
    function startDividendsPaymentsAndFundDividendsPayout() external payable returns (bool success) {
        startDividendsPayments();
        return fundDividendsPayout();
    }

    /* ============= ERC20 functions ============ */

    /**
    * dev:
    * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md#approve
    * there is an attack:
    * https://github.com/CORIONplatform/solidity/issues/6,
    * https://drive.google.com/file/d/0ByMtMw2hul0EN3NCaVFHSFdxRzA/view
    * but this function is required by ERC-20:
    * To prevent attack vectors like the one described on https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/
    * and discussed on https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 ,
    * clients SHOULD make sure to create user interfaces in such a way that they set the allowance first to 0 before
    * setting it to another value for the same spender.
    * THOUGH The contract itself shouldn't enforce it, to allow backwards compatibility with contracts deployed before
    *
    * @param _spender The address which will spend the funds.
    * @param _value The amount of tokens to be spent.
    */
    function approve(address _spender, uint _value) public returns (bool success){
        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    /**
    * @notice Approve another address to spend tokens from the tokenholder account
    * dev: Overloaded approve function
    *      See https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/
    * @param _spender The address which will spend the funds.
    * @param _currentValue The current value of allowance for spender
    * @param _value The amount of tokens to be spent.
    */
    function approve(address _spender, uint _currentValue, uint _value) external returns (bool success){
        require(
            allowance[msg.sender][_spender] == _currentValue,
            "Current value in contract is different than provided current value"
        );
        return approve(_spender, _value);
    }

    /**
    * dev: private function that checks and changes balances and allowances for transfer functions
    */
    function _transferFrom(address _from, address _to, uint _value) private returns (bool success) {

        require(
            _to != address(0),
            "_to was 0x0 address"
        );

        require(
            !dividendsRound[dividendsRoundsCounter].roundIsRunning,
            "Transfers blocked while dividends are distributed"
        );

        require(
            _from == msg.sender || _value <= allowance[_from][msg.sender],
            "Sender not authorized"
        );

        // check if _from account has the required amount, if not, throw an exception
        require(
            _value <= balanceOf[_from],
            "Account doesn't have required amount"
        );

        balanceOf[_from] = balanceOf[_from].sub(_value);
        balanceOf[_to] = balanceOf[_to].add(_value);

        uint fromId = shareholderID[_from];
        uint toId = shareholderID[_to];

        if (fromId > 0) {
            shareholdersLedgerByEthAddress[_from].balanceOf = balanceOf[_from];
            shareholdersLedgerByIdNumber[fromId].balanceOf = balanceOf[_from];
        }

        if (toId > 0) {
            shareholdersLedgerByEthAddress[_to].balanceOf = balanceOf[_to];
            shareholdersLedgerByIdNumber[toId].balanceOf = balanceOf[_to];
        }

        if (fromId > 0 && toId == 0) {
            // shares goes from registered address to unregistered address
            // subtract from 'registeredShares'
            registeredShares = registeredShares.sub(_value);
        } else if (fromId == 0 && toId > 0) {
            // shares goes from unregistered address to registered address
            // add to 'registeredShares'
            registeredShares = registeredShares.add(_value);
        }

        // If allowance used, change allowances correspondingly
        if (_from != msg.sender) {
            allowance[_from][msg.sender] = allowance[_from][msg.sender].sub(_value);
        }

        emit Transfer(_from, _to, _value);

        return true;
    }