text:
/**
 * @file posixHelper.cc
 * @author Rafal Slota
 * @copyright (C) 2015 ACK CYFRONET AGH
 * @copyright This software is released under the MIT license cited in
 * 'LICENSE.txt'
 */

#ifdef linux
/* For pread()/pwrite()/utimensat() */
#define _XOPEN_SOURCE 700
#endif // linux

#include "posixHelper.h"
#include "helpers/logging.h"
#include "monitoring/monitoring.h"

#include <boost/any.hpp>

#include <cerrno>
#include <dirent.h>
#if FUSE_USE_VERSION > 30
#include <fuse3/fuse.h>
#else
#include <fuse/fuse.h>
#endif
#include <sys/stat.h>
#include <sys/xattr.h>

#if defined(__linux__)
#include <sys/fsuid.h>
#endif

#include <functional>
#include <map>
#include <memory>
#include <set>
#include <string>

#if defined(__APPLE__)
/**
 * These funtions provide drop-in replacements for setfsuid and setfsgid on OSX
 */
static inline int setfsuid(uid_t uid)
{
    LOG_FCALL() << LOG_FARG(uid);

    uid_t olduid = geteuid();

    seteuid(uid);

    if (errno != EINVAL)
        errno = 0;

    return olduid;
}

static inline int setfsgid(gid_t gid)
{
    LOG_FCALL() << LOG_FARG(gid);

    gid_t oldgid = getegid();

    setegid(gid);

    if (errno != EINVAL)
        errno = 0;

    return oldgid;
}
#endif

namespace {

// Retry only in case one of these errors occured
const std::set<int> &POSIXRetryErrors()
{
    static const std::set<int> POSIX_RETRY_ERRORS = {
        EINTR,
        EIO,
        EAGAIN,
        EACCES,
        EBUSY,
        EMFILE,
        ETXTBSY,
        ESPIPE,
        EMLINK,
        EPIPE,
        EDEADLK,
        EWOULDBLOCK,
        ENOLINK,
        EADDRINUSE,
        EADDRNOTAVAIL,
        ENETDOWN,
        ENETUNREACH,
        ECONNABORTED,
        ECONNRESET,
        ENOTCONN,
        EHOSTUNREACH,
        ECANCELED,
        ESTALE
#if !defined(__APPLE__)
        ,
        ENONET,
        EHOSTDOWN,
        EREMOTEIO,
        ENOMEDIUM
#endif
    };
    return POSIX_RETRY_ERRORS;
}

inline bool POSIXRetryCondition(int result, const std::string &operation)
{
    auto ret = (result >= 0 ||
        POSIXRetryErrors().find(errno) == POSIXRetryErrors().end());

    if (!ret) {
        LOG(WARNING) << "Retrying POSIX helper operation '" << operation
                     << "' due to error: " << errno;
        ONE_METRIC_COUNTER_INC(
            "comp.helpers.mod.posix." + operation + ".retries");
    }

    return ret;
}

template <typename... Args1, typename... Args2>
inline void setResult(folly::Promise<folly::Unit> &promise,
    const std::string &operation, int (*fun)(Args2...), Args1 &&...args)
{
    auto ret =
        one::helpers::retry([&]() { return fun(std::forward<Args1>(args)...); },
            std::bind(POSIXRetryCondition, std::placeholders::_1, operation));

    if (ret < 0)
        promise.setException(one::helpers::makePosixException(errno));
    else
        promise.setValue();
}

template <typename... Args1, typename... Args2>
inline folly::Future<folly::Unit> setResult(
    const std::string &operation, int (*fun)(Args2...), Args1 &&...args)
{
    auto ret =
        one::helpers::retry([&]() { return fun(std::forward<Args1>(args)...); },
            std::bind(POSIXRetryCondition, std::placeholders::_1, operation));

    if (ret < 0)
        return one::helpers::makeFuturePosixException(errno);

    return folly::makeFuture();
}

} // namespace

