Problem: Misha hacked the Codeforces site. Then he decided to let all the users change their handles. A user can now change his handle any number of times. But each new handle must not be equal to any handle that is already used or that was used at some point.

Misha has a list of handle change requests. After completing the requests he wants to understand the relation between the original and the new handles of the users. Help him to do that.

Input

The first line contains integer q (1 ≤ q ≤ 1000), the number of handle change requests.

Next q lines contain the descriptions of the requests, one per line.

Each query consists of two non-empty strings old and new, separated by a space. The strings consist of lowercase and uppercase Latin letters and digits. Strings old and new are distinct. The lengths of the strings do not exceed 20.

The requests are given chronologically. In other words, by the moment of a query there is a single person with handle old, and handle new is not used and has not been used by anyone.

Output

In the first line output the integer n — the number of users that changed their handles at least once.

In the next n lines print the mapping between the old and the new handles of the users. Each of them must contain two strings, old and new, separated by a space, meaning that before the user had handle old, and after all the requests are completed, his handle is new. You may output lines in any order.

Each user who changes the handle must occur exactly once in this description.

Examples

Input

5
Misha ILoveCodeforces
Vasya Petrov
Petrov VasyaPetrov123
ILoveCodeforces MikeMirzayanov
Petya Ivanov


Output

3
Petya Ivanov
Misha MikeMirzayanov
Vasya VasyaPetrov123

Solution (in JAVA):

Solution:
/*
 ID: govind.3, GhpS, govindpatel
 LANG: JAVA
 TASK: Main 
 */

import java.io.*;
import java.math.BigInteger;
import java.util.*;
import java.util.Map.Entry;

public class Main {

    /**
     * Min segment Tree takes the minimum number at the root
     */
    class MinSegmentTree {

        /**
         * root: Tree root, balance: input array, rl,rr:
         * rl=0,rr=inputArray.length-1 minTree:segment Tree
         */
        private void initMinTree(int root, int rl, int rr, int[] balance, int[] minTree) {
            if (rl == rr) {
                minTree[root] = balance[rl];
                return;
            }
            int rm = (rl + rr) / 2;
            initMinTree(root * 2 + 1, rl, rm, balance, minTree);
            initMinTree(root * 2 + 2, rm + 1, rr, balance, minTree);
            minTree[root] = Math.min(minTree[root * 2 + 1], minTree[root * 2 + 2]);
        }

        /**
         * minTree:segment tree root:0 rl:0,rr:inputarray.length-1
         * l=queryleft-1(If 1 based index),r = queryright(1-based)
         */
        private int getMin(int[] minTree, int root, int rl, int rr, int l, int r) {
            //l = query left-1, r = query right
            if (l > r) {
                return Integer.MAX_VALUE;
            }
            if (l == rl && r == rr) {
                return minTree[root];
            }
            int rm = (rl + rr) / 2;
            return Math.min(getMin(minTree, root * 2 + 1, rl, rm, l, Math.min(r, rm)),
                    getMin(minTree, root * 2 + 2, rm + 1, rr, Math.max(rm + 1, l), r));
        }
    }
    //dsu next operation
    int[] next;

    private int next(int i) {
        if (next[i] == i) {
            return i;
        }
        return next[i] = next(next[i]);
    }

    //segment tree...
    private void set(int[] t, int ind, int val) {
        ind += (t.length / 2);
        t[ind] = val;
        int curr = 0;
        while (ind > 1) {
            ind >>= 1;
            if (curr == 0) {
                t[ind] = t[ind * 2] | t[ind * 2 + 1];
            } else {
                t[ind] = t[ind * 2] ^ t[2 * ind + 1];
            }
            curr ^= 1;
        }
    }

    //Binary Index tree
    class FenwickTree {

        int[] ft;
        int N;

        FenwickTree(int n) {
            this.N = n;
            ft = new int[N];
        }

        private int lowbit(int x) {
            return x & (-x);
        }

        void update(int pos, int val) {
            while (pos < N) {
                ft[pos] += val;
                pos |= pos + 1;//0-index
            }
        }

        int sum(int pos) {
            int sum = 0;
            while (pos >= 0) {
                sum += ft[pos];
                pos = (pos & (pos + 1)) - 1;
            }
            return sum;
        }

        int rangeSum(int left, int right) {
            return sum(right) - sum(left - 1);
        }
    }

