<commit_before>// LICENSE/*{{{*/
/*
  sxc - Simple Xmpp Client
  Copyright (C) 2008 Dennis Felsing, Andreas Waidler

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/*}}}*/

// INCLUDES/*{{{*/

#ifdef HAVE_CONFIG_H
#   include <config.hxx>
#   include <print.hxx>
#endif

#include <cerrno>
#include <sstream>
#include <sys/stat.h>

#include <string>
#include <fstream>
#include <pthread.h>
#include <signal.h>

#include <File/AbcInput.hxx>
#include <Exception/FileInputException.hxx>
#include <Exception/Errno.hxx>
#include <libsxc/Exception/Type.hxx>

/*}}}*/

File::AbcInput::AbcInput()/*{{{*/
: _isFifoValid(false),
  _isListening(false),
  _mustClose(false)
{
}

/*}}}*/
File::AbcInput::~AbcInput()/*{{{*/
{
    if (_isListening)
        close();
}

/*}}}*/
void File::AbcInput::initialize(bool notPhysical)/*{{{*/
{
    _path = _createPath();

    if (!notPhysical) {
        try {
            _validate();
        } catch (Exception::FileInputException &e) {
            // If the file is missing, create it. Anything else means that someone
            // tampered with the file.
            if (libsxc::Exception::FileMissing != e.getType())
                throw e;
            _create();
        }
    }
}

/*}}}*/
void File::AbcInput::_create()/*{{{*/
{
    // Try to create FIFO with chmod 600.
    if (0 == mkfifo(_path.c_str(), S_IRUSR | S_IWUSR))
        return;

    // Creation of FIFO failed.
    libsxc::Exception::Type type = Exception::errnoToType(errno);
    std::string message  = "Could not create FIFO " + _path;
    throw Exception::FileInputException(type, message);
}

/*}}}*/
void File::AbcInput::_validate()/*{{{*/
{
    // Try to get file stats, needed for analyzing the chmod of the file.
    struct stat fstat;
    if (0 != stat(_path.c_str(), &fstat)) {
        libsxc::Exception::Type type = Exception::errnoToType(errno);
        std::string message  = "Could not get FIFO fstat: " + _path;
        throw Exception::FileInputException(type, message);
    }

    // Is this really a FIFO?
    if (!S_ISFIFO(fstat.st_mode)) {
        std::string message  = "Not a FIFO: " + _path;
        throw Exception::FileInputException(libsxc::Exception::BadFile, message);
    }

    // Check for chmod 600:
    // if (0 == fstat.st_mode & S_IRUSR
    // || 0 == fstat.st_mode & S_IWUSR
    // || 0 != fstat.st_mode & S_IRGRP
    // || 0 != fstat.st_mode & S_IWGRP
    // || 0 != fstat.st_mode & S_IROTH
    // || 0 != fstat.st_mode & S_IWOTH) {
    if (fstat.st_mode
    &  (S_IRUSR | S_IWUSR | ~S_IRGRP | ~S_IWGRP | ~S_IROTH | ~S_IWOTH)
    == (S_IRUSR | S_IWUSR | ~S_IRGRP | ~S_IWGRP | ~S_IROTH | ~S_IWOTH)) {
        // Converts __mode_t st_mode to human-readable string (octal notation):
        std::stringstream mode;
        mode << std::oct << fstat.st_mode;
        // Extract only necessary part (user, group, other) from file mode:
        std::string message = _path + ": Chmod should be 600, found "
                            + mode.str().substr(2);
        throw Exception::FileInputException(libsxc::Exception::BadFile, message);
    }

    _isFifoValid = true;
}

/*}}}*/
void File::AbcInput::_read()/*{{{*/
{
    _fifo.open(_path.c_str());

    // See docblock of close().
    if (_mustClose)
        return;

    std::string lineBuffer;
    std::string input; // Filled with lineBuffer until other end closes the pipe
    while (getline(_fifo, lineBuffer)) {
        input += lineBuffer;
    }

    _handleInput(input);

    _fifo.close();
}

/*}}}*/
void File::AbcInput::listen(bool blocking)/*{{{*/
{
    // Prevent input from being handled twice:
    if (_isListening) {
        std::string message = "Already listening on " + _path;
        throw Exception::FileInputException(libsxc::Exception::FileLocked, message);
    }
    _isListening = true;

#ifdef DEBUG
    printLog("Creating thread.");
#endif

    // Start the thread in the background.
    pthread_create(&_thread, NULL, _listen, (void*)this);

#ifdef DEBUG
    printLog("Thread created.");
#endif

    // Join the thread when this functions should read in a blocking way.
    if (true == blocking)
        pthread_join(_thread, NULL);

#ifdef DEBUG
    printLog("listen() ends here.");
#endif
}

/*}}}*/
void File::AbcInput::close()/*{{{*/
{
    if (_isListening) {
        _mustClose = true;
        // Open an close FIFO in order to unblock subthread.
        std::ofstream out(_path.c_str());
        out.close();
        pthread_join(_thread, NULL);
    }

    _mustClose   = false;
    _isListening = false;
}

/*}}}*/
void *File::AbcInput::_listen(void *fifo)/*{{{*/
{
#ifdef DEBUG
    printLog("Thread running.");
#endif
    // FIXME: Add exception handling.
    AbcInput *that = (AbcInput *) fifo;
    do {
        // _read() reads blocking until the other end closes the pipe. This
        // loop will always restart _read() after it handled some input and
        // returned.
        that->_read();
    } while (!that->_mustClose);

#ifdef DEBUG
    printLog("Thread terminating.");
#endif

    return NULL;
}

/*}}}*/

// Use no tabs at all; four spaces indentation; max. eighty chars per line.
// vim: et ts=4 sw=4 tw=80 fo+=c fdm=marker
<commit_msg>AbcInput::_read(): - fixed various issues, works now perfectly. - added debug statements.<commit_after>// LICENSE/*{{{*/
/*
  sxc - Simple Xmpp Client
  Copyright (C) 2008 Dennis Felsing, Andreas Waidler

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/*}}}*/

// INCLUDES/*{{{*/

#ifdef HAVE_CONFIG_H
#   include <config.hxx>
#   include <print.hxx>
#endif

#include <cerrno>
#include <sstream>
#include <sys/stat.h>

#include <string>
#include <fstream>
#include <pthread.h>
#include <signal.h>

#include <File/AbcInput.hxx>
#include <Exception/FileInputException.hxx>
#include <Exception/Errno.hxx>
#include <libsxc/Exception/Type.hxx>

/*}}}*/

File::AbcInput::AbcInput()/*{{{*/
: _isFifoValid(false),
  _isListening(false),
  _mustClose(false)
{
}

/*}}}*/
File::AbcInput::~AbcInput()/*{{{*/
{
    if (_isListening)
        close();
}

/*}}}*/
void File::AbcInput::initialize(bool notPhysical)/*{{{*/
{
    _path = _createPath();

    if (!notPhysical) {
        try {
            _validate();
        } catch (Exception::FileInputException &e) {
            // If the file is missing, create it. Anything else means that someone
            // tampered with the file.
            if (libsxc::Exception::FileMissing != e.getType())
                throw e;
            _create();
        }
    }
}

/*}}}*/
void File::AbcInput::_create()/*{{{*/
{
    // Try to create FIFO with chmod 600.
    if (0 == mkfifo(_path.c_str(), S_IRUSR | S_IWUSR))
        return;

    // Creation of FIFO failed.
    libsxc::Exception::Type type = Exception::errnoToType(errno);
    std::string message  = "Could not create FIFO " + _path;
    throw Exception::FileInputException(type, message);
}

/*}}}*/
void File::AbcInput::_validate()/*{{{*/
{
    // Try to get file stats, needed for analyzing the chmod of the file.
    struct stat fstat;
    if (0 != stat(_path.c_str(), &fstat)) {
        libsxc::Exception::Type type = Exception::errnoToType(errno);
        std::string message  = "Could not get FIFO fstat: " + _path;
        throw Exception::FileInputException(type, message);
    }

    // Is this really a FIFO?
    if (!S_ISFIFO(fstat.st_mode)) {
        std::string message  = "Not a FIFO: " + _path;
        throw Exception::FileInputException(libsxc::Exception::BadFile, message);
    }

    // Check for chmod 600:
    // if (0 == fstat.st_mode & S_IRUSR
    // || 0 == fstat.st_mode & S_IWUSR
    // || 0 != fstat.st_mode & S_IRGRP
    // || 0 != fstat.st_mode & S_IWGRP
    // || 0 != fstat.st_mode & S_IROTH
    // || 0 != fstat.st_mode & S_IWOTH) {
    if (fstat.st_mode
    &  (S_IRUSR | S_IWUSR | ~S_IRGRP | ~S_IWGRP | ~S_IROTH | ~S_IWOTH)
    == (S_IRUSR | S_IWUSR | ~S_IRGRP | ~S_IWGRP | ~S_IROTH | ~S_IWOTH)) {
        // Converts __mode_t st_mode to human-readable string (octal notation):
        std::stringstream mode;
        mode << std::oct << fstat.st_mode;
        // Extract only necessary part (user, group, other) from file mode:
        std::string message = _path + ": Chmod should be 600, found "
                            + mode.str().substr(2);
        throw Exception::FileInputException(libsxc::Exception::BadFile, message);
    }

    _isFifoValid = true;
}

/*}}}*/
void File::AbcInput::_read()/*{{{*/
{
    _fifo.open(_path.c_str());

    if (_mustClose)
        return;

    std::string buffer;
    std::string input;
    bool isFirstLine = true;
    while (!_fifo.eof()) {
        getline(_fifo, buffer);
        if (_fifo.eof() && buffer.empty()) {
#ifdef DEBUG
            std::string msg = "AbcInput::_read() (while): ";
            msg.append("EOF, empty buffer. Not appending trailing newline.");
            printLog(msg);
#endif
            break;
        }
        if (isFirstLine) {
            isFirstLine = false;
        } else {
            input += '\n';
        }
        input.append(buffer);
#ifdef DEBUG
        printLog("AbcInput::_read(): Read '" + buffer + "'.");
        printLog("AbcInput::_read(): Input is now: '" + input + "'.");
#endif
    }
#ifdef DEBUG
    printLog("AbcInput::_read(): EOF. Input was: '" + input + "'.");
#endif

    _handleInput(input);

    _fifo.close();
}

