<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "watch.h"
#include "errhandle.h"
#include "service.h"
#include "forward.h"
#include "conf.h"
#include "perform.h"
#include "cmdbuf.h"
#include <glob.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <vespa/vespalib/util/sig_catch.h>

LOG_SETUP("");

namespace logdemon {
namespace {

// wait until 1 second has passed since "start"
void snooze(const struct timeval &start)
{
    struct timeval sincestart;
    gettimeofday(&sincestart, 0);
    // compute time elapsed since start:
    sincestart.tv_sec  -= start.tv_sec;
    sincestart.tv_usec -= start.tv_usec;

    // how many microseconds to wait:
    long wait_usecs = (1000000 - sincestart.tv_usec);
    wait_usecs     -= (1000000 * sincestart.tv_sec);

    if (wait_usecs <= 0) {
        // already used enough time, no sleep
        return;
    }

    struct timespec tsp;
    tsp.tv_sec  = (wait_usecs / 1000000);
    tsp.tv_nsec = (wait_usecs % 1000000) * 1000;

    if (nanosleep(&tsp, nullptr) != 0 && errno != EINTR) {
        LOG(error, "nanosleep %ld s %ld ns failed: %s",
            (long)tsp.tv_sec, (long)tsp.tv_nsec, strerror(errno));
        throw SomethingBad("nanosleep failed");
    }
}

int elapsed(struct timeval &start) {
    struct timeval now;
    gettimeofday(&now, 0);
    int diffsecs = now.tv_sec - start.tv_sec;
    if (now.tv_usec < start.tv_usec) {
        --diffsecs;
    }
    return diffsecs;
}

constexpr size_t G_BUFSIZE = 1024*1024;
} // namespace logdemon::<unnamed>

Watcher::Watcher(ConfSub &cfs, Forwarder &fw)
    : _buffer(G_BUFSIZE),
      _confsubscriber(cfs),
      _forwarder(fw),
      _wfd(-1)
{
}

Watcher::~Watcher()
{
    if (_wfd >= 0) {
        LOG(debug, "~Watcher closing %d", _wfd);
        close(_wfd);
    }
}

struct donecache {
    dev_t st_dev; /* device */
    ino_t st_ino; /* inode number */
    off_t offset;
    bool  valid;
};

class StateSaver {
public:
    StateSaver();
    ~StateSaver();
    void saveState(const donecache&, Services&);
    bool loadState(donecache&, Forwarder&);
    void doFullsave() { _cachecounter = 300; }
private:
    int _savefd;
    int _cachecounter;
};

void StateSaver::saveState(const donecache& already, Services& currentserv)
{
    if (_savefd < 0) {
        // cannot save state
        return;
    }
    off_t origin = 0;
    lseek(_savefd, origin, SEEK_SET);
    if (write(_savefd, &already, sizeof(already)) != sizeof(already)) {
        LOG(error, "error writing to donecachefile: %s", strerror(errno));
        close(_savefd);
        _savefd = -1;
    } else if (++_cachecounter > 300) {
        currentserv.dumpState(_savefd);
        off_t here = lseek(_savefd, (off_t)0, SEEK_CUR);
        LOG(debug, "cached already %d/%d %d, trunc at %d",
            (int)already.st_dev, (int)already.st_ino,
            (int)already.offset, (int)here);
        if (here == (off_t)-1) {
            LOG(error, "lseek failed: %s", strerror(errno));
        } else if (ftruncate(_savefd, here) < 0) {
            LOG(error, "ftruncate %d=%d failed: %s", _savefd, (int)here, strerror(errno));
        }
        _cachecounter = 0;
    }
}

bool
StateSaver::loadState(donecache& already, Forwarder& fwd)
{
    if (_savefd >= 0 &&
        read(_savefd, &already, sizeof(already)) == sizeof(already))
    {
        InternalPerformer iperf(fwd.knownServices);
        CmdBuf filebuf;
        while (filebuf.readFile(_savefd)) {
            while (filebuf.hasCmd()) {
                filebuf.doCmd(iperf);
            }
        }
        return true;
    } else {
        return false;
    }
}

StateSaver::StateSaver() : _savefd(-1), _cachecounter(300)
{
    _savefd = open("var/db/vespa/logd.donestate", O_RDWR|O_CREAT, 0664);
    if (_savefd < 0) {
        LOG(warning, "could not open var/db/vespa/logd.donestate: %s", strerror(errno));
    }
}

StateSaver::~StateSaver()
{
    LOG(debug, "~StateSaver closing %d", _savefd);
    if (_savefd >= 0) {
        close(_savefd);
    }
}

void
Watcher::watchfile()
{
    struct donecache already;

    char *target = getenv("VESPA_LOG_TARGET");
    if (target == nullptr || strncmp(target, "file:", 5) != 0) {
        LOG(error, "expected VESPA_LOG_TARGET (%s) to be a file: target", target);
        throw SomethingBad("bad log target");
    }
    const char *filename = target+5;

    if (strlen(filename) + 50 > FILENAME_MAX) {
        LOG(error, "too long filename '%s'", filename);
        throw SomethingBad("too long filename in watchfile");
    }

    ExternalPerformer performer(_forwarder, _forwarder.knownServices);
    CmdBuf cmdbuf;

    StateSaver dcf;
    if (dcf.loadState(already, _forwarder)) {
        already.valid = true;
    }

    _forwarder.sendMode();

    vespalib::SigCatch catcher;
    int sleepcount = 0;
    time_t created = 0;

 again:
    // XXX should close and/or check _wfd first ?
    _wfd = open(filename, O_RDONLY|O_CREAT, 0664);
    if (_wfd < 0) {
        LOG(error, "open(%s) failed: %s", filename, strerror(errno));
        throw SomethingBad("could not create or open logfile");
    }

    bool rotate = false;
    struct timeval rotStart;
    off_t offset = 0;

    while (1) {
        struct stat sb;
        if (fstat(_wfd, &sb) != 0) {
            LOG(error, "fstat(%s) failed: %s", filename, strerror(errno));
            throw SomethingBad("fstat failed");
        }
        if (created == 0) {
            created = sb.st_ctime;
        }
        if (already.valid) {
            if (sb.st_dev == already.st_dev &&
                sb.st_ino == already.st_ino &&
                sb.st_size >= already.offset)
            {
                offset = already.offset;
            }
            // only update offset from cache once:
            already.valid = false;
        }

        if (sb.st_size < offset) {
            // this is bad, maybe somebody else truncated the file
            LOG(error, "file mysteriously shrunk %d -> %d", (int)offset, (int)sb.st_size);
            return;
        }

        struct timeval tickStart;
        gettimeofday(&tickStart, 0);

        if (sb.st_size > offset) {
            lseek(_wfd, offset, SEEK_SET);
            char *buffer = getBuf();
            ssize_t rsize = read(_wfd, buffer, (getBufSize() - 1));
            if (rsize > 0) {
                buffer[rsize] = '\0';
                char *l = buffer;
                char *nnl = (char *)memchr(buffer, '\n', rsize);
                if (nnl == nullptr && rsize == (getBufSize() - 1)) {
                    LOG(error, "no newline in %ld bytes, skipping", static_cast<long>(rsize));
                    offset += rsize;
                }
                while (nnl != nullptr && elapsed(tickStart) < 1) {
                    ++nnl;
                    _forwarder.forwardLine(l, nnl);
                    ssize_t wsize = nnl - l;
                    offset += wsize;
                    l = nnl;
                    nnl = strchr(l, '\n');
                }
            } else {
                LOG(error, "could not read from %s: %s", filename, strerror(errno));
                throw SomethingBad("read failed");
            }
        }

        already.offset = offset;
        already.st_dev = sb.st_dev;
        already.st_ino = sb.st_ino;

        time_t now = time(nullptr);
        bool wantrotate = (now > created + _confsubscriber.getRotateAge())
                          || (sb.st_size > _confsubscriber.getRotateSize());

        if (rotate) {
            int rotTime = elapsed(rotStart);
            if (rotTime > 59 || (sb.st_size == offset && rotTime > 4)) {
                removeOldLogs(filename);
                if (sb.st_size != offset) {
                    LOG(warning, "logfile rotation incomplete after %d s (dropping %lu bytes)",
                        rotTime, sb.st_size - offset);
                } else {
                    LOG(debug, "logfile rotation complete after %d s", rotTime);
                }
                created = now;
                rotate = false;
                close(_wfd);
                goto again;
            }
        } else if (stat(filename, &sb) != 0
            || sb.st_dev != already.st_dev
            || sb.st_ino != already.st_ino)
        {
            LOG(warning, "logfile rotated away underneath");
            created = now;
            close(_wfd);
            goto again;
        } else if (wantrotate) {
            rotate = true;
            gettimeofday(&rotStart, 0);
            LOG(debug, "preparing to rotate logfile, old logfile size %d, age %d seconds",
                (int)offset, (int)(now-created));
            char newfn[FILENAME_MAX];
            int l = strlen(filename);
            strcpy(newfn, filename);
            struct tm *nowtm = gmtime(&now);
            if (strftime(newfn+l, FILENAME_MAX-l-1, "-%Y-%m-%d.%H-%M-%S", nowtm) < 10)
            {
                LOG(error, "could not strftime");
                throw SomethingBad("strftime failed");
            }

            if (rename(filename, newfn) != 0) {
                LOG(error, "could not rename logfile %s -> %s: %s", filename, newfn, strerror(errno));
                throw SomethingBad("rename failed");
            } else {
                LOG(debug, "old logfile name: %s", newfn);
            }
        }

        dcf.saveState(already, _forwarder.knownServices);

        if (_confsubscriber.checkAvailable()) {
            LOG(debug, "new config available, doing reconfigure");
            return;
        }

        if (_confsubscriber.useLogserver()) {
            cmdbuf.maybeRead(_forwarder.getLogserverFD());
            while (cmdbuf.hasCmd()) {
                cmdbuf.doCmd(performer);
                // in case forwarding changes
                dcf.doFullsave();
            }
        }

        if (catcher.receivedStopSignal()) {
            throw SigTermException("caught signal");
        }
        snooze(tickStart);
        if (catcher.receivedStopSignal()) {
            throw SigTermException("caught signal");
        }
        if (++sleepcount > 99) {
            if (_forwarder._badLines) {
                LOG(info, "seen %d bad loglines in %d iterations", _forwarder._badLines, sleepcount);
                _forwarder._badLines = 0;
                sleepcount=0;
            }
        }
    }
}

static int globerrfunc(const char *path, int errno_was)
{
    LOG(warning, "glob %s: %s", path, strerror(errno_was));
    return 0;
}

void
Watcher::removeOldLogs(const char *prefix)
{
    const char suffix[] = "-*-*-*.*-*-*";
    char pattern[FILENAME_MAX];
    int l = strlen(prefix) + sizeof(suffix) + 20;
    if (l > FILENAME_MAX) {
        LOG(error, "too long filename prefix in removeOldLog()");
        return;
    }

    strcpy(pattern, prefix);
    strcat(pattern, suffix);

    glob_t myglob;
    myglob.gl_pathc = 0;
    myglob.gl_offs = 0;
    myglob.gl_flags = 0;
    myglob.gl_pathv = nullptr;

    off_t totalsize = 0;

    int globresult = glob(pattern, 0, &globerrfunc, &myglob);
    if (globresult == 0) {
        for (int i = 0; i < (int)myglob.gl_pathc; i++) {
            const char *fname = myglob.gl_pathv[myglob.gl_pathc-i-1];

            struct stat sb;
            if (stat(fname, &sb) != 0) {
                LOG(warning, "cannot stat %s: %s", fname, strerror(errno));
                continue;
            }
            if (S_ISREG(sb.st_mode)) {
                if (sb.st_mtime +
                    _confsubscriber.getRemoveAge() * 86400 < time(nullptr))
                {
                    LOG(info, "removing %s, too old (%f days)", fname,
                        (double)(time(nullptr)-sb.st_mtime)/86400.0);

                    if (unlink(fname) != 0) {
                        LOG(warning, "cannot remove %s: %s",
                            fname, strerror(errno));
                    }
                    continue;
                }
                totalsize += sb.st_size;
                if (totalsize > (_confsubscriber.getRemoveMegabytes() * 1048576LL))
                {
                    LOG(info, "removing %s, total size (%ld) too big", fname, static_cast<int64_t>(totalsize));
                    if (unlink(fname) != 0) {
                        LOG(warning, "cannot remove %s: %s", fname, strerror(errno));
                    }
                }
            } else {
                LOG(warning, "not a regular file: %s", fname);
            }
        }
    } else if (globresult == GLOB_NOMATCH) {
        LOG(info, "no old logfiles matching %s", pattern);
    } else {
        LOG(warning, "glob %s failed: %d", pattern, globresult);
    }
    globfree(&myglob);
}

} // namespace
<commit_msg>Fix format strings in logd module.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "watch.h"
#include "errhandle.h"
#include "service.h"
#include "forward.h"
#include "conf.h"
#include "perform.h"
#include "cmdbuf.h"
#include <glob.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <vespa/vespalib/util/sig_catch.h>

