int main() {
    InputData* data = new InputData();

    while (fgets(data->buffer, data->capacity, stdin))
        if (strncmp(data->buffer, ">THREE", 6) == 0)
            break;

    int cpus = numCPUS();
    WorkerThread threads[cpus];
    for (int i = 0; i<cpus-1; i++) {
        pthread_create(&(threads[i].pthread), NULL, (void *(*)(void *))doWork, &threads[i]);
    }

    size_t totalBytesRead = 0;
    while (fgets(&data->buffer[data->length], (data->capacity + 1) - data->length, stdin)) {
        data->length += strlen(&data->buffer[data->length]);
        if (data->buffer[data->length-1] == '\n') {
            data->buffer[--(data->length)] == 0;
        }

        if (data->length == data->capacity) {
            data->addToWorkList();
            totalBytesRead += data->length;
            data = new InputData(*data);
        }
    }

    if (data->length) {
        totalBytesRead += data->length;
        data->addToWorkList();
    }

    moreWorkIsPossible = 0;
    doWork(&threads[cpus-1]);
    for (int i=0; i<cpus-1; i++) {
        pthread_join(threads[i].pthread, NULL);
    }

    printFreq<1>(threads, cpus, (float)totalBytesRead);
    printFreq<2>(threads, cpus, (float)(totalBytesRead - 1));

    printCount<3>(threads, cpus, fragments[2]);
    printCount<4>(threads, cpus, fragments[3]);
    printCount<6>(threads, cpus, fragments[4]);
    printCount<12>(threads, cpus, fragments[5]);
    printCount<18>(threads, cpus, fragments[6]);

    return 0;
}