<commit_before>#include <algorithm>
#include <iostream>
#include <vtkIndent.h>
#include <vtkTable.h>
#include <vtkVariant.h>
#include "persistence_curve_widget.h"

void PersistenceCurveWidget::draw
(const char* label, CurveData& curve)
{
    if (ImGui::Begin(label))
    {
        curve.ID = ImGui::GetID(label);

	// draw button
	ImGui::Checkbox("X log scale", &xlog);
	ImGui::SameLine();
	ImGui::Checkbox("y log scale", &ylog);
	std::string mode = "current scale: ";
	if (xlog && ylog) {
	    curve_idx = 4;
	}
	else if (xlog) {
	    curve_idx = 3;
	}
	else if (ylog) {
	    curve_idx = 2;
	}
	else {
	    curve_idx = 1;
	}

	// draw two sliders
	ImGui::SliderFloat("min persistence", &curve.threshold[0], curve.data_min[0], curve.data_max[0]);
	ImGui::SliderFloat("max persistence", &curve.threshold[1], curve.data_min[0], curve.data_max[0]);

	// draw rect
	const int offset = 40;
	const glm::vec2 canvas_pos (ImGui::GetCursorScreenPos().x,    ImGui::GetCursorScreenPos().y + offset);
	const glm::vec2 canvas_size(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - offset);
	const glm::vec2 view_scale (canvas_size.x, -canvas_size.y);
	const glm::vec2 view_offset(canvas_pos.x, canvas_pos.y + canvas_size.y);

	ImDrawList *draw_list = ImGui::GetWindowDrawList();
	draw_list->AddRect(canvas_pos, canvas_pos + canvas_size, ImColor(255, 0, 255));
	draw_list->PushClipRect(canvas_pos, canvas_pos + canvas_size);

	// draw curve
	int current_frame = ImGui::GetFrameCount();
	if (curve.last_frame != current_frame)
	{
	    const glm::vec2 scale = (curve.data_max - curve.data_min);
	    // curve
	    for (int i = 0; i < static_cast<int>(curve.data.size())-1; ++i) {
		const glm::vec2 ra = (curve.data[i]   - curve.data_min);
		const glm::vec2 rb = (curve.data[i+1] - curve.data_min);
		const glm::vec2 a(ra[0] / scale[0], ra[1] / scale[1]);
		const glm::vec2 b(rb[0] / scale[0], rb[1] / scale[1]);
		draw_list->AddLine(view_offset + view_scale * a, view_offset + view_scale * b, curve.color, 2.0f);
	    }
	    // threshold left
	    {
		float v = (curve.threshold[0] - curve.data_min[0]) / scale[0];
		const glm::vec2 a(v, 0.0f);
		const glm::vec2 b(v, 1.0f);
		draw_list->AddLine(view_offset + view_scale * a, view_offset + view_scale * b, 0xff0000ff, 2.0f);
	    }
	    // threshold right
	    {
		float v = (curve.threshold[1] - curve.data_min[0]) / scale[0];
		const glm::vec2 a(v, 0.0f);
		const glm::vec2 b(v, 1.0f);
		draw_list->AddLine(view_offset + view_scale * a, view_offset + view_scale * b, 0xff0000ff, 2.0f);
	    }
	    curve.last_frame = current_frame;
	}
	draw_list->PopClipRect();
    }
    ImGui::End();
}

int PersistenceCurveWidget::compute(vtkDataSet* input)
{
    std::cout << "[PersistenceCurve] start" << std::endl;
    vtkcurve = vtkSmartPointer<vtkPersistenceCurve>::New();
    vtkcurve->SetInputData(input);
    vtkcurve->SetComputeSaddleConnectors(false);
    vtkcurve->SetUseAllCores(true);
    vtkcurve->SetdebugLevel_(debuglevel);
    vtkcurve->Update();

    std::cout << "[computing curve] start" << std::endl;
    vtkTable* table = vtkcurve->getResult(1);  // all pairs
    for(vtkIdType r = 0; r < table->GetNumberOfRows(); r++)
    {
	// x axis: persistence
	// y axis: number of pairs
	glm::vec2 curr(table->GetValue(r,0).ToFloat(), table->GetValue(r,1).ToFloat());
	// linear interpolate in between two values
	if (curr[0] > -0.1f && curr[1] > -0.1f) { // skip first entry
	    curves[1].AddValue(curr);
	}
	// log interpolate in between two values
	if (curr[0] > 0.0f && curr[1] > 0.0f) { // skip first entry
	    curves[2].AddValue(curr[0], glm::log(curr[1]));
	    curves[3].AddValue(glm::log(curr[0]), curr[1]);
	    curves[4].AddValue(glm::log(curr));
	}
    }
    std::cout << "[computing curve] finish adding points" << std::endl;
    std::cout << "[computing curve] Number of Rows: " << table->GetNumberOfRows() << std::endl;
    std::cout << "[computing curve] Number of Columns: " << table->GetNumberOfColumns() << std::endl;
    return 0;
}
<commit_msg>Go through the getoutputinformation API to get the output port data<commit_after>#include <algorithm>
#include <iostream>
#include <vtkIndent.h>
#include <vtkTable.h>
#include <vtkVariant.h>
#include "persistence_curve_widget.h"

void PersistenceCurveWidget::draw
(const char* label, CurveData& curve)
{
    if (ImGui::Begin(label))
    {
        curve.ID = ImGui::GetID(label);

	// draw button
	ImGui::Checkbox("X log scale", &xlog);
	ImGui::SameLine();
	ImGui::Checkbox("y log scale", &ylog);
	std::string mode = "current scale: ";
	if (xlog && ylog) {
	    curve_idx = 4;
	}
	else if (xlog) {
	    curve_idx = 3;
	}
	else if (ylog) {
	    curve_idx = 2;
	}
	else {
	    curve_idx = 1;
	}

	// draw two sliders
	ImGui::SliderFloat("min persistence", &curve.threshold[0], curve.data_min[0], curve.data_max[0]);
	ImGui::SliderFloat("max persistence", &curve.threshold[1], curve.data_min[0], curve.data_max[0]);

	// draw rect
	const int offset = 40;
	const glm::vec2 canvas_pos (ImGui::GetCursorScreenPos().x,    ImGui::GetCursorScreenPos().y + offset);
	const glm::vec2 canvas_size(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - offset);
	const glm::vec2 view_scale (canvas_size.x, -canvas_size.y);
	const glm::vec2 view_offset(canvas_pos.x, canvas_pos.y + canvas_size.y);

	ImDrawList *draw_list = ImGui::GetWindowDrawList();
	draw_list->AddRect(canvas_pos, canvas_pos + canvas_size, ImColor(255, 0, 255));
	draw_list->PushClipRect(canvas_pos, canvas_pos + canvas_size);

	// draw curve
	int current_frame = ImGui::GetFrameCount();
	if (curve.last_frame != current_frame)
	{
	    const glm::vec2 scale = (curve.data_max - curve.data_min);
	    // curve
	    for (int i = 0; i < static_cast<int>(curve.data.size())-1; ++i) {
		const glm::vec2 ra = (curve.data[i]   - curve.data_min);
		const glm::vec2 rb = (curve.data[i+1] - curve.data_min);
		const glm::vec2 a(ra[0] / scale[0], ra[1] / scale[1]);
		const glm::vec2 b(rb[0] / scale[0], rb[1] / scale[1]);
		draw_list->AddLine(view_offset + view_scale * a, view_offset + view_scale * b, curve.color, 2.0f);
	    }
	    // threshold left
	    {
		float v = (curve.threshold[0] - curve.data_min[0]) / scale[0];
		const glm::vec2 a(v, 0.0f);
		const glm::vec2 b(v, 1.0f);
		draw_list->AddLine(view_offset + view_scale * a, view_offset + view_scale * b, 0xff0000ff, 2.0f);
	    }
	    // threshold right
	    {
		float v = (curve.threshold[1] - curve.data_min[0]) / scale[0];
		const glm::vec2 a(v, 0.0f);
		const glm::vec2 b(v, 1.0f);
		draw_list->AddLine(view_offset + view_scale * a, view_offset + view_scale * b, 0xff0000ff, 2.0f);
	    }
	    curve.last_frame = current_frame;
	}
	draw_list->PopClipRect();
    }
    ImGui::End();
}

int PersistenceCurveWidget::compute(vtkDataSet* input)
{
    std::cout << "[PersistenceCurve] start" << std::endl;
    vtkcurve = vtkSmartPointer<vtkPersistenceCurve>::New();
    vtkcurve->SetInputData(input);
    vtkcurve->SetComputeSaddleConnectors(false);
    vtkcurve->SetUseAllCores(true);
    vtkcurve->SetdebugLevel_(debuglevel);
    vtkcurve->Update();

    std::cout << "[computing curve] start" << std::endl;
	// Tree type mapping to persistence curve output index:
	// Join Tree: 0
	// Morse Smale Curve: 1
	// Split Tree: 2
	// Contour Tree: 3
	vtkTable* table = dynamic_cast<vtkTable*>(vtkcurve->GetOutputInformation(3)->Get(vtkDataObject::DATA_OBJECT()));
    for(vtkIdType r = 0; r < table->GetNumberOfRows(); r++)
    {
	// x axis: persistence
	// y axis: number of pairs
	glm::vec2 curr(table->GetValue(r,0).ToFloat(), table->GetValue(r,1).ToFloat());
	// linear interpolate in between two values
	if (curr[0] > -0.1f && curr[1] > -0.1f) { // skip first entry
	    curves[1].AddValue(curr);
	}
	// log interpolate in between two values
	if (curr[0] > 0.0f && curr[1] > 0.0f) { // skip first entry
	    curves[2].AddValue(curr[0], glm::log(curr[1]));
	    curves[3].AddValue(glm::log(curr[0]), curr[1]);
	    curves[4].AddValue(glm::log(curr));
	}
    }
    std::cout << "[computing curve] finish adding points" << std::endl;
    std::cout << "[computing curve] Number of Rows: " << table->GetNumberOfRows() << std::endl;
    std::cout << "[computing curve] Number of Columns: " << table->GetNumberOfColumns() << std::endl;
    return 0;
}
<|endoftext|>


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

#include "config_subscriber.h"
#include "exceptions.h"
#include "forwarder.h"
#include "watcher.h"
#include <vespa/vespalib/util/sig_catch.h>
#include <vespa/vespalib/util/time.h>
#include <thread>
#include <fcntl.h>
#include <glob.h>
#include <sys/stat.h>
#include <unistd.h>

#include <vespa/log/log.h>
LOG_SETUP("");

