#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <sstream>

using namespace std;

struct Event {
    string id;
    string title;
    string acronym;
    string projectCode;
    string threeDigitCode;
    string recordType;
    string parentId;
};

// Pour parser une ligne CSV en tenant compte des guillemets échappés
vector<string> parseCSVLine(const string& line) {
    vector<string> result;
    stringstream ss(line);
    string item;
    bool inQuotes = false;
    string currentField;
    
    for (char ch : line) {
        if (ch == '"') {
            if (inQuotes && ss.peek() == '"') { // double quotes
                currentField += ch;
                ss.get();
            } else {
                inQuotes = !inQuotes;
            }
        } else if (ch == ',' && !inQuotes) {
            result.push_back(currentField);
            currentField.clear();
        } else {
            currentField += ch;
        }
    }
    result.push_back(currentField);
    return result;
}

bool compareEvents(const Event& a, const Event& b) {
    if (a.acronym != b.acronym) return a.acronym < b.acronym;
    if (a.recordType != b.recordType) return a.recordType == "Parent Event";
    if (a.title != b.title) return a.title < b.title;
    return a.id < b.id;
}

int main() {
    string line;
    vector<Event> events;
    map<string, vector<Event>> eventsByAcronym;
    
    // Lire les données
    while (getline(cin, line)) {
        vector<string> fields = parseCSVLine(line);
        if (fields.size() >= 6) {
            Event e;
            e.id = fields[0];
            e.title = fields[1];
            e.acronym = fields[2];
            e.projectCode = fields[3];
            e.threeDigitCode = fields[4];
            e.recordType = fields[5];
            if (fields.size() > 6) e.parentId = fields[6];
            
            if (!e.acronym.empty()) {
                events.push_back(e);
                eventsByAcronym[e.acronym].push_back(e);
            }
        }
    }
    
    // Traiter les données
    vector<Event> validEvents;
    for (auto& pair : eventsByAcronym) {
        vector<Event>& group = pair.second;
        
        // Compter les parents
        int parentCount = 0;
        Event* parent = nullptr;
        for (Event& e : group) {
            if (e.recordType == "Parent Event") {
                parentCount++;
                parent = &e;
            }
        }
        
        // Vérifier les conditions de validité
        if (parentCount == 1) {
            set<string> childCodes;
            vector<Event> children;
            
            for (Event& e : group) {
                if (e.recordType != "Parent Event") {
                    children.push_back(e);
                    if (!e.threeDigitCode.empty()) {
                        childCodes.insert(e.threeDigitCode);
                    }
                }
            }
            
            if (!children.empty()) {
                // Mettre à jour le code à 3 chiffres du parent
                if (childCodes.size() == 1) {
                    parent->threeDigitCode = *childCodes.begin();
                } else {
                    parent->threeDigitCode = "???";
                }
                
                // Ajouter le parent et ses enfants
                validEvents.push_back(*parent);
                for (Event& child : children) {
                    child.parentId = parent->id;
                    validEvents.push_back(child);
                }
            }
        }
    }
    
    // Trier et afficher les résultats
    sort(validEvents.begin(), validEvents.end(), compareEvents);
    
    for (const Event& e : validEvents) {
        cout << e.id << ",\"" << e.title << "\",\"" << e.acronym << "\"," 
             << e.projectCode << "," << e.threeDigitCode << ",\"" << e.recordType << "\"";
        if (!e.parentId.empty()) cout << "," << e.parentId;
        cout << "\n";
    }
    
    return 0;
}