library Helpers {

    /**
     * @dev Internal function to convert bytes32 to string and trim zeroes.
     */
    function toString(bytes32 data) internal pure returns (string memory) {
        uint256 counter = 0;
        for (uint256 i = 0; i < 32; i++) {
            if (data[i] != bytes1(0)) {
                counter++;
            }
        }

        bytes memory result = new bytes(counter);
        counter = 0;
        for (uint256 i = 0; i < 32; i++) {
            if (data[i] != bytes1(0)) {
                result[counter] = data[i];
                counter++;
            }
        }

        return string(result);
    }

    /**
     * @dev Internal function to convert uint256 to string.
     */
    function toString(uint256 data) internal pure returns (string memory) {
        uint256 length = 0;

        uint256 dataCopy = data;
        while (dataCopy != 0) {
            length++;
            dataCopy /= 10;
        }

        bytes memory result = new bytes(length);
        dataCopy = data;

        // Here, we have on-purpose underflow cause we need case `i = 0` to be included in the loop
        for (uint256 i = length - 1; i < length; i--) {
            result[i] = bytes1(uint8(48 + dataCopy % 10));
            dataCopy /= 10;
        }

        return string(result);
    }
}
/**
 * @notice Library helps to convert different types to strings.
 * @author Igor Sobolev <sobolev@zerion.io>
 */
function toString(uint256 data) internal pure returns (string memory) {
    uint256 length = 0;

    uint256 dataCopy = data;
    while (dataCopy != 0) {
        length++;
        dataCopy /= 10;
    }

    bytes memory result = new bytes(length);
    dataCopy = data;

    // Here, we have on-purpose underflow cause we need case `i = 0` to be included in the loop
    for (uint256 i = length - 1; i < length; i--) {
        result[i] = bytes1(uint8(48 + dataCopy % 10));
        dataCopy /= 10;
    }

    return string(result);
}

/**
 * @dev Internal function to convert uint256 to string.
 */