#include <bits/stdc++.h>
using namespace std;
const double EPS = 1e-8;
const long long INF = 0x3f3f3f3f3f3f3f3f;
inline bool Equal(double x, double y) { return (x < y + EPS && x > y - EPS); }
inline bool Larger(double x, double y) { return (x > y + EPS); }
inline bool Less(double x, double y) { return (x < y - EPS); }
inline long long UB(vector<long long> &v, long long x) {
  return upper_bound(v.begin(), v.end(), x) - v.begin();
}
inline long long LB(vector<long long> &v, long long x) {
  return lower_bound(v.begin(), v.end(), x) - v.begin();
}
const long long Mod = 10;
inline long long PowMod(long long a, long long b) {
  long long res = 1;
  a %= Mod;
  assert(b >= 0);
  for (; b; b >>= 1) {
    if (b & 1) res = res * a % Mod;
    a = a * a % Mod;
  }
  return res;
}
bool uMin(long long &a, long long b) { return a > b ? (a = b, true) : false; }
bool uMax(long long &a, long long b) { return a < b ? (a = b, true) : false; }
const long long MxSize = 1000006;
long long depth = 0;
string nodes[MxSize];
long long nodeHead = 1;
class StringDigitReader {
 private:
  char buff[MxSize];

 public:
  string src;
  friend istream &operator>>(istream &ins, StringDigitReader &sdr) {
    ins >> sdr.src;
    return ins;
  }
  long long SkipUntil(long long startId, char skipChar) {
    while (startId < src.length() && src[startId] != skipChar) startId++;
    return startId;
  }
  long long SkipNonDigitString(long long startId) {
    while (startId < src.length() && (src[startId] < '0' || src[startId] > '9'))
      startId++;
    return startId;
  }
  long long ReadInt(long long startId, char thousandChar, long long &result) {
    long long cnt = 0;
    while (startId < src.length() &&
           (src[startId] >= '0' && src[startId] <= '9' ||
            src[startId] == thousandChar)) {
      buff[cnt++] = src[startId++];
    }
    result = 0;
    for (size_t i = 0; i < cnt; i++)
      if (buff[i] != thousandChar) {
        result = result * 10 + buff[i] - '0';
      }
    return startId;
  }
  long long ReadDouble(long long startId, char thousandChar, double &result) {
    long long cnt = 0;
    while (startId < src.length() &&
           (src[startId] == '.' || src[startId] == thousandChar ||
            (src[startId] >= '0' && src[startId] <= '9'))) {
      buff[cnt++] = src[startId++];
    }
    result = 0;
    if (cnt >= 4 && buff[cnt - 3] == '.') {
      double factor = 0.1;
      for (size_t i = 0; i < cnt; i++) {
        if (i < cnt - 3 && buff[i] == thousandChar) continue;
        if (i < cnt - 3)
          result = result * 10 + buff[i] - '0';
        else if (i > cnt - 3) {
          result += (buff[i] - '0') * factor;
          factor /= 10;
        }
      }
    } else {
      for (size_t i = 0; i < cnt; i++) {
        if (buff[i] == thousandChar) continue;
        result = result * 10 + buff[i] - '0';
      }
    }
    return startId;
  }
};
StringDigitReader sr;
void onSideEnumerating(long long x, long long y, long long weight);
void BeforeGroupDetection_inDFS(long long x);
bool CanAddPointToGroup_inDFS(long long x);
void AddingNewPointToGroup_inDFS(long long x);
void AfterGroupDetected_inDFS(long long x);
void BeforeProcess_inDP(long long x);
void EnteringNode_inDP(long long x);
long long LeavingNode_inDP(long long x);
void HandleSubNodeResult_inDP(long long x, long long y, long long returnValue);
void AfterProcess_inDP(long long x);
void BeforeProcess_inBFS(long long x);
void VisitingNode_inBFS(long long x, long long lv);
void AfterProcess_inBFS(long long x);
class VectorArrayBasedGraphics {
 private:
  long long dFrom, dTo;
  vector<pair<long long, long long>> p[MxSize];

