public void map(
        LongWritable lineid, Text nodetxt, OutputCollector<Text, Text> output, Reporter reporter)
        throws IOException {
      Node node = new Node();
      node.fromNodeMsg(nodetxt.toString());

      for (String adj : Node.dirs) {
        node.setCanCompress(adj, false);

        TailInfo next = node.gettail(adj);

        if (next != null /*&& node.getBlackEdges() == null*/) {
          if (next.id.equals(node.getNodeId())) {
            continue;
          }

          reporter.incrCounter("Brush", "remotemark", 1);

          output.collect(
              new Text(next.id), new Text(Node.HASUNIQUEP + "\t" + node.getNodeId() + "\t" + adj));
        }
      }

      output.collect(new Text(node.getNodeId()), new Text(node.toNodeMsg()));

      reporter.incrCounter("Brush", "nodes", 1);
    }
    public void reduce(
        Text key, Iterator<Text> iter, OutputCollector<Text, Text> output, Reporter reporter)
        throws IOException {
      Node node = new Node(key.toString());
      Set<String> f_unique = new HashSet<String>();
      Set<String> r_unique = new HashSet<String>();

      int sawnode = 0;

      while (iter.hasNext()) {
        String msg = iter.next().toString();

        // System.err.println(key.toString() + "\t" + msg);

        String[] vals = msg.split("\t");

        if (vals[0].equals(Node.NODEMSG)) {
          node.parseNodeMsg(vals, 0);
          sawnode++;
        } else if (vals[0].equals(Node.HASUNIQUEP)) {
          if (vals[2].equals("f")) {
            f_unique.add(vals[1]);
          } else if (vals[2].equals("r")) {
            r_unique.add(vals[1]);
          }
        } else {
          throw new IOException("Unknown msgtype: " + msg);
        }
      }

      if (sawnode != 1) {
        throw new IOException(
            "ERROR: Didn't see exactly 1 nodemsg (" + sawnode + ") for " + key.toString());
      }

      for (String adj : Node.dirs) {
        TailInfo next = node.gettail(adj);

        if (next != null) {
          if ((next.dir.equals("f") && r_unique.contains(next.id))
              || (next.dir.equals("r") && f_unique.contains(next.id))) {
            // for path compress
            if (node.getBlackEdges() == null) {
              node.setCanCompress(adj, true);
            }
            reporter.incrCounter("Brush", "compressible", 1);
          }
        }
      }
      // System.err.println(node.getNodeId() + " " + node.toNodeMsg() );
      output.collect(new Text(node.getNodeId()), new Text(node.toNodeMsg()));
    }