    /**
     * BINARY SEARCH IN FENWICK TREE: l=1, r=N(length), at=sumRequired,
     * letter=TreeIndex(if there are many ft), ft=arrays of FT
     */
    private int binarySearch(int l, int r, int at, int letter, FenwickTree[] ft) {
        while (r - l > 0) {
            int mid = (l + r) / 2;
            int sum = ft[letter].sum(mid);
            if (sum < at) {
                l = mid + 1;
            } else {
                r = mid;
            }
        }
        return l;
    }

    private int[] compress(int[] a) {
        int[] b = new int[a.length];
        for (int i = 0; i < a.length; i++) {
            b[i] = a[i];
        }
        Arrays.sort(b);
        int m = 0;
        for (int i = 0; i < b.length;) {
            int j = i;
            while (j < b.length && b[j] == b[i]) {
                j++;
            }
            b[m++] = b[i];
            i = j;
        }
        for (int i = 0; i < a.length; i++) {
            a[i] = Arrays.binarySearch(b, 0, m, a[i]);
        }
        return a;
    }

    class Dijkstra {

        class Edge implements Comparable<Edge> {

            int to;
            long weight;

            Edge(int t, long w) {
                to = t;
                weight = w;
            }

            public int compareTo(Edge other) {
                return (int) Math.signum(weight - other.weight);
            }
        }
        public static final long INF = (long) 1e17;
        private ArrayList<Edge> adj[];
        private int nodes;
        private long[] dist;
        private int[] prev;
        private boolean[] visited;

        public Dijkstra(int n) {
            nodes = n;
            adj = new ArrayList[nodes];
            dist = new long[nodes];
            prev = new int[nodes];
            visited = new boolean[nodes];
            for (int i = 0; i < nodes; i++) {
                adj[i] = new ArrayList<Edge>();
                dist[i] = INF;
                prev[i] = -1;
            }
        }

        public void add(int u, int v, long cost) {
            adj[u].add(new Edge(v, cost));
        }

        public void dist() {
            //src vertex = 0;
            dist[0] = 0;
            Queue<Edge> q = new PriorityQueue<Edge>();
            q.add(new Edge(0, 0));
            while (!q.isEmpty()) {
                Edge e = q.poll();
                int ind = e.to;
                if (visited[ind]) {
                    continue;
                }
                visited[ind] = true;

                for (Edge edge : adj[ind]) {
                    long newDistance = e.weight + edge.weight;
                    if (newDistance < dist[edge.to]) {
                        dist[edge.to] = newDistance;
                        prev[edge.to] = ind;
                        q.add(new Edge(edge.to, dist[edge.to]));
                    }
                }
            }
        }

        public ArrayList<Integer> getPrevList(int last) {
            ArrayList<Integer> al = new ArrayList<Integer>();
            while (last != -1) {
                al.add(last);
                last = prev[last];
            }
            return al;
        }

        public int[] getPrev() {
            return prev;
        }

        public long[] getDistance() {
            return dist;
        }

        public boolean[] getVisited() {
            return visited;
        }
    }
    int[] up;

    class Edge {

        int u, v, cap, flow, cost;
        Edge rev;

        Edge(int u, int v, int cap, int cost) {
            this.u = u;
            this.v = v;
            this.cap = cap;//limit
            this.cost = cost;
        }
    }

    class Result {

        int cost, flow;

        Result(int cost, int flow) {
            this.cost = cost;
            this.flow = flow;
        }
    }

    int[] getAlphabet(String s) {
        int[] res = new int[totalLetters];
        for (int i = 0; i < s.length(); i++) {
            res[s.charAt(i) - 'a']++;
        }
        return res;
    }
    final int totalLetters = 26;
    final int maxVertexes = 1 + 1 + 26 + 100;//src,sink,chars,length...

    void addEdge(int u, int v, int cap, int cost, ArrayList<Edge>[] g) {
        Edge a = new Edge(u, v, cap, cost);
        Edge b = new Edge(v, u, 0, -cost);//rev..
        a.rev = b;
        b.rev = a;
        g[u].add(a);
        g[v].add(b);
    }

    void appendTestCase(int test) {
        out.print("Case #");
        out.print(test);
        out.print(": ");
    }
    Map<Integer, Integer> map;

