Problem: There are some websites that are accessible through several different addresses. For example, for a long time Codeforces was accessible with two hostnames codeforces.com and codeforces.ru.

You are given a list of page addresses being queried. For simplicity we consider all addresses to have the form http://<hostname>[/<path>], where:

  * <hostname> — server name (consists of words and maybe some dots separating them), 
  * /<path> — optional part, where <path> consists of words separated by slashes. 



We consider two <hostname> to correspond to one website if for each query to the first <hostname> there will be exactly the same query to the second one and vice versa — for each query to the second <hostname> there will be the same query to the first one. Take a look at the samples for further clarifications.

Your goal is to determine the groups of server names that correspond to one website. Ignore groups consisting of the only server name.

Please note, that according to the above definition queries http://<hostname> and http://<hostname>/ are different.

Input

The first line of the input contains a single integer n (1 ≤ n ≤ 100 000) — the number of page queries. Then follow n lines each containing exactly one address. Each address is of the form http://<hostname>[/<path>], where:

  * <hostname> consists of lowercase English letters and dots, there are no two consecutive dots, <hostname> doesn't start or finish with a dot. The length of <hostname> is positive and doesn't exceed 20. 
  * <path> consists of lowercase English letters, dots and slashes. There are no two consecutive slashes, <path> doesn't start with a slash and its length doesn't exceed 20. 



Addresses are not guaranteed to be distinct.

Output

First print k — the number of groups of server names that correspond to one website. You should count only groups of size greater than one.

Next k lines should contain the description of groups, one group per line. For each group print all server names separated by a single space. You are allowed to print both groups and names inside any group in arbitrary order.

Examples

Input

10
http://abacaba.ru/test
http://abacaba.ru/
http://abacaba.com
http://abacaba.com/test
http://abacaba.de/
http://abacaba.ru/test
http://abacaba.de/test
http://abacaba.com/
http://abacaba.com/t
http://abacaba.com/test


Output

1
http://abacaba.de http://abacaba.ru 


Input

14
http://c
http://ccc.bbbb/aba..b
http://cba.com
http://a.c/aba..b/a
http://abc/
http://a.c/
http://ccc.bbbb
http://ab.ac.bc.aa/
http://a.a.a/
http://ccc.bbbb/
http://cba.com/
http://cba.com/aba..b
http://a.a.a/aba..b/a
http://abc/aba..b/a


Output

2
http://cba.com http://ccc.bbbb 
http://a.a.a http://a.c http://abc 

Solution (in JAVA):

Solution:
import java.io.*;
import java.util.*;
import java.security.*;

import static java.lang.StrictMath.*;

public class HostnameAliases {

    private static final String INPUT_FILE = "input.txt";
    
    private static final String ONLINE_JUDGE = "ONLINE_JUDGE";

    public static void main(String[] args) {
        boolean oj = System.getProperty(ONLINE_JUDGE) != null;

        try {
            InputReader reader = new InputReader(oj ? System.in : new FileInputStream(INPUT_FILE));
            PrintWriter writer = new PrintWriter(System.out);
            new Solver(reader).run(writer);
            writer.close();
        }
        catch (IOException e) {
            new RuntimeException(e);
        }
    }
}

class Solver {

    public static final int HOST_NAME_BEGIN_POSITION = 7;

    public Solver(InputReader reader) throws IOException {
        n = reader.nextInt();
        a = new String[n];
        for (int i = 0; i < n; ++i) {
            a[i] = reader.next();
        }
        try {
            hasher = MessageDigest.getInstance("SHA-1"); 
        }
        catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    public void run(PrintWriter writer) throws IOException {
        hosts = new TreeSet<>();
        temp = new Host("");
        for (String s: a) {
            add(s);
        }
        descriptors = new TreeSet<>();
        StringBuilder sb = new StringBuilder();
        int multiCount = 0;
        for (Host host: hosts) {
            if (add(sb, host)) {
               ++multiCount; 
            }
        }
        writer.println(multiCount);
        for (HostDescriptor desc: descriptors) {
            if (desc.isMulti()) {
                desc.print(writer);
            }
        }
    }

    private boolean add(StringBuilder sb, Host host) {
        HostDescriptor desc = new HostDescriptor(host, sb, hasher);
        HostDescriptor exist = descriptors.floor(desc);
        if (exist != null && exist.compareTo(desc) == 0) {
            return exist.addName(host.name);
        }
        else {
            descriptors.add(desc);
            return false;
        }
    }

    private void add(String address) {
        int p = findBeginPathPosition(address);
        String host = getHost(p, address);
        String path = getPath(p, address);
        add(host, path);
    }

    private void add(String host, String path) {
        temp.name = host;
        Host h = hosts.floor(temp);
        if (h == null || !h.name.equals(host)) {
            h = new Host(host);
            hosts.add(h);
        }
        h.pathes.add(path);
    }

    private String getHost(int p, String address) {
        return p == -1 ? 
            address.substring(HOST_NAME_BEGIN_POSITION) : 
            address.substring(HOST_NAME_BEGIN_POSITION, p);
    }

    private String getPath(int p, String address) {
        return p == -1 ? "" : address.substring(p);
    }

    private int findBeginPathPosition(String address) {
        return address.indexOf("/", HOST_NAME_BEGIN_POSITION);
    }

    private Host temp;
    private TreeSet<Host> hosts;

    private MessageDigest hasher;
    private TreeSet<HostDescriptor> descriptors;

    private int n;
    private String[] a;
}

class Host implements Comparable<Host> {