/*}}}*/
void File::AbcInput::listen(bool blocking)/*{{{*/
{
    // Prevent input from being handled twice:
    if (_isListening) {
        std::string message = "Already listening on " + _path;
        throw Exception::FileInputException(libsxc::Exception::FileLocked, message);
    }
    _isListening = true;

#ifdef DEBUG
    printLog("Creating thread.");
#endif

    // Start the thread in the background.
    pthread_create(&_thread, NULL, _listen, (void*)this);

#ifdef DEBUG
    printLog("Thread created.");
#endif

    // Join the thread when this functions should read in a blocking way.
    if (true == blocking)
        pthread_join(_thread, NULL);

#ifdef DEBUG
    printLog("listen() ends here.");
#endif
}

/*}}}*/
void File::AbcInput::close()/*{{{*/
{
    if (_isListening) {
        _mustClose = true;
        // Open an close FIFO in order to unblock subthread.
        std::ofstream out(_path.c_str());
        out.close();
        pthread_join(_thread, NULL);
    }

    _mustClose   = false;
    _isListening = false;
}

/*}}}*/
void *File::AbcInput::_listen(void *fifo)/*{{{*/
{
#ifdef DEBUG
    printLog("Thread running.");
#endif
    // FIXME: Add exception handling.
    AbcInput *that = (AbcInput *) fifo;
    do {
        // _read() reads blocking until the other end closes the pipe. This
        // loop will always restart _read() after it handled some input and
        // returned.
        that->_read();
    } while (!that->_mustClose);

#ifdef DEBUG
    printLog("Thread terminating.");
#endif

    return NULL;
}

/*}}}*/

// Use no tabs at all; four spaces indentation; max. eighty chars per line.
// vim: et ts=4 sw=4 tw=80 fo+=c fdm=marker
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include "catch.hpp"

#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_types.hpp>
#include <mapnik/geometry_type.hpp>

namespace {

template <typename T>
std::string vector_to_string(T const& vec)
{
    std::stringstream s;
    for (auto const& item : vec)
    {
        s << item << "\n";
    }
    return s.str();
}

template <>
std::string vector_to_string(std::vector<mapnik::attribute_descriptor> const& vec)
{
    std::stringstream s;
    for (auto const& item : vec)
    {
        s << item.get_name() << "\n";
    }
    return s.str();
}

inline void require_field_names(std::vector<mapnik::attribute_descriptor> const &fields,
                         std::initializer_list<std::string> const &names)
{
    INFO("fields: " + vector_to_string(fields) + " names: " +  vector_to_string(names));
    REQUIRE(fields.size() == names.size());
    auto itr_a = fields.begin();
    auto const end_a = fields.end();
    auto itr_b = names.begin();
    for (; itr_a != end_a; ++itr_a, ++itr_b)
    {
        CHECK(itr_a->get_name() == *itr_b);
    }
}

inline void require_field_types(std::vector<mapnik::attribute_descriptor> const &fields,
                         std::initializer_list<mapnik::eAttributeType> const &types) {
    REQUIRE(fields.size() == types.size());
    auto itr_a = fields.begin();
    auto const end_a = fields.end();
    auto itr_b = types.begin();
    for (; itr_a != end_a; ++itr_a, ++itr_b) {
        CHECK(itr_a->get_type() == *itr_b);
    }
}

inline mapnik::featureset_ptr all_features(mapnik::datasource_ptr ds) {
    auto fields = ds->get_descriptor().get_descriptors();
    mapnik::query query(ds->envelope());
    for (auto const &field : fields) {
        query.add_property_name(field.get_name());
    }
    return ds->features(query);
}

inline std::size_t count_features(mapnik::featureset_ptr features) {
    std::size_t count = 0;
    while (features->next()) {
        ++count;
    }
    return count;
}

using attr = std::tuple<std::string, mapnik::value>;
inline void require_attributes(mapnik::feature_ptr feature,
                        std::initializer_list<attr> const &attrs) {
    REQUIRE(bool(feature));
    for (auto const &kv : attrs) {
        REQUIRE(feature->has_key(std::get<0>(kv)));
        CHECK(feature->get(std::get<0>(kv)) == std::get<1>(kv));
    }
}

namespace detail {
struct feature_count {
    template <typename T>
    std::size_t operator()(T const &geom) const {
        return mapnik::util::apply_visitor(*this, geom);
    }

    std::size_t operator()(mapnik::geometry::geometry_empty const &) const {
        return 0;
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::point<T> const &) const {
        return 1;
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::line_string<T> const &) const {
        return 1;
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::polygon<T> const &) const {
        return 1;
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::multi_point<T> const &mp) const {
        return mp.size();
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::multi_line_string<T> const &mls) const {
        return mls.size();
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::multi_polygon<T> const &mp) const {
        return mp.size();
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::geometry_collection<T> const &col) const {
        std::size_t sum = 0;
        for (auto const &geom : col) {
            sum += operator()(geom);
        }
        return sum;
    }
};
} // namespace detail

template <typename T>
inline std::size_t feature_count(mapnik::geometry::geometry<T> const &g) {
    return detail::feature_count()(g);
}

inline void require_geometry(mapnik::feature_ptr feature,
                      std::size_t num_parts,
                      mapnik::geometry::geometry_types type) {
    REQUIRE(bool(feature));
    CHECK(mapnik::geometry::geometry_type(feature->get_geometry()) == type);
    CHECK(feature_count(feature->get_geometry()) == num_parts);
}

}
<commit_msg>make available test functions as macros to allow catch to report correct line numbers<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include "catch.hpp"

#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_types.hpp>
#include <mapnik/geometry_type.hpp>

namespace {

template <typename T>
std::string vector_to_string(T const& vec)
{
    std::stringstream s;
    for (auto const& item : vec)
    {
        s << item << "\n";
    }
    return s.str();
}

template <>
std::string vector_to_string(std::vector<mapnik::attribute_descriptor> const& vec)
{
    std::stringstream s;
    for (auto const& item : vec)
    {
        s << item.get_name() << "\n";
    }
    return s.str();
}

#define REQUIRE_FIELD_NAMES(fields, names) \
    INFO("fields: " + vector_to_string(fields) + " names: " +  vector_to_string(names)); \
    REQUIRE(fields.size() == names.size()); \
    auto itr_a = fields.begin(); \
    auto const end_a = fields.end(); \
    auto itr_b = names.begin(); \
    for (; itr_a != end_a; ++itr_a, ++itr_b) \
    { \
        CHECK(itr_a->get_name() == *itr_b); \
    } \

inline void require_field_names(std::vector<mapnik::attribute_descriptor> const &fields,
                         std::initializer_list<std::string> const &names)
{
    REQUIRE_FIELD_NAMES(fields,names);
}

#define REQUIRE_FIELD_TYPES(fields, types) \
    REQUIRE(fields.size() == types.size()); \
    auto itr_a = fields.begin(); \
    auto const end_a = fields.end(); \
    auto itr_b = types.begin(); \
    for (; itr_a != end_a; ++itr_a, ++itr_b) { \
        CHECK(itr_a->get_type() == *itr_b); \
    } \

inline void require_field_types(std::vector<mapnik::attribute_descriptor> const &fields,
                         std::initializer_list<mapnik::eAttributeType> const &types)
{
    REQUIRE_FIELD_TYPES(fields, types);
}

inline mapnik::featureset_ptr all_features(mapnik::datasource_ptr ds) {
    auto fields = ds->get_descriptor().get_descriptors();
    mapnik::query query(ds->envelope());
    for (auto const &field : fields) {
        query.add_property_name(field.get_name());
    }
    return ds->features(query);
}

inline std::size_t count_features(mapnik::featureset_ptr features) {
    std::size_t count = 0;
    while (features->next()) {
        ++count;
    }
    return count;
}

using attr = std::tuple<std::string, mapnik::value>;
inline void require_attributes(mapnik::feature_ptr feature,
                        std::initializer_list<attr> const &attrs) {
    REQUIRE(bool(feature));
    for (auto const &kv : attrs) {
        REQUIRE(feature->has_key(std::get<0>(kv)));
        CHECK(feature->get(std::get<0>(kv)) == std::get<1>(kv));
    }
}

namespace detail {
struct feature_count {
    template <typename T>
    std::size_t operator()(T const &geom) const {
        return mapnik::util::apply_visitor(*this, geom);
    }

    std::size_t operator()(mapnik::geometry::geometry_empty const &) const {
        return 0;
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::point<T> const &) const {
        return 1;
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::line_string<T> const &) const {
        return 1;
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::polygon<T> const &) const {
        return 1;
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::multi_point<T> const &mp) const {
        return mp.size();
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::multi_line_string<T> const &mls) const {
        return mls.size();
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::multi_polygon<T> const &mp) const {
        return mp.size();
    }

    template <typename T>
    std::size_t operator()(mapnik::geometry::geometry_collection<T> const &col) const {
        std::size_t sum = 0;
        for (auto const &geom : col) {
            sum += operator()(geom);
        }
        return sum;
    }
};
} // namespace detail

template <typename T>
inline std::size_t feature_count(mapnik::geometry::geometry<T> const &g) {
    return detail::feature_count()(g);
}

inline void require_geometry(mapnik::feature_ptr feature,
                      std::size_t num_parts,
                      mapnik::geometry::geometry_types type) {
    REQUIRE(bool(feature));
    CHECK(mapnik::geometry::geometry_type(feature->get_geometry()) == type);
    CHECK(feature_count(feature->get_geometry()) == num_parts);
}

}
<|endoftext|>


<commit_before>// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "nns_index_iterator.h"
#include <vespa/searchlib/tensor/nearest_neighbor_index.h>
#include <cmath>

using Hit = search::tensor::NearestNeighborIndex::Neighbor;

namespace search::queryeval {

/**
 * Search iterator for K nearest neighbor matching,
 * where the actual search is done up front and this class
 * just iterates over a vector held by the blueprint.
 **/
class NeighborVectorIterator : public NnsIndexIterator
{
private:
    fef::TermFieldMatchData &_tfmd;
    const std::vector<Hit> &_hits;
    uint32_t _idx;
    double _last_sq_dist;
public:
    NeighborVectorIterator(fef::TermFieldMatchData &tfmd,
                           const std::vector<Hit> &hits)
        : _tfmd(tfmd),
          _hits(hits),
          _idx(0),
          _last_sq_dist(0.0)
    {}

    void initRange(uint32_t begin_id, uint32_t end_id) override {
        SearchIterator::initRange(begin_id, end_id);
        _idx = 0;
    }

