Problem: A rare article in the Internet is posted without a possibility to comment it. On a Polycarp's website each article has comments feed.

Each comment on Polycarp's website is a non-empty string consisting of uppercase and lowercase letters of English alphabet. Comments have tree-like structure, that means each comment except root comments (comments of the highest level) has exactly one parent comment.

When Polycarp wants to save comments to his hard drive he uses the following format. Each comment he writes in the following format: 

  * at first, the text of the comment is written; 
  * after that the number of comments is written, for which this comment is a parent comment (i. e. the number of the replies to this comments); 
  * after that the comments for which this comment is a parent comment are written (the writing of these comments uses the same algorithm). 

All elements in this format are separated by single comma. Similarly, the comments of the first level are separated by comma.

For example, if the comments look like:

<image>

then the first comment is written as "hello,2,ok,0,bye,0", the second is written as "test,0", the third comment is written as "one,1,two,2,a,0,b,0". The whole comments feed is written as: "hello,2,ok,0,bye,0,test,0,one,1,two,2,a,0,b,0". For a given comments feed in the format specified above print the comments in a different format: 

  * at first, print a integer d — the maximum depth of nesting comments; 
  * after that print d lines, the i-th of them corresponds to nesting level i; 
  * for the i-th row print comments of nesting level i in the order of their appearance in the Policarp's comments feed, separated by space. 

Input

The first line contains non-empty comments feed in the described format. It consists of uppercase and lowercase letters of English alphabet, digits and commas. 

It is guaranteed that each comment is a non-empty string consisting of uppercase and lowercase English characters. Each of the number of comments is integer (consisting of at least one digit), and either equals 0 or does not contain leading zeros.

The length of the whole string does not exceed 106. It is guaranteed that given structure of comments is valid. 

Output

Print comments in a format that is given in the statement. For each level of nesting, comments should be printed in the order they are given in the input.

Examples

Input

hello,2,ok,0,bye,0,test,0,one,1,two,2,a,0,b,0


Output

3
hello test one 
ok bye two 
a b 


Input

a,5,A,0,a,0,A,0,a,0,A,0


Output

2
a 
A a A a A 


Input

A,3,B,2,C,0,D,1,E,0,F,1,G,0,H,1,I,1,J,0,K,1,L,0,M,2,N,0,O,1,P,0


Output

4
A K M 
B F H L N O 
C D G I P 
E J 

Note

The first example is explained in the statements. 

Solution (in CPP):

Solution:
#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:
  queue<pair<long long, long long>> que;

 public:
  void Start_BFS_Process(long long root) {
    BeforeProcess_inBFS(root);
    bfs(root);
    AfterProcess_inBFS(root);
  }
  void bfs(long long node) {
    long long lv = 0;
    que.push(make_pair(node, lv));
    while (!que.empty()) {
      node = que.front().first;
      lv = que.front().second;
      VisitingNode_inBFS(node, lv);
      long long tNode;
      for (long long i = 0; i < p[node].size(); i++) {
        tNode = p[node][i].first;
        que.push(make_pair(tNode, lv + 1));
      }
      que.pop();
    }
  }
};
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;
}