if (dotExecutable == null) setupDotPath();
  private void layoutDotFile(String dotPathname, boolean minimizeGraph) {    // Create a file handle for the dot file    // This will be used later to get the size of the file    File dotFile = null;    try {      dotFile = new File(dotPathname);    } catch (NullPointerException e) {      System.out.println("CSMARTGraph: Could not open file handle for " + dotPathname);    }        // This is the size of the dot file, use this    // for initializing the Buffer for reading the dot.exe process output    long dotFileSize = dotFile.length();    // done with dotFile File handle    //    System.out.println("CSMARTGraph: Got dot file of size " + dotFileSize +    //		       " at: " + System.currentTimeMillis()/1000);        // run the dot file through the dot utility to produce a directed graph    //    String command = "dot.exe " + dotPathname;    String command = dotExecutable + ' ' + dotPathname;        //    System.out.println("Starting: " + command + " at: " +     //		       System.currentTimeMillis()/1000);    Process proc = null;    try {      proc = Runtime.getRuntime().exec(command);    } catch(Exception ex) {      System.out.println("Exception while executing: " + 			 command + " " + ex.getMessage());      ex.printStackTrace(System.err);      proc = null;    }    // get the input stream of the dot process from which     // we read the dot-processed file    InputStream fromFilterRaw = null;    try {      if (proc == null) {	throw new Exception("proc is null");      } else {	fromFilterRaw = proc.getInputStream();      }    } catch(Exception e) {      System.out.println("CSMARTGraph: Couldn't get from filter: " + e);    }    // Use a special BufferedReader which does the newlines    // thing for us.  By using this Reader, we can avoid    // creating the large StringBuffer altogether    // We'll just pass this reader directly into the Parser    BufferedReader fromFilter =       new GrappaDotReader(new InputStreamReader(fromFilterRaw));    // now invoke the parser on the dot-processed file    // AMH - pass in the original BufferedReader that reads    // directly from the dot.exe process    // create a new graph to get the results of the layout    Parser program = null;    Graph newGraph = null;    if (minimizeGraph) {      newGraph = new Graph("Layout", true, true);      program = new Parser(fromFilter, getErrorWriter(), newGraph);    } else      program = new Parser(fromFilter, getErrorWriter(), this);    // garbage collect before parsing    Runtime runtime = Runtime.getRuntime();    //    System.out.println("Free memory: " + runtime.freeMemory());    runtime.gc();    //    System.out.println("After gc; Free memory: " + runtime.freeMemory());    //    System.out.println("Invoking parser at: " + System.currentTimeMillis()/1000 + "...");    try {      program.parse();    } catch(Exception ex) {      System.out.println("CSMARTGraph: parser exception: " + ex.getMessage());      ex.printStackTrace();    }    //    System.out.println("Parser finished at: " + System.currentTimeMillis()/1000);    // AMH: Close our special Buffered Reader    try {      fromFilter.close();    } catch (IOException io) {      System.out.println("Error closing special reader");    }    stripAttributeQuotes(this);    if (!minimizeGraph) {      buildShapes();      return;    }    // copy the results of the layout into this graph    // get position and size information for nodes    Vector newNodes = newGraph.vectorOfElements(GrappaConstants.NODE);    for (int i = 0; i < newNodes.size(); i++) {      Node newNode = (Node)newNodes.elementAt(i);      Node node = (Node)UIDToNode.get(newNode.getName());      if (node == null) {	System.out.println("CSMARTGraph: WARNING: node not found: " + newNode.getName());      } else {	node.setAttribute(GrappaConstants.POS_ATTR,			  newNode.getAttributeValue(GrappaConstants.POS_ATTR));	node.setAttribute(GrappaConstants.WIDTH_ATTR,			  newNode.getAttributeValue(GrappaConstants.WIDTH_ATTR));	node.setAttribute(GrappaConstants.HEIGHT_ATTR,			  newNode.getAttributeValue(GrappaConstants.HEIGHT_ATTR));      }    }    // get position information for edges    Vector newEdges = newGraph.vectorOfElements(GrappaConstants.EDGE);    for (int i = 0; i < newEdges.size(); i++) {      Edge newEdge = (Edge)newEdges.elementAt(i);      String name = newEdge.getTail().getName() + newEdge.getHead().getName();      Edge edge = (Edge)UIDToEdge.get(name);      if (edge == null)	System.out.println("CSMARTGraph: WARNING: edge not found: " + name);      else	edge.setAttribute(GrappaConstants.POS_ATTR,			  newEdge.getAttributeValue(GrappaConstants.POS_ATTR));    }    // and build the resultant graph    buildShapes();    //    System.out.println("Finished building grappa nodes at: " + System.currentTimeMillis()/1000);  } // end of layoutDotFile