LOG_SETUP("");

namespace logdemon {
namespace {

// wait until 1 second has passed since "start"
void snooze(const struct timeval &start)
{
    struct timeval sincestart;
    gettimeofday(&sincestart, 0);
    // compute time elapsed since start:
    sincestart.tv_sec  -= start.tv_sec;
    sincestart.tv_usec -= start.tv_usec;

    // how many microseconds to wait:
    long wait_usecs = (1000000 - sincestart.tv_usec);
    wait_usecs     -= (1000000 * sincestart.tv_sec);

    if (wait_usecs <= 0) {
        // already used enough time, no sleep
        return;
    }

    struct timespec tsp;
    tsp.tv_sec  = (wait_usecs / 1000000);
    tsp.tv_nsec = (wait_usecs % 1000000) * 1000;

    if (nanosleep(&tsp, nullptr) != 0 && errno != EINTR) {
        LOG(error, "nanosleep %ld s %ld ns failed: %s",
            (long)tsp.tv_sec, (long)tsp.tv_nsec, strerror(errno));
        throw SomethingBad("nanosleep failed");
    }
}

int elapsed(struct timeval &start) {
    struct timeval now;
    gettimeofday(&now, 0);
    int diffsecs = now.tv_sec - start.tv_sec;
    if (now.tv_usec < start.tv_usec) {
        --diffsecs;
    }
    return diffsecs;
}

constexpr size_t G_BUFSIZE = 1024*1024;
} // namespace logdemon::<unnamed>

Watcher::Watcher(ConfSub &cfs, Forwarder &fw)
    : _buffer(G_BUFSIZE),
      _confsubscriber(cfs),
      _forwarder(fw),
      _wfd(-1)
{
}

Watcher::~Watcher()
{
    if (_wfd >= 0) {
        LOG(debug, "~Watcher closing %d", _wfd);
        close(_wfd);
    }
}

struct donecache {
    dev_t st_dev; /* device */
    ino_t st_ino; /* inode number */
    off_t offset;
    bool  valid;
};

class StateSaver {
public:
    StateSaver();
    ~StateSaver();
    void saveState(const donecache&, Services&);
    bool loadState(donecache&, Forwarder&);
    void doFullsave() { _cachecounter = 300; }
private:
    int _savefd;
    int _cachecounter;
};

void StateSaver::saveState(const donecache& already, Services& currentserv)
{
    if (_savefd < 0) {
        // cannot save state
        return;
    }
    off_t origin = 0;
    lseek(_savefd, origin, SEEK_SET);
    if (write(_savefd, &already, sizeof(already)) != sizeof(already)) {
        LOG(error, "error writing to donecachefile: %s", strerror(errno));
        close(_savefd);
        _savefd = -1;
    } else if (++_cachecounter > 300) {
        currentserv.dumpState(_savefd);
        off_t here = lseek(_savefd, (off_t)0, SEEK_CUR);
        LOG(debug, "cached already %d/%d %d, trunc at %d",
            (int)already.st_dev, (int)already.st_ino,
            (int)already.offset, (int)here);
        if (here == (off_t)-1) {
            LOG(error, "lseek failed: %s", strerror(errno));
        } else if (ftruncate(_savefd, here) < 0) {
            LOG(error, "ftruncate %d=%d failed: %s", _savefd, (int)here, strerror(errno));
        }
        _cachecounter = 0;
    }
}

bool
StateSaver::loadState(donecache& already, Forwarder& fwd)
{
    if (_savefd >= 0 &&
        read(_savefd, &already, sizeof(already)) == sizeof(already))
    {
        InternalPerformer iperf(fwd.knownServices);
        CmdBuf filebuf;
        while (filebuf.readFile(_savefd)) {
            while (filebuf.hasCmd()) {
                filebuf.doCmd(iperf);
            }
        }
        return true;
    } else {
        return false;
    }
}

StateSaver::StateSaver() : _savefd(-1), _cachecounter(300)
{
    _savefd = open("var/db/vespa/logd.donestate", O_RDWR|O_CREAT, 0664);
    if (_savefd < 0) {
        LOG(warning, "could not open var/db/vespa/logd.donestate: %s", strerror(errno));
    }
}

StateSaver::~StateSaver()
{
    LOG(debug, "~StateSaver closing %d", _savefd);
    if (_savefd >= 0) {
        close(_savefd);
    }
}

void
Watcher::watchfile()
{
    struct donecache already;

    char *target = getenv("VESPA_LOG_TARGET");
    if (target == nullptr || strncmp(target, "file:", 5) != 0) {
        LOG(error, "expected VESPA_LOG_TARGET (%s) to be a file: target", target);
        throw SomethingBad("bad log target");
    }
    const char *filename = target+5;

    if (strlen(filename) + 50 > FILENAME_MAX) {
        LOG(error, "too long filename '%s'", filename);
        throw SomethingBad("too long filename in watchfile");
    }

    ExternalPerformer performer(_forwarder, _forwarder.knownServices);
    CmdBuf cmdbuf;

    StateSaver dcf;
    if (dcf.loadState(already, _forwarder)) {
        already.valid = true;
    }

    _forwarder.sendMode();

    vespalib::SigCatch catcher;
    int sleepcount = 0;
    time_t created = 0;

 again:
    // XXX should close and/or check _wfd first ?
    _wfd = open(filename, O_RDONLY|O_CREAT, 0664);
    if (_wfd < 0) {
        LOG(error, "open(%s) failed: %s", filename, strerror(errno));
        throw SomethingBad("could not create or open logfile");
    }

    bool rotate = false;
    struct timeval rotStart;
    off_t offset = 0;

    while (1) {
        struct stat sb;
        if (fstat(_wfd, &sb) != 0) {
            LOG(error, "fstat(%s) failed: %s", filename, strerror(errno));
            throw SomethingBad("fstat failed");
        }
        if (created == 0) {
            created = sb.st_ctime;
        }
        if (already.valid) {
            if (sb.st_dev == already.st_dev &&
                sb.st_ino == already.st_ino &&
                sb.st_size >= already.offset)
            {
                offset = already.offset;
            }
            // only update offset from cache once:
            already.valid = false;
        }

        if (sb.st_size < offset) {
            // this is bad, maybe somebody else truncated the file
            LOG(error, "file mysteriously shrunk %d -> %d", (int)offset, (int)sb.st_size);
            return;
        }

        struct timeval tickStart;
        gettimeofday(&tickStart, 0);

        if (sb.st_size > offset) {
            lseek(_wfd, offset, SEEK_SET);
            char *buffer = getBuf();
            ssize_t rsize = read(_wfd, buffer, (getBufSize() - 1));
            if (rsize > 0) {
                buffer[rsize] = '\0';
                char *l = buffer;
                char *nnl = (char *)memchr(buffer, '\n', rsize);
                if (nnl == nullptr && rsize == (getBufSize() - 1)) {
                    LOG(error, "no newline in %ld bytes, skipping", static_cast<long>(rsize));
                    offset += rsize;
                }
                while (nnl != nullptr && elapsed(tickStart) < 1) {
                    ++nnl;
                    _forwarder.forwardLine(l, nnl);
                    ssize_t wsize = nnl - l;
                    offset += wsize;
                    l = nnl;
                    nnl = strchr(l, '\n');
                }
            } else {
                LOG(error, "could not read from %s: %s", filename, strerror(errno));
                throw SomethingBad("read failed");
            }
        }

        already.offset = offset;
        already.st_dev = sb.st_dev;
        already.st_ino = sb.st_ino;

        time_t now = time(nullptr);
        bool wantrotate = (now > created + _confsubscriber.getRotateAge())
                          || (sb.st_size > _confsubscriber.getRotateSize());

        if (rotate) {
            int rotTime = elapsed(rotStart);
            if (rotTime > 59 || (sb.st_size == offset && rotTime > 4)) {
                removeOldLogs(filename);
                if (sb.st_size != offset) {
                    LOG(warning, "logfile rotation incomplete after %d s (dropping %" PRIu64 " bytes)",
                        rotTime, static_cast<uint64_t>(sb.st_size - offset));
                } else {
                    LOG(debug, "logfile rotation complete after %d s", rotTime);
                }
                created = now;
                rotate = false;
                close(_wfd);
                goto again;
            }
        } else if (stat(filename, &sb) != 0
            || sb.st_dev != already.st_dev
            || sb.st_ino != already.st_ino)
        {
            LOG(warning, "logfile rotated away underneath");
            created = now;
            close(_wfd);
            goto again;
        } else if (wantrotate) {
            rotate = true;
            gettimeofday(&rotStart, 0);
            LOG(debug, "preparing to rotate logfile, old logfile size %d, age %d seconds",
                (int)offset, (int)(now-created));
            char newfn[FILENAME_MAX];
            int l = strlen(filename);
            strcpy(newfn, filename);
            struct tm *nowtm = gmtime(&now);
            if (strftime(newfn+l, FILENAME_MAX-l-1, "-%Y-%m-%d.%H-%M-%S", nowtm) < 10)
            {
                LOG(error, "could not strftime");
                throw SomethingBad("strftime failed");
            }

            if (rename(filename, newfn) != 0) {
                LOG(error, "could not rename logfile %s -> %s: %s", filename, newfn, strerror(errno));
                throw SomethingBad("rename failed");
            } else {
                LOG(debug, "old logfile name: %s", newfn);
            }
        }

        dcf.saveState(already, _forwarder.knownServices);

        if (_confsubscriber.checkAvailable()) {
            LOG(debug, "new config available, doing reconfigure");
            return;
        }

        if (_confsubscriber.useLogserver()) {
            cmdbuf.maybeRead(_forwarder.getLogserverFD());
            while (cmdbuf.hasCmd()) {
                cmdbuf.doCmd(performer);
                // in case forwarding changes
                dcf.doFullsave();
            }
        }

        if (catcher.receivedStopSignal()) {
            throw SigTermException("caught signal");
        }
        snooze(tickStart);
        if (catcher.receivedStopSignal()) {
            throw SigTermException("caught signal");
        }
        if (++sleepcount > 99) {
            if (_forwarder._badLines) {
                LOG(info, "seen %d bad loglines in %d iterations", _forwarder._badLines, sleepcount);
                _forwarder._badLines = 0;
                sleepcount=0;
            }
        }
    }
}

static int globerrfunc(const char *path, int errno_was)
{
    LOG(warning, "glob %s: %s", path, strerror(errno_was));
    return 0;
}

void
Watcher::removeOldLogs(const char *prefix)
{
    const char suffix[] = "-*-*-*.*-*-*";
    char pattern[FILENAME_MAX];
    int l = strlen(prefix) + sizeof(suffix) + 20;
    if (l > FILENAME_MAX) {
        LOG(error, "too long filename prefix in removeOldLog()");
        return;
    }

    strcpy(pattern, prefix);
    strcat(pattern, suffix);

    glob_t myglob;
    myglob.gl_pathc = 0;
    myglob.gl_offs = 0;
    myglob.gl_flags = 0;
    myglob.gl_pathv = nullptr;

    off_t totalsize = 0;

    int globresult = glob(pattern, 0, &globerrfunc, &myglob);
    if (globresult == 0) {
        for (int i = 0; i < (int)myglob.gl_pathc; i++) {
            const char *fname = myglob.gl_pathv[myglob.gl_pathc-i-1];

            struct stat sb;
            if (stat(fname, &sb) != 0) {
                LOG(warning, "cannot stat %s: %s", fname, strerror(errno));
                continue;
            }
            if (S_ISREG(sb.st_mode)) {
                if (sb.st_mtime +
                    _confsubscriber.getRemoveAge() * 86400 < time(nullptr))
                {
                    LOG(info, "removing %s, too old (%f days)", fname,
                        (double)(time(nullptr)-sb.st_mtime)/86400.0);

                    if (unlink(fname) != 0) {
                        LOG(warning, "cannot remove %s: %s",
                            fname, strerror(errno));
                    }
                    continue;
                }
                totalsize += sb.st_size;
                if (totalsize > (_confsubscriber.getRemoveMegabytes() * 1048576LL))
                {
                    LOG(info, "removing %s, total size (%" PRId64 ") too big", fname, static_cast<int64_t>(totalsize));
                    if (unlink(fname) != 0) {
                        LOG(warning, "cannot remove %s: %s", fname, strerror(errno));
                    }
                }
            } else {
                LOG(warning, "not a regular file: %s", fname);
            }
        }
    } else if (globresult == GLOB_NOMATCH) {
        LOG(info, "no old logfiles matching %s", pattern);
    } else {
        LOG(warning, "glob %s failed: %d", pattern, globresult);
    }
    globfree(&myglob);
}

} // namespace
<|endoftext|>


