import std.algorithm, std.conv, std.regex, std.range, std.stdio, std.string, std.ascii;

struct PersonaData
{
    uint totalWordsSpoken;
    uint[string] wordCount;
}

void addParagraph(string line, ref PersonaData[string] info)
{
    // Вы­де­лить имя пер­со­на­жа и его ре­п­ли­ку
    line = strip(line);
    // auto sentence = std.algorithm.find(line, ". ");
    auto sentence = line.find(". ");    
    if (sentence.empty)
    {
        return;
    }
    auto persona = line[0 .. $ - sentence.length];
    sentence = toLower(strip(sentence[2 .. $]));
    // Вы­де­лить про­из­не­сен­ные сло­ва
    auto words = split(sentence, regex("[ \t,.;:?]+"));
    // Вставка или обновление информации
    if (!(persona in info))
    {
        // Пер­вая ре­п­ли­ка пер­со­на­жа
        info[persona] = PersonaData();
    }
    info[persona].totalWordsSpoken += words.length;
    foreach (word; words)
    {
        ++info[persona].wordCount[word];
    }
}

void printResults(PersonaData[string] info)
{
    foreach (persona, data; info)
    {
        writefln("%20s %6u %6u", persona, data.totalWordsSpoken, data.wordCount.length);
    }
}

void main()
{
    // На­ка­пл­и­ва­ет ин­фор­ма­цию о глав­ных ге­ро­ях
    PersonaData[string] info;
    // За­пол­нить info
    string currentParagraph;
    foreach (line; stdin.byLine())
    {
        // 4 символа отступа
        if (line.startsWith("    ") && line.length > 4 && isAlpha(line[4]))
        {
            // Пер­со­наж про­дол­жа­ет вы­ска­зы­ва­ние
            currentParagraph ~= line[3 .. $];
        }
        // 2 символа отступа
        else if (line.startsWith("  ") && line.length > 2 && isAlpha(line[2]))
        {
            // Пер­со­наж толь­ко что на­чал го­во­рить
            addParagraph(currentParagraph, info);
            currentParagraph = to!string(line[2 .. $]);
        }
    }
    // За­кон­чи­ли, те­перь на­пе­ча­та­ем со­б­ран­ную ин­фор­ма­цию
    printResults(info);
}