    private void solve() throws IOException {
        HashMap<String, String> map = new HashMap<String, String>();
        int test = nextInt();
        for (int i = 0; i < test; i++) {
            String oldName = nextToken();
            String newName = nextToken();
            boolean added = false;
            for (String name : map.keySet()) {
                String nName = map.get(name);
                if (nName.equals(oldName)) {
                    map.put(name, newName);
                    added = true;
                    break;
                }
            }
            if (!added) {
                map.put(oldName, newName);
            }
        }
        out.println(map.size());
        for (String s : map.keySet()) {
            out.println(s + " " + map.get(s));
        }
    }

    /**
     * Radix sort. Stable. O(N*(32/4)) = O(N)
     */
    class RadixSort {

        void radixSort(int[] a) {
            int[] aux = new int[a.length];
            int r = 4;//size of the each groups
            int b = 32;//no. of total bits.
            int[] count = new int[1 << r];//to store the count
            int[] pref = new int[1 << r];//cumulative sum..
            int groups = (int) Math.ceil(b * 1.0 / r);//No. of groups
            int mask = (1 << r) - 1;//mask = 0xFF for r=4. i.e., "1111" in binary
            //loops for each groups...
            for (int c = 0, shift = 0; c < groups; c++, shift += r) {
                //fill the count with zero...
                Arrays.fill(count, 0);
                // count the number of time the group occur.
                for (int i = 0; i < a.length; i++) {
                    count[(a[i] >> shift) & mask]++;
                }
                //do the cumulative sum
                pref[0] = 0;
                for (int i = 1; i < count.length; i++) {
                    pref[i] = pref[i - 1] + count[i - 1];
                }
                // set the number back to where they should be placed.
                for (int i = 0; i < a.length; i++) {
                    aux[pref[(a[i] >> shift) & mask]++] = a[i];
                }
                //copy back auxillary to our input array.
                for (int i = 0; i < a.length; i++) {
                    a[i] = aux[i];
                }
            }
        }
    }

    /**
     * Binary Search Tree.Map "key,value" pair.
     */
    class BST<Key extends Comparable<Key>, Value> {

        private class Node {

            Key key;
            Value value;
            Node left, right;
            int count;

            public Node(Key k, Value v) {
                key = k;
                value = v;
            }
        }
        private Node root;
        private int size = 0;

        public int size() {
            return size(root);
        }

        private int size(Node x) {
            if (x == null) {
                return 0;
            }
            return x.count;
        }

        public Value get(Key key) {
            Node x = root;
            while (x != null) {
                int cmp = key.compareTo(x.key);
                if (cmp < 0) {
                    x = x.left;
                } else if (cmp > 0) {
                    x = x.right;
                } else {
                    return x.value;
                }
            }
            return null;
        }

        public void put(Key k, Value v) {
            size++;
            root = put(root, k, v);
        }

        private Node put(Node root, Key key, Value value) {
            if (root == null) {
                return new Node(key, value);
            }
            int cmp = key.compareTo(root.key);
            if (cmp < 0) {
                root.left = put(root.left, key, value);
            } else if (cmp > 0) {
                root.right = put(root.right, key, value);
            } else//update the value.
            {
                root.value = value;
            }
            root.count = 1 + size(root.left) + size(root.right);
            return root;
        }

        private Node leftMostNode(Node x) {
            if (x == null) {
                return null;
            }
            //go left...
            while (x.left != null) {
                x = x.left;
            }
            return x;
        }

        public Key smallestKey() {
            Node x = leftMostNode(root);
            return x == null ? null : x.key;
        }

        public Value smallestKeyValue() {
            Node x = leftMostNode(root);
            return x == null ? null : x.value;
        }

        private Node rightMostNode(Node x) {
            if (x == null) {
                return null;
            }
            //go left...
            while (x.right != null) {
                x = x.right;
            }
            return x;
        }

        public Key largestKey() {
            Node x = rightMostNode(root);
            return x == null ? null : x.key;
        }

        public Value largestKeyValue() {
            Node x = rightMostNode(root);
            return x == null ? null : x.value;
        }

        //floor = closest minimum.
        public Key floor(Key key) {
            //floor of 1.3 is 1.
            //floor of 1 is 1.
            Node x = root;
            Node floor = floor(x, key);
            return floor == null ? null : floor.key;
        }