    void doSeek(uint32_t docId) override {
        while (_idx < _hits.size()) {
            uint32_t hit_id = _hits[_idx].docid;
            if (hit_id < docId) {
                ++_idx;
            } else if (hit_id < getEndId()) {
                setDocId(hit_id);
                _last_sq_dist = _hits[_idx].distance;
                return;
            } else {
                _idx = _hits.size();
            }
        }
        setAtEnd();
    }

    void doUnpack(uint32_t docId) override {
        _tfmd.setRawScore(docId, sqrt(_last_sq_dist));
    }

    Trinary is_strict() const override { return Trinary::True; }
};

std::unique_ptr<NnsIndexIterator>
NnsIndexIterator::create(
        fef::TermFieldMatchData &tfmd,
        const std::vector<Hit> &hits)
{
    return std::make_unique<NeighborVectorIterator>(tfmd, hits);
}

} // namespace
<commit_msg>keep "Neighbor" as name of struct<commit_after>// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "nns_index_iterator.h"
#include <vespa/searchlib/tensor/nearest_neighbor_index.h>
#include <cmath>

using Neighbor = search::tensor::NearestNeighborIndex::Neighbor;

namespace search::queryeval {

/**
 * Search iterator for K nearest neighbor matching,
 * where the actual search is done up front and this class
 * just iterates over a vector held by the blueprint.
 **/
class NeighborVectorIterator : public NnsIndexIterator
{
private:
    fef::TermFieldMatchData &_tfmd;
    const std::vector<Neighbor> &_hits;
    uint32_t _idx;
    double _last_sq_dist;
public:
    NeighborVectorIterator(fef::TermFieldMatchData &tfmd,
                           const std::vector<Neighbor> &hits)
        : _tfmd(tfmd),
          _hits(hits),
          _idx(0),
          _last_sq_dist(0.0)
    {}

    void initRange(uint32_t begin_id, uint32_t end_id) override {
        SearchIterator::initRange(begin_id, end_id);
        _idx = 0;
    }

    void doSeek(uint32_t docId) override {
        while (_idx < _hits.size()) {
            uint32_t hit_id = _hits[_idx].docid;
            if (hit_id < docId) {
                ++_idx;
            } else if (hit_id < getEndId()) {
                setDocId(hit_id);
                _last_sq_dist = _hits[_idx].distance;
                return;
            } else {
                _idx = _hits.size();
            }
        }
        setAtEnd();
    }

    void doUnpack(uint32_t docId) override {
        _tfmd.setRawScore(docId, sqrt(_last_sq_dist));
    }

    Trinary is_strict() const override { return Trinary::True; }
};

std::unique_ptr<NnsIndexIterator>
NnsIndexIterator::create(
        fef::TermFieldMatchData &tfmd,
        const std::vector<Neighbor> &hits)
{
    return std::make_unique<NeighborVectorIterator>(tfmd, hits);
}

} // namespace
<|endoftext|>


<commit_before>#include "JsonResOP.h"

#include <ee/SymbolFile.h>
#include <ee/SymbolType.h>

#include <sprite2/SymType.h>
#include <gum/FilepathHelper.h>

#include <fstream>