namespace one {
namespace helpers {

#if defined(__linux__) || defined(__APPLE__)
UserCtxSetter::UserCtxSetter(const uid_t uid, const gid_t gid)
    : m_uid{uid}
    , m_gid{gid}
    , m_prevUid{static_cast<uid_t>(setfsuid(uid))}
    , m_prevGid{static_cast<gid_t>(setfsgid(gid))}
    , m_currUid{static_cast<uid_t>(setfsuid(-1))}
    , m_currGid{static_cast<gid_t>(setfsgid(-1))}
{
}

UserCtxSetter::~UserCtxSetter()
{
    setfsuid(m_prevUid);
    setfsgid(m_prevGid);
}

bool UserCtxSetter::valid() const
{
    return (m_uid == static_cast<uid_t>(-1) || m_currUid == m_uid) &&
        (m_gid == static_cast<gid_t>(-1) || m_currGid == m_gid);
}
#else
UserCtxSetter::UserCtxSetter(const int, const int) { }
UserCtxSetter::~UserCtxSetter() { }
bool UserCtxSetter::valid() const { return true; }
#endif

std::shared_ptr<PosixFileHandle> PosixFileHandle::create(
    const folly::fbstring &fileId, const uid_t uid, const gid_t gid,
    const int fileHandle, std::shared_ptr<PosixHelper> helper,
    std::shared_ptr<folly::Executor> executor, Timeout timeout)
{
    auto ptr = std::shared_ptr<PosixFileHandle>(new PosixFileHandle(fileId, uid,
        gid, fileHandle, std::move(helper), std::move(executor), timeout));
    ptr->initOpScheduler(ptr);
    return ptr;
}

PosixFileHandle::PosixFileHandle(const folly::fbstring &fileId, const uid_t uid,
    const gid_t gid, const int fileHandle, std::shared_ptr<PosixHelper> helper,
    std::shared_ptr<folly::Executor> executor, Timeout timeout)
    : FileHandle{fileId, std::move(helper)}
    , m_uid{uid}
    , m_gid{gid}
    , m_fh{fileHandle}
    , m_executor{std::move(executor)}
    , m_timeout{timeout}
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(uid) << LOG_FARG(gid)
                << LOG_FARG(fileHandle);
}

void PosixFileHandle::initOpScheduler(std::shared_ptr<PosixFileHandle> self)
{
    opScheduler = FlatOpScheduler<HandleOp, OpExec>::create(
        m_executor, std::make_shared<OpExec>(self));
}

PosixFileHandle::~PosixFileHandle()
{
    LOG_FCALL();

    if (m_needsRelease.exchange(false)) {
        UserCtxSetter userCTX{m_uid, m_gid};
        if ((helper()->executionContext() == ExecutionContext::ONEPROVIDER) &&
            !userCTX.valid()) {
            LOG(WARNING) << "Failed to release file " << m_fh
                         << ": failed to set user context";
            return;
        }

        if (close(m_fh) == -1) {
            auto ec = makePosixError(errno);
            LOG(WARNING) << "Failed to release file " << m_fh << ": "
                         << ec.message();
        }
    }
}

PosixFileHandle::OpExec::OpExec(const std::shared_ptr<PosixFileHandle> &handle)
    : m_handle{handle}
{
}

std::unique_ptr<UserCtxSetter> PosixFileHandle::OpExec::startDrain()
{
    if (auto handle = m_handle.lock()) {
        auto userCtx =
            std::make_unique<UserCtxSetter>(handle->m_uid, handle->m_gid);
        m_validCtx = (handle->helper()->executionContext() ==
                         ExecutionContext::ONECLIENT) ||
            userCtx->valid();
        return userCtx;
    }

    return std::unique_ptr<UserCtxSetter>{nullptr};
}

void PosixFileHandle::OpExec::operator()(ReadOp &op) const
{
    if (!m_validCtx) {
        op.promise.setException(makePosixException(EDOM));
        return;
    }

    using one::logging::log_timer;
    using one::logging::csv::log;
    using one::logging::csv::read_write_perf;

    log_timer<> logTimer;

    auto handle = m_handle.lock();
    if (!handle) {
        op.promise.setException(makePosixException(ECANCELED));
        return;
    }

    folly::IOBufQueue buf{folly::IOBufQueue::cacheChainLength()};

    void *data = buf.preallocate(op.size, op.size).first;

    LOG_DBG(2) << "Attempting to read " << op.size << " bytes at offset "
               << op.offset << " from file " << handle->fileId();

    auto res =
        retry([&]() { return ::pread(handle->m_fh, data, op.size, op.offset); },
            std::bind(POSIXRetryCondition, std::placeholders::_1, "pread"));

    if (res == -1) {
        LOG_DBG(1) << "Reading from file " << handle->fileId()
                   << " failed with error " << errno;
        ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.errors.read");
        op.promise.setException(makePosixException(errno));
        return;
    }

    buf.postallocate(res);

    log<read_write_perf>(handle->fileId(), "PosixHelper", "read", op.offset,
        op.size, logTimer.stop());

    LOG_DBG(2) << "Read " << res << " bytes from file " << handle->fileId();

    ONE_METRIC_TIMERCTX_STOP(op.timer, res);

    op.promise.setValue(std::move(buf));
}

void PosixFileHandle::OpExec::operator()(WriteOp &op) const
{
    if (!m_validCtx) {
        op.promise.setException(makePosixException(EDOM));
        return;
    }

    using one::logging::log_timer;
    using one::logging::csv::log;
    using one::logging::csv::read_write_perf;

    log_timer<> logTimer;

    auto handle = m_handle.lock();
    if (!handle) {
        op.promise.setException(makePosixException(ECANCELED));
        return;
    }

    auto res = ::lseek(handle->m_fh, op.offset, SEEK_SET);
    if (res == -1) {
        op.promise.setException(makePosixException(errno));
        return;
    }

    if (op.buf.empty()) {
        op.promise.setValue(0);
        return;
    }

    auto iobuf = op.buf.empty() ? folly::IOBuf::create(0) : op.buf.move();
    if (iobuf->isChained()) {
        LOG_DBG(2) << "Coalescing chained buffer at offset " << op.offset
                   << " of size: " << iobuf->length();
        iobuf->unshare();
        iobuf->coalesce();
    }

    auto iov = iobuf->getIov();
    auto iov_size = iov.size();
    auto size = 0;

    LOG_DBG(2) << "Attempting to write " << iobuf->length()
               << " bytes at offset " << op.offset << " to file "
               << handle->fileId();

    for (std::size_t iov_off = 0; iov_off < iov_size; iov_off += IOV_MAX) {
        res = retry(
            [&]() {
                // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
                return ::writev(handle->m_fh, iov.data() + iov_off,
                    std::min<std::size_t>(IOV_MAX, iov_size - iov_off));
            },
            [](int result) { return result != -1; });

        if (res == -1) {
            LOG(ERROR) << "Writing to file " << handle->fileId()
                       << " failed with error " << errno;
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.errors.write");
            op.promise.setException(makePosixException(errno));
            return;
        }
        size += res;
    }

    log<read_write_perf>(handle->fileId(), "PosixHelper", "write", op.offset,
        size, logTimer.stop());

    LOG_DBG(2) << "Written " << size << " bytes to file " << handle->fileId()
               << " at offset " << op.offset;

    ONE_METRIC_TIMERCTX_STOP(op.timer, size);

    op.promise.setValue(size);
}

void PosixFileHandle::OpExec::operator()(ReleaseOp &op) const
{
    if (!m_validCtx) {
        op.promise.setException(makePosixException(EDOM));
        return;
    }

    auto handle = m_handle.lock();
    if (!handle) {
        op.promise.setException(makePosixException(ECANCELED));
        return;
    }

    ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.release");
    LOG_DBG(2) << "Closing file " << handle->fileId();
    setResult(op.promise, "close", close, handle->m_fh);
}

void PosixFileHandle::OpExec::operator()(FsyncOp &op) const
{
    if (!m_validCtx) {
        op.promise.setException(makePosixException(EDOM));
        return;
    }

    auto handle = m_handle.lock();
    if (!handle) {
        op.promise.setException(makePosixException(ECANCELED));
        return;
    }

    ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.fsync");
    LOG_DBG(2) << "Syncing file " << handle->fileId();
    setResult(op.promise, "fsync", ::fsync, handle->m_fh);
}

void PosixFileHandle::OpExec::operator()(FlushOp &op) const
{
    if (!m_validCtx) {
        op.promise.setException(makePosixException(EDOM));
        return;
    }

    auto handle = m_handle.lock();
    if (!handle) {
        op.promise.setException(makePosixException(ECANCELED));
        return;
    }

    ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.flush");
    LOG_DBG(2) << "Flushing file " << handle->fileId();
    op.promise.setValue();
}

folly::Future<folly::IOBufQueue> PosixFileHandle::read(
    const off_t offset, const std::size_t size)
{
    LOG_FCALL() << LOG_FARG(offset) << LOG_FARG(size);
    auto timer = ONE_METRIC_TIMERCTX_CREATE("comp.helpers.mod.posix.read");
    return opScheduler->schedule(ReadOp{{}, offset, size, std::move(timer)});
}

folly::Future<std::size_t> PosixFileHandle::write(
    const off_t offset, folly::IOBufQueue buf, WriteCallback &&writeCb)
{
    LOG_FCALL() << LOG_FARG(offset) << LOG_FARG(buf.chainLength());
    auto timer = ONE_METRIC_TIMERCTX_CREATE("comp.helpers.mod.posix.write");
    return opScheduler
        ->schedule(WriteOp{{}, offset, std::move(buf), std::move(timer)})
        .thenValue([writeCb = std::move(writeCb)](std::size_t &&written) {
            if (writeCb)
                writeCb(written);
            return written;
        });
}

folly::Future<folly::Unit> PosixFileHandle::release()
{
    LOG_FCALL();

    if (!m_needsRelease.exchange(false))
        return folly::makeFuture();

    return opScheduler->schedule(ReleaseOp{});
}

folly::Future<folly::Unit> PosixFileHandle::flush()
{
    LOG_FCALL();
    return opScheduler->schedule(FlushOp{});
}

folly::Future<folly::Unit> PosixFileHandle::fsync(bool /*isDataSync*/)
{
    LOG_FCALL();
    return opScheduler->schedule(FsyncOp{});
}

PosixHelper::PosixHelper(std::shared_ptr<PosixHelperParams> params,
    std::shared_ptr<folly::Executor> executor,
    ExecutionContext executionContext)
    : StorageHelper{executionContext}
    , m_executor{std::move(executor)}
{
    LOG_FCALL();

    invalidateParams()->setValue(std::move(params));
}

folly::Future<struct stat> PosixHelper::getattr(const folly::fbstring &fileId)
{
    LOG_FCALL() << LOG_FARG(fileId);

    return folly::via(
        m_executor.get(), [filePath = root(fileId), uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.getattr");

            struct stat stbuf = {};

            LOG_DBG(2) << "Attempting to stat file " << filePath;

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException<struct stat>(EDOM);

            auto res = retry(
                [&]() { return ::lstat(filePath.c_str(), &stbuf); },
                std::bind(POSIXRetryCondition, std::placeholders::_1, "lstat"));

            if (res == -1) {
                LOG_DBG(1) << "Stating file " << filePath
                           << " failed with error " << errno;
                return makeFuturePosixException<struct stat>(errno);
            }

            return folly::makeFuture(stbuf);
        });
}

folly::Future<folly::Unit> PosixHelper::access(
    const folly::fbstring &fileId, const int mask)
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(mask);

    return folly::via(m_executor.get(),
        [filePath = root(fileId), mask, uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.access");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            LOG_DBG(2) << "Attempting to access file " << filePath;

            return setResult("access", ::access, filePath.c_str(), mask);
        });
}

folly::Future<folly::fbvector<folly::fbstring>> PosixHelper::readdir(
    const folly::fbstring &fileId, off_t offset, size_t count)
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(offset) << LOG_FARG(count);

    return folly::via(m_executor.get(),
        [filePath = root(fileId), offset, count, uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.readdir");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException<
                    folly::fbvector<folly::fbstring>>(EDOM);

            folly::fbvector<folly::fbstring> ret;

            LOG_DBG(2) << "Attempting to read directory " << filePath;

            DIR *dir{nullptr};
            struct dirent *dp{nullptr};
            dir = retry([&]() { return opendir(filePath.c_str()); },
                [](DIR *d) {
                    return d != nullptr ||
                        POSIXRetryErrors().find(errno) ==
                        POSIXRetryErrors().end();
                });

            if (dir == nullptr) {
                LOG_DBG(1) << "Opening directory " << filePath
                           << " failed with error " << errno;
                return makeFuturePosixException<
                    folly::fbvector<folly::fbstring>>(errno);
            }

            int offset_ = offset;
            int count_ = count;
            while ((dp = retry([&]() { return ::readdir(dir); },
                        [](struct dirent *de) {
                            return de != nullptr ||
                                POSIXRetryErrors().find(errno) ==
                                POSIXRetryErrors().end();
                        })) != nullptr &&
                count_ > 0) {
                if (strcmp(static_cast<char *>(dp->d_name), ".") != 0 &&
                    strcmp(static_cast<char *>(dp->d_name), "..") != 0) {
                    if (offset_ > 0) {
                        --offset_;
                    }
                    else {
                        ret.push_back(
                            folly::fbstring(static_cast<char *>(dp->d_name)));
                        --count_;
                    }
                }
            }
            closedir(dir);

            LOG_DBG(2) << "Read directory " << filePath << " at offset "
                       << offset << " with entries " << LOG_VEC(ret);

            return folly::makeFuture<folly::fbvector<folly::fbstring>>(
                std::move(ret));
        });
}