<commit_before>static const double cm=1;
static const double cm3=cm*cm*cm;
static const double volt=1;
static const double C=1; // Coulomb
static const double e=1.6e-19*C; // electron charge
static const double epsilon0=8.854187817e-14*C/volt/cm; // vacuum permittivity
// https://link.springer.com/chapter/10.1007/10832182_519
static const double epsilon=15.8; // Ge dielectric constant
//______________________________________________________________________________
// V"(x)=a, https://www.wolframalpha.com/input/?i=V%27%27(x)%3Da
double V(double *coordinates, double *parameters)
{
   double x = coordinates[0];// there is no phi and z dependence
   double x0= parameters[0]; // lower electrode
   double x1= parameters[1]; // upper electrode
   double v0= parameters[2]; // lower voltage
   double v1= parameters[3]; // upper voltage
   double rho=parameters[4]; // space charge density [C/cm3]

   double a =-rho/epsilon0/epsilon;
   double c2= (v1-v0)/(x1-x0) - a/2*(x1+x0);
   double c1= (v0*x1-v1*x0)/(x1-x0) + a/2*x0*x1;
   return a*x*x/2 + c2*x + c1;
}
//______________________________________________________________________________
// E=-V'
double E(double *coordinates, double *parameters)
{
   double x = coordinates[0];
   double x0= parameters[0];
   double x1= parameters[1];
   double v0= parameters[2];
   double v1= parameters[3];
   double rho=parameters[4];

   double a =-rho/epsilon0/epsilon;
   double c2= (v1-v0)/(x1-x0) - a/2*(x1+x0);
   return -a*x - c2;
}
//______________________________________________________________________________
//
const int n=5; // number of curves
double rho[n]={-3.5e10*e/cm3, -1.5e10*e/cm3, 0, 1.5e10*e/cm3, 3.5e10*e/cm3};

void drawV()
{
   TLegend *l = new TLegend(0.15,0.60,0.40,0.95);
   l->SetHeader("Impurity [cm^{-3}]");

   TF1 *fV[n]={0};
   double x0[n]={0}, x1[n], v0[n]={0}, v1[n];
   for (int i=0; i<n; i++) {
      x1[i] = 1*cm;
      v1[i] = 2000*volt;
      fV[i] = new TF1(Form("fV%d",i), V, x0[i], x1[i], 5);
      fV[i]->SetParameters(x0[i],x1[i],v0[i],v1[i],rho[i]);
      fV[i]->SetLineStyle(i+1);
      fV[i]->SetLineColor(i+1);
      if (i+1==5) fV[i]->SetLineColor(kMagenta); // yellow -> magenta
      if (i==0) fV[i]->Draw();
      else fV[i]->Draw("same");
      l->AddEntry(fV[i],Form("%8.1e",rho[i]/e*cm3),"l");
   }
   fV[0]->SetTitle("");
   fV[0]->GetXaxis()->SetTitle("Thickness [cm]");
   fV[0]->GetYaxis()->SetTitle("Voltage [V]");

   l->Draw();
   gPad->Print("Vx.png");
}
//______________________________________________________________________________
//
void drawE()
{
   TLegend *l = new TLegend(0.45,0.65,0.68,0.98);
   l->SetHeader("Impurity [cm^{-3}]");

   TF1 *fE[n]={0};
   double x0[n]={0}, x1[n], v0[n]={0}, v1[n];
   for (int i=0; i<n; i++) {
      x1[i] = 1*cm;
      v1[i] = 2000*volt;
      fE[i] = new TF1(Form("fE%d",i), E, x0[i], x1[i], 5);
      fE[i]->SetParameters(x0[i],x1[i],v0[i],v1[i],rho[i]);
      fE[i]->SetLineStyle(i+1);
      fE[i]->SetLineColor(i+1);
      if (i+1==5) fE[i]->SetLineColor(kMagenta); // yellow -> magenta
      if (i==0) fE[i]->Draw();
      else fE[i]->Draw("same");
      l->AddEntry(fE[i],Form("%8.1e",rho[i]/e*cm3),"l");
   }
   fE[0]->SetTitle("");
   fE[0]->GetXaxis()->SetTitle("Thickness [cm]");
   fE[0]->GetYaxis()->SetTitle("Electric field [V/cm]");

   l->Draw();
   gPad->Print("Ex.png");
}
//______________________________________________________________________________
//
void planar()
{
   gROOT->SetStyle("Plain"); // pick up a good default drawing style
   // modify the default style
   gStyle->SetLegendBorderSize(0);
   gStyle->SetLegendFont(132);
   gStyle->SetLabelFont(132,"XY");
   gStyle->SetTitleFont(132,"XY");
   gStyle->SetLabelSize(0.05,"XY");
   gStyle->SetTitleSize(0.05,"XY");
   gStyle->SetTitleOffset(1.2,"Y");
   gStyle->SetPadRightMargin(0.01);
   gStyle->SetPadLeftMargin(0.12);
   gStyle->SetPadTopMargin(0.01);
   gStyle->SetPadBottomMargin(0.11);

   drawV();
   drawE();
}
<commit_msg>fixed a comment<commit_after>static const double cm=1;
static const double cm3=cm*cm*cm;
static const double volt=1;
static const double C=1; // Coulomb
static const double e=1.6e-19*C; // electron charge
static const double epsilon0=8.854187817e-14*C/volt/cm; // vacuum permittivity
// https://link.springer.com/chapter/10.1007/10832182_519
static const double epsilon=15.8; // Ge dielectric constant
//______________________________________________________________________________
// V"(x)=a, https://www.wolframalpha.com/input/?i=V%27%27(x)%3Da
double V(double *coordinates, double *parameters)
{
   double x = coordinates[0];// there is no y and z dependence
   double x0= parameters[0]; // lower electrode
   double x1= parameters[1]; // upper electrode
   double v0= parameters[2]; // lower voltage
   double v1= parameters[3]; // upper voltage
   double rho=parameters[4]; // space charge density [C/cm3]

   double a =-rho/epsilon0/epsilon;
   double c2= (v1-v0)/(x1-x0) - a/2*(x1+x0);
   double c1= (v0*x1-v1*x0)/(x1-x0) + a/2*x0*x1;
   return a*x*x/2 + c2*x + c1;
}
//______________________________________________________________________________
// E=-V'
double E(double *coordinates, double *parameters)
{
   double x = coordinates[0];
   double x0= parameters[0];
   double x1= parameters[1];
   double v0= parameters[2];
   double v1= parameters[3];
   double rho=parameters[4];

   double a =-rho/epsilon0/epsilon;
   double c2= (v1-v0)/(x1-x0) - a/2*(x1+x0);
   return -a*x - c2;
}
//______________________________________________________________________________
//
const int n=5; // number of curves
double rho[n]={-3.5e10*e/cm3, -1.5e10*e/cm3, 0, 1.5e10*e/cm3, 3.5e10*e/cm3};