namespace edb
{

const std::string JsonResOP::KEY_SPR  = "sprite";
const std::string JsonResOP::KEY_COMP = "components";
const std::string JsonResOP::KEY_PATH = "filepath";

JsonResOP::JsonResOP(const std::string& filepath)
	: m_filepath(filepath)
{
	m_base_dir = gum::FilepathHelper::Dir(m_filepath);
}

void JsonResOP::Do()
{
	Clear();

	int type = ee::SymbolFile::Instance()->Type(m_filepath);
	switch (type)
	{
	case s2::SYM_IMAGE:
		break;
	case s2::SYM_SCALE9:
		DoCommon(KEY_SPR);
		break;
	case s2::SYM_ICON:
		break;
	case s2::SYM_TEXTURE:
		DoTexture();
		break;
	case s2::SYM_COMPLEX:
		DoCommon(KEY_SPR);
		break;
	case s2::SYM_ANIMATION:
		DoAnim();
		break;
	case s2::SYM_ANIM2:
		// todo
		break;
	case s2::SYM_PARTICLE3D:
		DoCommon(KEY_COMP);
		break;
	case s2::SYM_PARTICLE2D:
		DoCommon(KEY_COMP);
		break;
	case s2::SYM_SHAPE:
		// todo
		break;
	case s2::SYM_MESH:
		DoMesh();
		break;
	case s2::SYM_MASK:
		DoMask();
		break;
	case s2::SYM_TRAIL:
		// todo
		break;
	case s2::SYM_SKELETON:
		// todo
		break;
	case s2::SYM_MODEL:
		// todo
		break;
	case ee::SYM_UIWND:
		DoUIWnd();
		break;
	case ee::SYM_UI:
		DoUI();
		break;
	}
}

bool JsonResOP::DoFile(Json::Value& val, const std::string& key)
{
	std::string filepath = val[key].asString();
	if (filepath == ee::SYM_GROUP_TAG) {
		return DoGroup(val, key);
	} else {
		std::string absolute;
		if (!filepath.empty()) {
			absolute = gum::FilepathHelper::Absolute(m_base_dir, filepath);
			absolute = gum::FilepathHelper::Format(absolute);
		}
		return OnDoFile(absolute, val, key);
	}
}

bool JsonResOP::DoGroup(Json::Value& val, const std::string& key)
{
	bool dirty = false;
	for (int i = 0, n = val["group"].size(); i < n; ++i) {
		if (DoFile(val["group"][i], "filepath")) {
			dirty = true;
		}
	}
	AfterDoGroup(dirty, val);
	return dirty;
}

void JsonResOP::DoCommon(const std::string& key)
{
	Json::Value value;
	LoadJson(m_filepath, value);

	BeforeDoCommon(value);

	bool dirty = false;
	int n = value[key].size();
	for (int i = 0; i < n; ++i) {
		if (DoFile(value[key][i], KEY_PATH)) {
			dirty = true;
		}
	}

	AfterDoCommon(dirty, value, key);

	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoUIWnd()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	BeforeDoCommon(value);

	bool dirty = false;
	int n = value[KEY_SPR].size();
	for (int i = 0; i < n; ++i) {
		if (DoFile(value[KEY_SPR][i], KEY_PATH)) {
			dirty = true;
		}
	}

	if (DoFile(value["ref_spr"], KEY_PATH)) {
		dirty = true;
	}

	AfterDoCommon(dirty, value, KEY_SPR);

	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoTexture()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	bool dirty = false;
	for (int i = 0, n = value["shapes"].size(); i < n; ++i)
	{
		if (!value["shapes"][i].isMember("material")) {
			continue;
		}
		Json::Value& val_mat = value["shapes"][i]["material"];
		if (val_mat["type"] == "texture") {
			if (DoFile(val_mat, "texture path")) {
				dirty = true;
			}
		}
	}

	AfterDoTexture(dirty, value);

	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoAnim()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	BeforeDoAinm(value);

	bool dirty = false;
	for (int layer_i = 0, layer_n = value["layer"].size(); layer_i < layer_n; ++layer_i) {
		Json::Value& layer_val = value["layer"][layer_i];
		for (int frame_i = 0, frame_n = layer_val["frame"].size(); frame_i < frame_n; ++frame_i) {
			Json::Value& frame_val = layer_val["frame"][frame_i];
			for (int actor_i = 0, actor_n = frame_val["actor"].size(); actor_i < actor_n; ++actor_i) {
				if (DoFile(frame_val["actor"][actor_i], KEY_PATH)) {
					dirty = true;
				}
			}
		}
	}

	AfterDoAnim(dirty, value);

	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoMesh()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	if (DoFile(value, "base_symbol")) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoMask()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	bool dirty = false;
	if (DoFile(value["base"], KEY_PATH)) {
		dirty = true;
	}
	if (DoFile(value["mask"], KEY_PATH)) {
		dirty = true;
	}
	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoUI()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	bool dirty = false;
	if (DoFile(value, "items filepath")) {
		dirty = true;
	}
	if (DoFile(value, "wrapper filepath")) {
		dirty = true;
	}
	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::LoadJson(const std::string& filepath, Json::Value& val)
{
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(filepath.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, val);
	fin.close();
}

void JsonResOP::StoreJson(const std::string& filepath, const Json::Value& val)
{
	Json::StyledStreamWriter writer;
	std::locale::global(std::locale(""));
	std::ofstream fout(filepath.c_str());
	std::locale::global(std::locale("C"));
	writer.write(fout, val);
	fout.close();
}

}<commit_msg>[FIXED] parse uiwnd ref_spr<commit_after>#include "JsonResOP.h"

#include <ee/SymbolFile.h>
#include <ee/SymbolType.h>

#include <sprite2/SymType.h>
#include <gum/FilepathHelper.h>

#include <fstream>

namespace edb
{

const std::string JsonResOP::KEY_SPR  = "sprite";
const std::string JsonResOP::KEY_COMP = "components";
const std::string JsonResOP::KEY_PATH = "filepath";

JsonResOP::JsonResOP(const std::string& filepath)
	: m_filepath(filepath)
{
	m_base_dir = gum::FilepathHelper::Dir(m_filepath);
}

void JsonResOP::Do()
{
	Clear();

	int type = ee::SymbolFile::Instance()->Type(m_filepath);
	switch (type)
	{
	case s2::SYM_IMAGE:
		break;
	case s2::SYM_SCALE9:
		DoCommon(KEY_SPR);
		break;
	case s2::SYM_ICON:
		break;
	case s2::SYM_TEXTURE:
		DoTexture();
		break;
	case s2::SYM_COMPLEX:
		DoCommon(KEY_SPR);
		break;
	case s2::SYM_ANIMATION:
		DoAnim();
		break;
	case s2::SYM_ANIM2:
		// todo
		break;
	case s2::SYM_PARTICLE3D:
		DoCommon(KEY_COMP);
		break;
	case s2::SYM_PARTICLE2D:
		DoCommon(KEY_COMP);
		break;
	case s2::SYM_SHAPE:
		// todo
		break;
	case s2::SYM_MESH:
		DoMesh();
		break;
	case s2::SYM_MASK:
		DoMask();
		break;
	case s2::SYM_TRAIL:
		// todo
		break;
	case s2::SYM_SKELETON:
		// todo
		break;
	case s2::SYM_MODEL:
		// todo
		break;
	case ee::SYM_UIWND:
		DoUIWnd();
		break;
	case ee::SYM_UI:
		DoUI();
		break;
	}
}

bool JsonResOP::DoFile(Json::Value& val, const std::string& key)
{
	std::string filepath = val[key].asString();
	if (filepath == ee::SYM_GROUP_TAG) {
		return DoGroup(val, key);
	} else {
		std::string absolute;
		if (!filepath.empty()) {
			absolute = gum::FilepathHelper::Absolute(m_base_dir, filepath);
			absolute = gum::FilepathHelper::Format(absolute);
		}
		return OnDoFile(absolute, val, key);
	}
}

bool JsonResOP::DoGroup(Json::Value& val, const std::string& key)
{
	bool dirty = false;
	for (int i = 0, n = val["group"].size(); i < n; ++i) {
		if (DoFile(val["group"][i], "filepath")) {
			dirty = true;
		}
	}
	AfterDoGroup(dirty, val);
	return dirty;
}

void JsonResOP::DoCommon(const std::string& key)
{
	Json::Value value;
	LoadJson(m_filepath, value);

	BeforeDoCommon(value);

	bool dirty = false;
	int n = value[key].size();
	for (int i = 0; i < n; ++i) {
		if (DoFile(value[key][i], KEY_PATH)) {
			dirty = true;
		}
	}

	AfterDoCommon(dirty, value, key);

	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoUIWnd()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	BeforeDoCommon(value);

	bool dirty = false;
	int n = value[KEY_SPR].size();
	for (int i = 0; i < n; ++i) {
		if (DoFile(value[KEY_SPR][i], KEY_PATH)) {
			dirty = true;
		}
	}

	if (value.isMember("ref_spr"))
	{
		for (int i = 0, n = value["ref_spr"].size(); i < n; ++i) {
			if (DoFile(value["ref_spr"][i], KEY_PATH)) {
				dirty = true;
			}
		}
	}

	AfterDoCommon(dirty, value, KEY_SPR);

	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoTexture()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	bool dirty = false;
	for (int i = 0, n = value["shapes"].size(); i < n; ++i)
	{
		if (!value["shapes"][i].isMember("material")) {
			continue;
		}
		Json::Value& val_mat = value["shapes"][i]["material"];
		if (val_mat["type"] == "texture") {
			if (DoFile(val_mat, "texture path")) {
				dirty = true;
			}
		}
	}

	AfterDoTexture(dirty, value);

	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoAnim()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	BeforeDoAinm(value);

	bool dirty = false;
	for (int layer_i = 0, layer_n = value["layer"].size(); layer_i < layer_n; ++layer_i) {
		Json::Value& layer_val = value["layer"][layer_i];
		for (int frame_i = 0, frame_n = layer_val["frame"].size(); frame_i < frame_n; ++frame_i) {
			Json::Value& frame_val = layer_val["frame"][frame_i];
			for (int actor_i = 0, actor_n = frame_val["actor"].size(); actor_i < actor_n; ++actor_i) {
				if (DoFile(frame_val["actor"][actor_i], KEY_PATH)) {
					dirty = true;
				}
			}
		}
	}

	AfterDoAnim(dirty, value);

	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoMesh()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	if (DoFile(value, "base_symbol")) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoMask()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	bool dirty = false;
	if (DoFile(value["base"], KEY_PATH)) {
		dirty = true;
	}
	if (DoFile(value["mask"], KEY_PATH)) {
		dirty = true;
	}
	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::DoUI()
{
	Json::Value value;
	LoadJson(m_filepath, value);

	bool dirty = false;
	if (DoFile(value, "items filepath")) {
		dirty = true;
	}
	if (DoFile(value, "wrapper filepath")) {
		dirty = true;
	}
	if (dirty) {
		StoreJson(m_filepath, value);
	}
}

void JsonResOP::LoadJson(const std::string& filepath, Json::Value& val)
{
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(filepath.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, val);
	fin.close();
}

void JsonResOP::StoreJson(const std::string& filepath, const Json::Value& val)
{
	Json::StyledStreamWriter writer;
	std::locale::global(std::locale(""));
	std::ofstream fout(filepath.c_str());
	std::locale::global(std::locale("C"));
	writer.write(fout, val);
	fout.close();
}

}<|endoftext|>


<commit_before>/*
 * This file is part of crash-reporter
 *
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 *
 * Contact: Ville Ilvonen <ville.p.ilvonen@nokia.com>
 * Author: Riku Halonen <riku.halonen@nokia.com>
 *
 * Copyright (C) 2013 Jolla Ltd.
 * Contact: Jakub Adam <jakub.adam@jollamobile.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This program 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 program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

// System includes.

#include <QListIterator>
#include <QStringList>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QDBusReply>

// User includes.

#include "creporterdaemonmonitor.h"
#include "creporterdaemonmonitor_p.h"
#include "creportercoreregistry.h"
#include "creporternwsessionmgr.h"
#include "creportersavedstate.h"
#include "creporterutils.h"
#include "creporterdialogserverproxy.h"
#include "creporterautouploaderproxy.h"
#include "creporternamespace.h"
#include "creporternotification.h"
#include "creporterprivacysettingsmodel.h"

// ******** Class CReporterHandledRichCore ********

// ======== MEMBER FUNCTIONS ========

// ----------------------------------------------------------------------------
// CReporterHandledRichCore::CReporterHandledRichCore
// ----------------------------------------------------------------------------
CReporterHandledRichCore::CReporterHandledRichCore(const QString &filePath):
  lastCountReset(QDateTime::currentDateTimeUtc())
{
    // Parse needed info for file path.
    QStringList rCoreInfo = CReporterUtils::parseCrashInfoFromFilename(filePath);

    binaryName = rCoreInfo[0];
    signalNumber = rCoreInfo[2].toInt();

    QFileInfo fi(filePath);

    count = 0;

    qDebug() << __PRETTY_FUNCTION__ << "Name:" << binaryName << ", Signal:" << signalNumber;
}

// ----------------------------------------------------------------------------
// CReporterHandledRichCore::~CReporterHandledRichCore
// ----------------------------------------------------------------------------
CReporterHandledRichCore::~CReporterHandledRichCore()
{
}

// ----------------------------------------------------------------------------
// CReporterHandledRichCore::operator==
// ----------------------------------------------------------------------------
bool CReporterHandledRichCore::operator==(const CReporterHandledRichCore &other) const
{
    return (binaryName == other.binaryName) &&
           (signalNumber == other.signalNumber);
}

// ******** Class CReporterDaemonMonitorPrivate ********

// ======== MEMBER FUNCTIONS ========

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::CReporterDaemonMonitorPrivate
// ----------------------------------------------------------------------------
CReporterDaemonMonitorPrivate::CReporterDaemonMonitorPrivate() :
  autoDelete(false), autoDeleteMaxSimilarCores(0), autoUpload(false),
  crashNotification(new CReporterNotification(
          CReporter::AutoUploaderNotificationEventType,
          CReporterSavedState::instance()->crashNotificationId(), this)),
  crashCount(0)
{
    connect(crashNotification, &CReporterNotification::timeouted,
            this, &CReporterDaemonMonitorPrivate::resetCrashCount);
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::~CReporterDaemonMonitorPrivate
// ----------------------------------------------------------------------------
CReporterDaemonMonitorPrivate::~CReporterDaemonMonitorPrivate()
{
    CReporterSavedState *state = CReporterSavedState::instance();
    state->setCrashNotificationId(crashNotification->id());

    qDeleteAll(handledRichCores);
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::addDirectoryWatcher
// ----------------------------------------------------------------------------
void CReporterDaemonMonitorPrivate::addDirectoryWatcher()
{
    qDebug() << __PRETTY_FUNCTION__ << "Adding core directory watcher...";

    // Subscribe to receive signals for changed directories.
    connect(&watcher, SIGNAL(directoryChanged(const QString&)),
            this, SLOT(handleDirectoryChanged(const QString&)));
    // Subscribe to receive signals for changes in core registry.
    connect(registry, SIGNAL(coreLocationsUpdated()),
                this, SLOT(addDirectoryWatcher()));

    QStringList* corePaths = registry->getCoreLocationPaths();

    if (!corePaths->isEmpty()) {
        registry->refreshRegistry();
        // Add monitored directories to QFileSystemWatcher. Paths are not added
        // if they do not exist, or if they are already being monitored by the file system watcher.
        watcher.addPaths(*corePaths);
    }

    delete corePaths;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::removeDirectoryWatcher()
// ----------------------------------------------------------------------------
void CReporterDaemonMonitorPrivate::removeDirectoryWatcher()
{
    qDebug() << __PRETTY_FUNCTION__ << "Removing core directory watcher...";

    // Remove watcher from directories.
    watcher.removePaths(watcher.directories());
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::handleDirectoryChanged
// ----------------------------------------------------------------------------
void CReporterDaemonMonitorPrivate::handleDirectoryChanged(const QString &path)
{
    qDebug() << __PRETTY_FUNCTION__ << "Directory:" << path << "has changed.";

    QDir changedDir(path);
    // Sanity check. QFileSystemWatcher will send signal, if monitored directory was removed.
    if (changedDir.exists()) {
        qDebug() << __PRETTY_FUNCTION__ << "Changed directory exists.";
        // Check for new cores in changed directory.
        QString filePath = registry->checkDirectoryForCores(path);

        if (!filePath.isEmpty()) {
            // New core found.
            qDebug() << __PRETTY_FUNCTION__ << "New rich-core file found: " << filePath;

            QStringList details = CReporterUtils::parseCrashInfoFromFilename(filePath);

            emit q_ptr->richCoreNotify(filePath);

            if (autoDelete && checkForDuplicates(filePath)
                && !filePath.contains(CReporter::LifelogPackagePrefix)) {
                // Check for dublicates, if auto-deleting is enabled. If Maximum number of duplicates
                // exeeded, delete file.
                if (CReporterPrivacySettingsModel::instance()->notificationsEnabled())
                {
                    CReporterNotification *notification =
                            new CReporterNotification(
                                    CReporter::ApplicationNotificationEventType,
                                    0, this);
                    notification->setTimeout(5000);
                    connect(notification, &CReporterNotification::timeouted,
                            notification, &QObject::deleteLater);
                    notification->update(QString("%1 has crashed again.").arg(details[0]),
                            "Duplicate crash report was deleted.");
                }
                CReporterUtils::removeFile(filePath);
                return;
            }

            if (!autoUpload)
            {
                QVariantList arguments;
                arguments << filePath;

                /* TODO: Here multiple-choice notification should be displayed
                 * with options to send or delete the crash report. So far
                 * disabling auto upload is not possible in the UI and we never
                 * get here. This code now at least leaks CReporterNotification
                 * and has to be re-implemented. Standard Sailfish notifications
                 * don't support multiple actions so far.*/