        private Node floor(Node x, Key key) {
            if (x == null) {
                return null;
            }
            int cmp = key.compareTo(x.key);
            if (cmp == 0) {
                return x;
            } else if (cmp < 0) {
                return floor(x.left, key);
            }

            Node t = floor(x.right, key);
            if (t != null) {
                return t;
            } else {
                return x;
            }
        }

        public void deleteMin() {
            root = deleteMin(root);
        }

        private Node deleteMin(Node x) {
            if (x.left == null) {
                return x.right;
            }
            x.left = deleteMin(x.left);
            x.count = 1 + size(x.left) + size(x.right);
            return x;
        }

        public void delete(Key key) {
            root = delete(root, key);
        }

        private Node delete(Node x, Key key) {
            if (x == null) {
                return null;
            }
            int cmp = key.compareTo(x.key);
            if (cmp < 0) {
                x.left = delete(x.left, key);
            } else if (cmp > 0) {
                x.right = delete(x.right, key);
            } else {//no child and 1 child..
                if (x.left == null) {
                    return x.right;
                }
                if (x.right == null) {
                    return x.left;
                }
                //two child...
                Node t = x;
                x = leftMostNode(t.right);
                x.right = deleteMin(t.right);
                x.left = t.left;
            }
            x.count = 1 + size(x.left) + size(x.right);
            return x;
        }
        //whether the binary tree is a BST(Binary search Tree).

        public boolean isBinaryTreeBST() {
            return isBinaryBST(root, null, null);
        }

        private boolean isBinaryBST(Node root, Key min, Key max) {
            if (root == null) {
                return true;
            }
            boolean between = false;
            if (min == null && max == null) {
                between = true;
            } else if (min == null) {//min is null.
                int cmp2 = root.key.compareTo(max);
                if (cmp2 < 0) {
                    between = true;
                }
            } else if (max == null) {
                int cmp1 = min.compareTo(root.key);
                if (cmp1 < 0) {
                    between = true;
                }
            } else {//both not null
                int cmp1 = min.compareTo(root.key);
                int cmp2 = root.key.compareTo(max);
                if (cmp1 < 0 && cmp2 < 0) {
                    between = true;
                }
            }
            if (!between) {
                return false;
            }
            return isBinaryBST(root.left, min, root.key) && isBinaryBST(root.right, root.key, max);
        }

        public Iterable<Key> keys() {
            ArrayDeque<Key> q = new ArrayDeque<>();
            inorder(root, q);
            return q;
        }

        private void inorder(Node x, ArrayDeque<Key> q) {
            if (x == null) {
                return;
            }
            if (x.left != null) {
                inorder(x.left, q);
            }
            q.addLast(x.key);
            if (x.right != null) {
                inorder(x.right, q);
            }
        }
    }

    /**
     * Heap. Largest key is at a[1]. parent of the node K is at K/2. child of
     * the node K are 2K and 2K+1. Heap-sort in descending order.
     */
    class Heap {

        private int[] array;
        private int size;
        private int end;

        Heap(int size) {
            array = new int[size + 10];
            end = 0;
            this.size = size;
            Arrays.fill(array, -5);
        }

        /**
         * Moving up the tree. insert method helper.
         */
        private void swim(int k) {
            //compare with root if the root is smaller then 
            //the current swap them and move k to point the root.(MAX_HEAP)
            //so that root remain max.
            while (k > 1 && array[k / 2] <= array[k]) {
                int t = array[k / 2];
                array[k / 2] = array[k];
                array[k] = t;
                k = k / 2;
            }
        }

        public void insert(int value) {
            //check if the end+1 is in the size limit.
            if (isFull()) {
                return;
            }
            array[++end] = value;
            swim(end);
        }

        private void sink(int k) {
            //compare the child swap the root with max of both.
            //so the root remain max.
            while (2 * k <= end) {
                int left = 2 * k;
                int right = 2 * k + 1;
                int swap = left;
                if (right <= end && array[right] > array[left]) {
                    swap = right;
                }
                //root is max.
                if (array[k] > array[swap]) {
                    break;
                }
                int t = array[swap];
                array[swap] = array[k];
                array[k] = t;
                k = swap;
            }
        }

        public boolean isEmpty() {
            return end <= 0;
        }

        public boolean isFull() {
            return end >= size;
        }