void drawV()
{
   TLegend *l = new TLegend(0.15,0.60,0.40,0.95);
   l->SetHeader("Impurity [cm^{-3}]");

   TF1 *fV[n]={0};
   double x0[n]={0}, x1[n], v0[n]={0}, v1[n];
   for (int i=0; i<n; i++) {
      x1[i] = 1*cm;
      v1[i] = 2000*volt;
      fV[i] = new TF1(Form("fV%d",i), V, x0[i], x1[i], 5);
      fV[i]->SetParameters(x0[i],x1[i],v0[i],v1[i],rho[i]);
      fV[i]->SetLineStyle(i+1);
      fV[i]->SetLineColor(i+1);
      if (i+1==5) fV[i]->SetLineColor(kMagenta); // yellow -> magenta
      if (i==0) fV[i]->Draw();
      else fV[i]->Draw("same");
      l->AddEntry(fV[i],Form("%8.1e",rho[i]/e*cm3),"l");
   }
   fV[0]->SetTitle("");
   fV[0]->GetXaxis()->SetTitle("Thickness [cm]");
   fV[0]->GetYaxis()->SetTitle("Voltage [V]");

   l->Draw();
   gPad->Print("Vx.png");
}
//______________________________________________________________________________
//
void drawE()
{
   TLegend *l = new TLegend(0.45,0.65,0.68,0.98);
   l->SetHeader("Impurity [cm^{-3}]");

   TF1 *fE[n]={0};
   double x0[n]={0}, x1[n], v0[n]={0}, v1[n];
   for (int i=0; i<n; i++) {
      x1[i] = 1*cm;
      v1[i] = 2000*volt;
      fE[i] = new TF1(Form("fE%d",i), E, x0[i], x1[i], 5);
      fE[i]->SetParameters(x0[i],x1[i],v0[i],v1[i],rho[i]);
      fE[i]->SetLineStyle(i+1);
      fE[i]->SetLineColor(i+1);
      if (i+1==5) fE[i]->SetLineColor(kMagenta); // yellow -> magenta
      if (i==0) fE[i]->Draw();
      else fE[i]->Draw("same");
      l->AddEntry(fE[i],Form("%8.1e",rho[i]/e*cm3),"l");
   }
   fE[0]->SetTitle("");
   fE[0]->GetXaxis()->SetTitle("Thickness [cm]");
   fE[0]->GetYaxis()->SetTitle("Electric field [V/cm]");

   l->Draw();
   gPad->Print("Ex.png");
}
//______________________________________________________________________________
//
void planar()
{
   gROOT->SetStyle("Plain"); // pick up a good default drawing style
   // modify the default style
   gStyle->SetLegendBorderSize(0);
   gStyle->SetLegendFont(132);
   gStyle->SetLabelFont(132,"XY");
   gStyle->SetTitleFont(132,"XY");
   gStyle->SetLabelSize(0.05,"XY");
   gStyle->SetTitleSize(0.05,"XY");
   gStyle->SetTitleOffset(1.2,"Y");
   gStyle->SetPadRightMargin(0.01);
   gStyle->SetPadLeftMargin(0.12);
   gStyle->SetPadTopMargin(0.01);
   gStyle->SetPadBottomMargin(0.11);

   drawV();
   drawE();
}
<|endoftext|>


<commit_before>#ifndef __ZOMBYE_FRAMEBUFFER_HPP__
#define __ZOMBYE_FRAMEBUFFER_HPP__

#include <memory>
#include <unordered_map>

#include <GL/glew.h>

namespace zombye {
	class texture;
}

namespace zombye {
	class framebuffer {
	private:
		GLuint id_;
		std::unordered_map<GLenum, std::unique_ptr<texture>> attachments_;

	public:
		framebuffer() noexcept;
		~framebuffer();

		framebuffer(const framebuffer& rhs) = delete;
		framebuffer& operator=(const framebuffer& rhs) = delete;

		framebuffer(framebuffer&& rhs) noexcept;
		framebuffer& operator=(framebuffer&& rhs) noexcept;

		void bind() const noexcept;

		template <typename... arguments>
		void attach(GLenum attachment, arguments&&... args) {
			bind();
			auto tex = std::make_unique<texture>(std::forward<arguments>(args)...);
			glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex->id_, 0);
			attachments_.insert(std::make_pair(attachment, std::move(tex)));
			bind_default();
		}

		texture& attachment(GLenum attachment) const;
		static void bind_default() noexcept;
	};
}

#endif
<commit_msg>add function for attaching cubemap to framebuffer<commit_after>#ifndef __ZOMBYE_FRAMEBUFFER_HPP__
#define __ZOMBYE_FRAMEBUFFER_HPP__

#include <memory>
#include <unordered_map>

#include <GL/glew.h>

namespace zombye {
	class texture;
}

namespace zombye {
	class framebuffer {
	private:
		GLuint id_;
		std::unordered_map<GLenum, std::unique_ptr<texture>> attachments_;

	public:
		framebuffer() noexcept;
		~framebuffer();

		framebuffer(const framebuffer& rhs) = delete;
		framebuffer& operator=(const framebuffer& rhs) = delete;

		framebuffer(framebuffer&& rhs) noexcept;
		framebuffer& operator=(framebuffer&& rhs) noexcept;

		void bind() const noexcept;

		template <typename... arguments>
		void attach(GLenum attachment, arguments&&... args) {
			bind();
			auto tex = std::make_unique<texture>(std::forward<arguments>(args)...);
			glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex->id_, 0);
			attachments_.insert(std::make_pair(attachment, std::move(tex)));
			bind_default();
		}

		template <typename... arguments>
		void attach_cubemap(arguments&&... args) {
			bind();
			auto tex = std::make_unique<texture>(std::forward<arguments>(args)...);
			for (auto i = 0; i < 6; ++i) {
				glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, tex->id_, 0);
			}
			attachments_.insert(std::make_pair(GL_TEXTURE_CUBE_MAP, std::move(tex)));
			bind_default();
		}

		texture& attachment(GLenum attachment) const;
		static void bind_default() noexcept;
	};
}

#endif
<|endoftext|>


<commit_before>/*
 * DataStore.cpp
 *
 *  Created on: Sep 10, 2008
 *      Author: rasmussn
 */

#include "DataStore.hpp"

#include <stdlib.h>

namespace PV
{

/**
 * @numBuffers
 * @bufSize
 * @numLevels
 */
DataStore::DataStore(int numBuffers, size_t bufSize, int numLevels)
{
	this->curLevel = numLevels - 1;  // start at bottom, work up
	this->bufSize = bufSize;
	this->numLevels = numLevels;
	this->numBuffers = numBuffers;
	this->recvBuffers = (char*) calloc(numBuffers * numLevels * bufSize, sizeof(char));
}

DataStore::~DataStore()
{
	free(recvBuffers);
}

}
<commit_msg>We've started to blow out memory with larger image sizes so added asserts for mallocs.<commit_after>/*
 * DataStore.cpp
 *
 *  Created on: Sep 10, 2008
 *      Author: rasmussn
 */

#include "DataStore.hpp"
#include <assert.h>

#include <stdlib.h>

namespace PV
{

/**
 * @numBuffers
 * @bufSize
 * @numLevels
 */
DataStore::DataStore(int numBuffers, size_t bufSize, int numLevels)
{
	this->curLevel = numLevels - 1;  // start at bottom, work up
	this->bufSize = bufSize;
	this->numLevels = numLevels;
	this->numBuffers = numBuffers;
	this->recvBuffers = (char*) calloc(numBuffers * numLevels * bufSize, sizeof(char));
	assert(this->recvBuffers != NULL);
}

DataStore::~DataStore()
{
	free(recvBuffers);
}

}
<|endoftext|>


<commit_before>#include "overlay.h"
#include <iostream>
#include <QInputDialog>

/**
 * @brief overlay::overlay
 */
overlay::overlay() {
}

/**
 * @brief overlay::draw_overlay
 * Draws an overlay on top of the specified QImage.
 * @param img QImage to draw on
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::draw_overlay(QImage &img, int frame_nr) {
    if (show_overlay) {
        foreach (shape* s, overlays[frame_nr]) {
            s->draw(img);
        }
    }
}

/**
 * @brief overlay::toggle_overlay
 * Toggles the showing of the overlay, and if video is paused updates
 * the frame in the GUI to show with/without overlay
 */
void overlay::toggle_overlay() {
    show_overlay = !show_overlay;
}

/**
 * @brief overlay::is_showing_overlay
 * @return Returns true if the overlay is currently on
 */
bool overlay::is_showing_overlay() {
    return show_overlay;
}

/**
 * @brief overlay::set_showing_overlay
 * @param value
 */
void overlay::set_showing_overlay(bool value) {
    show_overlay = value;
}

/**
 * @brief overlay::set_tool
 * Sets the overlay tool's shape.
 * If the tool is the text-tool the user is prompted to wnter a text.
 * @param s
 */
void overlay::set_tool(SHAPES s) {
    current_shape = s;
    if (s == TEXT) {
        current_string = QInputDialog::getText(NULL, "Text chooser", "Enter a text:");
    }
}

/**
 * @brief overlay::set_colour
 * Sets the overlay tool's colour.
 * @param col
 */
void overlay::set_colour(QColor col) {
    current_colour = col;
}

/**
 * @brief overlay::get_colour
 * @return The currenty choosen colour.
 */
QColor overlay::get_colour() {
    return current_colour;
}

/**
 * @brief overlay::get_shape
 * @return The currently choosen shape
 */
SHAPES overlay::get_shape() {
    return current_shape;
}

/**
 * @brief overlay::mouse_pressed
 * Creates a drawing shape with the prechoosen colour
 * and shape, if the overlay is visible.
 * @param pos Mouse coordinates on the frame.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::mouse_pressed(QPoint pos, int frame_nr) {
    if (show_overlay) {
        switch (current_shape) {
            case RECTANGLE:
                overlays[frame_nr].append(new rectangle(current_colour, pos));
                break;
            case CIRCLE:
                overlays[frame_nr].append(new circle(current_colour, pos));
                break;
            case LINE:
                overlays[frame_nr].append(new line(current_colour, pos));
                break;
            case ARROW:
                overlays[frame_nr].append(new arrow(current_colour, pos));
                break;
            case PEN:
                overlays[frame_nr].append(new pen(current_colour, pos));
                break;
            case TEXT:
                overlays[frame_nr].append(new text(current_colour, pos, current_string));
                break;
            default:
                break;
        }
    }
}

/**
 * @brief overlay::mouse_released
 * Ends drawing on the overlay when the mouse is
 * released, if the overlay is visible.
 * @param pos Mouse coordinates on the frame.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::mouse_released(QPoint pos, int frame_nr) {
    update_drawing_position(pos, frame_nr);
}

/**
 * @brief overlay::mouse_moved
 * Updates drawing on the overlay when the mouse is
 * moved, if the overlay is visible.
 * @param pos Mouse coordinates on the frame.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::mouse_moved(QPoint pos, int frame_nr) {
    update_drawing_position(pos, frame_nr);
}

/**
 * @brief overlay::update_drawing_position
 * Updates the position of the end point of the shape currently being drawn
 * @param pos Mouse coordinates on the frame.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::update_drawing_position(QPoint pos, int frame_nr) {
    if (show_overlay) {
        // The last appended shape is the one we're currently drawing.
        overlays[frame_nr].last()->update_drawing_pos(pos);
    }
}

/**
 * @brief overlay::undo
 * Undo the drawings on the overlay, if the overlay is visible.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::undo(int frame_nr) {
    if (show_overlay) {
        if (!overlays[frame_nr].isEmpty()) {
            overlays[frame_nr].takeLast(); // Requires a non-empty list.
        }
    }
}

/**
 * @brief overlay::clear
 * Clear the drawings on the overlay, if the overlay is visible.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::clear(int frame_nr) {
    if (show_overlay) {
        overlays[frame_nr].clear();
    }
}
<commit_msg>Fixed merge conflict.<commit_after>#include "overlay.h"
#include <iostream>
#include <QInputDialog>

/**
 * @brief overlay::overlay
 */
overlay::overlay() {
}