    public Host(String name) {
        this.name = name; 
        pathes = new TreeSet<String>();
    }

    @Override
    public int compareTo(Host other) {
        return name.compareTo(other.name);
    }

    String name;
    Set<String> pathes;
}

class HostDescriptor implements Comparable<HostDescriptor> {

    public HostDescriptor(Host host, StringBuilder sb, MessageDigest md) {

        pathesCount = host.pathes.size();

        joinedPathes = join(sb, host.pathes);
        hashes = md.digest(joinedPathes.getBytes()); 

        aliases = new ArrayList<String>();
        aliases.add(host.name);
    }

    public boolean addName(String name) {
        aliases.add(name);
        return aliases.size() == 2;
    }

    public boolean isMulti() {
        return aliases.size() > 1;
    }

    public void print(PrintWriter writer) {
        boolean first = true;
        for (String name: aliases) {
            if (first) {
                first = false;
            }
            else {
                writer.print(' ');
            }
            writer.print("http://");
            writer.print(name);
        }
        writer.println();
    }

    @Override
    public int compareTo(HostDescriptor other) {
        if (pathesCount != other.pathesCount) {
            return pathesCount - other.pathesCount;
        }
        return compareArrays(hashes, other.hashes);
    }

    private int compareArrays(byte[] a1, byte[] a2) {
        for (int i = 0; i < a1.length; ++i) {
            if (a1[i] != a2[i]) {
                return a1[i] < a2[i] ? -1 : 1;
            }
        }
        return 0;
    }

    private String join(StringBuilder sb, Set<String> l) {
        sb.setLength(0);
        for (String i: l) {
            sb.append("!&)");
            sb.append(i);
        }
        return sb.toString();
    }

    private int pathesCount;

    private byte[] hashes;

    private String joinedPathes;

    private List<String> aliases;
}

interface IStringMultiHasher {

    public int[] getHash(String s);
}

class StringMultiHasher implements IStringMultiHasher {

    public StringMultiHasher(int size) {
        this.size = size;
        hasher = new IStringHasher[size];
        for (int i = 0; i < size; ++i) {
            hasher[i] = new StringHasher();
        }
    }

    @Override
    public int[] getHash(String s) {
        int[] r = new int[size]; 
        for (int i = 0; i < size; ++i) {
            r[i] = hasher[i].getHash(s);
        }
        return r;
    }

    private int size;
    private IStringHasher hasher[];

    public static int compareArrays(int[] a, int[] b) {
        for (int i = 0; i < a.length; ++i) {
            if (a[i] != b[i]) {
                return a[i]-b[i];
            }
        }
        return 0;
    }
}

interface IStringHasher {
    
    public int getHash(String s);
}

class StringHasher implements IStringHasher {

    public static final int MIN_BASE = 127;
    public static final int MAX_BASE = 255;

    public static final int MIN_MODULE = 1_000_000;
    public static final int MAX_MODULE = 2_000_000;

    public StringHasher() {
        Random rng = getRNG();
        base = getNextPrime(getRandom(MIN_BASE, MAX_BASE, rng));
        module = getNextPrime(getRandom(MIN_MODULE, MAX_MODULE, rng));
        init = rng.nextInt(module);
    }

    @Override
    public int getHash(String s) {
        int hash = init;
        for (char c: s.toCharArray()) {
            hash *= base;
            hash += c;
            hash %= module;
        }
        return hash;
    }

    private int getNextPrime(int x) {
        while (!isPrime(x)) {
            ++x;
        }
        return x;
    }

    private int getRandom(int lo, int hi, Random rng) {
        return lo + rng.nextInt(hi-lo);
    }

    private boolean isPrime(int x) {
        for (int i = 2; i*i <= x; ++i) {
            if (x%i == 0) {
                return false;
            }
        }
        return true;
    }

    private Random getRNG() {
        return new Random(calls++); 
    }

    private static int calls;

    private int init;
    private int base;
    private int module;

}

class InputReader {
 	
    public BufferedReader reader;
    public StringTokenizer tokenizer;

    public InputReader(InputStream stream) {
        reader = new BufferedReader(new InputStreamReader(stream), 1<<15);
        tokenizer = null;
    }

    public String next() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }

    public int nextInt() {
        return Integer.parseInt(next());
    }

}