folly::Future<folly::fbstring> PosixHelper::readlink(
    const folly::fbstring &fileId)
{
    LOG_FCALL() << LOG_FARG(fileId);

    return folly::via(
        m_executor.get(), [filePath = root(fileId), uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.readlink");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException<folly::fbstring>(EDOM);

            LOG_DBG(1) << "Attempting to read link " << filePath;

            constexpr std::size_t maxSize = 1024;
            auto buf = folly::IOBuf::create(maxSize);
            auto res = retry(
                [&]() {
                    return ::readlink(filePath.c_str(),
                        reinterpret_cast<char *>(buf->writableData()),
                        maxSize - 1);
                },
                std::bind(
                    POSIXRetryCondition, std::placeholders::_1, "readlink"));

            if (res == -1) {
                LOG_DBG(1) << "Reading link " << filePath
                           << " failed with error " << errno;
                return makeFuturePosixException<folly::fbstring>(errno);
            }

            buf->append(res);

            auto target = buf->moveToFbString();

            LOG_DBG(2) << "Read link " << filePath << " - resolves to "
                       << target;

            return folly::makeFuture(std::move(target));
        });
}

folly::Future<folly::Unit> PosixHelper::mknod(const folly::fbstring &fileId,
    const mode_t unmaskedMode, const FlagsSet &flags, const dev_t rdev)
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(unmaskedMode)
                << LOG_FARG(flagsToMask(flags));

    const mode_t mode = unmaskedMode | flagsToMask(flags);
    return folly::via(m_executor.get(),
        [filePath = root(fileId), mode, rdev, uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.mknod");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            int res{0};

            /* On Linux this could just be 'mknod(path, mode, rdev)' but
               this is more portable */
            if (S_ISREG(mode)) {
                res = retry(
                    [&]() {
                        // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
                        return ::open(filePath.c_str(),
                            O_CREAT | O_EXCL | O_WRONLY, mode);
                    },
                    std::bind(
                        POSIXRetryCondition, std::placeholders::_1, "open"));

                if (res >= 0)
                    res = close(res);
            }
            else if (S_ISFIFO(mode)) {
                res = retry([&]() { return ::mkfifo(filePath.c_str(), mode); },
                    std::bind(
                        POSIXRetryCondition, std::placeholders::_1, "mkfifo"));
            }
            else {
                res = retry(
                    [&]() { return ::mknod(filePath.c_str(), mode, rdev); },
                    std::bind(
                        POSIXRetryCondition, std::placeholders::_1, "mknod"));
            }

            if (res == -1)
                return makeFuturePosixException(errno);

            return folly::makeFuture();
        });
}

folly::Future<folly::Unit> PosixHelper::mkdir(
    const folly::fbstring &fileId, const mode_t mode)
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(mode);

    return folly::via(m_executor.get(),
        [filePath = root(fileId), mode, uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.mkdir");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            return setResult("mkdir", ::mkdir, filePath.c_str(), mode);
        });
}

folly::Future<folly::Unit> PosixHelper::unlink(
    const folly::fbstring &fileId, const size_t /*currentSize*/)
{
    LOG_FCALL() << LOG_FARG(fileId);

    return folly::via(
        m_executor.get(), [filePath = root(fileId), uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.unlink");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            return setResult("unlink", ::unlink, filePath.c_str());
        });
}

folly::Future<folly::Unit> PosixHelper::rmdir(const folly::fbstring &fileId)
{
    LOG_FCALL() << LOG_FARG(fileId);

    return folly::via(
        m_executor.get(), [filePath = root(fileId), uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.rmdir");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            return setResult("rmdir", ::rmdir, filePath.c_str());
        });
}

folly::Future<folly::Unit> PosixHelper::symlink(
    const folly::fbstring &from, const folly::fbstring &to)
{
    LOG_FCALL() << LOG_FARG(from) << LOG_FARG(to);

    return folly::via(m_executor.get(),
        [from = root(from), to = root(to), uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.symlink");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            return setResult("symlink", ::symlink, from.c_str(), to.c_str());
        });
}

folly::Future<folly::Unit> PosixHelper::rename(
    const folly::fbstring &from, const folly::fbstring &to)
{
    LOG_FCALL() << LOG_FARG(from) << LOG_FARG(to);

    return folly::via(m_executor.get(),
        [from = root(from), to = root(to), uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.rename");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            return setResult("rename", ::rename, from.c_str(), to.c_str());
        });
}

folly::Future<folly::Unit> PosixHelper::link(
    const folly::fbstring &from, const folly::fbstring &to)
{
    LOG_FCALL() << LOG_FARG(from) << LOG_FARG(to);

    return folly::via(m_executor.get(),
        [from = root(from), to = root(to), uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.link");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            return setResult("link", ::link, from.c_str(), to.c_str());
        });
}

folly::Future<folly::Unit> PosixHelper::chmod(
    const folly::fbstring &fileId, const mode_t mode)
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(mode);

    return folly::via(m_executor.get(),
        [filePath = root(fileId), mode, uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.chmod");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            return setResult("chmod", ::chmod, filePath.c_str(), mode);
        });
}

folly::Future<folly::Unit> PosixHelper::chown(
    const folly::fbstring &fileId, const uid_t uid, const gid_t gid)
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(uid) << LOG_FARG(gid);

    return folly::via(m_executor.get(),
        [filePath = root(fileId), argUid = uid, argGid = gid, uid = this->uid(),
            gid = this->gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.chown");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            return setResult(
                "chown", ::chown, filePath.c_str(), argUid, argGid);
        });
}

folly::Future<folly::Unit> PosixHelper::truncate(const folly::fbstring &fileId,
    const off_t size, const size_t /*currentSize*/)
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(size);

    return folly::via(m_executor.get(),
        [filePath = root(fileId), size, uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.truncate");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            return setResult("truncate", ::truncate, filePath.c_str(), size);
        });
}

folly::Future<FileHandlePtr> PosixHelper::open(const folly::fbstring &fileId,
    const int flags, const Params & /*openParams*/)
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(flags);

    return folly::via(m_executor.get(),
        [fileId, filePath = root(fileId), flags, executor = m_executor,
            uid = uid(), gid = gid(), self = shared_from_this(),
            timeout = timeout()]() mutable {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.open");

            UserCtxSetter userCTX{uid, gid};
            if ((self->executionContext() == ExecutionContext::ONEPROVIDER) &&
                !userCTX.valid())
                return makeFuturePosixException<FileHandlePtr>(EDOM);

            int res = retry(
                [&]() {
                    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
                    return ::open(filePath.c_str(), flags);
                },
                std::bind(POSIXRetryCondition, std::placeholders::_1, "open"));

            if (res == -1)
                return makeFuturePosixException<FileHandlePtr>(errno);

            auto handle = PosixFileHandle::create(fileId, uid, gid, res,
                std::move(self), std::move(executor), timeout);

            return folly::makeFuture<FileHandlePtr>(std::move(handle));
        });
}

folly::Future<folly::fbstring> PosixHelper::getxattr(
    const folly::fbstring &fileId, const folly::fbstring &name)
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(name);

    return folly::via(m_executor.get(),
        [filePath = root(fileId), name, uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.getxattr");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException<folly::fbstring>(EDOM);

            constexpr std::size_t initialMaxSize = 256;
            auto buf = folly::IOBuf::create(initialMaxSize);

            int res = retry(
                [&]() {
                    return ::getxattr(filePath.c_str(), name.c_str(),
                        reinterpret_cast<char *>(buf->writableData()),
                        initialMaxSize - 1
#if defined(__APPLE__)
                        ,
                        0, 0
#endif
                    );
                },
                std::bind(
                    POSIXRetryCondition, std::placeholders::_1, "getxattr"));
            // If the initial buffer for xattr value was too small, try
            // again with maximum allowed value
            if (res == -1 && errno == ERANGE) {
                buf = folly::IOBuf::create(XATTR_SIZE_MAX);
                res = retry(
                    [&]() {
                        return ::getxattr(filePath.c_str(), name.c_str(),
                            reinterpret_cast<char *>(buf->writableData()),
                            XATTR_SIZE_MAX - 1
#if defined(__APPLE__)
                            ,
                            0, 0
#endif
                        );
                    },
                    std::bind(POSIXRetryCondition, std::placeholders::_1,
                        "getxattr"));
            }

            if (res == -1)
                return makeFuturePosixException<folly::fbstring>(errno);

            buf->append(res);
            return folly::makeFuture(buf->moveToFbString());
        });
}

folly::Future<folly::Unit> PosixHelper::setxattr(const folly::fbstring &fileId,
    const folly::fbstring &name, const folly::fbstring &value, bool create,
    bool replace)
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(name) << LOG_FARG(value)
                << LOG_FARG(create) << LOG_FARG(replace);

    return folly::via(m_executor.get(),
        [filePath = root(fileId), name, value, create, replace, uid = uid(),
            gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.setxattr");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException<folly::Unit>(EDOM);

            int flags = 0;

            if (create && replace) {
                return makeFuturePosixException<folly::Unit>(EINVAL);
            }

            if (create) {
                flags = XATTR_CREATE;
            }
            else if (replace) {
                flags = XATTR_REPLACE;
            }

            return setResult("setxattr", ::setxattr, filePath.c_str(),
                name.c_str(), value.c_str(), value.size(),
#if defined(__APPLE__)
                0,
#endif
                flags);
        });
}