/**
 * @brief overlay::draw_overlay
 * Draws an overlay on top of the specified QImage.
 * @param img QImage to draw on
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::draw_overlay(QImage &img, int frame_nr) {
    if (show_overlay) {
        foreach (shape* s, overlays[frame_nr]) {
            s->draw(img);
        }
    }
}

/**
 * @brief overlay::toggle_overlay
 * Toggles the showing of the overlay, and if video is paused updates
 * the frame in the GUI to show with/without overlay
 */
void overlay::toggle_overlay() {
    show_overlay = !show_overlay;
}

/**
 * @brief overlay::is_showing_overlay
 * @return Returns true if the overlay is currently on
 */
bool overlay::is_showing_overlay() {
    return show_overlay;
}

/**
 * @brief overlay::set_showing_overlay
 * @param value
 */
void overlay::set_showing_overlay(bool value) {
    show_overlay = value;
}

/**
 * @brief overlay::set_tool
 * Sets the overlay tool's shape.
 * If the tool is the text-tool the user is prompted to wnter a text.
 * @param s
 */
void overlay::set_tool(SHAPES s) {
    current_shape = s;
    if (s == TEXT) {
        current_string = QInputDialog::getText(NULL, "Text chooser", "Enter a text:");
    }
}

/**
 * @brief overlay::set_colour
 * Sets the overlay tool's colour.
 * @param col
 */
void overlay::set_colour(QColor col) {
    current_colour = col;
}

/**
 * @brief overlay::get_colour
 * @return The currenty choosen colour.
 */
QColor overlay::get_colour() {
    return current_colour;
}

/**
 * @brief overlay::get_shape
 * @return The currently choosen shape
 */
SHAPES overlay::get_shape() {
    return current_shape;
}

