void trigger(DataObject<D>& d) {
        boost::shared_lock_guard<boost::shared_mutex> lock(d._mtx_links);

        if (d._links.empty())
            return;

        for (auto &p : d._links)
            _tbbExecutionQueue.push(p.second);
    }
bool computeBiasFeaturesHelper(ParserT& parser,
                               tbb::concurrent_bounded_queue<TranscriptFeatures>& featQueue,
                               size_t& numComplete, size_t numThreads) {

    using stream_manager = jellyfish::stream_manager<std::vector<std::string>::iterator>;
    using sequence_parser = jellyfish::whole_sequence_parser<stream_manager>;

    size_t merLen = 2;
    Kmer lshift(2 * (merLen - 1));
    Kmer masq((1UL << (2 * merLen)) - 1);
    std::atomic<size_t> readNum{0};

    size_t numActors = numThreads;
    std::vector<std::thread> threads;
    auto tstart = std::chrono::steady_clock::now();

    for (auto i : boost::irange(size_t{0}, numActors)) {
        threads.push_back(std::thread(
	        [&featQueue, &numComplete, &parser, &readNum, &tstart, lshift, masq, merLen, numActors]() -> void {

                size_t cmlen, numKmers;
                jellyfish::mer_dna_ns::mer_base_dynamic<uint64_t> kmer(merLen);

                // while there are transcripts left to process
                while (true) { //producer.nextRead(s)) {
                    sequence_parser::job j(parser);
                    // If this job is empty, then we're done
                    if (j.is_empty()) { return; }

                    for (size_t i=0; i < j->nb_filled; ++i) {
                        ++readNum;
                        if (readNum % 100 == 0) {
                            auto tend = std::chrono::steady_clock::now();
                            auto sec = std::chrono::duration_cast<std::chrono::seconds>(tend-tstart);
                            auto nsec = sec.count();
                            auto rate = (nsec > 0) ? readNum / sec.count() : 0;
                            std::cerr << "processed " << readNum << " transcripts (" << rate << ") transcripts/s\r\r";
                        }

                        // we iterate over the entire read
                        const char* start     = j->data[i].seq.c_str();
                        uint32_t readLen      = j->data[i].seq.size();
                        const char* const end = start + readLen;

                        TranscriptFeatures tfeat{};

                        // reset all of the counts
                        numKmers = 0;
                        cmlen = 0;
                        kmer.polyA();

                        // the maximum number of kmers we'd have to store
                        uint32_t maxNumKmers = (readLen >= merLen) ? readLen - merLen + 1 : 0;
                        if (maxNumKmers == 0) { featQueue.push(tfeat); continue; }

                        // The transcript name
                        std::string fullHeader(j->data[i].header);
                        tfeat.name = fullHeader.substr(0, fullHeader.find(' '));
                        tfeat.length = readLen;
                        auto nfact = 1.0 / readLen;

                        // iterate over the read base-by-base
                        size_t offset{0};
                        size_t numChars{j->data[i].seq.size()};
                        while (offset < numChars) {
                            auto c = jellyfish::mer_dna::code(j->data[i].seq[offset]);
                            kmer.shift_left(c);
                            if (jellyfish::mer_dna::not_dna(c)) {
                                cmlen = 0;
                                ++offset;
                                continue;
                            }
                            if (++cmlen >= merLen) {
                                size_t twomer = kmer.get_bits(0, 2*merLen);
                                tfeat.diNucleotides[twomer]++;
                                switch(c) {
                                    case jellyfish::mer_dna::CODE_G:
                                    case jellyfish::mer_dna::CODE_C:
                                        tfeat.gcContent += nfact;
                                        break;
                                }
                            }
                            ++offset;
                        } // end while

                        char lastBase = j->data[i].seq.back();
                        auto c = jellyfish::mer_dna::code(lastBase);
                        switch(c) {
                            case jellyfish::mer_dna::CODE_G:
                            case jellyfish::mer_dna::CODE_C:
                                tfeat.gcContent += nfact;
                                break;
                        }

                        featQueue.push(tfeat);
                    } // end job
                } // end while(true)
            } // end lambda
            ));

        } // actor loop

        for (auto& t : threads) { t.join(); ++numComplete; }
        return true;
}