folly::Future<folly::Unit> PosixHelper::removexattr(
    const folly::fbstring &fileId, const folly::fbstring &name)
{
    LOG_FCALL() << LOG_FARG(fileId) << LOG_FARG(name);

    return folly::via(m_executor.get(),
        [filePath = root(fileId), name, uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.removexattr");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException(EDOM);

            return setResult(
                "removexattr", ::removexattr, filePath.c_str(), name.c_str()
#if defined(__APPLE__)
                                                                    ,
                0
#endif
            );
        });
}

folly::Future<folly::fbvector<folly::fbstring>> PosixHelper::listxattr(
    const folly::fbstring &fileId)
{
    LOG_FCALL() << LOG_FARG(fileId);

    return folly::via(
        m_executor.get(), [filePath = root(fileId), uid = uid(), gid = gid()] {
            ONE_METRIC_COUNTER_INC("comp.helpers.mod.posix.listxattr");

            UserCtxSetter userCTX{uid, gid};
            if (!userCTX.valid())
                return makeFuturePosixException<
                    folly::fbvector<folly::fbstring>>(EDOM);

            folly::fbvector<folly::fbstring> ret;

            ssize_t buflen = retry(
                [&]() {
                    return ::listxattr(filePath.c_str(), nullptr, 0
#if defined(__APPLE__)
                        ,
                        0
#endif
                    );
                },
                std::bind(
                    POSIXRetryCondition, std::placeholders::_1, "listxattr"));

            if (buflen == -1)
                return makeFuturePosixException<
                    folly::fbvector<folly::fbstring>>(errno);

            if (buflen == 0)
                return folly::makeFuture<folly::fbvector<folly::fbstring>>(
                    std::move(ret));

            auto buf = std::unique_ptr<char[]>(new char[buflen]); // NOLINT
            buflen = ::listxattr(filePath.c_str(), buf.get(), buflen
#if defined(__APPLE__)
                ,
                0
#endif
            );

            if (buflen == -1)
                return makeFuturePosixException<
                    folly::fbvector<folly::fbstring>>(errno);

            char *xattrNamePtr = buf.get();
            while (xattrNamePtr < buf.get() + buflen) {
                ret.emplace_back(xattrNamePtr);
                // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
                xattrNamePtr +=
                    strnlen(xattrNamePtr, buflen - (buf.get() - xattrNamePtr)) +
                    1;
            }

            return folly::makeFuture<folly::fbvector<folly::fbstring>>(
                std::move(ret));
        });
}

} // namespace helpers
} // namespace one

ext: cc

max_stars_repo_name: onedata/helpers

max_issues_repo_name: onedata/helpers

max_forks_repo_name: onedata/helpers


text:
#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_DESTINATION_HPP_20100624
#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_DESTINATION_HPP_20100624

// Copyright 2010 (C) Dean Michael Berris
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <boost/network/protocol/http/support/client_or_server.hpp>
#include <boost/network/support/pod_or_normal.hpp>
#include <boost/network/support/is_async.hpp>
#include <boost/thread/future.hpp>
#include <boost/concept/requires.hpp>

namespace boost { namespace network { namespace http {

    template <class Tag>
    struct basic_response;

    template <class Tag>
    struct basic_request;

    namespace impl {

        template <class Tag, class T>
        void destination(basic_response<Tag> & response, T const & value, mpl::false_ const &) {
            response << ::boost::network::destination(value);
        }

        template <class Tag, class T>
        void destination(basic_response<Tag> & response, T const & future, mpl::true_ const &) {
            response.destination(future);
        }

    }

    template <class Tag, class T>
    inline void
    destination(basic_response<Tag> & response, T const & value) {
        impl::destination(response, value, is_async<Tag>());
    }

    template <class R>
    struct ServerRequest;

    template <class Tag, class T>
    inline void
    destination_impl(basic_request<Tag> & request, T const & value, tags::server) {
        request.destination = value;
    }

    template <class Tag, class T>
    inline void
    destination_impl(basic_request<Tag> & request, T const & value, tags::pod) {
        request.destination = value;
    }

    template <class Tag, class T>
    inline void
    destination_impl(basic_request<Tag> & request, T const & value, tags::normal) {
        request.destination(value);
    }

    template <class Tag, class T>
    inline void
    destination_impl(basic_request<Tag> & request, T const & value, tags::client) {
        destination_impl(request, value, typename pod_or_normal<Tag>::type());
    }

    template <class Tag, class T>
    inline void
    destination(basic_request<Tag> & request, T const & value) {
        destination_impl(request, value, typename client_or_server<Tag>::type());
    }

} // namespace http

    namespace impl {

        template <class Message, class ValueType, class Async>
        inline void destination(Message const & message, ValueType const & destination_, http::tags::http_server, Async) {
            message.destination = destination_;
        }

    } /* impl */

} // namespace network

} // namespace boost

#include <boost/network/message/modifiers/destination.hpp>

#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_DESTINATION_HPP_20100624

ext: hpp

max_stars_repo_name: antoinelefloch/cpp-netlib

max_issues_repo_name: waTeim/boost

max_forks_repo_name: waTeim/boost


text:
//
// gnutls/rfc2818_verification.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2020 Paul-Louis Ageneau (paul-louis at ageneau dot org)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_ASIO_GNUTLS_RFC2818_VERIFICATION_HPP
#define BOOST_ASIO_GNUTLS_RFC2818_VERIFICATION_HPP

#include <boost/asio/gnutls/host_name_verification.hpp>

namespace boost {
namespace asio {
namespace gnutls {

// Verifies a certificate against a hostname according to the rules described in RFC 2818.
// Deprecated, use host_name_verification instead.
using rfc2818_verification = host_name_verification;

} // namespace gnutls
} // namespace asio
} // namespace boost

#endif // BOOST_ASIO_GNUTLS_RFC2818_VERIFICATION_HPP

max_stars_repo_name: SylemST-UtilCollection/libtorrent-build

max_issues_repo_name: SylemST-UtilCollection/libtorrent-build

max_forks_repo_name: SylemST-UtilCollection/libtorrent-build


text:
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/cppalliance/json
//

#ifndef BOOST_JSON_DETAIL_IMPL_HANDLER_HPP
#define BOOST_JSON_DETAIL_IMPL_HANDLER_HPP

#include <boost/json/detail/handler.hpp>
#include <utility>

BOOST_JSON_NS_BEGIN
namespace detail {

template<class... Args>
handler::
handler(Args&&... args)
    : st(std::forward<Args>(args)...)
{
}

bool
handler::
on_document_begin(
    error_code&)
{
    return true;
}

bool
handler::
on_document_end(
    error_code&)
{
    return true;
}

bool
handler::
on_object_begin(
    error_code&)
{
    return true;
}

bool
handler::
on_object_end(
    std::size_t n,
    error_code&)
{
    st.push_object(n);
    return true;
}

bool
handler::
on_array_begin(
    error_code&)
{
    return true;
}

bool
handler::
on_array_end(
    std::size_t n,
    error_code&)
{
    st.push_array(n);
    return true;
}

bool
handler::
on_key_part(
    string_view s,
    std::size_t,
    error_code&)
{
    st.push_chars(s);
    return true;
}

bool
handler::
on_key(
    string_view s,
    std::size_t,
    error_code&)
{
    st.push_key(s);
    return true;
}

bool
handler::
on_string_part(
    string_view s,
    std::size_t,
    error_code&)
{
    st.push_chars(s);
    return true;
}

bool
handler::
on_string(
    string_view s,
    std::size_t,
    error_code&)
{
    st.push_string(s);
    return true;
}

bool
handler::
on_number_part(
    string_view,
    error_code&)
{
    return true;
}

bool
handler::
on_int64(
    std::int64_t i,
    string_view,
    error_code&)
{
    st.push_int64(i);
    return true;
}

bool
handler::
on_uint64(
    std::uint64_t u,
    string_view,
    error_code&)
{
    st.push_uint64(u);
    return true;
}

bool
handler::
on_double(
    double d,
    string_view,
    error_code&)
{
    st.push_double(d);
    return true;
}

bool
handler::
on_bool(
    bool b,
    error_code&)
{
    st.push_bool(b);
    return true;
}

bool
handler::
on_null(error_code&)
{
    st.push_null();
    return true;
}

bool
handler::
on_comment_part(
    string_view,
    error_code&)
{
    return true;
}

bool
handler::
on_comment(
    string_view, error_code&)
{
    return true;
}

} // detail
BOOST_JSON_NS_END

#endif

ext: ipp

max_stars_repo_name: djarek/json

max_issues_repo_name: djarek/json

max_forks_repo_name: djarek/json