/**
 * @brief overlay::mouse_pressed
 * Creates a drawing shape with the prechoosen colour
 * and shape, if the overlay is visible.
 * @param pos Mouse coordinates on the frame.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::mouse_pressed(QPoint pos, int frame_nr) {
    if (show_overlay) {
        switch (current_shape) {
            case RECTANGLE:
                overlays[frame_nr].append(new rectangle(current_colour, pos));
                break;
            case CIRCLE:
                overlays[frame_nr].append(new circle(current_colour, pos));
                break;
            case LINE:
                overlays[frame_nr].append(new line(current_colour, pos));
                break;
            case ARROW:
                overlays[frame_nr].append(new arrow(current_colour, pos));
                break;
            case PEN:
                overlays[frame_nr].append(new pen(current_colour, pos));
                break;
            case TEXT:
                overlays[frame_nr].append(new text(current_colour, pos, current_string));
                break;
            default:
                break;
        }
    }
}

/**
 * @brief overlay::mouse_released
 * Ends drawing on the overlay when the mouse is
 * released, if the overlay is visible.
 * @param pos Mouse coordinates on the frame.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::mouse_released(QPoint pos, int frame_nr) {
    update_drawing_position(pos, frame_nr);
}

/**
 * @brief overlay::mouse_moved
 * Updates drawing on the overlay when the mouse is
 * moved, if the overlay is visible.
 * @param pos Mouse coordinates on the frame.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::mouse_moved(QPoint pos, int frame_nr) {
    update_drawing_position(pos, frame_nr);
}

/**
 * @brief overlay::update_drawing_position
 * Updates the position of the end point of the shape currently being drawn
 * @param pos Mouse coordinates on the frame.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::update_drawing_position(QPoint pos, int frame_nr) {
    if (show_overlay) {
        // The last appended shape is the one we're currently drawing.
        overlays[frame_nr].last()->update_drawing_pos(pos);
    }
}

/**
 * @brief overlay::undo
 * Undo the drawings on the overlay, if the overlay is visible.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::undo(int frame_nr) {
    if (show_overlay && !overlays[frame_nr].isEmpty()) {
        overlays[frame_nr].takeLast(); // Requires a non-empty list.
    }
}

/**
 * @brief overlay::clear
 * Clear the drawings on the overlay, if the overlay is visible.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::clear(int frame_nr) {
    if (show_overlay) {
        overlays[frame_nr].clear();
    }
}
<|endoftext|>


<commit_before>#ifndef CTHREAD_FORWARD_LIST
#define CTHREAD_FORWARD_LIST
#include<condition_variable>
#include<forward_list>
#include<memory>	//allocator
#include<mutex>
#include<utility>	//forward, move_if_noexcept

namespace nThread
{
	template<class T,class Alloc=std::allocator<T>>
	class CThread_forward_list	//a thread-safe std::forward_list
	{
	public:
		using allocator_type=Alloc;
		using value_type=T;
	private:
		std::condition_variable insert_;
		std::mutex insertMut_;
		std::forward_list<value_type,allocator_type> fwd_list_;
	public:
		CThread_forward_list()
			:CThread_forward_list{allocator_type()}{}
		explicit CThread_forward_list(const allocator_type &alloc)
			:fwd_list_{alloc}{}
		template<class ... Args>
		void emplace_front(Args &&...args)
		{
			std::lock_guard<std::mutex> lock{insertMut_};
			if(empty())
				insert_.notify_all();
			fwd_list_.emplace_front(std::forward<Args>(args)...);
		}
		inline bool empty() const noexcept
		{
			return fwd_list_.empty();
		}
		template<class UnaryPred>
		void remove_if(const UnaryPred pred)
		{
			std::lock_guard<std::mutex> lock{insertMut_};
			fwd_list_.remove_if(pred);
		}
		value_type wait_and_pop()
		{
			std::unique_lock<std::mutex> lock{insertMut_};
			insert_.wait(lock,[this]() noexcept{return !empty();});
			const auto temp{std::move_if_noexcept(fwd_list_.front())};
			fwd_list_.pop_front();
			lock.unlock();
			return temp;
		}
	};
}

#endif<commit_msg>fix emplace_front, update remove_if (forwarding reference)<commit_after>#ifndef CTHREAD_FORWARD_LIST
#define CTHREAD_FORWARD_LIST
#include<condition_variable>
#include<forward_list>
#include<memory>	//allocator
#include<mutex>
#include<utility>	//forward, move_if_noexcept

namespace nThread
{
	template<class T,class Alloc=std::allocator<T>>
	class CThread_forward_list	//a thread-safe std::forward_list
	{
	public:
		using allocator_type=Alloc;
		using value_type=T;
	private:
		std::condition_variable insert_;
		std::mutex insertMut_;
		std::forward_list<value_type,allocator_type> fwd_list_;
	public:
		CThread_forward_list()
			:CThread_forward_list{allocator_type()}{}
		explicit CThread_forward_list(const allocator_type &alloc)
			:fwd_list_{alloc}{}
		template<class ... Args>
		void emplace_front(Args &&...args)
		{
			std::lock_guard<std::mutex> lock{insertMut_};
			fwd_list_.emplace_front(std::forward<decltype(args)>(args)...);
			if(fwd_list_.size()==1)
				insert_.notify_all();
		}
		inline bool empty() const noexcept
		{
			return fwd_list_.empty();
		}
		template<class UnaryPred>
		void remove_if(UnaryPred &&pred)
		{
			std::lock_guard<std::mutex> lock{insertMut_};
			fwd_list_.remove_if(std::forward<decltype(pred)>(pred));
		}
		value_type wait_and_pop()
		{
			std::unique_lock<std::mutex> lock{insertMut_};
			insert_.wait(lock,[this]() noexcept{return !empty();});
			const auto temp{std::move_if_noexcept(fwd_list_.front())};
			fwd_list_.pop_front();
			lock.unlock();
			return temp;
		}
	};
}

#endif<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include "TestRequiringOptions.h"

int main(int argc, char** argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    std::string filename;
    if (argc < 2)
        filename = std::string("Wangscape/example/example_options.json");
    else
        filename = std::string(argv[1]);
    std::cout << "Using options file at " << filename << "\n";
    assert(TestRequiringOptions::initFilename(filename));
    return RUN_ALL_TESTS();
}<commit_msg>Newline<commit_after>#include <gtest/gtest.h>
#include "TestRequiringOptions.h"

int main(int argc, char** argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    std::string filename;
    if (argc < 2)
        filename = std::string("Wangscape/example/example_options.json");
    else
        filename = std::string(argv[1]);
    std::cout << "Using options file at " << filename << "\n";
    assert(TestRequiringOptions::initFilename(filename));
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>//
// Copyright 2015 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "Firebase.h"

const char* firebaseFingerprint = "7A 54 06 9B DC 7A 25 B3 86 8D 66 53 48 2C 0B 96 42 C7 B3 0A";
const uint16_t firebasePort = 443;

Firebase::Firebase(const String& host) : _host(host) {
  _http.setReuse(true);
}

Firebase& Firebase::auth(const String& auth) {
  _auth = auth;
  return *this;
}

Firebase& Firebase::child(const String& key) {
  _path = key;
  return *this;
}

String Firebase::val() {
  return sendRequest("GET");
}

String Firebase::push(const String& value) {
  return sendRequest("POST", (uint8_t*)value.c_str(), value.length());
}

String Firebase::sendRequest(const char* method, uint8_t* value, size_t size) {
  _error.reset();
  String url = "/" + _path + ".json";
  if (_auth.length() > 0) {
    url += "?auth=" + _auth;
  }
  _http.begin(_host.c_str(), firebasePort, url.c_str(), true, firebaseFingerprint);
  int statusCode = _http.sendRequest(method, value, size);
  if (statusCode < 0) {
    _error.set(statusCode,
	       String(method) + " " + url + ": "
	       + HTTPClient::errorToString(statusCode));
    return "";
  }
  // no _http.end() because of connection reuse.
  return _http.getString();
}

Firebase& Firebase::stream() {
  _http.begin(_host.c_str(), firebasePort, _path.c_str(), true, firebaseFingerprint);
  _http.addHeader("Accept", "text/event-stream");
  int statusCode = _http.sendRequest("GET", (uint8_t*)NULL, 0);
  return *this;
}

bool Firebase::connected() {
  return _http.connected();
}

bool Firebase::available() {
  return false;
}

String Firebase::read() {
  return "";
}
<commit_msg>handle stream redirect<commit_after>//
// Copyright 2015 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "Firebase.h"

const char* firebaseFingerprint = "7A 54 06 9B DC 7A 25 B3 86 8D 66 53 48 2C 0B 96 42 C7 B3 0A";
const uint16_t firebasePort = 443;

Firebase::Firebase(const String& host) : _host(host) {
  _http.setReuse(true);
}

Firebase& Firebase::auth(const String& auth) {
  _auth = auth;
  return *this;
}

Firebase& Firebase::child(const String& key) {
  _path = key;
  return *this;
}

String Firebase::val() {
  return sendRequest("GET");
}

String Firebase::push(const String& value) {
  return sendRequest("POST", (uint8_t*)value.c_str(), value.length());
}

Firebase& Firebase::stream() {
  String url = "/" + _path + ".json";
  const char* headers[] = {"Location"};
  _http.setReuse(false);
  _http.begin(_host.c_str(), firebasePort, url.c_str(), true, firebaseFingerprint);
  _http.collectHeaders(headers, 1);
  _http.addHeader("Accept", "text/event-stream");
  int statusCode = _http.sendRequest("GET", (uint8_t*)NULL, 0);
  String location = _http.header("Location");
  Serial.println(location);
  _http.setReuse(false);
  _http.begin(location, firebaseFingerprint);
  _http.collectHeaders(headers, 1);
  statusCode = _http.sendRequest("GET", (uint8_t*)NULL, 0);
  location = _http.header("Location");
  Serial.println(location);
  _http.setReuse(false);
  _http.begin(location, firebaseFingerprint);
  statusCode = _http.sendRequest("GET", (uint8_t*)NULL, 0);
}

String Firebase::sendRequest(const char* method, uint8_t* value, size_t size) {
  _error.reset();
  String url = "/" + _path + ".json";
  if (_auth.length() > 0) {
    url += "?auth=" + _auth;
  }
  _http.begin(_host.c_str(), firebasePort, url.c_str(), true, firebaseFingerprint);
  int statusCode = _http.sendRequest(method, value, size);
  if (statusCode < 0) {
    _error.set(statusCode,
	       String(method) + " " + url + ": "
	       + HTTPClient::errorToString(statusCode));
    return "";
  }
  // no _http.end() because of connection reuse.
  return _http.getString();
}

bool Firebase::connected() {
  return _http.connected();
}

bool Firebase::available() {
  return false;
}

String Firebase::read() {
  return "";
}
<|endoftext|>


<commit_before>#include "compressor.h"
#include <zlib.h>
#include "scope_guard.h"
#include "workaround.hpp"
#include "errors.h"
#include <stdio.h>
#include <fcntl.h>

using namespace es3;
using namespace boost::filesystem;

#define MINIMAL_BLOCK (1024*1024)

namespace es3
{
	struct compress_task : public sync_task
	{
		compressor_ptr parent_;
		uint64_t block_num_, offset_, size_, block_total_;

		virtual std::string get_class() const
		{
			return "compression"+int_to_string(get_class_limit());
		}
		virtual int get_class_limit() const
		{
			return parent_->context_->max_compressors_;
		}

		virtual void operator()(agenda_ptr agenda)
		{
			std::pair<std::string,uint64_t> res=do_compress();
			parent_->on_complete(res.first, block_num_, res.second);
		}

		std::pair<std::string,uint64_t> do_compress()
		{
			handle_t src(open(parent_->path_.c_str(), O_RDONLY));
			lseek64(src.get(), offset_, SEEK_SET) | libc_die;

			//Generate the temp name
			path tmp_nm = path(parent_->context_->scratch_path_) /
					unique_path("scratchy-%%%%-%%%%");
			handle_t tmp_desc(open(tmp_nm.c_str(), O_RDWR|O_CREAT));

			VLOG(2) << "Compressing part " << block_num_ << " out of " <<
					   block_total_ << " of " << parent_->path_;

			z_stream stream = {0};
			deflateInit2(&stream, 8, Z_DEFLATED,
							   15|16, //15 window bits | GZIP
							   8,
							   Z_DEFAULT_STRATEGY);
			ON_BLOCK_EXIT(&deflateEnd, &stream);

			char buf[65536*4];
			char buf_out[65536];
			size_t consumed=0;
			size_t raw_consumed=0;
			while(raw_consumed<size_)
			{
				size_t chunk = std::min(uint64_t(sizeof(buf)),
										size_-raw_consumed);
				ssize_t ln=read(src.get(), buf, chunk) | libc_die;
				assert(ln>0);
				raw_consumed+=ln;

				stream.avail_in = ln;
				stream.next_in = (Bytef*)buf;

				do
				{
					stream.avail_out= sizeof(buf_out);
					stream.next_out = (Bytef*)buf_out;
					int c_err=deflate(&stream, Z_NO_FLUSH);
					if (c_err!=Z_OK)
						err(errFatal) << "Failed to compress "
									  << parent_->path_;

					size_t cur_consumed=sizeof(buf_out) - stream.avail_out;
					write(tmp_desc.get(), buf_out, cur_consumed) | libc_die;
					consumed += cur_consumed;
				} while(stream.avail_in!=0);
			}
			assert(raw_consumed==size_);

			//We're writing the epilogue
			stream.avail_out= sizeof(buf_out);
			stream.next_out = (Bytef*)buf_out;
			int c_err=deflate(&stream, Z_FINISH);
			if (c_err!=Z_STREAM_END) //Epilogue must always fit
				err(errFatal) << "Failed to finish compression of "
							  << parent_->path_;
			size_t cur_consumed=sizeof(buf_out) - stream.avail_out;
			consumed += cur_consumed;
			write(tmp_desc.get(), buf_out, cur_consumed) | libc_die;

			return std::pair<std::string,uint64_t>(tmp_nm.c_str(), consumed);
		}
	};
}; //namespace es3

void file_compressor::operator()(agenda_ptr agenda)
{
	uint64_t file_sz=file_size(path_);
	if (file_sz<=MINIMAL_BLOCK)
	{
		handle_t desc(open(path_.c_str(), O_RDONLY));
		on_finish_(zip_result_ptr(new compressed_result(path_, desc.size())));
		return;
	}

	//Start compressing
	uint64_t estimate_num_blocks = file_sz / MINIMAL_BLOCK;
	assert(estimate_num_blocks>0);

	if (estimate_num_blocks> context_->max_compressors_)
		estimate_num_blocks = context_->max_compressors_;
	uint64_t block_sz = file_sz / estimate_num_blocks;
	assert(block_sz>0);
	uint64_t num_blocks = file_sz / block_sz +
			((file_sz%block_sz)==0?0:1);

	result_=zip_result_ptr(new compressed_result(num_blocks));
	num_pending_ = num_blocks;
	for(uint64_t f=0; f<num_blocks; ++f)
	{
		boost::shared_ptr<compress_task> ptr(new compress_task());
		ptr->parent_=shared_from_this();
		ptr->block_num_=f;
		ptr->block_total_=num_blocks;
		ptr->offset_=block_sz*f;
		ptr->size_=file_sz-ptr->offset_;
		if (ptr->size_>block_sz)
			ptr->size_=block_sz;

		agenda->schedule(ptr);
	}
}

void file_compressor::on_complete(const std::string &name, uint64_t num,
				 uint64_t resulting_size)
{
	{
		guard_t lock(m_);

		num_pending_--;
		result_->files_.at(num) = name;
		result_->sizes_.at(num) = resulting_size;
	}
	if (num_pending_==0)
	{
		on_finish_(result_);
	}
}
<commit_msg>Bigger buffers<commit_after>#include "compressor.h"
#include <zlib.h>
#include "scope_guard.h"
#include "workaround.hpp"
#include "errors.h"
#include <stdio.h>
#include <fcntl.h>

using namespace es3;
using namespace boost::filesystem;

#define MINIMAL_BLOCK (1024*1024)

namespace es3
{
	struct compress_task : public sync_task
	{
		compressor_ptr parent_;
		uint64_t block_num_, offset_, size_, block_total_;

		virtual std::string get_class() const
		{
			return "compression"+int_to_string(get_class_limit());
		}
		virtual int get_class_limit() const
		{
			return parent_->context_->max_compressors_;
		}

		virtual void operator()(agenda_ptr agenda)
		{
			std::pair<std::string,uint64_t> res=do_compress();
			parent_->on_complete(res.first, block_num_, res.second);
		}

		std::pair<std::string,uint64_t> do_compress()
		{
			handle_t src(open(parent_->path_.c_str(), O_RDONLY));
			lseek64(src.get(), offset_, SEEK_SET) | libc_die;

			//Generate the temp name
			path tmp_nm = path(parent_->context_->scratch_path_) /
					unique_path("scratchy-%%%%-%%%%");
			handle_t tmp_desc(open(tmp_nm.c_str(), O_RDWR|O_CREAT));

			VLOG(2) << "Compressing part " << block_num_ << " out of " <<
					   block_total_ << " of " << parent_->path_;

			z_stream stream = {0};
			deflateInit2(&stream, 8, Z_DEFLATED,
							   15|16, //15 window bits | GZIP
							   8,
							   Z_DEFAULT_STRATEGY);
			ON_BLOCK_EXIT(&deflateEnd, &stream);

			std::vector<char> buf;
			std::vector<char> buf_out;
			buf.resize(1024*1024*2);
			buf_out.resize(1024*1024);

			size_t consumed=0;
			size_t raw_consumed=0;
			while(raw_consumed<size_)
			{
				size_t chunk = std::min(uint64_t(buf.size()),
										size_-raw_consumed);
				ssize_t ln=read(src.get(), &buf[0], chunk) | libc_die;
				assert(ln>0);
				raw_consumed+=ln;

				stream.avail_in = ln;
				stream.next_in = (Bytef*)&buf[0];

				do
				{
					stream.avail_out= buf_out.size();
					stream.next_out = (Bytef*)&buf_out[0];
					int c_err=deflate(&stream, Z_NO_FLUSH);
					if (c_err!=Z_OK)
						err(errFatal) << "Failed to compress "
									  << parent_->path_;

					size_t cur_consumed=buf_out.size() - stream.avail_out;
					write(tmp_desc.get(), &buf_out[0], cur_consumed) | libc_die;
					consumed += cur_consumed;
				} while(stream.avail_in!=0);
			}
			assert(raw_consumed==size_);

			//We're writing the epilogue
			stream.avail_out= buf_out.size();
			stream.next_out = (Bytef*)&buf_out[0];
			int c_err=deflate(&stream, Z_FINISH);
			if (c_err!=Z_STREAM_END) //Epilogue must always fit
				err(errFatal) << "Failed to finish compression of "
							  << parent_->path_;
			size_t cur_consumed=buf_out.size() - stream.avail_out;
			consumed += cur_consumed;
			if (cur_consumed!=0)
				write(tmp_desc.get(), &buf_out[0], cur_consumed) | libc_die;

			return std::pair<std::string,uint64_t>(tmp_nm.c_str(), consumed);
		}
	};
}; //namespace es3

void file_compressor::operator()(agenda_ptr agenda)
{
	uint64_t file_sz=file_size(path_);
	if (file_sz<=MINIMAL_BLOCK)
	{
		handle_t desc(open(path_.c_str(), O_RDONLY));
		on_finish_(zip_result_ptr(new compressed_result(path_, desc.size())));
		return;
	}

	//Start compressing
	uint64_t estimate_num_blocks = file_sz / MINIMAL_BLOCK;
	assert(estimate_num_blocks>0);

	if (estimate_num_blocks> context_->max_compressors_)
		estimate_num_blocks = context_->max_compressors_;
	uint64_t block_sz = file_sz / estimate_num_blocks;
	assert(block_sz>0);
	uint64_t num_blocks = file_sz / block_sz +
			((file_sz%block_sz)==0?0:1);

	result_=zip_result_ptr(new compressed_result(num_blocks));
	num_pending_ = num_blocks;
	for(uint64_t f=0; f<num_blocks; ++f)
	{
		boost::shared_ptr<compress_task> ptr(new compress_task());
		ptr->parent_=shared_from_this();
		ptr->block_num_=f;
		ptr->block_total_=num_blocks;
		ptr->offset_=block_sz*f;
		ptr->size_=file_sz-ptr->offset_;
		if (ptr->size_>block_sz)
			ptr->size_=block_sz;

		agenda->schedule(ptr);
	}
}

void file_compressor::on_complete(const std::string &name, uint64_t num,
				 uint64_t resulting_size)
{
	{
		guard_t lock(m_);

		num_pending_--;
		result_->files_.at(num) = name;
		result_->sizes_.at(num) = resulting_size;
	}
	if (num_pending_==0)
	{
		on_finish_(result_);
	}
}
<|endoftext|>


<commit_before>#include <iostream>

#include <SFML/Audio/SoundBuffer.hpp>

#include <beatwave/game.hpp>
#include <beatwave/config.hpp>
#include <core/util.hpp>
#include <core/dsl.hpp>

namespace
{
}

Game::Game():
    player(config::PLAYER_INIT_POSITION,
           config::PLAYER_INIT_RADIUS,
           config::PLAYER_INIT_COLOR)
{}

bool Game::initSounds()
{
    if (!kickBuffer.loadFromFile("data/kick.wav")) {
        std::cout << "[ERROR] Cannot load data/kick.wav" << std::endl;
        return false;
    }

    if (!snareBuffer.loadFromFile("data/snare.wav")) {
        std::cout << "[ERROR] Cannot load data/snare.wav" << std::endl;
        return false;
    }

    if (!hihatBuffer.loadFromFile("data/hihat.wav")) {
        std::cout << "[ERROR] Cannot load data/hihat.wav" << std::endl;
        return false;
    }

    if (!shamanBuffer.loadFromFile("data/shaman.wav")) {
        std::cout << "[ERROR] Cannot load data/shaman.wav" << std::endl;
        return false;
    }

    kickSound.setBuffer(kickBuffer);
    snareSound.setBuffer(snareBuffer);
    hihatSound.setBuffer(hihatBuffer);
    shamanSound.setBuffer(shamanBuffer);

    return true;
}

bool Game::init()
{
    if (!initSounds()) {
        return false;
    }

    digTunnel("tunnel.txt", tunnel);

    return true;
}

void Game::tick(sf::Int32 deltaTime)
{
    player.tick(deltaTime);
}

void Game::render(sf::RenderTarget *renderTarget)
{
    renderTarget->clear(config::WALL_COLOR);
    player.centerView(renderTarget);

    for (const auto &rect: tunnel) {
        sf::RectangleShape shape;
        shape.setPosition(rect.left, rect.top);
        shape.setSize(sf::Vector2f(rect.width, rect.height));
        shape.setFillColor(sf::Color::Black);
        renderTarget->draw(shape);
    }

    player.render(renderTarget);
}

void Game::kick()
{
    player.step(sf::Color::Red,
                sf::Vector2f(config::PLAYER_MOVE_DISTANCE, 0.0f));
    kickSound.play();
}

void Game::snare()
{
    player.step(sf::Color::Green,
                sf::Vector2f(0.0f, config::PLAYER_MOVE_DISTANCE));
    snareSound.play();
}

void Game::hihat()
{
    player.step(sf::Color::Blue,
                sf::Vector2f(0.0f, -config::PLAYER_MOVE_DISTANCE));
    hihatSound.play();
}

void Game::shaman()
{
    player.step(sf::Color::Yellow,
                sf::Vector2f(-config::PLAYER_MOVE_DISTANCE, 0.0f));
    shamanSound.play();
}

void Game::killPlayer()
{
    player.kill();
}

void Game::reset()
{
    using namespace dsl;

    digTunnel("tunnel.txt", tunnel);

}
<commit_msg>Reset player on game reset (#10)<commit_after>#include <iostream>

#include <SFML/Audio/SoundBuffer.hpp>

#include <beatwave/game.hpp>
#include <beatwave/config.hpp>
#include <core/util.hpp>
#include <core/dsl.hpp>

namespace
{
}

Game::Game():
    player(config::PLAYER_INIT_POSITION,
           config::PLAYER_INIT_RADIUS,
           config::PLAYER_INIT_COLOR)
{}

bool Game::initSounds()
{
    if (!kickBuffer.loadFromFile("data/kick.wav")) {
        std::cout << "[ERROR] Cannot load data/kick.wav" << std::endl;
        return false;
    }

    if (!snareBuffer.loadFromFile("data/snare.wav")) {
        std::cout << "[ERROR] Cannot load data/snare.wav" << std::endl;
        return false;
    }

    if (!hihatBuffer.loadFromFile("data/hihat.wav")) {
        std::cout << "[ERROR] Cannot load data/hihat.wav" << std::endl;
        return false;
    }

    if (!shamanBuffer.loadFromFile("data/shaman.wav")) {
        std::cout << "[ERROR] Cannot load data/shaman.wav" << std::endl;
        return false;
    }

    kickSound.setBuffer(kickBuffer);
    snareSound.setBuffer(snareBuffer);
    hihatSound.setBuffer(hihatBuffer);
    shamanSound.setBuffer(shamanBuffer);

    return true;
}

bool Game::init()
{
    if (!initSounds()) {
        return false;
    }

    digTunnel("tunnel.txt", tunnel);

    return true;
}

void Game::tick(sf::Int32 deltaTime)
{
    player.tick(deltaTime);
}

void Game::render(sf::RenderTarget *renderTarget)
{
    renderTarget->clear(config::WALL_COLOR);
    player.centerView(renderTarget);

    for (const auto &rect: tunnel) {
        sf::RectangleShape shape;
        shape.setPosition(rect.left, rect.top);
        shape.setSize(sf::Vector2f(rect.width, rect.height));
        shape.setFillColor(sf::Color::Black);
        renderTarget->draw(shape);
    }

    player.render(renderTarget);
}

void Game::kick()
{
    player.step(sf::Color::Red,
                sf::Vector2f(config::PLAYER_MOVE_DISTANCE, 0.0f));
    kickSound.play();
}

void Game::snare()
{
    player.step(sf::Color::Green,
                sf::Vector2f(0.0f, config::PLAYER_MOVE_DISTANCE));
    snareSound.play();
}

void Game::hihat()
{
    player.step(sf::Color::Blue,
                sf::Vector2f(0.0f, -config::PLAYER_MOVE_DISTANCE));
    hihatSound.play();
}

void Game::shaman()
{
    player.step(sf::Color::Yellow,
                sf::Vector2f(-config::PLAYER_MOVE_DISTANCE, 0.0f));
    shamanSound.play();
}

void Game::killPlayer()
{
    player.kill();
}

void Game::reset()
{
    using namespace dsl;

    digTunnel("tunnel.txt", tunnel);
    player.reset();
}
<|endoftext|>


<commit_before>//  Natron
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
 * Created by Alexandre GAUTHIER-FOICHAT on 6/1/2012.
 * contact: immarespond at gmail dot com
 *
 */

