#include <cstdio>
#include <fstream>
#include <algorithm>

#include "include/HypGraph.h"

#include <set>
#include <string>
#include <cstdlib>
#include <cmath>

using namespace std;

set<string> nodes;

set<pair<string, string>> edges;

map<string, set<string> > ancestors;
map<string, set<string> > children;

set<string> roots;

void out_tree(FILE *f, FILE *tol, string label, int lv) {
  fprintf(f, "%d %s 0 html\n", lv, label.c_str());
  fprintf(tol, "(%s", label.c_str());
  for(auto ch: children[label]) { fprintf(tol, ","); out_tree(f, tol, ch, lv+1); }
  fprintf(tol, ")");
  }

int main() {

  srand(123456);

  while(!feof(stdin)) {
    char buf1[100], buf2[100];
    buf1[0] = 0; buf2[0] = 0;
    scanf("%s%s", buf1, buf2);
    if(buf1[0] == 0) break;
    nodes.insert(buf1);
    nodes.insert(buf2);
    ancestors[buf1].insert(buf2);
    }

  fprintf(stderr, "read, nodes = %d\n", int(nodes.size()));

  auto check1 = ancestors.begin()->first;
  auto check2 = *ancestors[check1].begin();
  if(ancestors[check2].count(check1)) {
    fprintf(stderr, "undirected graph\n");
    vector<string> nodes;
    for(auto& s: ancestors) nodes.push_back(s.first);
    for(int i=1; i<int(nodes.size()); i++) swap(nodes[i], nodes[rand() % (i+1)]);
    sort(nodes.begin(), nodes.end(), [] (string a, string b) { return ancestors[a].size() > ancestors[b].size(); });
    set<string> in_tree;
    while(in_tree.size() < nodes.size()) for(string s: nodes) {
      if(in_tree.empty()) {
        in_tree.insert(s); roots.insert(s);
        }
      else if(in_tree.count(s)) ;
      else {
        vector<string> in;
        for(auto v: ancestors[s]) if(in_tree.count(v)) in.push_back(v);
        if(!in.empty()) {
          auto w = in[rand() % in.size()];
          in_tree.insert(s);
          children[w].insert(s);
          }
        }
      }
    }
  else {
    for(auto w: nodes) {
      auto anc = ancestors[w];
      for(auto u1: anc) for(auto u2: ancestors[u1]) anc.erase(u2);
      if(anc.size() == 0) { roots.insert(w); continue; }
      int q = 0;
      if(anc.size() > 1) {
        fprintf(stderr, "too many ancestors (%d) for %s\n", int(anc.size()), w.c_str()); q = rand() % anc.size();
        }
      auto b = anc.begin(); for(int i=0; i<q; i++) b++;
      children[*b].insert(w);
      }

    fprintf(stderr, "number of roots = %d\n", roots.size());
    }

  if(1) {
    FILE *f = fopen("/tmp/treedata.txt", "wt");
    FILE *tol = fopen("/tmp/treedata-tol.txt", "wt");
    if(roots.size() > 1) { fprintf(f, "-1 TOP 0 host\n"); fprintf(tol, "(TOP"); }
    for(auto r: roots) { if(roots.size() > 1) fprintf(tol, ","); out_tree(f, tol, r, 0); }
    fclose(f); 
    if(roots.size() > 1) fprintf(tol, ")");
    fclose(tol);
    }

  HypData hd;
  ifstream f("/tmp/treedata.txt");
  HypGraph hg(&hd, f);

  HypPoint zero; zero.x = 0; zero.y = 0; zero.z = 0; zero.w = 1;

  double maxw = 0;

  for(auto n: nodes) {
    auto po = hg.getNodePosition(n);
    HypPoint pox = po.transformPoint(zero);
    maxw = max(maxw, pox.w);
    // printf("%f %f %f %f %s\n", pox.x, pox.y, pox.z, pox.w, n.c_str());
    printf("%s\n%30.25f\n%30.25f\n%30.25f\n", 
      n.c_str(), 
      pox.x / (pox.w+1), 
      pox.y / (pox.w+1), 
      pox.z / (pox.w+1)
      );
    }

  fprintf(stderr, "radius = %f\n", acosh(maxw));
  // printf("flat = %s\n", hg.saveTree().c_str());

  return 0;
  }