text:
// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the deep learning tools from the
    dlib C++ Library.  In it, we will show how to use the loss_metric layer to do
    metric learning.

    The main reason you might want to use this kind of algorithm is because you
    would like to use a k-nearest neighbor classifier or similar algorithm, but
    you don't know a good way to calculate the distance between two things.  A
    popular example would be face recognition.  There are a whole lot of papers
    that train some kind of deep metric learning algorithm that embeds face
    images in some vector space where images of the same person are close to each
    other and images of different people are far apart.  Then in that vector
    space it's very easy to do face recognition with some kind of k-nearest
    neighbor classifier.

    To keep this example as simple as possible we won't do face recognition.
    Instead, we will create a very simple network and use it to learn a mapping
    from 8D vectors to 2D vectors such that vectors with the same class labels
    are near each other.  If you want to see a more complex example that learns
    the kind of network you would use for something like face recognition read
    the dnn_metric_learning_on_images_ex.cpp example.

    You should also have read the examples that introduce the dlib DNN API before
    continuing.  These are dnn_introduction_ex.cpp and dnn_introduction2_ex.cpp.
*/

#include <dlib/dnn.h>
#include <iostream>

using namespace std;
using namespace dlib;

int main() try
{
    // The API for doing metric learning is very similar to the API for
    // multi-class classification.  In fact, the inputs are the same, a bunch of
    // labeled objects.  So here we create our dataset.  We make up some simple
    // vectors and label them with the integers 1,2,3,4.  The specific values of
    // the integer labels don't matter.
    std::vector<matrix<double,0,1>> samples;
    std::vector<unsigned long> labels;

    // class 1 training vectors
    samples.push_back({1,0,0,0,0,0,0,0}); labels.push_back(1);
    samples.push_back({0,1,0,0,0,0,0,0}); labels.push_back(1);

    // class 2 training vectors
    samples.push_back({0,0,1,0,0,0,0,0}); labels.push_back(2);
    samples.push_back({0,0,0,1,0,0,0,0}); labels.push_back(2);

    // class 3 training vectors
    samples.push_back({0,0,0,0,1,0,0,0}); labels.push_back(3);
    samples.push_back({0,0,0,0,0,1,0,0}); labels.push_back(3);

    // class 4 training vectors
    samples.push_back({0,0,0,0,0,0,1,0}); labels.push_back(4);
    samples.push_back({0,0,0,0,0,0,0,1}); labels.push_back(4);

    // Make a network that simply learns a linear mapping from 8D vectors to 2D
    // vectors.
    using net_type = loss_metric<fc<2,input<matrix<double,0,1>>>>;
    net_type net;
    dnn_trainer<net_type> trainer(net);
    trainer.set_learning_rate(0.1);

    // It should be emphasized out that it's really important that each mini-batch contain
    // multiple instances of each class of object.  This is because the metric learning
    // algorithm needs to consider pairs of objects that should be close as well as pairs
    // of objects that should be far apart during each training step.  Here we just keep
    // training on the same small batch so this constraint is trivially satisfied.
    while(trainer.get_learning_rate() >= 1e-4)
        trainer.train_one_step(samples, labels);

    // Wait for training threads to stop
    trainer.get_net();
    cout << "done training" << endl;

    // Run all the samples through the network to get their 2D vector embeddings.
    std::vector<matrix<float,0,1>> embedded = net(samples);

    // Print the embedding for each sample to the screen.  If you look at the
    // outputs carefully you should notice that they are grouped together in 2D
    // space according to their label.
    for (size_t i = 0; i < embedded.size(); ++i)
        cout << "label: " << labels[i] << "\t" << trans(embedded[i]);

    // Now, check if the embedding puts things with the same labels near each other and
    // things with different labels far apart.
    int num_right = 0;
    int num_wrong = 0;
    for (size_t i = 0; i < embedded.size(); ++i)
    {
        for (size_t j = i+1; j < embedded.size(); ++j)
        {
            if (labels[i] == labels[j])
            {
                // The loss_metric layer will cause things with the same label to be less
                // than net.loss_details().get_distance_threshold() distance from each
                // other.  So we can use that distance value as our testing threshold for
                // "being near to each other".
                if (length(embedded[i]-embedded[j]) < net.loss_details().get_distance_threshold())
                    ++num_right;
                else
                    ++num_wrong;
            }
            else
            {
                if (length(embedded[i]-embedded[j]) >= net.loss_details().get_distance_threshold())
                    ++num_right;
                else
                    ++num_wrong;
            }
        }
    }

    cout << "num_right: "<< num_right << endl;
    cout << "num_wrong: "<< num_wrong << endl;
}
catch(std::exception& e)
{
    cout << e.what() << endl;
}

ext: cpp


text:
/*  The compile and run commands are:

	Compile:- $ g++-7 mr-pr-cpp.cpp /usr/lib/x86_64-linux-gnu/libboost_system.a /usr/lib/x86_64-linux-gnu/libboost_iostreams.a /usr/lib/x86_64-linux-gnu/libboost_filesystem.a -pthread -o mr-pr-cpp.o
	Run:- $ ./mr-pr-cpp.o <input_file>.txt -o <output_file>.txt

	* Compile command assumes the presence of the Mapreduce include files in the cwd
	* Run command assumes the existence of a file <input_file>.txt in a directory named "test" in the cwd of the code
	* Run command also assumes the existence of a directory named "output" where it writes the outputs of the pagerank algorithm execution.

*/

// Including the Boost configurations
#include <boost/config.hpp>
#if defined(BOOST_MSVC)
#   pragma warning(disable: 4127)

// turn off checked iterators to avoid performance hit
#   if !defined(__SGI_STL_PORT)  &&  !defined(_DEBUG)
#       define _SECURE_SCL 0
#       define _HAS_ITERATOR_DEBUGGING 0
#   endif
#endif

#include <bits/stdc++.h>
#include "mapreduce.hpp"
using namespace std;

// Functions for the proper usage of the code
const char *OUTPUT_ARG = "-o";

void usage() {
    cerr << "Use the below format " << endl
    	 << "pagerank <graph_file> -o <output_file>" << endl
         << " -o enable output " << endl;
}

// Global variables for the pagerank algorithm
vector<vector<double>> intermediate_page(100000);
vector<vector<int>> outgoing_links(100000);
vector<double> pageranks(100000);
vector<double> pageranks_calc(100000);

// Parameters of alpha and convergence rate
double alpha = 0.85;
double conv = 0.00001;
double dangling_pointer =0.0f;
int total_webpages=0;

namespace page_rank {

template<typename MapTask>
class number_source : mapreduce::detail::noncopyable
{
  public:
    number_source()
      : sequence_(0)
    {
    }

    bool const setup_key(typename MapTask::key_type &key)
    {
        key = sequence_++;
        return (key <= total_webpages);
    }

    bool const get_data(typename MapTask::key_type const &key, typename MapTask::value_type &value)
    {
        value = pageranks[key];
        return true;
    }

  private:
    unsigned  sequence_;
};

struct map_task : public mapreduce::map_task<unsigned, double>
{
    template<typename Runtime>
    void operator()(Runtime &runtime, key_type const &key, value_type const &value) const
    {
		int chilren = outgoing_links[key].size();

		if(chilren!=0){
			for(int i =0; i<chilren; i++){
		        typename Runtime::reduce_task_type::key_type const emit_temp = outgoing_links[key][i];
		        double temp = double(value/chilren);
		        runtime.emit_intermediate(emit_temp, temp);
			}
		}

		// Debugging
		runtime.emit_intermediate(key,0);

    }
};

struct reduce_task : public mapreduce::reduce_task<unsigned, double>
{
    template<typename Runtime, typename It>
    void operator()(Runtime &runtime, key_type const &key, It it, It ite) const
    {
        value_type results(*it);
		double pagerank_temp = 0.0f;
        for (It it1=it; it1!=ite; it1++)
        {
			pagerank_temp += (double)(*it1);
        }

		// Applying the pagerank update rule
		double pageranks_calc_temp = pagerank_temp*alpha + (1-alpha)/total_webpages + alpha*dangling_pointer/total_webpages;

		// Emitting the (Key,Value) pair for the pageranks_calc
		results = pageranks_calc_temp;
		runtime.emit(key,results);
    }
};

typedef
mapreduce::job<page_rank::map_task,
               page_rank::reduce_task,
               mapreduce::null_combiner,
               page_rank::number_source<page_rank::map_task>
> job;

} // namespace page_rank

// Function to check the convergence
bool converging(vector<double> pageranks, vector<double> pageranks_calc, int total_webpages){
	bool isConverged= true;
	for (int i = 0; i < total_webpages; i++){
		if (abs(pageranks[i] - pageranks_calc[i])>conv){
			isConverged = false;
			break;
		}
	}
	return isConverged;
}