        //sort in descending order from MAX to MIN.
        public int[] heapSort() {
            int[] sortedArray = new int[size];
            int curr = 0;
            while (!isEmpty()) {
                sortedArray[curr++] = deleteMax();
            }
            return sortedArray;
        }

        public int deleteMax() {
            //check if the heap is already empty;
            if (isEmpty()) {
                return -1;
            }
            int value = array[1];
            //update the root with the last value of tree.
            array[1] = array[end];
            array[end] = -5;
            //decrease the size of the tree;
            end--;
            //sink the value down the tree.
            sink(1);
            return value;
        }

        @Override
        public String toString() {
            return Arrays.toString(array);
        }
    }

    /**
     * QuickSort and method to find the k-th minimum in an unsorted array.
     */
    class QuickSort {

        /**
         * Remove the comment to perform normal quick sort.
         */
        void qsort(int[] a) {
            shuffle(a);
            //Normal quick sort.
            //qsort(a, 0, a.length - 1);

            //Three way quick sort.
            quick3Sort(a, 0, a.length - 1);
        }

        void qsort(int[] a, int lo, int hi) {
            if (hi - lo <= 0) {
                return;
            }
            int m = (lo + hi) / 2;
            int t = a[m];
            a[m] = a[lo];
            a[lo] = t;

            int j = partition(a, lo, hi);
            qsort(a, lo, j - 1);
            qsort(a, j + 1, hi);
        }

        int partition(int[] a, int lo, int hi) {
            int i = lo;
            int j = hi + 1;
            while (true) {
                while (a[++i] < a[lo]) {
                    if (i >= hi) {
                        break;
                    }
                }

                while (a[--j] > a[lo]) {
                    if (j <= lo) {
                        break;
                    }
                }

                if (i >= j) {
                    break;
                }
                int t = a[i];
                a[i] = a[j];
                a[j] = t;
            }
            int t = a[lo];
            a[lo] = a[j];
            a[j] = t;
            return j;
        }

        /**
         * Perform 3-way quick sort.
         */
        void quick3Sort(int[] a, int lo, int hi) {
            if (hi - lo <= 0) {
                return;
            }
            int lt = lo, gt = hi;
            int i = lo;
            int v = a[lo];
            while (i <= gt) {
                int cmp = a[i] - v;
                if (cmp < 0) {
                    int t = a[lt];
                    a[lt] = a[i];
                    a[i] = t;
                    lt++;
                    i++;
                } else if (cmp > 0) {
                    int t = a[gt];
                    a[gt] = a[i];
                    a[i] = t;
                    gt--;
                } else {
                    i++;
                }
            }
            quick3Sort(a, lo, lt - 1);
            quick3Sort(a, gt + 1, hi);
        }

        /**
         * find the k-th smallest in the given array(unsorted).
         */
        int kthSelect(int[] a, int k) {
            int lo = 0;
            int hi = a.length - 1;
            shuffle(a);
            while (hi > lo) {
                int j = partition(a, lo, hi);
                if (j < k) {
                    lo = j + 1;
                } else if (j > k) {
                    hi = j - 1;
                } else {
                    return a[k];
                }
            }
            return a[k];
        }

        void shuffle(int[] a) {
            Random rnd = new Random();
            for (int i = 0; i < a.length; i++) {
                int j = rnd.nextInt(i + 1);
                int t = a[i];
                a[i] = a[j];
                a[j] = t;
            }
        }
    }

    /**
     * Merge sort and Inverse to count the number of inverse.
     */
    public class MergeSort {

        /**
         * inverse is used to count the number of inversion in the array. i.e.,
         * array = {2,1,3} have one inverse (2,1) and array = {4,1,3,2} have 4
         * inverse (4,1),(4,3),(4,2) and (3,2).
         */
        int inverse;

        void msort(int[] a) {
            int[] aux = new int[a.length];
            inverse = 0;
            inverse = msort(a, aux, 0, a.length - 1);
        }

        int msort(int[] a, int[] aux, int low, int high) {
            if (high - low <= 0) {
                return 0;
            }
            int mid = (low + high) / 2;
            int currInv = 0;
            currInv += msort(a, aux, low, mid);
            currInv += msort(a, aux, mid + 1, high);
            currInv += merge(a, aux, low, high, mid);
            return currInv;
        }

