/*
 * hosts ファイルの整理
 *
 * author: Leonardone @ NEETSDKASU
 */
//package myapp.tool;

import java.lang.Comparable;
import java.lang.String;
import java.lang.System;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.SortedMap;
import java.util.TreeMap;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintStream;

class Hosts
{
	private static final String ARG_INPUT = "-i";
	private static final String ARG_TEMPLATE = "-t";
	private static final String ARG_OUTPUT = "-o";
	
	public static void main (String[] args) throws java.lang.Exception
	{
		Map<String, String> argmap = parseArgs(args);
		BufferedReader in = null;
		PrintStream out = null;
		
		try {
			if (argmap.containsKey(ARG_INPUT)) {
				in = new BufferedReader(new FileReader(argmap.get(ARG_INPUT)));
			} else {
				in = new BufferedReader(new InputStreamReader(System.in));
			}
			
			String line, ip;
			Map<String, String> ips = new HashMap<>();
			Tree tree = new Tree();
			
			while ((line = in.readLine()) != null) {
				if (line.matches("^\\s*(\\d{1,3}\\.){3}\\d{1,3}(\\s+([^\\.]+\\.)+[^\\.]+)+") == false) {
					continue;
				}
				String[] tokens = line.split("\\s");
				ip = null;
				for (String s : tokens) {
					if (s.length() > 0) {
						if (ip == null) {
							ip = s;
							if (ips.containsKey(ip)) {
								ip = ips.get(ip);
							} else {
								ips.put(ip, ip);
							}
						} else {
							tree.add(s, ip);
						}
					}
				}
			}
			
			if (argmap.containsKey(ARG_OUTPUT)) {
				out = new PrintStream(argmap.get(ARG_OUTPUT));
			} else {
				out = System.out;
			}
			
			printHeader(out, argmap.get(ARG_TEMPLATE));
			
			tree.print(out);
			
		} catch (java.lang.Exception ex) {
			throw ex;
		} finally {
			if (in != null && argmap.containsKey(ARG_INPUT)) {
				in.close();
			}
			if (out != null && argmap.containsKey(ARG_OUTPUT)) {
				out.flush();
				out.close();
			}
		}
	}
	
	private static void printHeader(PrintStream out, String filepath) throws java.lang.Exception
	{
		if (filepath == null) {
			out.println("# hosts");
			out.println();
			return;
		}
		BufferedReader in = null;
		try {
			in = new BufferedReader(new FileReader(filepath));
			String line;
			while ((line = in.readLine()) != null) {
				out.println(line);
			}
		} catch (java.lang.Exception ex) {
			throw ex;
		} finally {
			if (in != null) {
				in.close();
			}
		}
	}
	
	private static enum Flag
	{
		ANY, INPUT, OUPUT, TEMPLATE
	}
	
	private static Map<String, String> parseArgs(String args[])
	{
		Map<String, String> argmap = new HashMap<>();
		if (args == null) {
			return argmap;
		}
		Flag flag = Flag.ANY;
		for (String arg : args) {
			switch (flag) {
			case ANY:
				switch (arg) {
				case ARG_TEMPLATE: flag = Flag.TEMPLATE; break;
				case ARG_OUTPUT: flag = Flag.OUPUT; break;
				case ARG_INPUT: flag = Flag.INPUT; break;
				default: 
					argmap.put(ARG_INPUT, arg); break;
				}
				break;
			case TEMPLATE:
				argmap.put(ARG_TEMPLATE, arg);
				flag = Flag.ANY;
				break;
			case OUPUT:
				argmap.put(ARG_OUTPUT, arg);
				flag = Flag.ANY;
				break;
			case INPUT:
				argmap.put(ARG_INPUT, arg);
				flag = Flag.ANY;
				break;
			default:
				break;
			}
		}
		return argmap;
	}
}

class Tree
{
	private class Node implements Comparable<Node>
	{
		SortedMap<String, Node> map = null;
		final String name;
		String ip = null;
		int depth = 0;
		
		Node(String name)
		{
			this.name = name;
		}
		
		void setIP(String ip)
		{
			this.ip = ip;
		}
		
		int calcDepth()
		{
			if (depth > 0) {
				return depth;
			}
			depth = 1;
			if (map != null) {
				int d = 1;
				for (Node node : map.values()) {
					int t = node.calcDepth();
					if (t > d) {
						d = t;
					}
				}
				depth = d + 1;
			}
			return depth;
		}
		
		public int compareTo(Node o)
		{
			return depth - o.depth;
		}
		
		Node add(String name)
		{
			depth = 0;
			if (map == null) {
				map = new TreeMap<>();
			}
			Node node = map.get(name);
			if (node == null) {
				map.put(name, node = new Node(name));
			}
			return node;
		}
		
		public boolean checkChildIP() {
			if (map != null) {
				for (Node node : map.values()) {
					if (node.ip != null) {
						return true;
					}
				}
			}
			return false;
		}
		
		int print(PrintStream out, String host) {
			String temp;
			if (host.length() > 0) {
				temp =  name + "." + host;
			} else {
				out.println();
				temp = name;
			}
 			if (map == null) {
				if (ip != null) {
					out.println("\t" + ip + "\t" + temp);
				}
				return 1;
			} else {
				if (temp.length() > 0) {
					if (host.length() == 0) {
						out.println("# ***********************************************");
						out.println("# ." + temp);
						out.println("# ***********************************************");
						out.println();
					} else  {
						out.println("# ." + temp);
					}
				}
				if (ip != null) {
					out.println("\t" + ip + "\t" + temp);
				}
				if (checkChildIP()) {
					Queue<Node> que = new PriorityQueue<>();
					for (Node node : map.values()) {
						que.add(node);
					}
					int n = 0;
					while (que.isEmpty() == false) {
						n += que.poll().print(out, temp);
					}
					if (n > 0) {
						out.println();
					}
				} else {
					int n = 0;
					for (Node node : map.values()) {
						n += node.print(out, temp);
					}
					if (n > 0) {
						out.println();
					}
				}
	
				return 0;
			}
		}
	}
	
	Node root;

	Tree()
	{
		root = new Node("");
	}
	
	void add(String hostname, String ip)
	{
		String[] tokens = hostname.split("\\.");
		Node node = root;
		
		for (int i = tokens.length - 1; i >= 0; i--) {
			node = node.add(tokens[i]);
		}
		node.setIP(ip);
		
	}
	
	void print(PrintStream out)
	{
		root.calcDepth();
		out.println();
		root.print(out, "");
	}
}