int main(int argc, char const *argv[])
{

	// File names
	string input_file;
	string output_file;

	// Reading the command line inputs
	if (argc == 4){
		if (!strcmp(argv[2],OUTPUT_ARG)){
			input_file=argv[1];
			output_file=argv[3];
		}

		else{
			usage();
			exit(1);
		}
	}

	else{
		usage();
		exit(1);
	}

	int max_page_id = 0;
	int min_page_id = 0;

	// Reading inputs from the specified file in the test folder of the standard pagerank repo
	ifstream fopen;
	fopen.open("test/" + input_file);
	while(!fopen.eof()){
		int a,b;
		fopen>>a>>b;
		outgoing_links[a].push_back(b);

		int max_temp = std::max(a,b);
		if (max_temp > max_page_id)
			max_page_id = max_temp;

		int min_temp = std::min(a,b);
		if (min_temp < min_page_id)
			min_page_id = min_temp;
	}

	// Total number of web-pages as: max_page_id - min_page_id + 1
	fopen.close();
	total_webpages = max_page_id - min_page_id + 1;

	// Initializing the pageranks;
	double pgr = double(1.0f/total_webpages);
	for(int i=0; i<total_webpages; i++){
		pageranks[i] = pgr;
	}

	// Initializing the Mapreduce specifications
    mapreduce::specification spec;
    spec.reduce_tasks = std::max(1U, std::thread::hardware_concurrency());

	while(true){

		cout << pageranks[0] << endl;

		// Handling dangling pointers
		dangling_pointer=0.0f;
		for(int i=0; i<total_webpages; i++){
			if (outgoing_links[i].size()==0){
				dangling_pointer+=pageranks[i];
			}
		}

		// Scheduling the map-reduce for the pagerank calculation
        page_rank::job::datasource_type number_source;
        page_rank::job job(number_source, spec);
        mapreduce::results result;

		#ifdef _DEBUG
			job.run<mapreduce::schedule_policy::sequential<page_rank::job> >(result);
		#else
			job.run<mapreduce::schedule_policy::cpu_parallel<page_rank::job> >(result);
		#endif

		// Storing the reults of the calculated pagerank
        for (auto it=job.begin_results(); it!=job.end_results(); it++){
            pageranks_calc[it->first] = it->second;
        }

		// Checking for convergence
		if(converging(pageranks, pageranks_calc, total_webpages)){
			break;
		}
		else{
			for(int i=0; i<total_webpages; i++){
				pageranks[i] = pageranks_calc[i];
			}
		}
	}

	// Writing to the file
	ofstream fout;
	fout.open("output/" + output_file);

	string str;
	double sumVal = 0.0;
	for(int i=0; i<total_webpages; i++){
		fout<<i<<" = "<<pageranks[i]<<endl;
		sumVal += pageranks[i];
	}

	fout << "sum " << sumVal << endl;
	fout.close();

	return 0;
}


text:
/*
 * Software License Agreement (BSD License)
 *
 *  Xin Wang
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * Author : Xin Wang
 * Email  : ericrussell@zju.edu.cn
 *
 */

#include <sstream>
#include <vector>
#include <fstream>
#include <string>
#include <math.h>
#include <pcl/search/search.h>
#include <pcl/search/kdtree.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/surface/mls.h>
#include <pcl/surface/convex_hull.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/ModelCoefficients.h>
#include <pcl/filters/project_inliers.h>
#include <Eigen/src/Core/Matrix.h>
#include "SaveTraceMapWorker.h"
#include "omp.h"
#include "globaldef.h"
#include "dataLibrary.h"

using namespace std;

bool SaveTraceMapWorker::is_para_satisfying(QString &message)
{
    if((dataLibrary::clusters.size() == 0)&&(dataLibrary::cluster_patches.size() == 0))
	{
        message = QString("savetracemap: You Haven't Performed Any Segmentation or Opened Any Clusters Files Yet!");
		return false;
	}
    else
    {
        if(dataLibrary::clusters.size() != 0){
            this->setClustersFromFilesFlag(false);
        }
        if(dataLibrary::cluster_patches.size() != 0){
            this->setClustersFromFilesFlag(true);
        }
        this->setParaSize(1);
		if(dataLibrary::Workflow[dataLibrary::current_workline_index].parameters.size()>0)
		{
			this->setFileName(QString::fromUtf8(dataLibrary::Workflow[dataLibrary::current_workline_index].parameters[0].c_str()));
			this->setParaIndex(this->getParaSize());
			this->setDefaltFMAP_Mode();
			bool need_expand_ratio(false);
			if((dataLibrary::Workflow[dataLibrary::current_workline_index].parameters.size()>this->getParaIndex())&&(dataLibrary::Workflow[dataLibrary::current_workline_index].parameters[this->getParaIndex()] == "circular"))
			{
				this->setFMAP_Mode(FMAP_CIRCULAR);
				need_expand_ratio = true;
				this->setParaIndex(this->getParaIndex()+1);
			}
			else if((dataLibrary::Workflow[dataLibrary::current_workline_index].parameters.size()>this->getParaIndex())&&(dataLibrary::Workflow[dataLibrary::current_workline_index].parameters[this->getParaIndex()] == "rectangular"))
			{
				this->setFMAP_Mode(FMAP_RECTANGULAR);
				need_expand_ratio = true;
				this->setParaIndex(this->getParaIndex()+1);
			}
			if(need_expand_ratio)
			{
				if((dataLibrary::Workflow[dataLibrary::current_workline_index].parameters.size()>this->getParaIndex())&&(dataLibrary::isOnlyDouble(dataLibrary::Workflow[dataLibrary::current_workline_index].parameters[this->getParaIndex()].c_str())))
				{
					double ratio;
					std::stringstream ss(dataLibrary::Workflow[dataLibrary::current_workline_index].parameters[this->getParaIndex()]);
					ss >> ratio;
					this->setExpandRatio(ratio);
					this->setParaIndex(this->getParaIndex()+1);
				}
				else
				{
					message = QString("savetracemap: The Expand Ratio (double) Is Needed For the 'circular' and 'rectangular' Options.");
					return false;
				}
			}
			return true;
		}
		else
		{
			message = QString("savetracemap: Path Not Provided.");
			return false;
		}
    }
}

void SaveTraceMapWorker::prepare()
{
	this->setTrimTraceEdgesMode(true);
	if((dataLibrary::Workflow[dataLibrary::current_workline_index].parameters.size()>this->getParaIndex())&&(dataLibrary::Workflow[dataLibrary::current_workline_index].parameters[this->getParaIndex()] == "notrimedges"))
	{
		this->setTrimTraceEdgesMode(false);
		this->setParaIndex(this->getParaIndex()+1);
	}
	this->setUnmute();
	this->setWriteLog();
	this->check_mute_nolog();
}