#include "DiskCacheNode.h"
#include "Engine/Node.h"
#include "Engine/Image.h"
#include "Engine/AppInstance.h"
#include "Engine/KnobTypes.h"
#include "Engine/TimeLine.h"

using namespace Natron;

struct DiskCacheNodePrivate
{
    boost::shared_ptr<Choice_Knob> frameRange;
    boost::shared_ptr<Int_Knob> firstFrame;
    boost::shared_ptr<Int_Knob> lastFrame;
    boost::shared_ptr<Button_Knob> preRender;

    DiskCacheNodePrivate()
    {

    }
};

DiskCacheNode::DiskCacheNode(boost::shared_ptr<Node> node)
: OutputEffectInstance(node)
, _imp(new DiskCacheNodePrivate())
{
    setSupportsRenderScaleMaybe(eSupportsYes);
}

void
DiskCacheNode::addAcceptedComponents(int /*inputNb*/,std::list<Natron::ImageComponentsEnum>* comps)
{
    comps->push_back(Natron::eImageComponentRGBA);
    comps->push_back(Natron::eImageComponentRGB);
    comps->push_back(Natron::eImageComponentAlpha);
}
void
DiskCacheNode::addSupportedBitDepth(std::list<Natron::ImageBitDepthEnum>* depths) const
{
    depths->push_back(Natron::eImageBitDepthFloat);
}

bool
DiskCacheNode::shouldCacheOutput() const
{
    return true;
}

void
DiskCacheNode::initializeKnobs()
{
    boost::shared_ptr<Page_Knob> page = Natron::createKnob<Page_Knob>(this, "Controls");

    _imp->frameRange = Natron::createKnob<Choice_Knob>(this, "Frame range");
    _imp->frameRange->setName("frameRange");
    _imp->frameRange->setAnimationEnabled(false);
    std::vector<std::string> choices;
    choices.push_back("Input frame range");
    choices.push_back("Timeline bounds");
    choices.push_back("Manual");
    _imp->frameRange->populateChoices(choices);
    _imp->frameRange->setDefaultValue(0);
    page->addKnob(_imp->frameRange);

    _imp->firstFrame = Natron::createKnob<Int_Knob>(this, "First frame");
    _imp->firstFrame->setAnimationEnabled(false);
    _imp->firstFrame->setName("firstFrame");
    _imp->firstFrame->disableSlider();
    _imp->firstFrame->turnOffNewLine();
    _imp->firstFrame->setDefaultValue(1);
    _imp->firstFrame->setSecret(true);
    page->addKnob(_imp->firstFrame);

    _imp->lastFrame = Natron::createKnob<Int_Knob>(this, "Last frame");
    _imp->lastFrame->setAnimationEnabled(false);
    _imp->lastFrame->setName("LastFrame");
    _imp->lastFrame->disableSlider();
    _imp->lastFrame->setDefaultValue(100);
    _imp->lastFrame->setSecret(true);
    page->addKnob(_imp->lastFrame);

    _imp->preRender = Natron::createKnob<Button_Knob>(this, "Pre-cache");
    _imp->preRender->setName("preRender");
    _imp->preRender->setEvaluateOnChange(false);
    _imp->preRender->setHintToolTip("Cache the frame range specified by rendering images at zoom-level 100% only.");
    page->addKnob(_imp->preRender);

}

void
DiskCacheNode::knobChanged(KnobI* k, Natron::ValueChangedReasonEnum /*reason*/, int /*view*/, SequenceTime /*time*/)
{
    if (_imp->frameRange.get() == k) {
        int idx = _imp->frameRange->getValue();
        switch (idx) {
            case 0:
            case 1:
                _imp->firstFrame->setSecret(true);
                _imp->lastFrame->setSecret(true);
                break;
            case 2:
                _imp->firstFrame->setSecret(false);
                _imp->lastFrame->setSecret(false);
                break;
            default:
                break;
        }
    } else if (_imp->preRender.get() == k) {
        AppInstance::RenderWork w;
        w.writer = dynamic_cast<OutputEffectInstance*>(this);
        w.firstFrame = INT_MIN;
        w.lastFrame = INT_MAX;
        std::list<AppInstance::RenderWork> works;
        works.push_back(w);
        getApp()->startWritersRendering(works);
    }
}