        int merge(int[] a, int[] aux, int low, int hi, int mid) {
            for (int i = low; i <= hi; i++) {
                aux[i] = a[i];
            }
            int cntInvr = 0;
            int i = low;
            int j = mid + 1;
            for (int k = low; k <= hi; k++) {
                if (i > mid) {
                    a[k] = aux[j++];
                } else if (j > hi) {
                    a[k] = aux[i++];
                } else if (aux[i] <= aux[j]) {
                    a[k] = aux[i++];
                } else {
                    a[k] = aux[j++];
                    cntInvr += (mid - i + 1);
                }
            }
            return cntInvr;
        }
    }

    /**
     * min-max
     */
    Result minCostMaxFlow(int s, int t, ArrayList<Edge>[] g) {
        for (int i = 0; i < g.length; i++) {
            Collections.shuffle(g[i]);
        }
        int resFlow = 0, resCost = 0;
        int[] d = new int[g.length];
        Queue<Integer> q = new ArrayDeque<Integer>();
        Edge[] edgeUsed = new Edge[g.length];

        while (true) {
            Arrays.fill(d, Integer.MAX_VALUE);
            d[s] = 0;

            q.add(s);

            while (!q.isEmpty()) {
                int u = q.poll();
                for (Edge e : g[u]) {
                    if (e.cap - e.flow > 0 && d[u] + e.cost < d[e.v]) {
                        d[e.v] = d[u] + e.cost;
                        edgeUsed[e.v] = e;
                        q.add(e.v);
                    }
                }
            }
            if (d[t] == Integer.MAX_VALUE) {
                break;
            }

            ++resFlow;
            resCost += d[t];

            int ptr = t;
            while (ptr != s) {
                Edge e = edgeUsed[ptr];
                e.flow++;
                e.rev.flow--;
                ptr = e.u;
            }
        }
        return new Result(resCost, resFlow);
    }

    void merge(int a, int b) {
        a = get(a);
        b = get(b);
        if (a != b) {
            up[a] = b;
        }
    }

    int get(int a) {
        if (up[a] == a) {
            return a;
        }
        return up[a] = get(up[a]);
//        while (up[a] != a) {
//            up[a] = up[up[a]];
//            a = up[a];
//        }
//        return a;
    }

    boolean isSorted(ArrayList<Integer> al) {
        int size = al.size();
        for (int i = 1; i < size - 2; i++) {
            if (al.get(i) > al.get(i + 1)) {
                return false;
            }
        }
        return true;
    }

    /**
     * SHUFFLE: shuffle the array 'a' of size 'N'
     */
    private void shuffle(int[] a, int N) {
        for (int i = 0; i < N; i++) {
            int r = i + (int) ((N - i) * Math.random());
            int t = a[i];
            a[i] = a[r];
            a[r] = t;
        }
    }

    /**
     * TEMPLATE-STUFF: main method, run method - ( fileIO and stdIO ) and
     * various methods for input like nextInt, nextLong, nextToken and
     * nextDouble with some declarations.
     */
    /**
     * For solution to the problem ... see the solve method
     */
    public static void main(String[] args) {
        new Main().run();
    }

    public void run() {
        try {
            in = new BufferedReader(new FileReader("C-small-practice.in"));
            out = new PrintWriter(new BufferedWriter(new FileWriter("Main.out")));
            tok = null;
            solve();
            in.close();
            out.close();
            System.exit(0);
        } catch (IOException e) {//(FileNotFoundException e) {
            try {
                in = new BufferedReader(new InputStreamReader(System.in));
                out = new PrintWriter(new OutputStreamWriter(System.out));
                tok = null;
                solve();
                in.close();
                out.close();
                System.exit(0);
            } catch (IOException ex) {
                System.out.println(ex.getMessage());
                System.exit(0);
            }
        }
    }

    private String nextToken() throws IOException {
        while (tok == null || !tok.hasMoreTokens()) {
            tok = new StringTokenizer(in.readLine());
        }
        return tok.nextToken();
    }

    private int nextInt() throws IOException {
        return Integer.parseInt(nextToken());
    }

    private long nextLong() throws IOException {
        return Long.parseLong(nextToken());
    }

    private double nextDouble() throws IOException {
        return Double.parseDouble(nextToken());
    }
    BufferedReader in;
    StringTokenizer tok;
    PrintWriter out;
}