namespace logdemon {
namespace {

// wait until 1 second has passed since "start"
void snooze(vespalib::Timer & timer)
{
    if (timer.elapsed() > 1000ms) {
        // already used enough time, no sleep
        return;
    }

    std::this_thread::sleep_for(1000ms - timer.elapsed());
}

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

Watcher::Watcher(ConfigSubscriber &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 {
    donecache() : st_dev(0), st_ino(0), offset(0), valid(false) { memset(pad, 0, sizeof(pad)); }
    dev_t st_dev; /* device */
    ino_t st_ino; /* inode number */
    off_t offset;
    bool  valid;
    char pad[7];
};

class StateSaver {
public:
    StateSaver();
    ~StateSaver();
    void saveState(const donecache&);
    bool loadState(donecache&);
private:
    int _savefd;
};

void StateSaver::saveState(const donecache& already)
{
    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;
    }
}

bool
StateSaver::loadState(donecache& already)
{
    if (_savefd >= 0 &&
        read(_savefd, &already, sizeof(already)) == sizeof(already))
    {
        return true;
    } else {
        return false;
    }
}

StateSaver::StateSaver() : _savefd(-1)
{
    _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 newfn[FILENAME_MAX];

    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");
    }

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

    vespalib::SigCatch catcher;
    int sleepcount = 0;
    vespalib::system_time created = vespalib::system_time::min();

 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;
    vespalib::Timer rotTimer;
    off_t offset = 0;