void
DiskCacheNode::getFrameRange(SequenceTime *first,SequenceTime *last)
{
    int idx = _imp->frameRange->getValue();
    switch (idx) {
        case 0: {
            EffectInstance* input = getInput(0);
            if (input) {
                input->getFrameRange_public(input->getHash(), first, last);
            }
        } break;
        case 1: {
            boost::shared_ptr<TimeLine> tl = getApp()->getTimeLine();
            *first = tl->leftBound();
            *last = tl->rightBound();
        } break;
        case 2: {
            *first = _imp->firstFrame->getValue();
            *last = _imp->lastFrame->getValue();
        };
        default:
            break;
    }
}

void
DiskCacheNode::getPreferredDepthAndComponents(int /*inputNb*/,Natron::ImageComponentsEnum* comp,Natron::ImageBitDepthEnum* depth) const
{
    EffectInstance* input = getInput(0);
    if (input) {
        return input->getPreferredDepthAndComponents(-1, comp, depth);
    } else {
        *comp = eImageComponentRGBA;
        *depth = eImageBitDepthFloat;
    }
}

Natron::ImagePremultiplicationEnum
DiskCacheNode::getOutputPremultiplication() const
{
    EffectInstance* input = getInput(0);
    if (input) {
        return input->getOutputPremultiplication();
    } else {
        return eImagePremultiplicationPremultiplied;
    }

}

double
DiskCacheNode::getPreferredAspectRatio() const
{
    EffectInstance* input = getInput(0);
    if (input) {
        return input->getPreferredAspectRatio();
    } else {
        return 1.;
    }

}

Natron::StatusEnum
DiskCacheNode::render(SequenceTime time,
                      const RenderScale& originalScale,
                      const RenderScale & /*mappedScale*/,
                      const RectI & roi, //!< renderWindow in pixel coordinates
                      int view,
                      bool /*isSequentialRender*/,
                      bool /*isRenderResponseToUserInteraction*/,
                      boost::shared_ptr<Natron::Image> output)
{

    EffectInstance* input = getInput(0);
    if (!input) {
        return eStatusFailed;
    }

    ImageBitDepthEnum bitdepth;
    ImageComponentsEnum components;
    input->getPreferredDepthAndComponents(-1, &components, &bitdepth);
    double par = input->getPreferredAspectRatio();

    RectI roiPixel;
    boost::shared_ptr<Image> srcImg = getImage(0, time, originalScale, view, NULL, components, bitdepth, par, false, &roiPixel);

    if (srcImg->getMipMapLevel() != output->getMipMapLevel()) {
        throw std::runtime_error("Host gave image with wrong scale");
    }
    if (srcImg->getComponents() != output->getComponents() || srcImg->getBitDepth() != output->getBitDepth()) {

        srcImg->convertToFormat(roi, getApp()->getDefaultColorSpaceForBitDepth( srcImg->getBitDepth() ),
                                getApp()->getDefaultColorSpaceForBitDepth(output->getBitDepth()), 3, false, true, false, output.get());
    } else {
        output->pasteFrom(*srcImg, roi, true);
    }

    return eStatusOK;
}

<commit_msg>DiskCache: all parameters do not evaluate on change<commit_after>//  Natron
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
 * Created by Alexandre GAUTHIER-FOICHAT on 6/1/2012.
 * contact: immarespond at gmail dot com
 *
 */

#include "DiskCacheNode.h"
#include "Engine/Node.h"
#include "Engine/Image.h"
#include "Engine/AppInstance.h"
#include "Engine/KnobTypes.h"
#include "Engine/TimeLine.h"

using namespace Natron;

struct DiskCacheNodePrivate
{
    boost::shared_ptr<Choice_Knob> frameRange;
    boost::shared_ptr<Int_Knob> firstFrame;
    boost::shared_ptr<Int_Knob> lastFrame;
    boost::shared_ptr<Button_Knob> preRender;

    DiskCacheNodePrivate()
    {

    }
};

DiskCacheNode::DiskCacheNode(boost::shared_ptr<Node> node)
: OutputEffectInstance(node)
, _imp(new DiskCacheNodePrivate())
{
    setSupportsRenderScaleMaybe(eSupportsYes);
}

void
DiskCacheNode::addAcceptedComponents(int /*inputNb*/,std::list<Natron::ImageComponentsEnum>* comps)
{
    comps->push_back(Natron::eImageComponentRGBA);
    comps->push_back(Natron::eImageComponentRGB);
    comps->push_back(Natron::eImageComponentAlpha);
}
void
DiskCacheNode::addSupportedBitDepth(std::list<Natron::ImageBitDepthEnum>* depths) const
{
    depths->push_back(Natron::eImageBitDepthFloat);
}

bool
DiskCacheNode::shouldCacheOutput() const
{
    return true;
}

void
DiskCacheNode::initializeKnobs()
{
    boost::shared_ptr<Page_Knob> page = Natron::createKnob<Page_Knob>(this, "Controls");

    _imp->frameRange = Natron::createKnob<Choice_Knob>(this, "Frame range");
    _imp->frameRange->setName("frameRange");
    _imp->frameRange->setAnimationEnabled(false);
    std::vector<std::string> choices;
    choices.push_back("Input frame range");
    choices.push_back("Timeline bounds");
    choices.push_back("Manual");
    _imp->frameRange->populateChoices(choices);
    _imp->frameRange->setEvaluateOnChange(false);
    _imp->frameRange->setDefaultValue(0);
    page->addKnob(_imp->frameRange);

    _imp->firstFrame = Natron::createKnob<Int_Knob>(this, "First frame");
    _imp->firstFrame->setAnimationEnabled(false);
    _imp->firstFrame->setName("firstFrame");
    _imp->firstFrame->disableSlider();
    _imp->firstFrame->setEvaluateOnChange(false);
    _imp->firstFrame->turnOffNewLine();
    _imp->firstFrame->setDefaultValue(1);
    _imp->firstFrame->setSecret(true);
    page->addKnob(_imp->firstFrame);

    _imp->lastFrame = Natron::createKnob<Int_Knob>(this, "Last frame");
    _imp->lastFrame->setAnimationEnabled(false);
    _imp->lastFrame->setName("LastFrame");
    _imp->lastFrame->disableSlider();
    _imp->lastFrame->setEvaluateOnChange(false);
    _imp->lastFrame->setDefaultValue(100);
    _imp->lastFrame->setSecret(true);
    page->addKnob(_imp->lastFrame);

    _imp->preRender = Natron::createKnob<Button_Knob>(this, "Pre-cache");
    _imp->preRender->setName("preRender");
    _imp->preRender->setEvaluateOnChange(false);
    _imp->preRender->setHintToolTip("Cache the frame range specified by rendering images at zoom-level 100% only.");
    page->addKnob(_imp->preRender);

}

void
DiskCacheNode::knobChanged(KnobI* k, Natron::ValueChangedReasonEnum /*reason*/, int /*view*/, SequenceTime /*time*/)
{
    if (_imp->frameRange.get() == k) {
        int idx = _imp->frameRange->getValue();
        switch (idx) {
            case 0:
            case 1:
                _imp->firstFrame->setSecret(true);
                _imp->lastFrame->setSecret(true);
                break;
            case 2:
                _imp->firstFrame->setSecret(false);
                _imp->lastFrame->setSecret(false);
                break;
            default:
                break;
        }
    } else if (_imp->preRender.get() == k) {
        AppInstance::RenderWork w;
        w.writer = dynamic_cast<OutputEffectInstance*>(this);
        w.firstFrame = INT_MIN;
        w.lastFrame = INT_MAX;
        std::list<AppInstance::RenderWork> works;
        works.push_back(w);
        getApp()->startWritersRendering(works);
    }
}

void
DiskCacheNode::getFrameRange(SequenceTime *first,SequenceTime *last)
{
    int idx = _imp->frameRange->getValue();
    switch (idx) {
        case 0: {
            EffectInstance* input = getInput(0);
            if (input) {
                input->getFrameRange_public(input->getHash(), first, last);
            }
        } break;
        case 1: {
            boost::shared_ptr<TimeLine> tl = getApp()->getTimeLine();
            *first = tl->leftBound();
            *last = tl->rightBound();
        } break;
        case 2: {
            *first = _imp->firstFrame->getValue();
            *last = _imp->lastFrame->getValue();
        };
        default:
            break;
    }
}

void
DiskCacheNode::getPreferredDepthAndComponents(int /*inputNb*/,Natron::ImageComponentsEnum* comp,Natron::ImageBitDepthEnum* depth) const
{
    EffectInstance* input = getInput(0);
    if (input) {
        return input->getPreferredDepthAndComponents(-1, comp, depth);
    } else {
        *comp = eImageComponentRGBA;
        *depth = eImageBitDepthFloat;
    }
}

Natron::ImagePremultiplicationEnum
DiskCacheNode::getOutputPremultiplication() const
{
    EffectInstance* input = getInput(0);
    if (input) {
        return input->getOutputPremultiplication();
    } else {
        return eImagePremultiplicationPremultiplied;
    }

}

double
DiskCacheNode::getPreferredAspectRatio() const
{
    EffectInstance* input = getInput(0);
    if (input) {
        return input->getPreferredAspectRatio();
    } else {
        return 1.;
    }

}

Natron::StatusEnum
DiskCacheNode::render(SequenceTime time,
                      const RenderScale& originalScale,
                      const RenderScale & /*mappedScale*/,
                      const RectI & roi, //!< renderWindow in pixel coordinates
                      int view,
                      bool /*isSequentialRender*/,
                      bool /*isRenderResponseToUserInteraction*/,
                      boost::shared_ptr<Natron::Image> output)
{

    EffectInstance* input = getInput(0);
    if (!input) {
        return eStatusFailed;
    }

    ImageBitDepthEnum bitdepth;
    ImageComponentsEnum components;
    input->getPreferredDepthAndComponents(-1, &components, &bitdepth);
    double par = input->getPreferredAspectRatio();

    RectI roiPixel;
    boost::shared_ptr<Image> srcImg = getImage(0, time, originalScale, view, NULL, components, bitdepth, par, false, &roiPixel);

    if (srcImg->getMipMapLevel() != output->getMipMapLevel()) {
        throw std::runtime_error("Host gave image with wrong scale");
    }
    if (srcImg->getComponents() != output->getComponents() || srcImg->getBitDepth() != output->getBitDepth()) {

        srcImg->convertToFormat(roi, getApp()->getDefaultColorSpaceForBitDepth( srcImg->getBitDepth() ),
                                getApp()->getDefaultColorSpaceForBitDepth(output->getBitDepth()), 3, false, true, false, output.get());
    } else {
        output->pasteFrom(*srcImg, roi, true);
    }

    return eStatusOK;
}

<|endoftext|>


<commit_before>#include "Entity.h"

namespace Engine
{
	Entity::Entity(uint32 Id)
	{
		EntityId = Id;
		Active = true;
	}

	void Entity::Spawn()
	{
	}

	void Entity::Destroy()
	{
	}

	void Entity::Draw()
	{
	}

	void Entity::Tick(float DeltaTime)
	{
	}
}<commit_msg>Update Entity.cpp<commit_after>#include "Entity.h"

namespace Engine
{
	Entity::Entity(EID Id)
	{
		EntityId = Id;
		Active = true;
	}

	void Entity::Spawn()
	{
	}

	void Entity::Destroy()
	{
	}

	void Entity::Draw()
	{
	}

	void Entity::Tick(float DeltaTime)
	{
	}
}
<|endoftext|>