                if (!q_ptr->notifyCrashReporterUI(CReporter::NotifyNewDialogType, arguments)) {
                    // UI failed to launch. Try to show notification instead.
                    // Daemon is not a Meego Touch application, thus translation with MLocale
                    // won't work here.

                    QString notificationSummary;
                    if (filePath.contains(CReporter::LifelogPackagePrefix))
                    {
                        notificationSummary = "New lifelog report is ready.";
                    }
                    else
                    {
                        notificationSummary = "The application %1 crashed.";
                        notificationSummary = notificationSummary.arg(details.at(0));
                    }

                    QString notificationBody("Unable to start Crash Reporter UI");

                    CReporterNotification *notification = new CReporterNotification(
                            CReporter::ApplicationNotificationEventType,
                            notificationSummary, notificationBody);
                    notification->setParent(this);

                    connect(notification, SIGNAL(activated()), this, SLOT(handleNotificationEvent()));
                    connect(notification, SIGNAL(timeouted()), this, SLOT(handleNotificationEvent()));
                }
            }
            else
            {
                if (CReporterPrivacySettingsModel::instance()->notificationsEnabled() &&
                    !filePath.contains(CReporter::LifelogPackagePrefix)) {

                    QString body;
                    if (++crashCount > 1) {
                        body = QString("%1 crashes total").arg(crashCount);
                    }

                    crashNotification->update(
                            QString("%1 has crashed.").arg(details.at(0)),
                            body, crashCount);
                }
                if (!CReporterNwSessionMgr::unpaidConnectionAvailable()) {
                    qDebug() << __PRETTY_FUNCTION__
                             << "WiFi not available, not uploading now.";
                } else {
                    /* In auto-upload mode try to upload all crash reports each
                     * time a new one appears. */
                    if (!CReporterUtils::notifyAutoUploader(registry->collectAllCoreFiles())) {
                        qWarning() << __PRETTY_FUNCTION__
                                   << "Failed to start Auto Uploader.";
                    }
                }
            }
        }
    }
    else // Monitored directory was deleted
    {
        // Re-add core dirs when the parent dir changes so that monitoring is resumed
        // after usb mass storage mode has been disconnected
        QDir changedDir(path);
        if (changedDir.cd("../.."))
        {
            connect(&parentDirWatcher, SIGNAL(directoryChanged(QString)), SLOT(handleParentDirectoryChanged()));
            parentDirWatcher.addPath(changedDir.absolutePath());
            qDebug() << __PRETTY_FUNCTION__ << "Directory was deleted. Started parent dir monitoring.";
        }
        else
        {
            qDebug() << __PRETTY_FUNCTION__ << "Directory was deleted. Parent dir does not exist.";
        }
    }
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::handleParentDirectoryChanged
// ----------------------------------------------------------------------------
void CReporterDaemonMonitorPrivate::handleParentDirectoryChanged()
{
    qDebug() << __PRETTY_FUNCTION__ << "Parent dir has changed. Trying to re-add directory watchers.";
    QStringList* corePaths = registry->getCoreLocationPaths();
    int numWatchPaths = watcher.directories().count();

    if (!corePaths->isEmpty()) {
        registry->refreshRegistry();
        // Add monitored directories to QFileSystemWatcher. Paths are not added
        // if they do not exist, or if they are already being monitored by the file system watcher.
        watcher.addPaths(*corePaths);
    }

    delete corePaths;

    if (watcher.directories().count() > numWatchPaths)
    {
        qDebug() << __PRETTY_FUNCTION__ << "Successfully started watching core-dump dir";
        disconnect(this, SLOT(handleParentDirectoryChanged()));
        parentDirWatcher.removePaths(parentDirWatcher.directories());
    }
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::checkForDuplicates
// ----------------------------------------------------------------------------
bool CReporterDaemonMonitorPrivate::checkForDuplicates(const QString &path)
{
    qDebug() << __PRETTY_FUNCTION__ << "Checking, if" << path << "has been handled for"
            << autoDeleteMaxSimilarCores << "times.";

    // Create new entry.
    CReporterHandledRichCore *rCore = new CReporterHandledRichCore(path);

    foreach (CReporterHandledRichCore *handled, handledRichCores) {
        // Loop through list to find duplicates.
        qDebug() << __PRETTY_FUNCTION__  << "Compare to:"
               << "Name:" << handled->binaryName << ", Signal:" << handled->signalNumber;

        if (*handled == *rCore) {
            /* Check if more than a day has passed from last duplicate counter
             * reset. */
            QDateTime now(QDateTime::currentDateTimeUtc());
            if (handled->lastCountReset.addDays(1) < now) {
                qDebug() << __PRETTY_FUNCTION__ << "More than a day has passed,"
                            " resetting duplicate counter";
                handled->count = 0;
                handled->lastCountReset = now;
            }

            handled->count++;
            // Duplicate found. Increment counter.
            qDebug() << __PRETTY_FUNCTION__  << "Matches. Count is now:" << handled->count;

            if (handled->count > autoDeleteMaxSimilarCores) {
                // Maximum exeeded.
                qDebug() << __PRETTY_FUNCTION__  << "Maximum number of duplicates exceeded.";
                delete rCore;
                return true;
            }
            // Maximum not yet exeeded.
            delete rCore;
            return false;
        }
    }
    // Not found. Add to handled list.
    rCore->count++;
    handledRichCores << rCore;

    return false;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::handleNotificationEvent
// ----------------------------------------------------------------------------
void CReporterDaemonMonitorPrivate::handleNotificationEvent()
{
    // Handle timeouted and activated signals from CReporterNotification
    // and destroy instance.
    CReporterNotification *notification = qobject_cast<CReporterNotification *>(sender());

    if (notification != 0) {
        delete notification;
    }
}

void CReporterDaemonMonitorPrivate::resetCrashCount()
{
    crashCount = 0;
    qDebug() << __PRETTY_FUNCTION__ << "Crash counter was reset.";
}

// ******** Class CReporterDaemonMonitor ********

// ======== MEMBER FUNCTIONS ========

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::CReporterDaemonMonitor
// ----------------------------------------------------------------------------
CReporterDaemonMonitor::CReporterDaemonMonitor(CReporterCoreRegistry *reg) :
    d_ptr(new CReporterDaemonMonitorPrivate())
{
    d_ptr->q_ptr = this;
    d_ptr->registry = reg;

	// Add watcher to core directories.
    d_ptr->addDirectoryWatcher();
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::~CReporterDaemonMonitor
// ----------------------------------------------------------------------------
CReporterDaemonMonitor::~CReporterDaemonMonitor()
{
    d_ptr->removeDirectoryWatcher();

	delete d_ptr;
    d_ptr = 0;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::notifyCrashReporterUI
// ----------------------------------------------------------------------------
bool CReporterDaemonMonitor::notifyCrashReporterUI(const QString &dialogName,
                                              const QVariantList &arguments)
{
    qDebug() << __PRETTY_FUNCTION__ << "Sending rich-core(s) to the client.";

    CReporterDialogServerProxy proxy(CReporter::DialogServerServiceName,
                                     CReporter::DialogServerObjectPath, QDBusConnection::sessionBus());

    QDBusPendingReply <bool> pReply =
            proxy.requestDialog(dialogName, arguments);
    // This blocks.
    pReply.waitForFinished();

    if (pReply.isError()) {
        qWarning() << __PRETTY_FUNCTION__ << "D-Bus error occured.";

        // Trace error.
        QDBusError dBusError(pReply.error());
        QString errorName = dBusError.name();

        qDebug() << __PRETTY_FUNCTION__ << "Name:" << errorName;
        qDebug() << __PRETTY_FUNCTION__ << "Message:" << dBusError.message();
        qDebug() << __PRETTY_FUNCTION__ << "Error string:" << dBusError.errorString(dBusError.type());

        if (errorName != "org.freedesktop.DBus.Error.Spawn.ChildSignaled") {
            // If crash-reporter-ui exited by another reason than on a signal.
            // Check, if Crash Reporter UI was started. If, not then system has encountered a
            // serious error preventing UI from starting and DBus message was not delivered.
            QDBusConnection connection = proxy.connection();
            QDBusReply<bool> reply =
                    connection.interface()->isServiceRegistered(CReporter::DialogServerServiceName);

            qDebug() << __PRETTY_FUNCTION__ << "Crash Reporter UI launched:" << reply.value();

            if (!reply.value()) {
                // Launcing UI failed.
                return false;
            }
        }
    }
    return true;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::autoDeleteEnabled
// ----------------------------------------------------------------------------
bool CReporterDaemonMonitor::autoDeleteEnabled()
{
    return d_ptr->autoDelete;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::setAutoDelete
// ----------------------------------------------------------------------------
void CReporterDaemonMonitor::setAutoDelete(bool state)
{
    d_ptr->autoDelete = state;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::autoDeleteMaxSimilarCores
// ----------------------------------------------------------------------------
int CReporterDaemonMonitor::autoDeleteMaxSimilarCores()
{
    return d_ptr->autoDeleteMaxSimilarCores;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::setAutoDeleteMaxSimilarCores
// ----------------------------------------------------------------------------
void CReporterDaemonMonitor::setAutoDeleteMaxSimilarCores(int value)
{
    d_ptr->autoDeleteMaxSimilarCores = value;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::autoUploadEnabled
// ----------------------------------------------------------------------------
bool CReporterDaemonMonitor::autoUploadEnabled()
{
    return d_ptr->autoUpload;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::setAutoUpload
// ----------------------------------------------------------------------------
void CReporterDaemonMonitor::setAutoUpload(bool state)
{
    d_ptr->autoUpload = state;
    if (!state)
    {
        qDebug() << __PRETTY_FUNCTION__ << "Calling quit() on Auto Uploader.";
        CReporterAutoUploaderProxy proxy(CReporter::AutoUploaderServiceName,
                                         CReporter::AutoUploaderObjectPath, QDBusConnection::sessionBus());

        QDBusPendingReply <bool> reply = proxy.quit();
        // This blocks.
        reply.waitForFinished();
    }
}

// End of file.
<commit_msg>[refactoring] reduce nested scopes in handleDirectoryChanged() I<commit_after>/*
 * This file is part of crash-reporter
 *
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 *
 * Contact: Ville Ilvonen <ville.p.ilvonen@nokia.com>
 * Author: Riku Halonen <riku.halonen@nokia.com>
 *
 * Copyright (C) 2013 Jolla Ltd.
 * Contact: Jakub Adam <jakub.adam@jollamobile.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This program 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 program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

// System includes.

#include <QListIterator>
#include <QStringList>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QDBusReply>

// User includes.

#include "creporterdaemonmonitor.h"
#include "creporterdaemonmonitor_p.h"
#include "creportercoreregistry.h"
#include "creporternwsessionmgr.h"
#include "creportersavedstate.h"
#include "creporterutils.h"
#include "creporterdialogserverproxy.h"
#include "creporterautouploaderproxy.h"
#include "creporternamespace.h"
#include "creporternotification.h"
#include "creporterprivacysettingsmodel.h"

// ******** Class CReporterHandledRichCore ********

// ======== MEMBER FUNCTIONS ========

// ----------------------------------------------------------------------------
// CReporterHandledRichCore::CReporterHandledRichCore
// ----------------------------------------------------------------------------
CReporterHandledRichCore::CReporterHandledRichCore(const QString &filePath):
  lastCountReset(QDateTime::currentDateTimeUtc())
{
    // Parse needed info for file path.
    QStringList rCoreInfo = CReporterUtils::parseCrashInfoFromFilename(filePath);

    binaryName = rCoreInfo[0];
    signalNumber = rCoreInfo[2].toInt();

    QFileInfo fi(filePath);

    count = 0;

    qDebug() << __PRETTY_FUNCTION__ << "Name:" << binaryName << ", Signal:" << signalNumber;
}

// ----------------------------------------------------------------------------
// CReporterHandledRichCore::~CReporterHandledRichCore
// ----------------------------------------------------------------------------
CReporterHandledRichCore::~CReporterHandledRichCore()
{
}

// ----------------------------------------------------------------------------
// CReporterHandledRichCore::operator==
// ----------------------------------------------------------------------------
bool CReporterHandledRichCore::operator==(const CReporterHandledRichCore &other) const
{
    return (binaryName == other.binaryName) &&
           (signalNumber == other.signalNumber);
}

// ******** Class CReporterDaemonMonitorPrivate ********

// ======== MEMBER FUNCTIONS ========

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::CReporterDaemonMonitorPrivate
// ----------------------------------------------------------------------------
CReporterDaemonMonitorPrivate::CReporterDaemonMonitorPrivate() :
  autoDelete(false), autoDeleteMaxSimilarCores(0), autoUpload(false),
  crashNotification(new CReporterNotification(
          CReporter::AutoUploaderNotificationEventType,
          CReporterSavedState::instance()->crashNotificationId(), this)),
  crashCount(0)
{
    connect(crashNotification, &CReporterNotification::timeouted,
            this, &CReporterDaemonMonitorPrivate::resetCrashCount);
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::~CReporterDaemonMonitorPrivate
// ----------------------------------------------------------------------------
CReporterDaemonMonitorPrivate::~CReporterDaemonMonitorPrivate()
{
    CReporterSavedState *state = CReporterSavedState::instance();
    state->setCrashNotificationId(crashNotification->id());

    qDeleteAll(handledRichCores);
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::addDirectoryWatcher
// ----------------------------------------------------------------------------
void CReporterDaemonMonitorPrivate::addDirectoryWatcher()
{
    qDebug() << __PRETTY_FUNCTION__ << "Adding core directory watcher...";

    // Subscribe to receive signals for changed directories.
    connect(&watcher, SIGNAL(directoryChanged(const QString&)),
            this, SLOT(handleDirectoryChanged(const QString&)));
    // Subscribe to receive signals for changes in core registry.
    connect(registry, SIGNAL(coreLocationsUpdated()),
                this, SLOT(addDirectoryWatcher()));

    QStringList* corePaths = registry->getCoreLocationPaths();

    if (!corePaths->isEmpty()) {
        registry->refreshRegistry();
        // Add monitored directories to QFileSystemWatcher. Paths are not added
        // if they do not exist, or if they are already being monitored by the file system watcher.
        watcher.addPaths(*corePaths);
    }

    delete corePaths;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::removeDirectoryWatcher()
// ----------------------------------------------------------------------------
void CReporterDaemonMonitorPrivate::removeDirectoryWatcher()
{
    qDebug() << __PRETTY_FUNCTION__ << "Removing core directory watcher...";

    // Remove watcher from directories.
    watcher.removePaths(watcher.directories());
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::handleDirectoryChanged
// ----------------------------------------------------------------------------
void CReporterDaemonMonitorPrivate::handleDirectoryChanged(const QString &path)
{
    qDebug() << __PRETTY_FUNCTION__ << "Directory:" << path << "has changed.";

    QDir changedDir(path);
    // QFileSystemWatcher will send signal if monitored directory was removed.
    if (!changedDir.exists()) {
        /* Re-add core dirs when the parent dir changes, so that monitoring is
         * resumed after USB mass storage mode has been disconnected */
        if (changedDir.cd("../..")) {
            connect(&parentDirWatcher, SIGNAL(directoryChanged(QString)),
                    SLOT(handleParentDirectoryChanged()));
            parentDirWatcher.addPath(changedDir.absolutePath());
            qDebug() << __PRETTY_FUNCTION__
                     << "Directory was deleted. Started parent dir monitoring.";
        } else {
            qDebug() << __PRETTY_FUNCTION__
                     << "Directory was deleted. Parent dir does not exist.";
        }

        return;
    }

    qDebug() << __PRETTY_FUNCTION__ << "Changed directory exists.";
    // Check for new cores in changed directory.
    QString filePath = registry->checkDirectoryForCores(path);

    if (!filePath.isEmpty()) {
        // New core found.
        qDebug() << __PRETTY_FUNCTION__ << "New rich-core file found: " << filePath;

        QStringList details = CReporterUtils::parseCrashInfoFromFilename(filePath);

        emit q_ptr->richCoreNotify(filePath);

        if (autoDelete && checkForDuplicates(filePath)
            && !filePath.contains(CReporter::LifelogPackagePrefix)) {
            // Check for dublicates, if auto-deleting is enabled. If Maximum number of duplicates
            // exeeded, delete file.
            if (CReporterPrivacySettingsModel::instance()->notificationsEnabled())
            {
                CReporterNotification *notification =
                        new CReporterNotification(
                                CReporter::ApplicationNotificationEventType,
                                0, this);
                notification->setTimeout(5000);
                connect(notification, &CReporterNotification::timeouted,
                        notification, &QObject::deleteLater);
                notification->update(QString("%1 has crashed again.").arg(details[0]),
                        "Duplicate crash report was deleted.");
            }
            CReporterUtils::removeFile(filePath);
            return;
        }

        if (!autoUpload) {
            QVariantList arguments;
            arguments << filePath;

            /* TODO: Here multiple-choice notification should be displayed
             * with options to send or delete the crash report. So far
             * disabling auto upload is not possible in the UI and we never
             * get here. This code now at least leaks CReporterNotification
             * and has to be re-implemented. Standard Sailfish notifications
             * don't support multiple actions so far.*/

            if (!q_ptr->notifyCrashReporterUI(CReporter::NotifyNewDialogType, arguments)) {
                // UI failed to launch. Try to show notification instead.
                // Daemon is not a Meego Touch application, thus translation with MLocale
                // won't work here.

                QString notificationSummary;
                if (filePath.contains(CReporter::LifelogPackagePrefix))
                {
                    notificationSummary = "New lifelog report is ready.";
                }
                else
                {
                    notificationSummary = "The application %1 crashed.";
                    notificationSummary = notificationSummary.arg(details.at(0));
                }

                QString notificationBody("Unable to start Crash Reporter UI");

                CReporterNotification *notification = new CReporterNotification(
                        CReporter::ApplicationNotificationEventType,
                        notificationSummary, notificationBody);
                notification->setParent(this);

                connect(notification, SIGNAL(activated()), this, SLOT(handleNotificationEvent()));
                connect(notification, SIGNAL(timeouted()), this, SLOT(handleNotificationEvent()));
            }
        } else {
            if (CReporterPrivacySettingsModel::instance()->notificationsEnabled() &&
                !filePath.contains(CReporter::LifelogPackagePrefix)) {

                QString body;
                if (++crashCount > 1) {
                    body = QString("%1 crashes total").arg(crashCount);
                }

                crashNotification->update(
                        QString("%1 has crashed.").arg(details.at(0)),
                        body, crashCount);
            }
            if (!CReporterNwSessionMgr::unpaidConnectionAvailable()) {
                qDebug() << __PRETTY_FUNCTION__
                         << "WiFi not available, not uploading now.";
            } else {
                /* In auto-upload mode try to upload all crash reports each
                 * time a new one appears. */
                if (!CReporterUtils::notifyAutoUploader(registry->collectAllCoreFiles())) {
                    qWarning() << __PRETTY_FUNCTION__
                               << "Failed to start Auto Uploader.";
                }
            }
        }
    }
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::handleParentDirectoryChanged
// ----------------------------------------------------------------------------
void CReporterDaemonMonitorPrivate::handleParentDirectoryChanged()
{
    qDebug() << __PRETTY_FUNCTION__ << "Parent dir has changed. Trying to re-add directory watchers.";
    QStringList* corePaths = registry->getCoreLocationPaths();
    int numWatchPaths = watcher.directories().count();

    if (!corePaths->isEmpty()) {
        registry->refreshRegistry();
        // Add monitored directories to QFileSystemWatcher. Paths are not added
        // if they do not exist, or if they are already being monitored by the file system watcher.
        watcher.addPaths(*corePaths);
    }

    delete corePaths;

    if (watcher.directories().count() > numWatchPaths)
    {
        qDebug() << __PRETTY_FUNCTION__ << "Successfully started watching core-dump dir";
        disconnect(this, SLOT(handleParentDirectoryChanged()));
        parentDirWatcher.removePaths(parentDirWatcher.directories());
    }
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::checkForDuplicates
// ----------------------------------------------------------------------------
bool CReporterDaemonMonitorPrivate::checkForDuplicates(const QString &path)
{
    qDebug() << __PRETTY_FUNCTION__ << "Checking, if" << path << "has been handled for"
            << autoDeleteMaxSimilarCores << "times.";

    // Create new entry.
    CReporterHandledRichCore *rCore = new CReporterHandledRichCore(path);

    foreach (CReporterHandledRichCore *handled, handledRichCores) {
        // Loop through list to find duplicates.
        qDebug() << __PRETTY_FUNCTION__  << "Compare to:"
               << "Name:" << handled->binaryName << ", Signal:" << handled->signalNumber;

        if (*handled == *rCore) {
            /* Check if more than a day has passed from last duplicate counter
             * reset. */
            QDateTime now(QDateTime::currentDateTimeUtc());
            if (handled->lastCountReset.addDays(1) < now) {
                qDebug() << __PRETTY_FUNCTION__ << "More than a day has passed,"
                            " resetting duplicate counter";
                handled->count = 0;
                handled->lastCountReset = now;
            }

            handled->count++;
            // Duplicate found. Increment counter.
            qDebug() << __PRETTY_FUNCTION__  << "Matches. Count is now:" << handled->count;

            if (handled->count > autoDeleteMaxSimilarCores) {
                // Maximum exeeded.
                qDebug() << __PRETTY_FUNCTION__  << "Maximum number of duplicates exceeded.";
                delete rCore;
                return true;
            }
            // Maximum not yet exeeded.
            delete rCore;
            return false;
        }
    }
    // Not found. Add to handled list.
    rCore->count++;
    handledRichCores << rCore;

    return false;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitorPrivate::handleNotificationEvent
// ----------------------------------------------------------------------------
void CReporterDaemonMonitorPrivate::handleNotificationEvent()
{
    // Handle timeouted and activated signals from CReporterNotification
    // and destroy instance.
    CReporterNotification *notification = qobject_cast<CReporterNotification *>(sender());

    if (notification != 0) {
        delete notification;
    }
}

void CReporterDaemonMonitorPrivate::resetCrashCount()
{
    crashCount = 0;
    qDebug() << __PRETTY_FUNCTION__ << "Crash counter was reset.";
}

// ******** Class CReporterDaemonMonitor ********

// ======== MEMBER FUNCTIONS ========

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::CReporterDaemonMonitor
// ----------------------------------------------------------------------------
CReporterDaemonMonitor::CReporterDaemonMonitor(CReporterCoreRegistry *reg) :
    d_ptr(new CReporterDaemonMonitorPrivate())
{
    d_ptr->q_ptr = this;
    d_ptr->registry = reg;

	// Add watcher to core directories.
    d_ptr->addDirectoryWatcher();
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::~CReporterDaemonMonitor
// ----------------------------------------------------------------------------
CReporterDaemonMonitor::~CReporterDaemonMonitor()
{
    d_ptr->removeDirectoryWatcher();

	delete d_ptr;
    d_ptr = 0;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::notifyCrashReporterUI
// ----------------------------------------------------------------------------
bool CReporterDaemonMonitor::notifyCrashReporterUI(const QString &dialogName,
                                              const QVariantList &arguments)
{
    qDebug() << __PRETTY_FUNCTION__ << "Sending rich-core(s) to the client.";

    CReporterDialogServerProxy proxy(CReporter::DialogServerServiceName,
                                     CReporter::DialogServerObjectPath, QDBusConnection::sessionBus());

    QDBusPendingReply <bool> pReply =
            proxy.requestDialog(dialogName, arguments);
    // This blocks.
    pReply.waitForFinished();

    if (pReply.isError()) {
        qWarning() << __PRETTY_FUNCTION__ << "D-Bus error occured.";

        // Trace error.
        QDBusError dBusError(pReply.error());
        QString errorName = dBusError.name();

        qDebug() << __PRETTY_FUNCTION__ << "Name:" << errorName;
        qDebug() << __PRETTY_FUNCTION__ << "Message:" << dBusError.message();
        qDebug() << __PRETTY_FUNCTION__ << "Error string:" << dBusError.errorString(dBusError.type());

        if (errorName != "org.freedesktop.DBus.Error.Spawn.ChildSignaled") {
            // If crash-reporter-ui exited by another reason than on a signal.
            // Check, if Crash Reporter UI was started. If, not then system has encountered a
            // serious error preventing UI from starting and DBus message was not delivered.
            QDBusConnection connection = proxy.connection();
            QDBusReply<bool> reply =
                    connection.interface()->isServiceRegistered(CReporter::DialogServerServiceName);

            qDebug() << __PRETTY_FUNCTION__ << "Crash Reporter UI launched:" << reply.value();

            if (!reply.value()) {
                // Launcing UI failed.
                return false;
            }
        }
    }
    return true;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::autoDeleteEnabled
// ----------------------------------------------------------------------------
bool CReporterDaemonMonitor::autoDeleteEnabled()
{
    return d_ptr->autoDelete;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::setAutoDelete
// ----------------------------------------------------------------------------
void CReporterDaemonMonitor::setAutoDelete(bool state)
{
    d_ptr->autoDelete = state;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::autoDeleteMaxSimilarCores
// ----------------------------------------------------------------------------
int CReporterDaemonMonitor::autoDeleteMaxSimilarCores()
{
    return d_ptr->autoDeleteMaxSimilarCores;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::setAutoDeleteMaxSimilarCores
// ----------------------------------------------------------------------------
void CReporterDaemonMonitor::setAutoDeleteMaxSimilarCores(int value)
{
    d_ptr->autoDeleteMaxSimilarCores = value;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::autoUploadEnabled
// ----------------------------------------------------------------------------
bool CReporterDaemonMonitor::autoUploadEnabled()
{
    return d_ptr->autoUpload;
}

// ----------------------------------------------------------------------------
// CReporterDaemonMonitor::setAutoUpload
// ----------------------------------------------------------------------------
void CReporterDaemonMonitor::setAutoUpload(bool state)
{
    d_ptr->autoUpload = state;
    if (!state)
    {
        qDebug() << __PRETTY_FUNCTION__ << "Calling quit() on Auto Uploader.";
        CReporterAutoUploaderProxy proxy(CReporter::AutoUploaderServiceName,
                                         CReporter::AutoUploaderObjectPath, QDBusConnection::sessionBus());

        QDBusPendingReply <bool> reply = proxy.quit();
        // This blocks.
        reply.waitForFinished();
    }
}

// End of file.
<|endoftext|>


<commit_before>#include "TrimImage.h"
#include "check_params.h"

#include <drag2d.h>
#include <easyimage.h>

namespace edb
{

std::string TrimImage::Command() const
{
	return "trim-image";
}

std::string TrimImage::Description() const
{
	return "trim image, clip blank part";
}

std::string TrimImage::Usage() const
{
	return Command() + " [dir path]";
}

void TrimImage::Run(int argc, char *argv[])
{
	// trim-image e:/test2/1001

	if (!check_number(this, argc, 3)) return;
	if (!check_folder(argv[2])) return;

	Trigger(argv[2]);
}

void TrimImage::Trigger(const std::string& dir)
{
	wxArrayString files;
	d2d::FilenameTools::fetchAllFiles(dir, files);
	for (int i = 0, n = files.size(); i < n; ++i)
	{
		wxFileName filename(files[i]);
		filename.Normalize();
		wxString filepath = filename.GetFullPath();
		if (d2d::FileNameParser::isType(filepath, d2d::FileNameParser::e_image))
		{
			d2d::Image* img = d2d::ImageMgr::Instance()->getItem(filepath);
			eimage::ImageProcessor proc(img);
			d2d::Rect r = proc.trim();
			const unsigned char* pixels = proc.clip(r.xMin, r.xMax, r.yMin, r.yMax);
			d2d::ImageSaver::storeToFile(pixels, r.xLength(), r.yLength(),
				filepath.ToStdString(), d2d::ImageSaver::e_png);
		}
	}
}

}<commit_msg>[CHANGED] trimimage 命令改成trim<commit_after>#include "TrimImage.h"
#include "check_params.h"

#include <drag2d.h>
#include <easyimage.h>

namespace edb
{

std::string TrimImage::Command() const
{
	return "trim";
}

std::string TrimImage::Description() const
{
	return "trim image, clip blank part";
}

std::string TrimImage::Usage() const
{
	return Command() + " [dir path]";
}

void TrimImage::Run(int argc, char *argv[])
{
	// trim-image e:/test2/1001

	if (!check_number(this, argc, 3)) return;
	if (!check_folder(argv[2])) return;

	Trigger(argv[2]);
}

void TrimImage::Trigger(const std::string& dir)
{
	wxArrayString files;
	d2d::FilenameTools::fetchAllFiles(dir, files);
	for (int i = 0, n = files.size(); i < n; ++i)
	{
		wxFileName filename(files[i]);
		filename.Normalize();
		wxString filepath = filename.GetFullPath();
		if (d2d::FileNameParser::isType(filepath, d2d::FileNameParser::e_image))
		{
			d2d::Image* img = d2d::ImageMgr::Instance()->getItem(filepath);
			eimage::ImageProcessor proc(img);
			d2d::Rect r = proc.trim();
			const unsigned char* pixels = proc.clip(r.xMin, r.xMax, r.yMin, r.yMax);
			d2d::ImageSaver::storeToFile(pixels, r.xLength(), r.yLength(),
				filepath.ToStdString(), d2d::ImageSaver::e_png);
		}
	}
}

}<|endoftext|>


<commit_before>#ifndef __PROBABILITY_DISTRIBUTIONS__MIXTURE_HPP__
#define __PROBABILITY_DISTRIBUTIONS__MIXTURE_HPP__

#include "discrete.hpp"
#include "distribution.hpp"

#include "binary_combination.hpp"
#include "clean_tuple.hpp"
#include "clean_type.hpp"
#include "repeated_tuple.hpp"
#include "sequence.hpp"

#include <tuple>
#include <type_traits>

namespace ProbabilityDistributions {

  template <unsigned int SS, class D, class W = D, class T = W, class... Dists>
  class Mixture: public Distribution<D,W,T> {
    private:
      typedef typename CompileUtils::clean_tuple<Dists...>::type tuple_type;

    public:
      static constexpr unsigned int sample_size = SS;
      static constexpr unsigned int K = sizeof...(Dists);

      Mixture(Dists&&... dists);

      void set_stop_condition(T condition) { stop_condition_ = condition; }
      T get_stop_condition() const { return stop_condition_; }

      void set_max_iterations(size_t it) { max_iterations_ = it; }
      size_t get_max_iterations() const { return max_iterations_; }

      Discrete<K,D,W,T>& get_mixture_weights() { return mixture_weights_; }
      Discrete<K,D,W,T> const& get_mixture_weights() const {
        return mixture_weights_; }

      template <size_t I>
      typename std::tuple_element<I,tuple_type>::type& get_component() {
        return std::get<I>(components_); }
      template <size_t I>
      typename std::tuple_element<I,tuple_type>::type const& get_component() const {
        return std::get<I>(components_); }

      Distribution<D,W,T>* get_component_pointer(size_t i) {
        return components_pointers_[i]; }
      Distribution<D,W,T> const* get_component_pointer(size_t i) const {
        return components_pointers_[i]; }

      template <class RNG>
      void sample(MA::Array<D>& samples, size_t n_samples, RNG& rng) const;

      using Distribution<D,W,T>::log_likelihood;
      T log_likelihood(MA::ConstArray<D> const& data,
          MA::ConstArray<W> const& weight) const;
      T log_likelihood(MA::ConstArray<D> const& data,
          std::vector<unsigned int> const& labels) const;

      using Distribution<D,W,T>::MLE;
      void MLE(MA::ConstArray<D> const& data, MA::ConstArray<W> const& weight,
          std::vector<size_t> const& indexes = std::vector<size_t>());

    private:
      void check_data_and_weight(MA::ConstArray<D> const& data,
          MA::ConstArray<W> const& weight) const;

      template <size_t... S>
      void create_component_pointers(CompileUtils::sequence<S...>);

      template <class RNG, size_t... S>
      void sample_components(MA::Array<D>& sample, size_t component_id,
          RNG& rng, CompileUtils::sequence<S...>) const;

      template <size_t I, class RNG>
      bool sample_component(MA::Array<D>& sample, size_t component_id,
          RNG& rng) const;

      T internal_log_likelihood(MA::ConstArray<D> const& data,
          MA::ConstArray<W> const& expected_weight) const;

      void build_expectation(MA::Array<W>& expected_weight,
          MA::ConstArray<W> const& weight, MA::ConstArray<D> const& data) const;

      MA::Array<W> transpose(MA::Array<W> const& original) const;

      T stop_condition_;
      size_t max_iterations_;
      Discrete<K,D,W,T> mixture_weights_;
      tuple_type components_;
      std::vector<Distribution<D,W,T>*> components_pointers_;
  };

  template <class D1, class... Dists>
  Mixture<CompileUtils::clean_type<D1>::type::sample_size,
          typename CompileUtils::clean_type<D1>::type::data_type,
          typename CompileUtils::clean_type<D1>::type::weight_type,
          typename CompileUtils::clean_type<D1>::type::float_type, D1, Dists...>
  make_mixture(D1&& dist1, Dists&&... dists) {
    const unsigned int n_dists = 1 + sizeof...(Dists);

    static_assert(std::is_same<
        std::tuple<typename CompileUtils::clean_type<D1>::type::data_type,
                   typename CompileUtils::clean_type<Dists>::type::data_type...>,
        typename CompileUtils::repeated_tuple<n_dists,
          typename CompileUtils::clean_type<D1>::type::data_type>::type
        >::value, "All distributions must have the same data type");
    static_assert(std::is_same<
        std::tuple<typename CompileUtils::clean_type<D1>::type::weight_type,
                   typename CompileUtils::clean_type<Dists>::type::weight_type...>,
        typename CompileUtils::repeated_tuple<n_dists,
          typename CompileUtils::clean_type<D1>::type::weight_type>::type
        >::value, "All distributions must have the same weight type");
    static_assert(std::is_same<
        std::tuple<typename CompileUtils::clean_type<D1>::type::float_type,
                   typename CompileUtils::clean_type<Dists>::type::float_type...>,
        typename CompileUtils::repeated_tuple<n_dists,
          typename CompileUtils::clean_type<D1>::type::float_type>::type
        >::value, "All distributions must have the same float type");
    static_assert(
        CompileUtils::and_<CompileUtils::clean_type<D1>::type::sample_size ==
        CompileUtils::clean_type<Dists>::type::sample_size...>::value,
        "All distributions must have the same sample size");

    return Mixture<CompileUtils::clean_type<D1>::type::sample_size,
           typename CompileUtils::clean_type<D1>::type::data_type,
           typename CompileUtils::clean_type<D1>::type::weight_type,
           typename CompileUtils::clean_type<D1>::type::float_type, D1,
           Dists...>(std::forward<D1>(dist1), std::forward<Dists>(dists)...);
  }
};

#include "mixture_impl.hpp"

#endif
<commit_msg>Added another static check to make_mixture.<commit_after>#ifndef __PROBABILITY_DISTRIBUTIONS__MIXTURE_HPP__
#define __PROBABILITY_DISTRIBUTIONS__MIXTURE_HPP__

#include "discrete.hpp"
#include "distribution.hpp"

#include "binary_combination.hpp"
#include "clean_tuple.hpp"
#include "clean_type.hpp"
#include "repeated_tuple.hpp"
#include "sequence.hpp"

#include <tuple>
#include <type_traits>

namespace ProbabilityDistributions {
  template <unsigned int SS, class D, class W = D, class T = W, class... Dists>
  class Mixture: public Distribution<D,W,T> {
    private:
      typedef typename CompileUtils::clean_tuple<Dists...>::type tuple_type;

    public:
      static constexpr unsigned int sample_size = SS;
      static constexpr unsigned int K = sizeof...(Dists);

      explicit Mixture(Dists&&... dists);

      void set_stop_condition(T condition) { stop_condition_ = condition; }
      T get_stop_condition() const { return stop_condition_; }

      void set_max_iterations(size_t it) { max_iterations_ = it; }
      size_t get_max_iterations() const { return max_iterations_; }

      Discrete<K,D,W,T>& get_mixture_weights() { return mixture_weights_; }
      Discrete<K,D,W,T> const& get_mixture_weights() const {
        return mixture_weights_; }

      template <size_t I>
      typename std::tuple_element<I,tuple_type>::type& get_component() {
        return std::get<I>(components_); }
      template <size_t I>
      typename std::tuple_element<I,tuple_type>::type const& get_component() const {
        return std::get<I>(components_); }

      Distribution<D,W,T>* get_component_pointer(size_t i) {
        return components_pointers_[i]; }
      Distribution<D,W,T> const* get_component_pointer(size_t i) const {
        return components_pointers_[i]; }

      template <class RNG>
      void sample(MA::Array<D>& samples, size_t n_samples, RNG& rng) const;

      using Distribution<D,W,T>::log_likelihood;
      T log_likelihood(MA::ConstArray<D> const& data,
          MA::ConstArray<W> const& weight) const;
      T log_likelihood(MA::ConstArray<D> const& data,
          std::vector<unsigned int> const& labels) const;

      using Distribution<D,W,T>::MLE;
      void MLE(MA::ConstArray<D> const& data, MA::ConstArray<W> const& weight,
          std::vector<size_t> const& indexes = std::vector<size_t>());

    private:
      void check_data_and_weight(MA::ConstArray<D> const& data,
          MA::ConstArray<W> const& weight) const;

      template <size_t... S>
      void create_component_pointers(CompileUtils::sequence<S...>);

      template <class RNG, size_t... S>
      void sample_components(MA::Array<D>& sample, size_t component_id,
          RNG& rng, CompileUtils::sequence<S...>) const;

      template <size_t I, class RNG>
      bool sample_component(MA::Array<D>& sample, size_t component_id,
          RNG& rng) const;

      T internal_log_likelihood(MA::ConstArray<D> const& data,
          MA::ConstArray<W> const& expected_weight) const;

      void build_expectation(MA::Array<W>& expected_weight,
          MA::ConstArray<W> const& weight, MA::ConstArray<D> const& data) const;

      MA::Array<W> transpose(MA::Array<W> const& original) const;

      T stop_condition_;
      size_t max_iterations_;
      Discrete<K,D,W,T> mixture_weights_;
      tuple_type components_;
      std::vector<Distribution<D,W,T>*> components_pointers_;
  };

  template <class D1, class... Dists>
  Mixture<CompileUtils::clean_type<D1>::type::sample_size,
          typename CompileUtils::clean_type<D1>::type::data_type,
          typename CompileUtils::clean_type<D1>::type::weight_type,
          typename CompileUtils::clean_type<D1>::type::float_type, D1, Dists...>
  make_mixture(D1&& dist1, Dists&&... dists) {
    const unsigned int n_dists = 1 + sizeof...(Dists);

    static_assert(std::is_same<
        std::tuple<typename CompileUtils::clean_type<D1>::type::data_type,
                   typename CompileUtils::clean_type<Dists>::type::data_type...>,
        typename CompileUtils::repeated_tuple<n_dists,
          typename CompileUtils::clean_type<D1>::type::data_type>::type
        >::value, "All distributions must have the same data type");
    static_assert(std::is_same<
        std::tuple<typename CompileUtils::clean_type<D1>::type::weight_type,
                   typename CompileUtils::clean_type<Dists>::type::weight_type...>,
        typename CompileUtils::repeated_tuple<n_dists,
          typename CompileUtils::clean_type<D1>::type::weight_type>::type
        >::value, "All distributions must have the same weight type");
    static_assert(std::is_same<
        std::tuple<typename CompileUtils::clean_type<D1>::type::float_type,
                   typename CompileUtils::clean_type<Dists>::type::float_type...>,
        typename CompileUtils::repeated_tuple<n_dists,
          typename CompileUtils::clean_type<D1>::type::float_type>::type
        >::value, "All distributions must have the same float type");
    static_assert(
        CompileUtils::and_<CompileUtils::clean_type<D1>::type::sample_size ==
        CompileUtils::clean_type<Dists>::type::sample_size...>::value,
        "All distributions must have the same sample size");

    typedef Distribution<
      typename CompileUtils::clean_type<D1>::type::data_type,
      typename CompileUtils::clean_type<D1>::type::weight_type,
      typename CompileUtils::clean_type<D1>::type::float_type> base_distribution;

    static_assert(
        CompileUtils::and_<
          std::is_base_of<base_distribution,
                          typename CompileUtils::clean_type<D1>::type>::value,
          std::is_base_of<base_distribution,
                          typename CompileUtils::clean_type<Dists>::type>::value...
          >::value,
          "Distributions must be derived from abstract distribution class");

    return Mixture<CompileUtils::clean_type<D1>::type::sample_size,
           typename CompileUtils::clean_type<D1>::type::data_type,
           typename CompileUtils::clean_type<D1>::type::weight_type,
           typename CompileUtils::clean_type<D1>::type::float_type, D1,
           Dists...>(std::forward<D1>(dist1), std::forward<Dists>(dists)...);
  }
};

#include "mixture_impl.hpp"

#endif
<|endoftext|>