    while (true) {
        struct stat sb;
        if (fstat(_wfd, &sb) != 0) {
            LOG(error, "fstat(%s) failed: %s", filename, strerror(errno));
            throw SomethingBad("fstat failed");
        }
        if (created == vespalib::system_time::min()) {
            created = vespalib::system_time(std::chrono::seconds(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;
        }

        vespalib::Timer timer;

        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 && (timer.elapsed() < 1000ms)) {
                    ++nnl;
                    _forwarder.forwardLine(std::string_view(l, (nnl - l) - 1));
                    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;

        vespalib::system_time now = vespalib::system_clock::now();
        bool wantrotate = (now > created + _confsubscriber.getRotateAge())
                          || (sb.st_size > _confsubscriber.getRotateSize());

        if (rotate) {
            vespalib::duration rotTime = rotTimer.elapsed();
            if (rotTime > 59s || (sb.st_size == offset && rotTime > 4s)) {
                removeOldLogs(filename);
                if (sb.st_size != offset) {
                    LOG(warning, "logfile rotation incomplete after %2.3f s (dropping %" PRIu64 " bytes)",
                        vespalib::to_s(rotTime), static_cast<uint64_t>(sb.st_size - offset));
                } else {
                    LOG(debug, "logfile rotation complete after %2.3f s", vespalib::to_s(rotTime));
                }
                if (((now - created) < (rotTime + 300s))
                    && (sb.st_size > (1.1 * _confsubscriber.getRotateSize())))
                {
                    LOG(warning, "logfile spamming, aggressively removing %s", newfn);
                    unlink(newfn);
                }
                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;
            rotTimer = vespalib::Timer();
            LOG(debug, "preparing to rotate logfile, old logfile size %d, age %2.3f seconds",
                (int)offset, vespalib::to_s(now-created));
            int l = strlen(filename);
            strcpy(newfn, filename);
            time_t seconds = vespalib::count_s(now.time_since_epoch());
            struct tm *nowtm = gmtime(&seconds);
            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);
            }
        }

        _forwarder.flush();
        dcf.saveState(already);

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

        if (catcher.receivedStopSignal()) {
            throw SigTermException("caught signal");
        }
        snooze(timer);
        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.resetBadLines();
                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)) {
                vespalib::system_time mtime = vespalib::system_time(std::chrono::seconds(sb.st_mtime));
                vespalib::system_time now = vespalib::system_clock::now();
                if ((mtime + _confsubscriber.getRemoveAge()) < now) {
                    LOG(info, "removing %s, too old (%f days)", fname, vespalib::to_s(now - 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
<commit_msg>only do aggressive removal if spamming detected at least 3 times<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "config_subscriber.h"
#include "exceptions.h"
#include "forwarder.h"
#include "watcher.h"
#include <vespa/vespalib/util/sig_catch.h>
#include <vespa/vespalib/util/time.h>
#include <thread>
#include <fcntl.h>
#include <glob.h>
#include <sys/stat.h>
#include <unistd.h>

#include <vespa/log/log.h>
LOG_SETUP("");

namespace logdemon {
namespace {

// wait until 1 second has passed since "start"
void snooze(vespalib::Timer & timer)
{
    if (timer.elapsed() > 1000ms) {
        // already used enough time, no sleep
        return;
    }

    std::this_thread::sleep_for(1000ms - timer.elapsed());
}

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

Watcher::Watcher(ConfigSubscriber &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 {
    donecache() : st_dev(0), st_ino(0), offset(0), valid(false) { memset(pad, 0, sizeof(pad)); }
    dev_t st_dev; /* device */
    ino_t st_ino; /* inode number */
    off_t offset;
    bool  valid;
    char pad[7];
};

class StateSaver {
public:
    StateSaver();
    ~StateSaver();
    void saveState(const donecache&);
    bool loadState(donecache&);
private:
    int _savefd;
};

void StateSaver::saveState(const donecache& already)
{
    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;
    }
}

bool
StateSaver::loadState(donecache& already)
{
    if (_savefd >= 0 &&
        read(_savefd, &already, sizeof(already)) == sizeof(already))
    {
        return true;
    } else {
        return false;
    }
}

StateSaver::StateSaver() : _savefd(-1)
{
    _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 newfn[FILENAME_MAX];
    int spamfill_counter = 0;

    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");
    }

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

    vespalib::SigCatch catcher;
    int sleepcount = 0;
    vespalib::system_time created = vespalib::system_time::min();

 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;
    vespalib::Timer rotTimer;
    off_t offset = 0;

    while (true) {
        struct stat sb;
        if (fstat(_wfd, &sb) != 0) {
            LOG(error, "fstat(%s) failed: %s", filename, strerror(errno));
            throw SomethingBad("fstat failed");
        }
        if (created == vespalib::system_time::min()) {
            created = vespalib::system_time(std::chrono::seconds(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;
        }

        vespalib::Timer timer;

        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 && (timer.elapsed() < 1000ms)) {
                    ++nnl;
                    _forwarder.forwardLine(std::string_view(l, (nnl - l) - 1));
                    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;

        vespalib::system_time now = vespalib::system_clock::now();
        bool wantrotate = (now > created + _confsubscriber.getRotateAge())
                          || (sb.st_size > _confsubscriber.getRotateSize());

        if (rotate) {
            vespalib::duration rotTime = rotTimer.elapsed();
            off_t overflow_size = (1.1 * _confsubscriber.getRotateSize());
            if ((rotTime > 59s) ||
                (sb.st_size == offset && rotTime > 4s) ||
                (sb.st_size > overflow_size && rotTime > 2s))
            {
                if (sb.st_size != offset) {
                    LOG(warning, "logfile rotation incomplete after %2.3f s (dropping %" PRIu64 " bytes)",
                        vespalib::to_s(rotTime), static_cast<uint64_t>(sb.st_size - offset));
                } else {
                    LOG(debug, "logfile rotation complete after %2.3f s", vespalib::to_s(rotTime));
                }
                if (((now - created) < (rotTime + 180s)) && (sb.st_size > overflow_size)) {
                    ++spamfill_counter;
                } else {
                    spamfill_counter = 0;
                }
                created = now;
                rotate = false;
                close(_wfd);
                if (spamfill_counter > 2) {
                    LOG(warning, "logfile spamming %d times, aggressively removing %s", spamfill_counter, newfn);
                    unlink(newfn);
                }
                removeOldLogs(filename);
                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;
            rotTimer = vespalib::Timer();
            LOG(debug, "preparing to rotate logfile, old logfile size %d, age %2.3f seconds",
                (int)offset, vespalib::to_s(now-created));
            int l = strlen(filename);
            strcpy(newfn, filename);
            time_t seconds = vespalib::count_s(now.time_since_epoch());
            struct tm *nowtm = gmtime(&seconds);
            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);
            }
        }

        _forwarder.flush();
        dcf.saveState(already);

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

        if (catcher.receivedStopSignal()) {
            throw SigTermException("caught signal");
        }
        snooze(timer);
        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.resetBadLines();
                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)) {
                vespalib::system_time mtime = vespalib::system_time(std::chrono::seconds(sb.st_mtime));
                vespalib::system_time now = vespalib::system_clock::now();
                if ((mtime + _confsubscriber.getRemoveAge()) < now) {
                    LOG(info, "removing %s, too old (%f days)", fname, vespalib::to_s(now - 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>/******************************************************************************
 * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "basejob.h"

#include "connectiondata.h"

#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QtCore/QTimer>

#include <array>

using namespace QMatrixClient;

struct NetworkReplyDeleter : public QScopedPointerDeleteLater
{
    static inline void cleanup(QNetworkReply* reply)
    {
        if (reply && reply->isRunning())
            reply->abort();
        QScopedPointerDeleteLater::cleanup(reply);
    }
};

class BaseJob::Private
{
    public:
        // Using an idiom from clang-tidy:
        // http://clang.llvm.org/extra/clang-tidy/checks/modernize-pass-by-value.html
        Private(const ConnectionData* c, HttpVerb v,
                QString endpoint, QUrlQuery q, Data data, bool nt)
            : connection(c), verb(v), apiEndpoint(std::move(endpoint))
            , requestQuery(std::move(q)), requestData(std::move(data))
            , needsToken(nt)
        { }

        void sendRequest();

        const ConnectionData* connection;

        // Contents for the network request
        HttpVerb verb;
        QString apiEndpoint;
        QUrlQuery requestQuery;
        Data requestData;
        bool needsToken;

        QScopedPointer<QNetworkReply, NetworkReplyDeleter> reply;
        Status status = NoError;

        QTimer timer;
        QTimer retryTimer;

        size_t maxRetries = 3;
        size_t retriesTaken = 0;

        LoggingCategory logCat = JOBS;
};

inline QDebug operator<<(QDebug dbg, const BaseJob* j)
{
    return dbg << "Job" << j->objectName();
}

BaseJob::BaseJob(const ConnectionData* connection, HttpVerb verb,
                 const QString& name, const QString& endpoint,
                 const Query& query, const Data& data, bool needsToken)
    : d(new Private(connection, verb, endpoint, query, data, needsToken))
{
    setObjectName(name);
    d->timer.setSingleShot(true);
    connect (&d->timer, &QTimer::timeout, this, &BaseJob::timeout);
    d->retryTimer.setSingleShot(true);
    connect (&d->retryTimer, &QTimer::timeout, this, &BaseJob::start);
    qCDebug(d->logCat) << this << "created";
}

BaseJob::~BaseJob()
{
    stop();
    qCDebug(d->logCat) << this << "destroyed";
}

const ConnectionData* BaseJob::connection() const
{
    return d->connection;
}

const QUrlQuery& BaseJob::query() const
{
    return d->requestQuery;
}

void BaseJob::setRequestQuery(const QUrlQuery& query)
{
    d->requestQuery = query;
}

const BaseJob::Data& BaseJob::requestData() const
{
    return d->requestData;
}

void BaseJob::setRequestData(const BaseJob::Data& data)
{
    d->requestData = data;
}

void BaseJob::Private::sendRequest()
{
    QUrl url = connection->baseUrl();
    url.setPath( url.path() + "/" + apiEndpoint );
    QUrlQuery q = requestQuery;
    if (needsToken)
        q.addQueryItem("access_token", connection->accessToken());
    url.setQuery(q);

    QNetworkRequest req {url};
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
    req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
    req.setMaximumRedirectsAllowed(10);
#endif
    switch( verb )
    {
        case HttpVerb::Get:
            reply.reset( connection->nam()->get(req) );
            break;
        case HttpVerb::Post:
            reply.reset( connection->nam()->post(req, requestData.serialize()) );
            break;
        case HttpVerb::Put:
            reply.reset( connection->nam()->put(req, requestData.serialize()) );
            break;
        case HttpVerb::Delete:
            reply.reset( connection->nam()->deleteResource(req) );
            break;
    }
}

void BaseJob::start()
{
    emit aboutToStart();
    d->retryTimer.stop(); // In case we were counting down at the moment
    d->sendRequest();
    connect( d->reply.data(), &QNetworkReply::sslErrors, this, &BaseJob::sslErrors );
    connect( d->reply.data(), &QNetworkReply::finished, this, &BaseJob::gotReply );
    d->timer.start(getCurrentTimeout());
    emit started();
}

void BaseJob::gotReply()
{
    setStatus(checkReply(d->reply.data()));
    if (status().good())
        setStatus(parseReply(d->reply->readAll()));

    finishJob();
}

BaseJob::Status BaseJob::checkReply(QNetworkReply* reply) const
{
    if (reply->error() != QNetworkReply::NoError)
        qCDebug(d->logCat) << this << "returned" << reply->error();
    switch( reply->error() )
    {
    case QNetworkReply::NoError:
        return NoError;

    case QNetworkReply::AuthenticationRequiredError:
    case QNetworkReply::ContentAccessDenied:
    case QNetworkReply::ContentOperationNotPermittedError:
        return { ContentAccessError, reply->errorString() };

    case QNetworkReply::ProtocolInvalidOperationError:
    case QNetworkReply::UnknownContentError:
        return { IncorrectRequestError, reply->errorString() };

    case QNetworkReply::ContentNotFoundError:
        return { NotFoundError, reply->errorString() };

    default:
        return { NetworkError, reply->errorString() };
    }
}

BaseJob::Status BaseJob::parseReply(QByteArray data)
{
    QJsonParseError error;
    QJsonDocument json = QJsonDocument::fromJson(data, &error);
    if( error.error == QJsonParseError::NoError )
        return parseJson(json);
    else
        return { JsonParseError, error.errorString() };
}

BaseJob::Status BaseJob::parseJson(const QJsonDocument&)
{
    return Success;
}

void BaseJob::stop()
{
    d->timer.stop();
    if (!d->reply)
    {
        qCWarning(d->logCat) << this << "stopped with empty network reply";
    }
    else if (d->reply->isRunning())
    {
        qCWarning(d->logCat) << this << "stopped without ready network reply";
        d->reply->disconnect(this); // Ignore whatever comes from the reply
        d->reply->abort();
    }
}

void BaseJob::finishJob()
{
    stop();
    if ((error() == NetworkError || error() == TimeoutError)
            && d->retriesTaken < d->maxRetries)
    {
        // TODO: The whole retrying thing should be put to ConnectionManager
        // otherwise independently retrying jobs make a bit of notification
        // storm towards the UI.
        const auto retryInterval = getNextRetryInterval();
        ++d->retriesTaken;
        qCWarning(d->logCat) << this << "will take retry" << d->retriesTaken
                   << "in" << retryInterval/1000 << "s";
        d->retryTimer.start(retryInterval);
        emit retryScheduled(d->retriesTaken, retryInterval);
        return;
    }

    // Notify those interested in any completion of the job (including killing)
    emit finished(this);

    emit result(this);
    if (error())
        emit failure(this);
    else
        emit success(this);

    deleteLater();
}

BaseJob::duration_t BaseJob::getCurrentTimeout() const
{
    static const std::array<int, 4> timeouts = { 90, 90, 120, 120 };
    return timeouts[std::min(d->retriesTaken, timeouts.size() - 1)] * 1000;
}

BaseJob::duration_t BaseJob::getNextRetryInterval() const
{
    static const std::array<int, 3> intervals = { 5, 10, 30 };
    return intervals[std::min(d->retriesTaken, intervals.size() - 1)] * 1000;
}

BaseJob::duration_t BaseJob::millisToRetry() const
{
    return d->retryTimer.isActive() ? d->retryTimer.remainingTime() : 0;
}

size_t BaseJob::maxRetries() const
{
    return d->maxRetries;
}

void BaseJob::setMaxRetries(size_t newMaxRetries)
{
    d->maxRetries = newMaxRetries;
}

BaseJob::Status BaseJob::status() const
{
    return d->status;
}

int BaseJob::error() const
{
    return d->status.code;
}

QString BaseJob::errorString() const
{
    return d->status.message;
}

void BaseJob::setStatus(Status s)
{
    d->status = s;
    if (!s.good())
    {
        qCWarning(d->logCat) << this << "status" << s.code
                                     << ":" << s.message;
    }
}

void BaseJob::setStatus(int code, QString message)
{
    setStatus({ code, message });
}

void BaseJob::abandon()
{
    deleteLater();
}

void BaseJob::timeout()
{
    setStatus( TimeoutError, "The job has timed out" );
    finishJob();
}

void BaseJob::sslErrors(const QList<QSslError>& errors)
{
    foreach (const QSslError &error, errors) {
        qCWarning(d->logCat) << "SSL ERROR" << error.errorString();
    }
    d->reply->ignoreSslErrors(); // TODO: insecure! should prompt user first
}

void BaseJob::setLoggingCategory(LoggingCategory lcf)
{
    d->logCat = lcf;
}

<commit_msg>Initialize more properly to fix a warning<commit_after>/******************************************************************************
 * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "basejob.h"

#include "connectiondata.h"

#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QtCore/QTimer>

#include <array>

using namespace QMatrixClient;

struct NetworkReplyDeleter : public QScopedPointerDeleteLater
{
    static inline void cleanup(QNetworkReply* reply)
    {
        if (reply && reply->isRunning())
            reply->abort();
        QScopedPointerDeleteLater::cleanup(reply);
    }
};

class BaseJob::Private
{
    public:
        // Using an idiom from clang-tidy:
        // http://clang.llvm.org/extra/clang-tidy/checks/modernize-pass-by-value.html
        Private(const ConnectionData* c, HttpVerb v,
                QString endpoint, QUrlQuery q, Data data, bool nt)
            : connection(c), verb(v), apiEndpoint(std::move(endpoint))
            , requestQuery(std::move(q)), requestData(std::move(data))
            , needsToken(nt)
        { }

        void sendRequest();

        const ConnectionData* connection;

        // Contents for the network request
        HttpVerb verb;
        QString apiEndpoint;
        QUrlQuery requestQuery;
        Data requestData;
        bool needsToken;

        QScopedPointer<QNetworkReply, NetworkReplyDeleter> reply;
        Status status = NoError;

        QTimer timer;
        QTimer retryTimer;

        size_t maxRetries = 3;
        size_t retriesTaken = 0;

        LoggingCategory logCat = JOBS;
};

inline QDebug operator<<(QDebug dbg, const BaseJob* j)
{
    return dbg << "Job" << j->objectName();
}

BaseJob::BaseJob(const ConnectionData* connection, HttpVerb verb,
                 const QString& name, const QString& endpoint,
                 const Query& query, const Data& data, bool needsToken)
    : d(new Private(connection, verb, endpoint, query, data, needsToken))
{
    setObjectName(name);
    d->timer.setSingleShot(true);
    connect (&d->timer, &QTimer::timeout, this, &BaseJob::timeout);
    d->retryTimer.setSingleShot(true);
    connect (&d->retryTimer, &QTimer::timeout, this, &BaseJob::start);
    qCDebug(d->logCat) << this << "created";
}

BaseJob::~BaseJob()
{
    stop();
    qCDebug(d->logCat) << this << "destroyed";
}

const ConnectionData* BaseJob::connection() const
{
    return d->connection;
}

const QUrlQuery& BaseJob::query() const
{
    return d->requestQuery;
}

void BaseJob::setRequestQuery(const QUrlQuery& query)
{
    d->requestQuery = query;
}

const BaseJob::Data& BaseJob::requestData() const
{
    return d->requestData;
}

void BaseJob::setRequestData(const BaseJob::Data& data)
{
    d->requestData = data;
}

void BaseJob::Private::sendRequest()
{
    QUrl url = connection->baseUrl();
    url.setPath( url.path() + "/" + apiEndpoint );
    QUrlQuery q = requestQuery;
    if (needsToken)
        q.addQueryItem("access_token", connection->accessToken());
    url.setQuery(q);

    QNetworkRequest req {url};
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
    req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
    req.setMaximumRedirectsAllowed(10);
#endif
    switch( verb )
    {
        case HttpVerb::Get:
            reply.reset( connection->nam()->get(req) );
            break;
        case HttpVerb::Post:
            reply.reset( connection->nam()->post(req, requestData.serialize()) );
            break;
        case HttpVerb::Put:
            reply.reset( connection->nam()->put(req, requestData.serialize()) );
            break;
        case HttpVerb::Delete:
            reply.reset( connection->nam()->deleteResource(req) );
            break;
    }
}

void BaseJob::start()
{
    emit aboutToStart();
    d->retryTimer.stop(); // In case we were counting down at the moment
    d->sendRequest();
    connect( d->reply.data(), &QNetworkReply::sslErrors, this, &BaseJob::sslErrors );
    connect( d->reply.data(), &QNetworkReply::finished, this, &BaseJob::gotReply );
    d->timer.start(getCurrentTimeout());
    emit started();
}

void BaseJob::gotReply()
{
    setStatus(checkReply(d->reply.data()));
    if (status().good())
        setStatus(parseReply(d->reply->readAll()));

    finishJob();
}

BaseJob::Status BaseJob::checkReply(QNetworkReply* reply) const
{
    if (reply->error() != QNetworkReply::NoError)
        qCDebug(d->logCat) << this << "returned" << reply->error();
    switch( reply->error() )
    {
    case QNetworkReply::NoError:
        return NoError;

    case QNetworkReply::AuthenticationRequiredError:
    case QNetworkReply::ContentAccessDenied:
    case QNetworkReply::ContentOperationNotPermittedError:
        return { ContentAccessError, reply->errorString() };

    case QNetworkReply::ProtocolInvalidOperationError:
    case QNetworkReply::UnknownContentError:
        return { IncorrectRequestError, reply->errorString() };

    case QNetworkReply::ContentNotFoundError:
        return { NotFoundError, reply->errorString() };

    default:
        return { NetworkError, reply->errorString() };
    }
}

BaseJob::Status BaseJob::parseReply(QByteArray data)
{
    QJsonParseError error;
    QJsonDocument json = QJsonDocument::fromJson(data, &error);
    if( error.error == QJsonParseError::NoError )
        return parseJson(json);
    else
        return { JsonParseError, error.errorString() };
}

BaseJob::Status BaseJob::parseJson(const QJsonDocument&)
{
    return Success;
}

void BaseJob::stop()
{
    d->timer.stop();
    if (!d->reply)
    {
        qCWarning(d->logCat) << this << "stopped with empty network reply";
    }
    else if (d->reply->isRunning())
    {
        qCWarning(d->logCat) << this << "stopped without ready network reply";
        d->reply->disconnect(this); // Ignore whatever comes from the reply
        d->reply->abort();
    }
}

void BaseJob::finishJob()
{
    stop();
    if ((error() == NetworkError || error() == TimeoutError)
            && d->retriesTaken < d->maxRetries)
    {
        // TODO: The whole retrying thing should be put to ConnectionManager
        // otherwise independently retrying jobs make a bit of notification
        // storm towards the UI.
        const auto retryInterval = getNextRetryInterval();
        ++d->retriesTaken;
        qCWarning(d->logCat) << this << "will take retry" << d->retriesTaken
                   << "in" << retryInterval/1000 << "s";
        d->retryTimer.start(retryInterval);
        emit retryScheduled(d->retriesTaken, retryInterval);
        return;
    }

    // Notify those interested in any completion of the job (including killing)
    emit finished(this);

    emit result(this);
    if (error())
        emit failure(this);
    else
        emit success(this);

    deleteLater();
}

BaseJob::duration_t BaseJob::getCurrentTimeout() const
{
    static const std::array<int, 4> timeouts ({ 90, 90, 120, 120 });
    return timeouts[std::min(d->retriesTaken, timeouts.size() - 1)] * 1000;
}

BaseJob::duration_t BaseJob::getNextRetryInterval() const
{
    static const std::array<int, 3> intervals ({ 5, 10, 30 });
    return intervals[std::min(d->retriesTaken, intervals.size() - 1)] * 1000;
}

BaseJob::duration_t BaseJob::millisToRetry() const
{
    return d->retryTimer.isActive() ? d->retryTimer.remainingTime() : 0;
}

size_t BaseJob::maxRetries() const
{
    return d->maxRetries;
}

void BaseJob::setMaxRetries(size_t newMaxRetries)
{
    d->maxRetries = newMaxRetries;
}

BaseJob::Status BaseJob::status() const
{
    return d->status;
}

int BaseJob::error() const
{
    return d->status.code;
}

QString BaseJob::errorString() const
{
    return d->status.message;
}

void BaseJob::setStatus(Status s)
{
    d->status = s;
    if (!s.good())
    {
        qCWarning(d->logCat) << this << "status" << s.code
                                     << ":" << s.message;
    }
}

void BaseJob::setStatus(int code, QString message)
{
    setStatus({ code, message });
}

void BaseJob::abandon()
{
    deleteLater();
}

void BaseJob::timeout()
{
    setStatus( TimeoutError, "The job has timed out" );
    finishJob();
}

void BaseJob::sslErrors(const QList<QSslError>& errors)
{
    foreach (const QSslError &error, errors) {
        qCWarning(d->logCat) << "SSL ERROR" << error.errorString();
    }
    d->reply->ignoreSslErrors(); // TODO: insecure! should prompt user first
}

void BaseJob::setLoggingCategory(LoggingCategory lcf)
{
    d->logCat = lcf;
}

<|endoftext|>


<commit_before><commit_msg>got rid of old code<commit_after><|endoftext|>


<commit_before>#include "Radio.h"

Radio::Radio(uint8_t pin) : pin(pin)
#ifdef ENABLE_DUAL_RATES
			  , lowRates(false)
#endif
{}

void Radio::begin() {
  pinMode(pin, OUTPUT);
  encoderBegin(pin);
}

void Radio::setModel(Model *m) {
  this->model = m;

  this->channels = m->channels;
  this->inputs = m->inputs;
  this->trim = m->trim;

  init(this->inputs, this->model->numInputs, 0);
  init(this->channels, this->model->numChannels, 0);

#ifdef ENABLE_DUAL_RATES
  this->lowRates = false;
#endif
}

void Radio::update(float *inputs) {

  uint8_t n = this->model->numInputs;
  uint8_t m = this->model->numChannels;

  // apply trim
  add(this->inputs, inputs, this->trim, n);

  // appy expo to input
  for (uint8_t i = 0; i < n; ++i) {
    this->inputs[i] = expo(this->model->expo[i], this->inputs[i]);
  }

  // process the mix
  mix(this->model->transform, this->inputs, this->channels, n, m);

#ifdef ENABLE_DUAL_RATES
  // limit throw with (dual) rates
  mult(this->channels, this->channels, this->lowRates ? this->model->drLow : this->model->drHigh, m);
#endif

  // ppm encode and send out
  for (uint8_t i = 0; i < m; ++i) {
    encoderWrite(i, toServo(&(this->channels[i])));
  }
}

float *Radio::getChannels() {
  return this->channels;
}

float *Radio::getTrim() {
  return this->trim;
}

void Radio::setTrim(float *trim, uint8_t n) {
  for (uint8_t i = 0; i < n; ++i) {
    this->trim[i] += trim[i];
  }
}

#ifdef ENABLE_DUAL_RATES
void Radio::toggleRates() {
  this->lowRates != this->lowRates;
}

bool Radio::isLowRates() {
  return this->lowRates;
}
#endif

float Radio::toServo(float *input) {

  if (*input > 1) {
    *input = 1;
  } else if (*input < -1) {
    *input = -1;
  }

  float val = MIN_SERVO_PULSE + (1 + *input) * RANGE / 2.0;
  return val;
}

/**
 * mix is matrix multiplication:  channel = transform * inputs
 * transform nxm matrix
 * inputs n float values coming from the controler
 * channels m outputs
 */
void Radio::mix(float *transform, float *inputs, float *channels, uint8_t n, uint8_t m) {
  init(channels, m, 0);
  for (uint8_t j = 0; j < m; ++j)  {
    for (uint8_t i = 0; i < n; ++i) {
      channels[j] = channels[j] + inputs[i] * transform[i+j*n];
    }
  }
}

<commit_msg>apply trim after expo<commit_after>#include "Radio.h"

Radio::Radio(uint8_t pin) : pin(pin)
#ifdef ENABLE_DUAL_RATES
			  , lowRates(false)
#endif
{}

void Radio::begin() {
  pinMode(pin, OUTPUT);
  encoderBegin(pin);
}

void Radio::setModel(Model *m) {
  this->model = m;

  this->channels = m->channels;
  this->inputs = m->inputs;
  this->trim = m->trim;

  init(this->inputs, this->model->numInputs, 0);
  init(this->channels, this->model->numChannels, 0);

#ifdef ENABLE_DUAL_RATES
  this->lowRates = false;
#endif
}

void Radio::update(float *inputs) {

  uint8_t n = this->model->numInputs;
  uint8_t m = this->model->numChannels;

  // appy expo to input
  for (uint8_t i = 0; i < n; ++i) {
    this->inputs[i] = expo(this->model->expo[i], inputs[i]);
  }

  // apply trim
  add(this->inputs, this->inputs, this->trim, n);

  // process the mix
  mix(this->model->transform, this->inputs, this->channels, n, m);

#ifdef ENABLE_DUAL_RATES
  // limit throw with (dual) rates
  mult(this->channels, this->channels, this->lowRates ? this->model->drLow : this->model->drHigh, m);
#endif

  // ppm encode and send out
  for (uint8_t i = 0; i < m; ++i) {
    encoderWrite(i, toServo(&(this->channels[i])));
  }
}

float *Radio::getChannels() {
  return this->channels;
}

float *Radio::getTrim() {
  return this->trim;
}

void Radio::setTrim(float *trim, uint8_t n) {
  for (uint8_t i = 0; i < n; ++i) {
    this->trim[i] += trim[i];
  }
}

#ifdef ENABLE_DUAL_RATES
void Radio::toggleRates() {
  this->lowRates != this->lowRates;
}

bool Radio::isLowRates() {
  return this->lowRates;
}
#endif

float Radio::toServo(float *input) {

  if (*input > 1) {
    *input = 1;
  } else if (*input < -1) {
    *input = -1;
  }

  float val = MIN_SERVO_PULSE + (1 + *input) * RANGE / 2.0;
  return val;
}

/**
 * mix is matrix multiplication:  channel = transform * inputs
 * transform nxm matrix
 * inputs n float values coming from the controler
 * channels m outputs
 */
void Radio::mix(float *transform, float *inputs, float *channels, uint8_t n, uint8_t m) {
  init(channels, m, 0);
  for (uint8_t j = 0; j < m; ++j)  {
    for (uint8_t i = 0; i < n; ++i) {
      channels[j] = channels[j] + inputs[i] * transform[i+j*n];
    }
  }
}

<|endoftext|>


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

#include "testbase.h"
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/document/base/testdocrepo.h>
#include <vespa/vespalib/util/exception.h>
#include <fcntl.h>
#include <unistd.h>
#include <algorithm>

#include <vespa/log/log.h>
LOG_SETUP(".testbase");

using document::DocumentTypeRepo;
using document::readDocumenttypesConfig;

TestBase::TestBase() :
    _repo(new DocumentTypeRepo(readDocumenttypesConfig(
            TEST_PATH("../../../test/cfg/testdoctypes.cfg")))),
    _dataPath(TEST_PATH("../../../test/crosslanguagefiles")),
    _loadTypes(),
    _protocol(_loadTypes, _repo),
    _tests()
{
    _loadTypes.addLoadType(34, "foo", Priority::PRI_NORMAL_2);
}

int
TestBase::Main()
{
    TEST_INIT("messages_test");

    // Retrieve version number to test for.
    LOG(info, "Running tests for version %s.", getVersion().toString().c_str());

    // Run registered tests.
    for (std::map<uint32_t, TEST_METHOD_PT>::iterator it = _tests.begin();
         it != _tests.end(); ++it)
    {
        LOG(info, "Running test for routable type %d.", it->first);
        EXPECT_TRUE( (this->*(it->second))() );
        TEST_FLUSH();
    }

    // Test routable type coverage.
    std::vector<uint32_t> expected, actual;
    EXPECT_TRUE(testCoverage(expected, actual));
    expected.push_back(0);
    EXPECT_TRUE(!testCoverage(expected, actual));
    actual.push_back(1);
    EXPECT_TRUE(!testCoverage(expected, actual));
    actual.push_back(0);
    EXPECT_TRUE(!testCoverage(expected, actual));
    expected.push_back(1);
    EXPECT_TRUE(testCoverage(expected, actual));

    expected.clear();
    _protocol.getRoutableTypes(getVersion(), expected);

    actual.clear();
    for (std::map<uint32_t, TEST_METHOD_PT>::iterator it = _tests.begin();
         it != _tests.end(); ++it)
    {
        actual.push_back(it->first);
    }
    if (shouldTestCoverage()) {
        EXPECT_TRUE(testCoverage(expected, actual, true));
    }
    TEST_DONE();
}

TestBase &
TestBase::putTest(uint32_t type, TEST_METHOD_PT test)
{
    _tests[type] = test;
    return *this;
}

bool
TestBase::testCoverage(const std::vector<uint32_t> &expected, const std::vector<uint32_t> &actual, bool report) const
{
    bool ret = true;

    std::vector<uint32_t> lst(actual);
    for (std::vector<uint32_t>::const_iterator it = expected.begin();
         it != expected.end(); ++it)
    {
        std::vector<uint32_t>::iterator occ = std::find(lst.begin(), lst.end(), *it);
        if (occ == lst.end()) {
            if (report) {
                LOG(error, "Routable type %d is registered in DocumentProtocol but not tested.", *it);
            }
            ret = false;
        } else {
            lst.erase(occ);
        }
    }
    if (!lst.empty()) {
        if (report) {
            for (std::vector<uint32_t>::iterator it = lst.begin();
                 it != lst.end(); ++it)
            {
                LOG(error, "Routable type %d is tested but not registered in DocumentProtocol.", *it);
            }
        }
        ret = false;
    }

    return ret;
}

uint32_t
TestBase::serialize(const string &filename, const mbus::Routable &routable)
{
    const vespalib::Version version = getVersion();
    string path = getPath(version.toString() + "-cpp-" + filename + ".dat");
    LOG(info, "Serializing to '%s'..", path.c_str());

    mbus::Blob blob = _protocol.encode(version, routable);
    if (!EXPECT_TRUE(writeFile(path, blob))) {
        LOG(error, "Could not open file '%s' for writing.", path.c_str());
        return 0;
    }
    mbus::Routable::UP obj = _protocol.decode(version, blob);
    if (!EXPECT_TRUE(obj.get() != NULL)) {
        LOG(error, "Protocol failed to decode serialized data.");
        return 0;
    }
    if (!EXPECT_TRUE(routable.getType() == obj->getType())) {
        LOG(error, "Expected class %d, got %d.", routable.getType(), obj->getType());
        return 0;
    }
    return blob.size();
}

mbus::Routable::UP
TestBase::deserialize(const string &filename, uint32_t classId, uint32_t lang)
{
    const vespalib::Version version = getVersion();
    string path = getPath(version.toString() + (lang == LANG_JAVA ? "-java" : "-cpp") + "-" + filename + ".dat");
    LOG(info, "Deserializing from '%s'..", path.c_str());

    mbus::Blob blob = readFile(path);
    if (!EXPECT_TRUE(blob.size() != 0)) {
        LOG(error, "Could not open file '%s' for reading.", path.c_str());
        return mbus::Routable::UP();
    }
    mbus::Routable::UP ret = _protocol.decode(version, blob);

    if (!EXPECT_TRUE(ret.get())) {
        LOG(error, "Unable to decode class %d", classId);
    } else if (!EXPECT_TRUE(classId == ret->getType())) {
        LOG(error, "Expected class %d, got %d.", classId, ret->getType());
        return mbus::Routable::UP();
    }
    return ret;
}

void
TestBase::dump(const mbus::Blob& blob) const
{
    fprintf(stderr, "[%ld]: ", blob.size());
    for(size_t i = 0; i < blob.size(); i++) {
        if (blob.data()[i] > 32 && blob.data()[i] < 126) {
            fprintf(stderr, "%c ", blob.data()[i]);
        }
        else {
            fprintf(stderr, "%d ", blob.data()[i]);
        }
    }
    fprintf(stderr, "\n");
}

bool
TestBase::writeFile(const string &filename, const mbus::Blob& blob) const
{
    int file = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (file == -1) {
        return false;
    }
    if (write(file, blob.data(), blob.size()) != (ssize_t)blob.size()) {
	throw vespalib::Exception("write failed");
    }
    close(file);
    return true;
}

mbus::Blob
TestBase::readFile(const string &filename) const
{
    int file = open(filename.c_str(), O_RDONLY);
    int len = (file == -1) ? 0 : lseek(file, 0, SEEK_END);
    mbus::Blob blob(len);
    if (file != -1) {
        lseek(file, 0, SEEK_SET);
        if (read(file, blob.data(), len) != len) {
	    throw vespalib::Exception("read failed");
	}
        close(file);
    }

    return blob;
}

<commit_msg>Write to temp file and do atomic rename in C++ DocumentAPI tests<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "testbase.h"
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/document/base/testdocrepo.h>
#include <vespa/vespalib/util/exception.h>
#include <fcntl.h>
#include <unistd.h>
#include <algorithm>

#include <vespa/log/log.h>
LOG_SETUP(".testbase");

using document::DocumentTypeRepo;
using document::readDocumenttypesConfig;

TestBase::TestBase() :
    _repo(new DocumentTypeRepo(readDocumenttypesConfig(
            TEST_PATH("../../../test/cfg/testdoctypes.cfg")))),
    _dataPath(TEST_PATH("../../../test/crosslanguagefiles")),
    _loadTypes(),
    _protocol(_loadTypes, _repo),
    _tests()
{
    _loadTypes.addLoadType(34, "foo", Priority::PRI_NORMAL_2);
}

int
TestBase::Main()
{
    TEST_INIT("messages_test");

    // Retrieve version number to test for.
    LOG(info, "Running tests for version %s.", getVersion().toString().c_str());

    // Run registered tests.
    for (std::map<uint32_t, TEST_METHOD_PT>::iterator it = _tests.begin();
         it != _tests.end(); ++it)
    {
        LOG(info, "Running test for routable type %d.", it->first);
        EXPECT_TRUE( (this->*(it->second))() );
        TEST_FLUSH();
    }

    // Test routable type coverage.
    std::vector<uint32_t> expected, actual;
    EXPECT_TRUE(testCoverage(expected, actual));
    expected.push_back(0);
    EXPECT_TRUE(!testCoverage(expected, actual));
    actual.push_back(1);
    EXPECT_TRUE(!testCoverage(expected, actual));
    actual.push_back(0);
    EXPECT_TRUE(!testCoverage(expected, actual));
    expected.push_back(1);
    EXPECT_TRUE(testCoverage(expected, actual));

    expected.clear();
    _protocol.getRoutableTypes(getVersion(), expected);

    actual.clear();
    for (std::map<uint32_t, TEST_METHOD_PT>::iterator it = _tests.begin();
         it != _tests.end(); ++it)
    {
        actual.push_back(it->first);
    }
    if (shouldTestCoverage()) {
        EXPECT_TRUE(testCoverage(expected, actual, true));
    }
    TEST_DONE();
}

TestBase &
TestBase::putTest(uint32_t type, TEST_METHOD_PT test)
{
    _tests[type] = test;
    return *this;
}

bool
TestBase::testCoverage(const std::vector<uint32_t> &expected, const std::vector<uint32_t> &actual, bool report) const
{
    bool ret = true;

    std::vector<uint32_t> lst(actual);
    for (std::vector<uint32_t>::const_iterator it = expected.begin();
         it != expected.end(); ++it)
    {
        std::vector<uint32_t>::iterator occ = std::find(lst.begin(), lst.end(), *it);
        if (occ == lst.end()) {
            if (report) {
                LOG(error, "Routable type %d is registered in DocumentProtocol but not tested.", *it);
            }
            ret = false;
        } else {
            lst.erase(occ);
        }
    }
    if (!lst.empty()) {
        if (report) {
            for (std::vector<uint32_t>::iterator it = lst.begin();
                 it != lst.end(); ++it)
            {
                LOG(error, "Routable type %d is tested but not registered in DocumentProtocol.", *it);
            }
        }
        ret = false;
    }

    return ret;
}

uint32_t
TestBase::serialize(const string &filename, const mbus::Routable &routable)
{
    const vespalib::Version version = getVersion();
    string path = getPath(version.toString() + "-cpp-" + filename + ".dat");
    LOG(info, "Serializing to '%s'..", path.c_str());

    mbus::Blob blob = _protocol.encode(version, routable);
    if (!EXPECT_TRUE(writeFile(path, blob))) {
        LOG(error, "Could not open file '%s' for writing.", path.c_str());
        return 0;
    }
    mbus::Routable::UP obj = _protocol.decode(version, blob);
    if (!EXPECT_TRUE(obj.get() != NULL)) {
        LOG(error, "Protocol failed to decode serialized data.");
        return 0;
    }
    if (!EXPECT_TRUE(routable.getType() == obj->getType())) {
        LOG(error, "Expected class %d, got %d.", routable.getType(), obj->getType());
        return 0;
    }
    return blob.size();
}

mbus::Routable::UP
TestBase::deserialize(const string &filename, uint32_t classId, uint32_t lang)
{
    const vespalib::Version version = getVersion();
    string path = getPath(version.toString() + (lang == LANG_JAVA ? "-java" : "-cpp") + "-" + filename + ".dat");
    LOG(info, "Deserializing from '%s'..", path.c_str());

    mbus::Blob blob = readFile(path);
    if (!EXPECT_TRUE(blob.size() != 0)) {
        LOG(error, "Could not open file '%s' for reading.", path.c_str());
        return mbus::Routable::UP();
    }
    mbus::Routable::UP ret = _protocol.decode(version, blob);

    if (!EXPECT_TRUE(ret.get())) {
        LOG(error, "Unable to decode class %d", classId);
    } else if (!EXPECT_TRUE(classId == ret->getType())) {
        LOG(error, "Expected class %d, got %d.", classId, ret->getType());
        return mbus::Routable::UP();
    }
    return ret;
}

void
TestBase::dump(const mbus::Blob& blob) const
{
    fprintf(stderr, "[%ld]: ", blob.size());
    for(size_t i = 0; i < blob.size(); i++) {
        if (blob.data()[i] > 32 && blob.data()[i] < 126) {
            fprintf(stderr, "%c ", blob.data()[i]);
        }
        else {
            fprintf(stderr, "%d ", blob.data()[i]);
        }
    }
    fprintf(stderr, "\n");
}

bool
TestBase::writeFile(const string &filename, const mbus::Blob& blob) const
{
    std::string tmp_filename = filename + ".tmp";
    int file = open(tmp_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (file == -1) {
        return false;
    }
    if (write(file, blob.data(), blob.size()) != static_cast<ssize_t>(blob.size())) {
	    throw vespalib::Exception("write failed");
    }
    close(file);
    if (rename(tmp_filename.c_str(), filename.c_str()) != 0) {
        throw vespalib::Exception("rename failed");
    }
    return true;
}

mbus::Blob
TestBase::readFile(const string &filename) const
{
    int file = open(filename.c_str(), O_RDONLY);
    int len = (file == -1) ? 0 : lseek(file, 0, SEEK_END);
    mbus::Blob blob(len);
    if (file != -1) {
        lseek(file, 0, SEEK_SET);
        if (read(file, blob.data(), len) != len) {
	    throw vespalib::Exception("read failed");
	}
        close(file);
    }

    return blob;
}

<|endoftext|>


<commit_before>#include "NotifyGVContactsTable.h"
#include "ContactsParserObject.h"

GVContactsTable::GVContactsTable (QObject *parent)
: QObject (parent)
, nwMgr (this)
, mutex(QMutex::Recursive)
, bLoggedIn(false)
, bRefreshRequested (false)
{
}//GVContactsTable::GVContactsTable

GVContactsTable::~GVContactsTable ()
{
}//GVContactsTable::~GVContactsTable

QNetworkReply *
GVContactsTable::postRequest (QString         strUrl,
                              QStringPairList arrPairs,
                              QObject        *receiver,
                              const char     *method)
{
    QStringList arrParams;
    foreach (QStringPair pairParam, arrPairs)
    {
        arrParams += QString("%1=%2")
                        .arg(pairParam.first)
                        .arg(pairParam.second);
    }
    QString strParams = arrParams.join ("&");

    QUrl url (strUrl);
    QNetworkRequest request(url);
    request.setHeader (QNetworkRequest::ContentTypeHeader,
                       "application/x-www-form-urlencoded");
    if (0 != strGoogleAuth.size ())
    {
        QByteArray byAuth = QString("GoogleLogin auth=%1")
                                    .arg(strGoogleAuth).toAscii ();
        request.setRawHeader ("Authorization", byAuth);
    }
    QByteArray byPostData = strParams.toAscii ();

    QObject::connect (&nwMgr   , SIGNAL (finished (QNetworkReply *)),
                       receiver, method);
    QNetworkReply *reply = nwMgr.post (request, byPostData);
    return (reply);
}//GVContactsTable::postRequest

QNetworkReply *
GVContactsTable::getRequest (QString         strUrl,
                             QObject        *receiver,
                             const char     *method)
{
    QUrl url (strUrl);
    QNetworkRequest request(url);
    request.setHeader (QNetworkRequest::ContentTypeHeader,
                       "application/x-www-form-urlencoded");
    if (0 != strGoogleAuth.size ())
    {
        QByteArray byAuth = QString("GoogleLogin auth=%1")
                                    .arg(strGoogleAuth).toAscii ();
        request.setRawHeader ("Authorization", byAuth);
    }

    QObject::connect (&nwMgr   , SIGNAL (finished (QNetworkReply *)),
                       receiver, method);
    QNetworkReply *reply = nwMgr.get (request);
    return (reply);
}//GVContactsTable::getRequest

void
GVContactsTable::refreshContacts ()
{
    QMutexLocker locker(&mutex);
    if (!bLoggedIn)
    {
        bRefreshRequested = true;
        return;
    }
    bRefreshRequested = false;
    bChangedSinceRefresh = false;

    QString strUrl = QString ("http://www.google.com/m8/feeds/contacts/%1/full"
                              "?max-results=10000")
                        .arg (strUser);

    bRefreshIsUpdate = false;
    if (dtUpdate.isValid ()) {
        QString strUpdate = dtUpdate.toString ("yyyy-MM-dd")
                          + "T"
                          + dtUpdate.toString ("hh:mm:ss");
        strUrl += QString ("&updated-min=%1&showdeleted=true").arg (strUpdate);
        bRefreshIsUpdate = true;
    }

    getRequest (strUrl, this , SLOT (onGotContacts (QNetworkReply *)));
}//GVContactsTable::refreshContacts

void
GVContactsTable::setUserPass (const QString &strU, const QString &strP)
{
    QMutexLocker locker(&mutex);
    strUser = strU;
    strPass = strP;
}//GVContactsTable::setUserPass

void
GVContactsTable::loginSuccess ()
{
    QMutexLocker locker(&mutex);

    QStringPairList arrPairs;
    arrPairs += QStringPair("accountType", "GOOGLE");
    arrPairs += QStringPair("Email"      , strUser);
    arrPairs += QStringPair("Passwd"     , strPass);
    arrPairs += QStringPair("service"    , "cp"); // name for contacts service
    arrPairs += QStringPair("source"     , "MyCompany-qgvdial-ver01");
    postRequest (GV_CLIENTLOGIN, arrPairs,
                 this , SLOT (onLoginResponse (QNetworkReply *)));
}//GVContactsTable::loginSuccess

void
GVContactsTable::loggedOut ()
{
    QMutexLocker locker(&mutex);
    bLoggedIn = false;

    strGoogleAuth.clear ();
}//GVContactsTable::loggedOut

void
GVContactsTable::onLoginResponse (QNetworkReply *reply)
{
    QObject::disconnect (&nwMgr, SIGNAL (finished (QNetworkReply *)),
                          this , SLOT   (onLoginResponse (QNetworkReply *)));

    QString msg;
    QString strReply = reply->readAll ();
    QString strCaptchaToken, strCaptchaUrl;

    strGoogleAuth.clear ();
    do // Begin cleanup block (not a loop)
    {
        QStringList arrParsed = strReply.split ('\n');
        foreach (QString strPair, arrParsed)
        {
            QStringList arrPair = strPair.split ('=');
            if (arrPair[0] == "Auth")
            {
                strGoogleAuth = arrPair[1];
            }
            else if (arrPair[0] == "CaptchaToken")
            {
                strCaptchaToken = arrPair[1];
            }
            else if (arrPair[0] == "CaptchaUrl")
            {
                strCaptchaUrl = arrPair[1];
            }
        }

        if (0 != strCaptchaUrl.size ())
        {
            qCritical ("Google requested CAPTCHA!!");
            qApp->quit ();

            break;
        }

        if (0 == strGoogleAuth.size ())
        {
            qWarning ("Failed to login!!");
            break;
        }

        QMutexLocker locker (&mutex);
        bLoggedIn = true;

        if (bRefreshRequested)
        {
            refreshContacts ();
        }
    } while (0); // End cleanup block (not a loop)
    reply->deleteLater ();
}//GVContactsTable::onLoginResponse

void
GVContactsTable::onGotContacts (QNetworkReply *reply)
{
    QObject::disconnect (&nwMgr, SIGNAL (finished (QNetworkReply *)),
                          this , SLOT   (onGotContacts (QNetworkReply *)));

    do // Begin cleanup block (not a loop)
    {
        QByteArray byData = reply->readAll ();
        if (byData.contains ("Authorization required"))
        {
            emit status("Authorization failed.");
            break;
        }

#if 0
        QFile temp("dump.txt");
        temp.open (QIODevice::ReadWrite);
        temp.write (byData);
        temp.close ();
#endif

        dtUpdate = QDateTime::currentDateTime().toUTC ();

        QThread *workerThread = new QThread(this);
        ContactsParserObject *pObj = new ContactsParserObject(byData);
        pObj->setEmitLog (false);
        pObj->moveToThread (workerThread);
        QObject::connect (workerThread, SIGNAL(started()),
                          pObj        , SLOT  (doWork()));
        QObject::connect (pObj, SIGNAL(done(bool)),
                          this, SLOT  (onContactsParsed(bool)));
        QObject::connect (pObj        , SIGNAL(done(bool)),
                          workerThread, SLOT  (quit()));
        QObject::connect (workerThread, SIGNAL(terminated()),
                          pObj        , SLOT  (deleteLater()));
        QObject::connect (workerThread, SIGNAL(terminated()),
                          workerThread, SLOT  (deleteLater()));
        QObject::connect (pObj, SIGNAL (status(const QString &, int)),
                          this, SIGNAL (status(const QString &, int)));
        QObject::connect (pObj, SIGNAL (gotOneContact (const ContactInfo &)),
                          this, SLOT   (gotOneContact (const ContactInfo &)));
        workerThread->start ();
    } while (0); // End cleanup block (not a loop)

    reply->deleteLater ();
}//GVContactsTable::onGotContacts

void
GVContactsTable::gotOneContact (const ContactInfo & /*contactInfo*/)
{
    QMutexLocker locker(&mutex);
    bChangedSinceRefresh = true;
}//GVContactsTable::gotOneContact

void
GVContactsTable::onContactsParsed (bool rv)
{
    emit allContacts (bChangedSinceRefresh, rv);
}//GVContactsTable::onContactsParsed
<commit_msg>fix notify signal slot to match the changes in qgvdial<commit_after>#include "NotifyGVContactsTable.h"
#include "ContactsParserObject.h"

GVContactsTable::GVContactsTable (QObject *parent)
: QObject (parent)
, nwMgr (this)
, mutex(QMutex::Recursive)
, bLoggedIn(false)
, bRefreshRequested (false)
{
}//GVContactsTable::GVContactsTable

GVContactsTable::~GVContactsTable ()
{
}//GVContactsTable::~GVContactsTable

QNetworkReply *
GVContactsTable::postRequest (QString         strUrl,
                              QStringPairList arrPairs,
                              QObject        *receiver,
                              const char     *method)
{
    QStringList arrParams;
    foreach (QStringPair pairParam, arrPairs)
    {
        arrParams += QString("%1=%2")
                        .arg(pairParam.first)
                        .arg(pairParam.second);
    }
    QString strParams = arrParams.join ("&");

    QUrl url (strUrl);
    QNetworkRequest request(url);
    request.setHeader (QNetworkRequest::ContentTypeHeader,
                       "application/x-www-form-urlencoded");
    if (0 != strGoogleAuth.size ())
    {
        QByteArray byAuth = QString("GoogleLogin auth=%1")
                                    .arg(strGoogleAuth).toAscii ();
        request.setRawHeader ("Authorization", byAuth);
    }
    QByteArray byPostData = strParams.toAscii ();

    QObject::connect (&nwMgr   , SIGNAL (finished (QNetworkReply *)),
                       receiver, method);
    QNetworkReply *reply = nwMgr.post (request, byPostData);
    return (reply);
}//GVContactsTable::postRequest

QNetworkReply *
GVContactsTable::getRequest (QString         strUrl,
                             QObject        *receiver,
                             const char     *method)
{
    QUrl url (strUrl);
    QNetworkRequest request(url);
    request.setHeader (QNetworkRequest::ContentTypeHeader,
                       "application/x-www-form-urlencoded");
    if (0 != strGoogleAuth.size ())
    {
        QByteArray byAuth = QString("GoogleLogin auth=%1")
                                    .arg(strGoogleAuth).toAscii ();
        request.setRawHeader ("Authorization", byAuth);
    }

    QObject::connect (&nwMgr   , SIGNAL (finished (QNetworkReply *)),
                       receiver, method);
    QNetworkReply *reply = nwMgr.get (request);
    return (reply);
}//GVContactsTable::getRequest

void
GVContactsTable::refreshContacts ()
{
    QMutexLocker locker(&mutex);
    if (!bLoggedIn)
    {
        bRefreshRequested = true;
        return;
    }
    bRefreshRequested = false;
    bChangedSinceRefresh = false;

    QString strUrl = QString ("http://www.google.com/m8/feeds/contacts/%1/full"
                              "?max-results=10000")
                        .arg (strUser);

    bRefreshIsUpdate = false;
    if (dtUpdate.isValid ()) {
        QString strUpdate = dtUpdate.toString ("yyyy-MM-dd")
                          + "T"
                          + dtUpdate.toString ("hh:mm:ss");
        strUrl += QString ("&updated-min=%1&showdeleted=true").arg (strUpdate);
        bRefreshIsUpdate = true;
    }

    getRequest (strUrl, this , SLOT (onGotContacts (QNetworkReply *)));
}//GVContactsTable::refreshContacts

void
GVContactsTable::setUserPass (const QString &strU, const QString &strP)
{
    QMutexLocker locker(&mutex);
    strUser = strU;
    strPass = strP;
}//GVContactsTable::setUserPass

void
GVContactsTable::loginSuccess ()
{
    QMutexLocker locker(&mutex);

    QStringPairList arrPairs;
    arrPairs += QStringPair("accountType", "GOOGLE");
    arrPairs += QStringPair("Email"      , strUser);
    arrPairs += QStringPair("Passwd"     , strPass);
    arrPairs += QStringPair("service"    , "cp"); // name for contacts service
    arrPairs += QStringPair("source"     , "MyCompany-qgvdial-ver01");
    postRequest (GV_CLIENTLOGIN, arrPairs,
                 this , SLOT (onLoginResponse (QNetworkReply *)));
}//GVContactsTable::loginSuccess

void
GVContactsTable::loggedOut ()
{
    QMutexLocker locker(&mutex);
    bLoggedIn = false;

    strGoogleAuth.clear ();
}//GVContactsTable::loggedOut

void
GVContactsTable::onLoginResponse (QNetworkReply *reply)
{
    QObject::disconnect (&nwMgr, SIGNAL (finished (QNetworkReply *)),
                          this , SLOT   (onLoginResponse (QNetworkReply *)));

    QString msg;
    QString strReply = reply->readAll ();
    QString strCaptchaToken, strCaptchaUrl;

    strGoogleAuth.clear ();
    do // Begin cleanup block (not a loop)
    {
        QStringList arrParsed = strReply.split ('\n');
        foreach (QString strPair, arrParsed)
        {
            QStringList arrPair = strPair.split ('=');
            if (arrPair[0] == "Auth")
            {
                strGoogleAuth = arrPair[1];
            }
            else if (arrPair[0] == "CaptchaToken")
            {
                strCaptchaToken = arrPair[1];
            }
            else if (arrPair[0] == "CaptchaUrl")
            {
                strCaptchaUrl = arrPair[1];
            }
        }

        if (0 != strCaptchaUrl.size ())
        {
            qCritical ("Google requested CAPTCHA!!");
            qApp->quit ();

            break;
        }

        if (0 == strGoogleAuth.size ())
        {
            qWarning ("Failed to login!!");
            break;
        }

        QMutexLocker locker (&mutex);
        bLoggedIn = true;

        if (bRefreshRequested)
        {
            refreshContacts ();
        }
    } while (0); // End cleanup block (not a loop)
    reply->deleteLater ();
}//GVContactsTable::onLoginResponse

void
GVContactsTable::onGotContacts (QNetworkReply *reply)
{
    QObject::disconnect (&nwMgr, SIGNAL (finished (QNetworkReply *)),
                          this , SLOT   (onGotContacts (QNetworkReply *)));

    do // Begin cleanup block (not a loop)
    {
        QByteArray byData = reply->readAll ();
        if (byData.contains ("Authorization required"))
        {
            emit status("Authorization failed.");
            break;
        }

#if 0
        QFile temp("dump.txt");
        temp.open (QIODevice::ReadWrite);
        temp.write (byData);
        temp.close ();
#endif

        dtUpdate = QDateTime::currentDateTime().toUTC ();

        QThread *workerThread = new QThread(this);
        ContactsParserObject *pObj = new ContactsParserObject(byData);
        pObj->setEmitLog (false);
        pObj->moveToThread (workerThread);
        QObject::connect (workerThread, SIGNAL(started()),
                          pObj        , SLOT  (doWork()));
        QObject::connect (pObj, SIGNAL(done(bool, quint32, quint32)),
                          this, SLOT  (onContactsParsed(bool)));
        QObject::connect (pObj        , SIGNAL(done(bool, quint32, quint32)),
                          workerThread, SLOT  (quit()));
        QObject::connect (workerThread, SIGNAL(terminated()),
                          pObj        , SLOT  (deleteLater()));
        QObject::connect (workerThread, SIGNAL(terminated()),
                          workerThread, SLOT  (deleteLater()));
        QObject::connect (pObj, SIGNAL (status(const QString &, int)),
                          this, SIGNAL (status(const QString &, int)));
        QObject::connect (pObj, SIGNAL (gotOneContact (const ContactInfo &)),
                          this, SLOT   (gotOneContact (const ContactInfo &)));
        workerThread->start ();
    } while (0); // End cleanup block (not a loop)

    reply->deleteLater ();
}//GVContactsTable::onGotContacts

void
GVContactsTable::gotOneContact (const ContactInfo & /*contactInfo*/)
{
    QMutexLocker locker(&mutex);
    bChangedSinceRefresh = true;
}//GVContactsTable::gotOneContact

void
GVContactsTable::onContactsParsed (bool rv)
{
    emit allContacts (bChangedSinceRefresh, rv);
}//GVContactsTable::onContactsParsed
<|endoftext|>


<commit_before><commit_msg>Incorrect chroma on the right border fixed. BUG=19113 TEST=Right border has correct color<commit_after><|endoftext|>


<commit_before>#include<iostream>
using namespace std;
// Best case: O(n)
// Avg. case: O(n^2)
// Worst case: O(n^2)
// Sorts array A in increasing order
// Qualities:
// 1) Efficient - for small data sets and other quadratic algorithms
// 2) Stable - Doesn't change the relative order
// 3) Inplace - Doesn't need additional memory sorts as it receives online
void insertion_sort(int A[], int n);
void swap(int *n1, int *n2);

int main() {
    int A[] = {5, 6, 8, 1, -1, 0, 11, 100, -5, 0, 1, 0, 6, 1, 2, 3, 5, 10000};
    int size = sizeof(A)/sizeof(int);
    cout<<"Size = "<<size<<endl;
    cout<<"Input Array: \n";
    for (int i = 0; i < size; i++) {
        cout<<A[i]<<" ";
    }
    insertion_sort(A, size);
    cout<<"\nInsertion Sorted Array: \n";
    for (int i = 0; i < size; i++) {
        cout<<A[i]<<" ";
    }
    cout<<endl;
    return 0;
}

// Algorithm:
// 1) i = start/prev element, j = next element
// 2) A[j] < A[j] swap(A[j], A[i])
// 3) continue 1) untill all elements are sorted.
void insertion_sort(int A[], int size) {
    int i, j, key;
    for (i = 1; i < size; i++) {
        key = A[i];
        for (j = i - 1; j >= 0 && A[j] > key; j--) {
            A[j+1] = A[j];
        }
        A[j+1] = key;
    }
}

void swap(int *n1, int *n2) {
    int temp = *n1;
    *n1 = *n2;
    *n2 = temp;
}
<commit_msg>Insertion sort change the comments<commit_after>#include<iostream>
using namespace std;
// Best case: O(n)
// Avg. case: O(n^2)
// Worst case: O(n^2)
// Sorts array A in increasing order
// Qualities:
// 1) Efficient - for small data sets and other quadratic algorithms
// 2) Stable - Doesn't change the relative order
// 3) Inplace - Doesn't need additional memory sorts as it receives online
void insertion_sort(int A[], int n);
void swap(int *n1, int *n2);

int main() {
    int A[] = {5, 6, 8, 1, -1, 0, 11, 100, -5, 0, 1, 0, 6, 1, 2, 3, 5, 10000};
    int size = sizeof(A)/sizeof(int);
    cout<<"Size = "<<size<<endl;
    cout<<"Input Array: \n";
    for (int i = 0; i < size; i++) {
        cout<<A[i]<<" ";
    }
    insertion_sort(A, size);
    cout<<"\nInsertion Sorted Array: \n";
    for (int i = 0; i < size; i++) {
        cout<<A[i]<<" ";
    }
    cout<<endl;
    return 0;
}

// Algorithm:
// 1) i = next element, j = prev element
// 2) set key = A[i]
// 3) find the position in the list to insert the key correctly
// 4) shift all the elements to next place
// 5) insert the key in the element found
void insertion_sort(int A[], int size) {
    int i, j, key;
    for (i = 1; i < size; i++) {
        key = A[i];
        for (j = i - 1; j >= 0 && A[j] > key; j--) {
            A[j+1] = A[j];
        }
        A[j+1] = key;
    }
}

void swap(int *n1, int *n2) {
    int temp = *n1;
    *n1 = *n2;
    *n2 = temp;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef _OOX_EXPORT_DRAWINGML_HXX_
#define _OOX_EXPORT_DRAWINGML_HXX_

#include <oox/dllapi.h>
#include <sax/fshelper.hxx>
#include <rtl/strbuf.hxx>
#include <com/sun/star/awt/FontDescriptor.hpp>
#include <com/sun/star/uno/XReference.hpp>
#include <tools/poly.hxx>
#include <filter/msfilter/escherex.hxx>

class Graphic;
class String;

namespace com { namespace sun { namespace star {
namespace beans {
    class XPropertySet;
    class XPropertyState;
}
namespace drawing {
    class XShape;
}
namespace text {
    class XTextContent;
    class XTextRange;
}
namespace io {
    struct XOutputStream;
}
}}}

namespace oox {
namespace core {
    class XmlFilterBase;
}

namespace drawingml {

class OOX_DLLPUBLIC DrawingML {
public:
    enum DocumentType { DOCUMENT_DOCX, DOCUMENT_PPTX, DOCUMENT_XLSX };

private:
    ::sax_fastparser::FSHelperPtr mpFS;
    ::oox::core::XmlFilterBase* mpFB;

    static int mnImageCounter;

    /// To specify where write eg. the images to (like 'ppt', or 'word' - according to the OPC).
    DocumentType meDocumentType;

protected:
    ::com::sun::star::uno::Any mAny;

    bool GetProperty( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet, String aName );
    bool GetPropertyAndState( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet,
                  ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyState > rXPropState,
                  String aName, ::com::sun::star::beans::PropertyState& eState );
    const char* GetFieldType( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > rRun, sal_Bool& bIsField );

    rtl::OUString WriteImage( const rtl::OUString& rURL );

public:
    DrawingML( ::sax_fastparser::FSHelperPtr pFS, ::oox::core::XmlFilterBase* pFB = NULL, DocumentType eDocumentType = DOCUMENT_PPTX ) : mpFS( pFS ), mpFB( pFB ), meDocumentType( eDocumentType ) {}
    void SetFS( ::sax_fastparser::FSHelperPtr pFS ) { mpFS = pFS; }
    ::sax_fastparser::FSHelperPtr GetFS() { return mpFS; }
    ::oox::core::XmlFilterBase* GetFB() { return mpFB; }
    DocumentType GetDocumentType() { return meDocumentType; }

    rtl::OUString WriteImage( const Graphic &rGraphic );

    void WriteColor( sal_uInt32 nColor );
    void WriteGradientStop( sal_uInt16 nStop, sal_uInt32 nColor );
    void WriteLineArrow( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet, sal_Bool bLineStart );
    void WriteConnectorConnections( EscherConnectorListEntry& rConnectorEntry, sal_Int32 nStartID, sal_Int32 nEndID );

    void WriteSolidFill( sal_uInt32 nColor );
    void WriteSolidFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );
    void WriteGradientFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );
    void WriteBlipFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet, String sURLPropName, sal_Int32 nXmlNamespace );
    void WriteBlipFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet, String sURLPropName );
    void WriteOutline( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );
    void WriteStretch();

    ::rtl::OUString WriteBlip( ::rtl::OUString& rURL );
    void WriteBlipMode( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );

    void WriteShapeTransformation( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > rXShape,
                  sal_Int32 nXmlNamespace, sal_Bool bFlipH = false, sal_Bool bFlipV = false, sal_Int32 nRotation = 0 );
    void WriteTransformation( const Rectangle& rRectangle,
                  sal_Int32 nXmlNamespace, sal_Bool bFlipH = false, sal_Bool bFlipV = false, sal_Int32 nRotation = 0 );

    void WriteText( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > rXShape );
    void WriteParagraph( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextContent > rParagraph );
    void WriteParagraphProperties( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextContent > rParagraph );
    void WriteParagraphNumbering( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet,
                                  sal_Int16 nLevel );
    void WriteRun( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > rRun );
    void WriteRunProperties( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rRun, sal_Bool bIsField );

    void WritePresetShape( const char* pShape );
    void WritePresetShape( const char* pShape, MSO_SPT eShapeType, sal_Bool bPredefinedHandlesUsed, sal_Int32 nAdjustmentsWhichNeedsToBeConverted, const ::com::sun::star::beans::PropertyValue& rProp );
    void WritePolyPolygon( const PolyPolygon& rPolyPolygon );
    void WriteFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xPropSet );

    static void ResetCounters();

    void GetUUID( ::rtl::OStringBuffer& rBuffer );

    static sal_Unicode SubstituteBullet( sal_Unicode cBulletId, ::com::sun::star::awt::FontDescriptor& rFontDesc );

    sal_uInt32 ColorWithIntensity( sal_uInt32 nColor, sal_uInt32 nIntensity );

    static const char* GetAlignment( sal_Int32 nAlignment );

    sax_fastparser::FSHelperPtr     CreateOutputStream (
                                        const ::rtl::OUString& sFullStream,
                                        const ::rtl::OUString& sRelativeStream,
                                        const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& xParentRelation,
                                        const char* sContentType,
                                        const char* sRelationshipType,
                                        ::rtl::OUString* pRelationshipId = NULL );

};

}
}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>XOutputStream is a class, not a struct<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef _OOX_EXPORT_DRAWINGML_HXX_
#define _OOX_EXPORT_DRAWINGML_HXX_

#include <oox/dllapi.h>
#include <sax/fshelper.hxx>
#include <rtl/strbuf.hxx>
#include <com/sun/star/awt/FontDescriptor.hpp>
#include <com/sun/star/uno/XReference.hpp>
#include <tools/poly.hxx>
#include <filter/msfilter/escherex.hxx>

class Graphic;
class String;

namespace com { namespace sun { namespace star {
namespace beans {
    class XPropertySet;
    class XPropertyState;
}
namespace drawing {
    class XShape;
}
namespace text {
    class XTextContent;
    class XTextRange;
}
namespace io {
    class XOutputStream;
}
}}}

namespace oox {
namespace core {
    class XmlFilterBase;
}

namespace drawingml {

class OOX_DLLPUBLIC DrawingML {
public:
    enum DocumentType { DOCUMENT_DOCX, DOCUMENT_PPTX, DOCUMENT_XLSX };

private:
    ::sax_fastparser::FSHelperPtr mpFS;
    ::oox::core::XmlFilterBase* mpFB;

    static int mnImageCounter;

    /// To specify where write eg. the images to (like 'ppt', or 'word' - according to the OPC).
    DocumentType meDocumentType;

protected:
    ::com::sun::star::uno::Any mAny;

    bool GetProperty( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet, String aName );
    bool GetPropertyAndState( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet,
                  ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyState > rXPropState,
                  String aName, ::com::sun::star::beans::PropertyState& eState );
    const char* GetFieldType( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > rRun, sal_Bool& bIsField );

    rtl::OUString WriteImage( const rtl::OUString& rURL );

public:
    DrawingML( ::sax_fastparser::FSHelperPtr pFS, ::oox::core::XmlFilterBase* pFB = NULL, DocumentType eDocumentType = DOCUMENT_PPTX ) : mpFS( pFS ), mpFB( pFB ), meDocumentType( eDocumentType ) {}
    void SetFS( ::sax_fastparser::FSHelperPtr pFS ) { mpFS = pFS; }
    ::sax_fastparser::FSHelperPtr GetFS() { return mpFS; }
    ::oox::core::XmlFilterBase* GetFB() { return mpFB; }
    DocumentType GetDocumentType() { return meDocumentType; }

    rtl::OUString WriteImage( const Graphic &rGraphic );

    void WriteColor( sal_uInt32 nColor );
    void WriteGradientStop( sal_uInt16 nStop, sal_uInt32 nColor );
    void WriteLineArrow( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet, sal_Bool bLineStart );
    void WriteConnectorConnections( EscherConnectorListEntry& rConnectorEntry, sal_Int32 nStartID, sal_Int32 nEndID );

    void WriteSolidFill( sal_uInt32 nColor );
    void WriteSolidFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );
    void WriteGradientFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );
    void WriteBlipFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet, String sURLPropName, sal_Int32 nXmlNamespace );
    void WriteBlipFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet, String sURLPropName );
    void WriteOutline( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );
    void WriteStretch();

    ::rtl::OUString WriteBlip( ::rtl::OUString& rURL );
    void WriteBlipMode( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );

    void WriteShapeTransformation( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > rXShape,
                  sal_Int32 nXmlNamespace, sal_Bool bFlipH = false, sal_Bool bFlipV = false, sal_Int32 nRotation = 0 );
    void WriteTransformation( const Rectangle& rRectangle,
                  sal_Int32 nXmlNamespace, sal_Bool bFlipH = false, sal_Bool bFlipV = false, sal_Int32 nRotation = 0 );

    void WriteText( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > rXShape );
    void WriteParagraph( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextContent > rParagraph );
    void WriteParagraphProperties( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextContent > rParagraph );
    void WriteParagraphNumbering( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet,
                                  sal_Int16 nLevel );
    void WriteRun( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > rRun );
    void WriteRunProperties( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rRun, sal_Bool bIsField );

    void WritePresetShape( const char* pShape );
    void WritePresetShape( const char* pShape, MSO_SPT eShapeType, sal_Bool bPredefinedHandlesUsed, sal_Int32 nAdjustmentsWhichNeedsToBeConverted, const ::com::sun::star::beans::PropertyValue& rProp );
    void WritePolyPolygon( const PolyPolygon& rPolyPolygon );
    void WriteFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xPropSet );

    static void ResetCounters();

    void GetUUID( ::rtl::OStringBuffer& rBuffer );

    static sal_Unicode SubstituteBullet( sal_Unicode cBulletId, ::com::sun::star::awt::FontDescriptor& rFontDesc );

    sal_uInt32 ColorWithIntensity( sal_uInt32 nColor, sal_uInt32 nIntensity );

    static const char* GetAlignment( sal_Int32 nAlignment );

    sax_fastparser::FSHelperPtr     CreateOutputStream (
                                        const ::rtl::OUString& sFullStream,
                                        const ::rtl::OUString& sRelativeStream,
                                        const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& xParentRelation,
                                        const char* sContentType,
                                        const char* sRelationshipType,
                                        ::rtl::OUString* pRelationshipId = NULL );

};

}
}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>