 public:
  VectorArrayBasedGraphics() {
    dFrom = 0;
    dTo = 0;
  }
  ~VectorArrayBasedGraphics() {}
  void Initialize(long long dataIdFrom, long long dataIdTo) {
    dFrom = dataIdFrom;
    dTo = dataIdTo;
    for (long long i = dataIdFrom; i <= dataIdTo; i++) {
      p[i].clear();
    }
  }
  void AddSide(long long v1, long long v2, long long weight = 1,
               bool isTwoWay = true) {
    p[v1].push_back(make_pair(v2, weight));
    if (isTwoWay) p[v2].push_back(make_pair(v1, weight));
  }
  template <typename T2>
  void CombineSamePropertyNodes(T2 propertyArray[], long long beginID,
                                long long endID) {
    for (long long i = beginID; i <= endID; i++) {
      for (vector<pair<long long, long long>>::iterator it = p[i].begin();
           it != p[i].end();) {
        if (propertyArray[i] == propertyArray[*it]) {
          long long itv = it->first;
          it = p[i].erase(it);
          for (vector<pair<long long, long long>>::iterator tit =
                   p[itv].begin();
               tit != p[itv].end(); tit++) {
            long long titv = tit->first;
            if (i == titv) continue;
            long long offset = it - p[i].begin();
            p[i].push_back(*tit);
            it = p[i].begin() + offset;
            for (vector<pair<long long, long long>>::iterator soManyIt =
                     p[titv].begin();
                 soManyIt != p[titv].end(); soManyIt++) {
              if (soManyIt->first == itv) {
                p[titv].erase(soManyIt);
                break;
              }
            }
            p[titv].push_back(make_pair(i, 0));
          }
          p[itv].clear();
        } else {
          it++;
        }
      }
    }
  }

 private:
  long long visitOrder[MxSize];
  long long level[MxSize];

 public:
  void Start_BFS_Process(long long root) {
    memset(visitOrder + dFrom, -1, sizeof(long long) * (dTo - dFrom + 1));
    memset(level + dFrom, 0, sizeof(long long) * (dTo - dFrom + 1));
    BeforeProcess_inBFS(root);
    bfs(root);
    AfterProcess_inBFS(root);
  }
  void bfs(long long node) {
    long long head = 0;
    long long tail = 1;
    visitOrder[head] = node;
    level[head] = 0;
    long long currentLevel = 0;
    while (head < tail) {
      node = visitOrder[head];
      currentLevel = level[head];
      head++;
      VisitingNode_inBFS(node, currentLevel);
      for (long long i = 0; i < p[node].size(); i++) {
        long long tNode = p[node][i].first;
        visitOrder[tail] = tNode;
        level[tail] = currentLevel + 1;
        tail++;
      }
    }
  }
};
VectorArrayBasedGraphics g;
void onSideEnumerating(long long node, long long y, long long weight) {}
void BeforeGroupDetection_inDFS(long long node) {}
bool CanAddPointToGroup_inDFS(long long node) { return true; }
void AddingNewPointToGroup_inDFS(long long node) {}
void AfterGroupDetected_inDFS(long long node) {}
void BeforeProcess_inDP(long long node) {}
void EnteringNode_inDP(long long node) {}
long long LeavingNode_inDP(long long node) { return 0; }
void HandleSubNodeResult_inDP(long long node, long long to,
                              long long returnValue) {}
void AfterProcess_inDP(long long node) {}
long long cLv;
void BeforeProcess_inBFS(long long node) { cLv = 0; }
void VisitingNode_inBFS(long long node, long long lv) {
  if (lv != cLv) cout << endl;
  cLv = lv;
  if (node != 0) cout << nodes[node] << ' ';
}
void AfterProcess_inBFS(long long node) {}
void AppendNode(long long &id, long long father, long long dep) {
  dep++;
  if (dep > depth) depth = dep;
  long long curr = nodeHead++;
  long long newID;
  newID = sr.SkipUntil(id, ',');
  nodes[curr] = sr.src.substr(id, newID - id);
  g.AddSide(father, curr, 0LL, false);
  id = newID + 1;
  long long x;
  newID = sr.ReadInt(id, '_', x);
  id = newID + 1;
  for (long long i = 0; i < x; i++) {
    AppendNode(id, curr, dep);
  }
}
int main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(0);
  cin >> sr;
  g.Initialize(0, MxSize - 2);
  long long id = 0;
  while (id < sr.src.length()) AppendNode(id, 0, 0);
  cout << depth;
  g.Start_BFS_Process(0);
  return 0;
}