void SaveTraceMapWorker::doWork()
{
	bool is_success(false);

    QByteArray ba = this->getFileName().toLocal8Bit();
    string* strfilename = new string(ba.data());

    dataLibrary::Status = STATUS_SAVETRACEMAP;

    this->timer_start();

	//begin of processing
    pcl::PointCloud<pcl::PointXYZ>::Ptr clusters_cloud_all (new pcl::PointCloud<pcl::PointXYZ>);
    std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> clusters_cloud_vec;
    if(this->IsClustersFromFiles()){
        for(int cluster_index = 0; cluster_index < dataLibrary::cluster_patches.size(); cluster_index++)
        {
            pcl::PointCloud<pcl::PointXYZ>::Ptr temp_xyz_cloud (new pcl::PointCloud<pcl::PointXYZ>);
            pcl::copyPointCloud(*dataLibrary::cluster_patches[cluster_index], *temp_xyz_cloud);
            *clusters_cloud_all += *temp_xyz_cloud;
            clusters_cloud_vec.push_back(temp_xyz_cloud);
        }
    }
    else{
        for(int cluster_index = 0; cluster_index < dataLibrary::clusters.size(); cluster_index++)
        {
            pcl::PointCloud<pcl::PointXYZ>::Ptr temp_xyz_cloud (new pcl::PointCloud<pcl::PointXYZ>);
            for(int j = 0; j < dataLibrary::clusters[cluster_index].indices.size(); j++){
                temp_xyz_cloud->push_back(dataLibrary::cloudxyz->at(dataLibrary::clusters[cluster_index].indices[j]));
            }
            *clusters_cloud_all += *temp_xyz_cloud;
            clusters_cloud_vec.push_back(temp_xyz_cloud);
        }
    }

    //compute centor point and normal
    Eigen::Vector3f centroid_all = dataLibrary::compute3DCentroid(*clusters_cloud_all);
    float nx_all, ny_all, nz_all;
    Eigen::Vector4f plane_normal_param = dataLibrary::fitPlaneManually(*clusters_cloud_all);
    nx_all = plane_normal_param(0);
    ny_all = plane_normal_param(1);
    nz_all = plane_normal_param(2);
    dataLibrary::plane_normal_all << nx_all, ny_all, nz_all;

    //project all points
    pcl::ModelCoefficients::Ptr coefficients_all (new pcl::ModelCoefficients());
    coefficients_all->values.resize(4);
    coefficients_all->values[0] = nx_all;
    coefficients_all->values[1] = ny_all;
    coefficients_all->values[2] = nz_all;
    coefficients_all->values[3] = - (nx_all*centroid_all[0] + ny_all*centroid_all[1] + nz_all*centroid_all[2]);

    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected_all (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::ProjectInliers<pcl::PointXYZ> proj_all;
    proj_all.setModelType(pcl::SACMODEL_PLANE);
    proj_all.setInputCloud(clusters_cloud_all);
    proj_all.setModelCoefficients(coefficients_all);
    proj_all.filter(*cloud_projected_all);

    //compute convex hull
    pcl::ConvexHull<pcl::PointXYZ> chull_all;
    chull_all.setInputCloud(cloud_projected_all);
	chull_all.setDimension(2);
    chull_all.reconstruct(*dataLibrary::cloud_hull_all);

    //compute area
    float area_all = 0.0f;
    int num_points_all = dataLibrary::cloud_hull_all->size();
    int j = 0;
    Eigen::Vector3f va_all, vb_all, res_all;
    res_all(0) = res_all(1) = res_all(2) = 0.0f;
    for(int i = 0; i < num_points_all; i++)
    {
        j = (i+1) % num_points_all;
        va_all = dataLibrary::cloud_hull_all->at(i).getVector3fMap();
        vb_all = dataLibrary::cloud_hull_all->at(j).getVector3fMap();
        res_all += va_all.cross(vb_all);
    }
    area_all = fabs(res_all.dot(dataLibrary::plane_normal_all) * 0.5);

    std::vector<bool> Flags;
    std::vector<float> Dip_Directions, Dips, Areas, Lengths, Fracture_Roughnesses, Displacements, Dip2Planes;
    std::vector<int> Num_Points;
    Flags.resize(clusters_cloud_vec.size(), false);
    Dip_Directions.resize(clusters_cloud_vec.size(), 0.0);
    Dips.resize(clusters_cloud_vec.size(), 0.0);
    Areas.resize(clusters_cloud_vec.size(), 0.0);
    Lengths.resize(clusters_cloud_vec.size(), 0.0);
    Fracture_Roughnesses.resize(clusters_cloud_vec.size(), 0.0);
    Displacements.resize(clusters_cloud_vec.size(), 0.0);
    Dip2Planes.resize(clusters_cloud_vec.size(), 0.0);
    Num_Points.resize(clusters_cloud_vec.size(), 0);
    std::vector<Eigen::Vector3f> Centroids, Normals;
    std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> Cloud_Projected_3ds, Cloud_Hulls;
    for(int cluster_index = 0; cluster_index < clusters_cloud_vec.size(); cluster_index++)
    {
        pcl::PointCloud<pcl::PointXYZ>::Ptr plane_cloud = clusters_cloud_vec[cluster_index];
        Num_Points[cluster_index] = plane_cloud->size();
        //prepare for projecting data onto plane
        Eigen::Vector3f centroid = dataLibrary::compute3DCentroid(*plane_cloud);
        Centroids.push_back(centroid);
        float nx, ny, nz;
        Eigen::Vector4f plane_normal_param_patch = dataLibrary::fitPlaneManually(*plane_cloud);
        nx = plane_normal_param_patch(0);
        ny = plane_normal_param_patch(1);
        nz = plane_normal_param_patch(2);
        Eigen::Vector3f normal;
        normal << nx, ny, nz;
        Normals.push_back(normal);

		Eigen::Vector3f any_vector;
        any_vector << 0.0, 0.0, 1.0;
        Eigen::Vector3f V1 = normal.cross(any_vector);
		V1 = V1/std::sqrt(V1.dot(V1));
		Eigen::Vector3f V2 = normal.cross(V1);
		V2 = V2/std::sqrt(V2.dot(V2));
		pcl::PointCloud<pcl::PointXY>::Ptr cloud_projected_2d (new pcl::PointCloud<pcl::PointXY>);
		dataLibrary::projection322(centroid, V1, V2, plane_cloud, cloud_projected_2d);
		pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected_3d (new pcl::PointCloud<pcl::PointXYZ>);
		dataLibrary::projection223(centroid, V1, V2, cloud_projected_2d, cloud_projected_3d);
        Cloud_Projected_3ds.push_back(cloud_projected_3d);

        //generate a concave or convex
        pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZ>);
        pcl::ConvexHull<pcl::PointXYZ> chull;
        chull.setInputCloud(cloud_projected_3d);
		chull.setDimension(2);
        chull.reconstruct(*cloud_hull);
        Cloud_Hulls.push_back(cloud_hull);
    }
    // #pragma omp parallel for
    for(int cluster_index = 0; cluster_index < clusters_cloud_vec.size(); cluster_index++)
    {
        pcl::PointCloud<pcl::PointXYZ>::Ptr plane_cloud = clusters_cloud_vec[cluster_index];
        // calculate polygon area
        float area = 0.0f;
        int num_points = Cloud_Hulls[cluster_index]->size();
        int j = 0;
        Eigen::Vector3f va, vb, res;
        res(0) = res(1) = res(2) = 0.0f;
        for(int i = 0; i < num_points; i++)
        {
            j = (i+1) % num_points;
            va = Cloud_Hulls[cluster_index]->at(i).getVector3fMap();
            vb = Cloud_Hulls[cluster_index]->at(j).getVector3fMap();
            res += va.cross(vb);
        }
        area = fabs(res.dot(Normals[cluster_index]) * 0.5);
        Areas[cluster_index] = area;

        float dip_direction, dip, nx, ny, nz;
        nx = Normals[cluster_index](0);
        ny = Normals[cluster_index](1);
        nz = Normals[cluster_index](2);
        if(nz < 0.0)
        {
            nx = -nx;
            ny = -ny;
            nz = -nz;
        }

        //Dip Direction
        if(nx == 0.0)
        {
            if((ny > 0.0)||(ny == 0.0))
                dip_direction = 0.0;
            else
                dip_direction = 180.0;
        }
        else if(nx > 0.0)
        {
            dip_direction = 90.0 - atan(ny/nx)*180/M_PI;
        }
        else
        {
            dip_direction = 270.0 - atan(ny/nx)*180/M_PI;
        }
        //dip
        if((nx*nx + ny*ny) == 0.0)
        {
            dip = 0.0;
        }
        else
        {
            dip = 90.0 - atan(fabs(nz)/sqrt((nx*nx + ny*ny)))*180/M_PI;
        }
        Dip_Directions[cluster_index] = dip_direction;
        Dips[cluster_index] = dip;

		// calculate fracture surface roughness
		float fracture_total_distance=0.0;
		for(int j = 0; j < plane_cloud->size(); j++)
		{
			Eigen::Vector3f Q;
			Q(0)=plane_cloud->at(j).x;
			Q(1)=plane_cloud->at(j).y;
			Q(2)=plane_cloud->at(j).z;
			fracture_total_distance+=std::abs((Q-Centroids[cluster_index]).dot(Normals[cluster_index])/std::sqrt((Normals[cluster_index].dot(Normals[cluster_index]))));
		}
		float fracture_roughness=fracture_total_distance/plane_cloud->size();
        Fracture_Roughnesses[cluster_index] = fracture_roughness;

		float length;
        bool flag;
		if(this->getFMAP_Mode() == FMAP_LOWER_BOUND)
			flag = dataLibrary::LowerBound(dataLibrary::plane_normal_all, centroid_all, dataLibrary::cloud_hull_all, Normals[cluster_index], Centroids[cluster_index], Cloud_Hulls[cluster_index], cluster_index, length, this->getTrimTraceEdgesMode(), false);
		else if(this->getFMAP_Mode() == FMAP_RECTANGULAR)
			flag = dataLibrary::Rectangular(dataLibrary::plane_normal_all, centroid_all, dataLibrary::cloud_hull_all, Normals[cluster_index], Centroids[cluster_index], Cloud_Hulls[cluster_index], cluster_index, length, this->getExpandRatio(), this->getTrimTraceEdgesMode(), false);
		else if(this->getFMAP_Mode() == FMAP_CIRCULAR)
			flag = dataLibrary::Circular(dataLibrary::plane_normal_all, centroid_all, dataLibrary::cloud_hull_all, Normals[cluster_index], Centroids[cluster_index], Cloud_Hulls[cluster_index], cluster_index, length, this->getExpandRatio(), this->getTrimTraceEdgesMode(), false);

        Flags[cluster_index] = flag;
        Lengths[cluster_index] = length;

        //calculate displacement
		Eigen::Vector3f line_direction = Normals[cluster_index].cross(dataLibrary::plane_normal_all.cross(Normals[cluster_index]));
		if((line_direction(0) == 0)&&(line_direction(1) == 0)&&(line_direction(2) == 0))
		{
			Displacements[cluster_index] = 0.0;
            Dip2Planes[cluster_index] = 0.0;
		}
		else
		{
			if(flag)
			{
				float max_value, min_value;
				int max_index, min_index;
				Eigen::Vector3f point;
				point(0) = Cloud_Projected_3ds[cluster_index]->at(0).x;
				point(1) = Cloud_Projected_3ds[cluster_index]->at(0).y;
				point(2) = Cloud_Projected_3ds[cluster_index]->at(0).z;
				float mod_line_direction = std::sqrt(line_direction.dot(line_direction));
				max_value = min_value = line_direction.dot(point - Centroids[cluster_index])/mod_line_direction;
				max_index = min_index = 0;
				for(int i=1; i<Cloud_Projected_3ds[cluster_index]->size(); i++)
				{
					Eigen::Vector3f point;
					point(0) = Cloud_Projected_3ds[cluster_index]->at(i).x;
					point(1) = Cloud_Projected_3ds[cluster_index]->at(i).y;
					point(2) = Cloud_Projected_3ds[cluster_index]->at(i).z;

					float value = line_direction.dot(point - Centroids[cluster_index])/mod_line_direction;

					if(max_value<value)
					{
						max_value = value;
						max_index = i;
					}
					if(min_value>value)
					{
						min_value = value;
						min_index = i;
					}
				}
				float alpha = std::acos(std::abs(dataLibrary::plane_normal_all.dot(Normals[cluster_index])/(std::sqrt(dataLibrary::plane_normal_all.dot(dataLibrary::plane_normal_all))*std::sqrt(Normals[cluster_index].dot(Normals[cluster_index])))));
				Dip2Planes[cluster_index] = alpha*360.0/TWOPI;
				float tangent_alpha = std::tan(alpha);
				float height_max = std::abs(dataLibrary::plane_normal_all.dot(Cloud_Projected_3ds[cluster_index]->at(max_index).getVector3fMap()-centroid_all)/std::sqrt(dataLibrary::plane_normal_all.dot(dataLibrary::plane_normal_all)));
				float height_min = std::abs(dataLibrary::plane_normal_all.dot(Cloud_Projected_3ds[cluster_index]->at(min_index).getVector3fMap()-centroid_all)/std::sqrt(dataLibrary::plane_normal_all.dot(dataLibrary::plane_normal_all)));
				float displacement_max = height_max/tangent_alpha;
				float displacement_min = height_min/tangent_alpha;
				Displacements[cluster_index] = (displacement_max+displacement_min)/2.0;
			}
            else{
                Displacements[cluster_index] = 0.0;
                Dip2Planes[cluster_index] = 0.0;
            }
		}
    }

    //initial total length of fracture traces
    float total_length=0.0;
	//initial over estimate length of fracture traces
	float error_length=0.0;
	//initial total displacement
	float total_displacement=0.0;
	//initial mean dip2plane angle
	float total_dip2plane=0.0;
	int inside_num=0;
    string area_file = strfilename->substr(0, strfilename->size()-4) += "_area.txt";
	string roughness_file = strfilename->substr(0, strfilename->size()-4) += "_roughness.txt";
    string textfilename = strfilename->substr(0, strfilename->size()-4) += "_table.txt";
	ofstream area_out(area_file.c_str());
	ofstream roughness_out(roughness_file.c_str());
    ofstream fout(textfilename.c_str());
    fout<<"Flag"<<"\t"<<"Number"<<"\t"<<"Points"<<"\t"<<"Direc"<<"\t"<<"Dip"<<"\t"<<"Area"<<"\t"<<"Length"<<"\t"<<"Roughness"<<"\n";
    for(int cluster_index = 0; cluster_index < clusters_cloud_vec.size(); cluster_index++){
        fout<<Flags[cluster_index]<<"\t"<<cluster_index+1<<"\t"<<Num_Points[cluster_index]<<"\t"<<Dip_Directions[cluster_index]<<"\t"<<Dips[cluster_index]<<"\t"<<Areas[cluster_index]<<"\t"<<Lengths[cluster_index]<<"\t"<<Fracture_Roughnesses[cluster_index]<<"\n";
        if(Flags[cluster_index]){
            total_length += Lengths[cluster_index];
            area_out<<Areas[cluster_index]<<"\n";
			roughness_out<<Fracture_Roughnesses[cluster_index]<<"\n";
            inside_num += 1;
        }
        else{
            error_length += Lengths[cluster_index];
        }
        total_displacement += Displacements[cluster_index];
        total_dip2plane += Dip2Planes[cluster_index];
    }
	fout<<flush;
    fout.close();
	area_out<<flush;
    area_out.close();
	roughness_out<<flush;
    roughness_out.close();
    string fracture_intensity = strfilename->substr(0, strfilename->size()-4) += "_fracture_intensity.txt";
    ofstream fracture_intensity_out(fracture_intensity.c_str());
	fracture_intensity_out<<"Total area:"<<"\t"<<area_all<<"\n";
	fracture_intensity_out<<"Percentage of displacement errors:"<<"\t"<<total_displacement/total_length*100<<" \%\n";
	fracture_intensity_out<<"Percentage of over estimated errors:"<<"\t"<<error_length/total_length*100<<" \%\n";
	fracture_intensity_out<<"Mean dip to plane angle:"<<"\t"<<total_dip2plane/inside_num<<"\n";
    fracture_intensity_out<<"Fracture Density:"<<"\t"<<total_length/area_all;
    fracture_intensity_out<<flush;
    fracture_intensity_out.close();

    //save outcrop convex hull and fracture traces, both 3d and 2d
	Eigen::Vector3f V_x = dataLibrary::cloud_hull_all->at(1).getVector3fMap() - dataLibrary::cloud_hull_all->at(0).getVector3fMap();
    Eigen::Vector3f V_y = dataLibrary::plane_normal_all.cross(V_x);
    std::vector<Eigen::Vector2f> convex_hull_all_2d;
    dataLibrary::projection322(V_x, V_y, dataLibrary::cloud_hull_all, convex_hull_all_2d);

    string hull_traces = strfilename->substr(0, strfilename->size()-4) += "_convex_hull&fracture_traces.txt";
    ofstream hull_traces_out(hull_traces.c_str());
    hull_traces_out<<"hull\t"<<dataLibrary::cloud_hull_all->points.size()<<"\t"<<dataLibrary::plane_normal_all(0)<<"\t"<<dataLibrary::plane_normal_all(1)<<"\t"<<dataLibrary::plane_normal_all(2)<<"\n";
    for(int i=0; i<dataLibrary::cloud_hull_all->points.size(); i++)
    {
        hull_traces_out<<dataLibrary::cloud_hull_all->points[i].x<<"\t"<<dataLibrary::cloud_hull_all->points[i].y<<"\t"<<dataLibrary::cloud_hull_all->points[i].z<<"\t"<<convex_hull_all_2d[i](0)<<"\t"<<convex_hull_all_2d[i](1)<<"\n";
    }
    hull_traces_out<<"traces\n";
	Eigen::Vector3f point_in_begin, point_in_end;
	Eigen::Vector2f point_out_begin, point_out_end;
    for(int i=0; i<dataLibrary::Lines.size(); i++)
    {
		point_in_begin(0)=dataLibrary::Lines[i].begin.x;
		point_in_begin(1)=dataLibrary::Lines[i].begin.y;
		point_in_begin(2)=dataLibrary::Lines[i].begin.z;
		point_in_end(0)=dataLibrary::Lines[i].end.x;
		point_in_end(1)=dataLibrary::Lines[i].end.y;
		point_in_end(2)=dataLibrary::Lines[i].end.z;

		dataLibrary::projection322(V_x, V_y, point_in_begin, point_out_begin);
		dataLibrary::projection322(V_x, V_y, point_in_end, point_out_end);

		hull_traces_out<<dataLibrary::Lines[i].begin.x<<"\t"<<dataLibrary::Lines[i].begin.y<<"\t"<<dataLibrary::Lines[i].begin.z<<"\t"<<dataLibrary::Lines[i].end.x<<"\t"<<dataLibrary::Lines[i].end.y<<"\t"<<dataLibrary::Lines[i].end.z<<"\t"<<point_out_begin(0)<<"\t"<<point_out_begin(1)<<"\t"<<point_out_end(0)<<"\t"<<point_out_end(1)<<"\n";
    }
    hull_traces_out<<flush;
    hull_traces_out.close();

	is_success = true;
	//end of processing

    this->timer_stop();

    if(this->getWriteLogMode()&&is_success)
    {
        std::string log_text = "\tSaving Clusters costs: ";
        std::ostringstream strs;
        strs << this->getTimer_sec();
        log_text += (strs.str() +" seconds.");
        dataLibrary::write_text_to_log_file(log_text);
    }

    if(is_success)
    {
        emit SaveTraceMapReady(this->getFileName());
        if(!this->getMuteMode()){
            emit ShowTraceMap();
        }
    }

    dataLibrary::Status = STATUS_READY;
    emit showReadyStatus();
	delete strfilename;
	if(this->getWorkFlowMode()&&is_success)
	{
		this->Sleep(1000);
		emit GoWorkFlow();
	}
}

max_stars_repo_name: EricAlex/structrock