SOYC Dashboard



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4221 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/CodeCollection.java b/tools/soyc-vis/src/com/google/gwt/soyc/CodeCollection.java
new file mode 100644
index 0000000..6575008
--- /dev/null
+++ b/tools/soyc-vis/src/com/google/gwt/soyc/CodeCollection.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.soyc;
+
+import java.util.TreeSet;
+
+public class CodeCollection {
+  
+  public String codeType = "";
+  public TreeSet<String> classes = new TreeSet<String>();
+  public TreeSet<String> stories = new TreeSet<String>();
+  public float cumPartialSize = 0f;
+  public int cumSize = 0;
+  public CodeCollection(String type){
+    codeType = type;
+  }
+  
+  
+  public int getCumSize(){
+    cumSize = 0;
+    for (String className : classes){
+      if (! GlobalInformation.classToSize.containsKey(className)){
+        System.err.println("*** NO SIZE FOUND FOR CLASS " + className + " *****");
+      }
+      else{
+        cumSize += GlobalInformation.classToSize.get(className);
+      }
+    }
+    return cumSize;
+ }
+  
+  public float getCumPartialSize(){
+    cumPartialSize = 0f;
+    for (String className : classes){
+      if (!GlobalInformation.classToPartialSize.containsKey(className)){
+        System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****");
+      }
+      else{
+        cumPartialSize += GlobalInformation.classToPartialSize.get(className);
+      }
+    }
+    return cumPartialSize;
+ }
+}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java b/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java
new file mode 100644
index 0000000..40b377c
--- /dev/null
+++ b/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+
+package com.google.gwt.soyc;
+
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.HashSet;
+import java.util.TreeSet;
+
+public class GlobalInformation {
+
+  public static HashMap<String, HashSet<String>> storiesToCorrClasses = new HashMap<String, HashSet<String>>();
+  public static HashMap<String, String> storiesToLitType = new HashMap<String, String>();
+  
+  public static HashMap<String, Integer> packageToSize = new HashMap<String, Integer>();
+  public static HashMap<String, Float> packageToPartialSize = new HashMap<String, Float>();
+
+  public static HashMap<String, String> classToPackage = new HashMap<String, String>();
+  
+  //TODO(kprobst): not currently used, but will be for dependencies
+  //public static HashMap<String, HashSet<String>> classToWhatItDependsOn = new HashMap<String, HashSet<String>>();
+  
+  public static HashMap<String, Integer> classToSize = new HashMap<String, Integer>();
+  public static HashMap<String, Float> classToPartialSize = new HashMap<String, Float>();
+  public static TreeMap<String, TreeSet<String>> packageToClasses = new TreeMap<String, TreeSet<String>>();
+  
+  public static HashSet<String> nonAttributedStories = new HashSet<String>();
+  public static int nonAttributedBytes = 0;
+  public static int numBytesDoubleCounted = 0;
+  
+  public static int cumSizeAllCode  = 0;
+  public static float cumPartialSizeFromPackages = 0f;
+  public static int cumSizeFromPackages = 0;
+  
+  public static HashMap<Integer, HashSet<String>> fragmentToStories = new HashMap<Integer, HashSet<String>>();
+  public static HashMap<Integer, Float> fragmentToPartialSize = new HashMap<Integer, Float>();
+  public static int numFragments = 0;
+  public static int numSplitPoints = 0;
+  public static int cumSizeInitialFragment = 0;
+    
+  public static void computePackageSizes(){
+    cumSizeFromPackages = 0;
+    packageToSize.clear();
+    for (String packageName : packageToClasses.keySet()){
+      packageToSize.put(packageName, 0);
+      for (String className : packageToClasses.get(packageName)){
+        if (! classToSize.containsKey(className)){
+          System.err.println("*** NO  SIZE FOUND FOR CLASS " + className + " *****");
+        }
+        else{
+          int curSize = classToSize.get(className);
+          cumSizeFromPackages += curSize;
+          int newSize = curSize + packageToSize.get(packageName);
+          packageToSize.put(packageName, newSize);
+        }
+      }
+    }
+  }
+  
+  public static void computePartialPackageSizes(){
+    cumPartialSizeFromPackages = 0;
+    packageToPartialSize.clear();
+    for (String packageName : packageToClasses.keySet()){
+      packageToPartialSize.put(packageName, 0f);
+      for (String className : packageToClasses.get(packageName)){
+        if (! classToPartialSize.containsKey(className)){
+          System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****");
+        }
+        else{
+          float curSize = classToPartialSize.get(className);
+          cumPartialSizeFromPackages += curSize;
+          float newSize = curSize + packageToPartialSize.get(packageName);
+          packageToPartialSize.put(packageName, newSize);
+        }
+      }
+    }
+  }
+
+}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/LiteralsCollection.java b/tools/soyc-vis/src/com/google/gwt/soyc/LiteralsCollection.java
new file mode 100644
index 0000000..ce17b5d
--- /dev/null
+++ b/tools/soyc-vis/src/com/google/gwt/soyc/LiteralsCollection.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.soyc;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.HashSet;
+import java.util.TreeMap;
+
+public class LiteralsCollection {
+  public String literalType = "";
+  public Map<String, HashSet<String>> literalToLocations = new TreeMap<String, HashSet<String>>();
+  public Map<String, HashSet<String> > storyToLocations = new HashMap<String, HashSet<String>>();
+  public TreeMap<String, String> stringLiteralToType = new TreeMap<String, String>();
+  public Map<String, Integer> stringTypeToSize = new HashMap<String, Integer>();
+  public Map<String, Integer> stringTypeToCount = new HashMap<String, Integer>();
+  public int cumSize = 0;
+  public int cumStringSize = 0;
+  
+  public LiteralsCollection(String type){
+    literalType = type;
+  }  
+
+  /**
+   * Utility method
+   */
+  public void printAllStrings(){
+    int iSum = 0;
+    System.out.println("--- now printing strings ---");
+    for (String st : stringLiteralToType.keySet()){
+        int numBytes = st.getBytes().length;
+        iSum += numBytes;
+        System.out.println(st + "[" + numBytes + "]");
+    }
+    System.out.println("sum: " + iSum);
+    System.out.println("--- done printing strings ---");
+  }
+  
+}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java b/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
new file mode 100644
index 0000000..d538be3
--- /dev/null
+++ b/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
@@ -0,0 +1,1046 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.soyc;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.TreeMap;
+
+public class MakeTopLevelHtmlForPerm {
+  
+  public static void makeHTMLShell(HashMap<String, CodeCollection> nameToCodeColl, TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+    //this will contain the place holder iframes where the actual information is going to go.
+
+    String fileName = "SoycDashboard-index.html";
+    
+    final PrintWriter outFile = new PrintWriter(fileName);
+    outFile.println("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">");
+    outFile.println("<html>");
+    outFile.println("<head>");
+    outFile.println("<title>Story of Your Compile - Top Level Dashboard for Permutation</title>");
+    
+    outFile.println("<style type=\"text/css\">");
+    outFile.println("body {background-color: #728FCE}");
+    outFile.println("h2 {background-color: transparent}");
+    outFile.println("p {background-color: fuchsia}");
+    outFile.println("</style>");
+    outFile.println("</head>");
+    
+    
+    outFile.println("<body>");
+    outFile.println("<center>");
+    outFile.println("<h3>Story of Your Compile Dashboard</h3>");
+    outFile.println("<hr>");
+    if (GlobalInformation.cumSizeInitialFragment != 0){
+      outFile.println("<b>Full code size: <span style=\"color:maroon\">" + GlobalInformation.cumSizeAllCode + "</span>, Size of Initial Download:  <span style=\"color:maroon\">" + GlobalInformation.cumSizeInitialFragment + "</span></b>");
+    }
+    else{
+      outFile.println("<b>Full code size: <span style=\"color:maroon\">" + GlobalInformation.cumSizeAllCode + "</span></b>");
+    }
+    outFile.println("</center>");
+    outFile.println("  <div style=\"width:50%;  float:left; padding-top: 10px;\">");
+    outFile.println("<b>Package breakdown</b>");
+    outFile.println("    </div>");
+    outFile.println("  <div style=\"width:48%;  float:right; padding-top: 10px; \">");
+    outFile.println("<b>Code type breakdown</b>");
+    outFile.println("    </div>");
+    
+
+    outFile.println("  <div style=\"width:50%;  float:left; padding-top: 10px;\">");
+    outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>");
+    outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Package Name</div>");
+    outFile.println("    </div>");
+    
+    
+    outFile.println("  <div style=\"width:48%;  float:right; padding-top: 10px;\">");
+    outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>");
+    outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Code Type</div>");
+    outFile.println("    </div>");
+    
+    
+    
+    outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:left;\">");
+    outFile.println("<iframe src=\"packageBreakdown.html\" width=100% height=100% scrolling=auto></iframe>");
+    outFile.println("  </div>");
+    makePackageHtml("packageBreakdown.html");
+    
+    outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:right;\">");
+    outFile.println("<iframe src=\"codeTypeBreakdown.html\" width=100% height=100% scrolling=auto></iframe>");
+    outFile.println("  </div>");
+    makeCodeTypeHtml("codeTypeBreakdown.html", nameToCodeColl);
+    
+    outFile.println("  <div style=\"width:50%;  float:left; padding-top: 10px;\">");
+    outFile.println("<b>Literals breakdown</b>");
+    outFile.println("    </div>");
+    outFile.println("  <div style=\"width:48%;  float:right; padding-top: 10px;  \">");
+    outFile.println("<b>String literals breakdown</b>");
+    outFile.println("    </div>");
+    
+
+    outFile.println("  <div style=\"width:50%;  float:left; padding-top: 10px;\">");
+    outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>");
+    outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Literal Type</div>");
+    outFile.println("    </div>");
+    
+    
+    outFile.println("  <div style=\"width:48%;  float:right; padding-top: 10px; \">");
+    outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>");
+    outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">String Literal Type</div>");
+    outFile.println("    </div>");
+    
+    
+    outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:left;\">");
+    outFile.println("<iframe src=\"literalsBreakdown.html\" width=100% height=100% scrolling=auto></iframe>");
+    outFile.println("</div>");
+    makeLiteralsHtml("literalsBreakdown.html", nameToLitColl);
+
+    outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:right;\">");
+    outFile.println("<iframe src=\"stringLiteralsBreakdown.html\" width=100% height=100% scrolling=auto></iframe>");
+    outFile.println("  </div>");
+    makeStringLiteralsHtml("stringLiteralsBreakdown.html", nameToLitColl);
+
+
+
+    if (GlobalInformation.fragmentToStories.size() == 1){
+      outFile.println("  <div style=\"width:100%;  float:left; padding-top: 10px;\">");
+      outFile.println("<b>Fragments breakdown</b>");
+      outFile.println("    </div>");
+  
+      outFile.println("  <div style=\"width:100%;  float:left; padding-top: 10px;\">");
+      outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>");
+      outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Fragment Name</div>");
+      outFile.println("    </div>");
+      
+      outFile.println("<div style=\"height:35%; width:50%; margin:0 auto; background-color:white; float:left;\">");
+      outFile.println("<iframe src=\"fragmentsBreakdown.html\" width=100% height=100% scrolling=auto></iframe>");
+      outFile.println("</div>");
+      makeFragmentsHtml("fragmentsBreakdown.html");
+    }
+
+    outFile.println("  </body>");
+    outFile.println("</html>");
+    outFile.close();
+    
+  }
+
+  
+  private static void makePackageHtml(String outFileName) throws IOException{
+    
+    
+    TreeMap<Float, String> sortedPackages = new TreeMap<Float, String>(Collections.reverseOrder());
+    float maxSize = 0f;
+    float sumSize = 0f;
+    for (String packageName : GlobalInformation.packageToPartialSize.keySet()){
+      sortedPackages.put(GlobalInformation.packageToPartialSize.get(packageName), packageName);
+      sumSize += GlobalInformation.packageToPartialSize.get(packageName);
+      if (GlobalInformation.packageToPartialSize.get(packageName) > maxSize){
+        maxSize = GlobalInformation.packageToPartialSize.get(packageName);
+      }
+    }
+    
+    final PrintWriter outFile = new PrintWriter(outFileName);
+    
+    outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+    outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+    outFile.println("<html>");
+    outFile.println("<head>");
+    outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+    outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">");
+    outFile.println("</head>");
+    outFile.println("<body>");
+
+    int yOffset = 0;
+    for (Float size : sortedPackages.keySet()){
+      
+      String packageName = sortedPackages.get(size);
+      String drillDownFileName = packageName + "Classes.html";
+      
+      float ratio = (size / maxSize) * 79;
+      
+      if (ratio < 3){
+        ratio = 3;
+      }
+
+      float perc = (size / sumSize) * 100;
+      
+      outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">");
+      outFile.println("<div id=\"lb\">");
+      outFile.println("<div id=\"rb\">");
+      outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+      outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+      outFile.println("<div id=\"content\">");
+      outFile.println("</div>");
+      outFile.println("</div></div></div></div>");
+      outFile.println("</div></div></div></div>");
+      outFile.println("</div>");
+      
+      int yOffsetText = yOffset+8;
+      outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+      outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc);
+      outFile.println("%</div>\n");
+      outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+packageName+"</a></div>");
+      
+      yOffset = yOffset + 25;
+
+    }
+    outFile.println("</body>");
+    outFile.println("</html>");
+    outFile.close();
+    
+  }
+  
+  
+  private static void makeFragmentsHtml(String outFileName) throws IOException{
+    
+    TreeMap<Float, Integer> sortedFragments = new TreeMap<Float, Integer>(Collections.reverseOrder());
+    float maxSize = 0f;
+    float sumSize = 0f;
+    for (Integer fragmentName : GlobalInformation.fragmentToPartialSize.keySet()){
+      sortedFragments.put(GlobalInformation.fragmentToPartialSize.get(fragmentName), fragmentName);
+      sumSize += GlobalInformation.fragmentToPartialSize.get(fragmentName);
+      if (GlobalInformation.fragmentToPartialSize.get(fragmentName) > maxSize){
+        maxSize = GlobalInformation.fragmentToPartialSize.get(fragmentName);
+      }
+    }
+    
+    final PrintWriter outFile = new PrintWriter(outFileName);
+    
+    outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+    outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+    outFile.println("<html>");
+    outFile.println("<head>");
+    outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+    outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">");
+    outFile.println("</head>");
+    outFile.println("<body>");
+
+    int yOffset = 0;
+    for (Float size : sortedFragments.keySet()){
+      
+      Integer fragmentName = sortedFragments.get(size);
+      String drillDownFileName = "fragment" + Integer.toString(fragmentName) + "Classes.html";
+      
+      float ratio = (size / maxSize) * 79;
+      
+      if (ratio < 3){
+        ratio = 3;
+      }
+
+      float perc = (size / sumSize) * 100;
+      
+      outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">");
+      outFile.println("<div id=\"lb\">");
+      outFile.println("<div id=\"rb\">");
+      outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+      outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+      outFile.println("<div id=\"content\">");
+      outFile.println("</div>");
+      outFile.println("</div></div></div></div>");
+      outFile.println("</div></div></div></div>");
+      outFile.println("</div>");
+      
+      int yOffsetText = yOffset+8;
+      outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+      outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:80px;\">%.1f", perc);
+      outFile.println("%</div>\n");
+      outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:120px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">fragment"+ Integer.toString(fragmentName) +"</a></div>");
+      
+      yOffset = yOffset + 25;
+
+    }
+    outFile.println("</body>");
+    outFile.println("</html>");
+    outFile.close();
+    
+  }
+  
+
+  
+  
+  private static void makeCodeTypeHtml(String outFileName, HashMap<String, CodeCollection> nameToCodeColl) throws IOException{
+    
+    
+    float maxSize = 0f;
+    float sumSize = 0f;
+    TreeMap<Float, String> sortedCodeTypes = new TreeMap<Float, String>(Collections.reverseOrder());
+    
+    //TODO(kprobst): turn this into a multimap? com.google.common.collect.TreeMultimap
+    for (String codeType : nameToCodeColl.keySet()){
+      float curSize = nameToCodeColl.get(codeType).getCumPartialSize();
+      sumSize += curSize;
+      
+      if (curSize != 0f){
+        sortedCodeTypes.put(curSize, codeType);
+        if (curSize > maxSize){
+          maxSize = curSize;
+        }
+      }
+    }
+    
+    final PrintWriter outFile = new PrintWriter(outFileName);
+    
+    outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+    outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+    outFile.println("<html>");
+    outFile.println("<head>");
+    outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+    outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">");
+    outFile.println("</head>");
+    outFile.println("<body>");
+
+    int yOffset = 0;
+    for (Float size : sortedCodeTypes.keySet()){
+      
+      String codeType = sortedCodeTypes.get(size);
+      String drillDownFileName = codeType + "Classes.html";
+      
+      float ratio = (size / maxSize) * 79;    
+      float perc = (size / sumSize) * 100;
+      
+      if (ratio < 3){
+        ratio = 3;
+      }
+
+      outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">");
+      outFile.println("<div id=\"lb\">");
+      outFile.println("<div id=\"rb\">");
+      outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+      outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+      outFile.println("<div id=\"content\">");
+      outFile.println("</div>");
+      outFile.println("</div></div></div></div>");
+      outFile.println("</div></div></div></div>");
+      outFile.println("</div>");
+      
+      int yOffsetText = yOffset+8;
+      outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+      outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc);
+      outFile.println("%</div>\n");
+      outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+codeType+"</a></div>");
+      
+      yOffset = yOffset + 25;
+
+    }
+    outFile.println("</body>");
+    outFile.println("</html>");
+    outFile.close();
+    
+    
+  }
+  
+
+
+  private static void makeLiteralsHtml(String outFileName, TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+    
+
+    float maxSize = 0f;
+    float sumSize = 0f;
+    TreeMap<Float, String> sortedLitTypes = new TreeMap<Float, String>(Collections.reverseOrder());
+ 
+    for (String literal : nameToLitColl.keySet()){
+      float curSize = nameToLitColl.get(literal).cumSize;
+      sumSize += curSize;
+      
+      if (curSize != 0f){
+        sortedLitTypes.put(curSize, literal);
+      
+        if (curSize > maxSize){
+          maxSize = curSize;
+        }
+      }
+    }
+
+
+    final PrintWriter outFile = new PrintWriter(outFileName);
+    
+    outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+    outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+    outFile.println("<html>");
+    outFile.println("<head>");
+    outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+    outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">");
+    outFile.println("</head>");
+    outFile.println("<body>");
+
+    int yOffset = 0;
+    for (Float size : sortedLitTypes.keySet()){
+      
+      String literal = sortedLitTypes.get(size);
+      String drillDownFileName = literal + "Lits.html";
+      
+      float ratio = (size / maxSize) * 79;   
+      float perc = (size / sumSize) * 100;
+      
+      if (ratio < 3){
+        ratio = 3;
+      }
+      
+      outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">");
+      outFile.println("<div id=\"lb\">");
+      outFile.println("<div id=\"rb\">");
+      outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+      outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+      outFile.println("<div id=\"content\">");
+      outFile.println("</div>");
+      outFile.println("</div></div></div></div>");
+      outFile.println("</div></div></div></div>");
+      outFile.println("</div>");
+      
+      int yOffsetText = yOffset+8;
+      outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+      outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc);
+      outFile.println("%</div>\n");
+      outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+literal+"</a></div>");
+      
+      yOffset = yOffset + 25;
+
+    }
+    outFile.println("</body>");
+    outFile.println("</html>");
+    outFile.close();
+    
+  }
+  
+
+  private static void makeStringLiteralsHtml(String outFileName, TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+
+    final PrintWriter outFile = new PrintWriter(outFileName);
+    
+    outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+    outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+    outFile.println("<html>");
+    outFile.println("<head>");
+    outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+    outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">");
+    outFile.println("</head>");
+    outFile.println("<body>");
+    
+    
+    if (nameToLitColl.get("string").stringTypeToSize.size() > 0){
+      
+      float maxSize = 0f;
+      float sumSize = 0f;
+      TreeMap<Float, String> sortedStLitTypes = new TreeMap<Float, String>(Collections.reverseOrder());
+      
+      for (String stringLiteral : nameToLitColl.get("string").stringTypeToSize.keySet()){
+        float curSize = nameToLitColl.get("string").stringTypeToSize.get(stringLiteral);
+        sumSize += curSize;
+        
+        if (curSize != 0f){
+          sortedStLitTypes.put(curSize, stringLiteral);
+          
+          if (curSize > maxSize){
+            maxSize = curSize;
+          }
+        }
+      }
+
+  
+      int yOffset = 0;
+      for (Float size : sortedStLitTypes.keySet()){
+        
+        String stringLiteral = sortedStLitTypes.get(size);
+        String drillDownFileName = stringLiteral + "Strings.html";
+        
+        float ratio = (size / maxSize) * 79;
+        float perc = (size / sumSize) * 100;
+        
+        if (ratio < 3){
+          ratio = 3;
+        }
+  
+        outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">");
+        outFile.println("<div id=\"lb\">");
+        outFile.println("<div id=\"rb\">");
+        outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+        outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+        outFile.println("<div id=\"content\">");
+        outFile.println("</div>");
+        outFile.println("</div></div></div></div>");
+        outFile.println("</div></div></div></div>");
+        outFile.println("</div>");
+        
+        int yOffsetText = yOffset+8;
+        outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+        outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc);
+        outFile.println("%</div>\n");
+        outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+stringLiteral+"</a></div>");
+        
+        yOffset = yOffset + 25;
+  
+      }
+    
+    }
+    
+    else{
+      outFile.println("No string literals found for this application.");
+      
+    }
+
+    outFile.println("</body>");
+    outFile.println("</html>");
+    outFile.close();
+  }
+  
+  
+
+  public static void makePackageClassesHtmls() throws IOException{
+        
+    for (String packageName : GlobalInformation.packageToClasses.keySet()){
+      
+      String outFileName = packageName + "Classes.html";
+      TreeMap<Float, String> sortedClasses = new TreeMap<Float, String>(Collections.reverseOrder());
+      float maxSize = 0f;
+      
+      //TODO(kprobst): not currently used, but will be for dependencies
+      //int maxDepCount = 0;
+
+      for (String className : GlobalInformation.packageToClasses.get(packageName)){
+        
+        float curSize = 0f;
+        if (! GlobalInformation.classToPartialSize.containsKey(className)){
+          System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****");
+        }
+        else{
+          curSize = GlobalInformation.classToPartialSize.get(className);
+        }
+          
+        //TODO(kprobst): not currently used, but will be for dependencies
+        /*int depCount = 0;
+        if (GlobalInformation.classToWhatItDependsOn.containsKey(className)){
+          depCount = GlobalInformation.classToWhatItDependsOn.get(className).size();
+        }*/
+        
+        if (curSize != 0f){
+          
+          sortedClasses.put(curSize, className);
+          if (curSize > maxSize){
+            maxSize = curSize;
+          }
+          //TODO(kprobst): not currently used, but will be for dependencies
+          /*if (depCount > maxDepCount){
+            maxDepCount = depCount;
+          }*/
+        }
+      }
+      
+        
+      final PrintWriter outFile = new PrintWriter(outFileName);
+      
+      outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+      outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+      outFile.println("<html>");
+      outFile.println("<head>");
+      outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+      outFile.println("<link rel=\"stylesheet\" href=\"classLevel.css\" media=\"screen\">");
+      outFile.println("<title>Classes in package \"" + packageName + "\"</title>");
+      outFile.println("</head>");
+      outFile.println("<body>");
+      
+
+      outFile.println("<center>");
+      outFile.println("<h2>Classes in package \"" + packageName + "\"</h2>");
+      outFile.println("</center>");
+      outFile.println("<hr>");
+
+      outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 90px; left:70px; position:absolute; background-color:white\"");
+
+  
+      int yOffset = 0;
+      for (Float size : sortedClasses.keySet()){
+        
+        String className = sortedClasses.get(size);
+        
+        //TODO(kprobst): switch out the commented/uncommented lines below when showing dependencies
+        //float ratio = (size / maxSize) * 45;
+        float ratio = (size / maxSize) * 85;
+         
+        if (ratio < 3){
+          ratio = 3;
+        }
+        
+        //TODO(kprobst): not currently used, but will be for dependencies
+/*        // get the dependency count
+        int depCount = 0;
+        if (GlobalInformation.classToWhatItDependsOn.containsKey(className)){
+          depCount = GlobalInformation.classToWhatItDependsOn.get(className).size();
+        }
+        float depRatio = (depCount / maxDepCount) * 25;
+        if (depRatio < 3){
+          depRatio = 3;
+        }*/
+  
+        outFile.println("<div class=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 60px;\">");
+        outFile.println("<div id=\"lb\">");
+        outFile.println("<div id=\"rb\">");
+        outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+        outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+        outFile.println("<div id=\"content\">");
+        outFile.println("</div>");
+        outFile.println("</div></div></div></div>");
+        outFile.println("</div></div></div></div>");
+        outFile.println("</div>");
+        
+        
+        //TODO(kprobst): not currently used, but will be for dependencies
+        // place holder for mock-up of dependency display  
+/*        outFile.println("<div class=\"box-right\" style=\"width:" + depRatio + "%; top: " + yOffset + "px; left: 50%\">");
+        outFile.println("<div id=\"lb\">");
+        outFile.println("<div id=\"rb\">");
+        outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+        outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+        outFile.println("<div id=\"content\">");
+        outFile.println("</div>");
+        outFile.println("</div></div></div></div>");
+        outFile.println("</div></div></div></div>");
+        outFile.println("</div>");
+        
+        
+        outFile.println("<div class=\"box-right\" style=\"width:10%; top: " + yOffset + "px; left: 75%\">");
+        outFile.println("<div id=\"lb\">");
+        outFile.println("<div id=\"rb\">");
+        outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+        outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+        outFile.println("<div id=\"content\">");
+        outFile.println("</div>");
+        outFile.println("</div></div></div></div>");
+        outFile.println("</div></div></div></div>");
+        outFile.println("</div>"); */
+        
+        int yOffsetText = yOffset+8;
+        outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+        outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">"+className+"</div>");
+        
+        yOffset = yOffset + 25;
+  
+      }
+      
+      outFile.println("</div>");
+      outFile.println("</body>");
+      outFile.println("</html>");
+      outFile.close();
+    }
+  }
+  
+
+  public static void makeCodeTypeClassesHtmls(HashMap<String, CodeCollection> nameToCodeColl) throws IOException{
+    
+    for (String codeType : nameToCodeColl.keySet()){
+      
+      //construct file name
+      String outFileName = codeType + "Classes.html";
+      
+  
+      float maxSize = 0f;
+      TreeMap<Float, String> sortedClasses = new TreeMap<Float, String>(Collections.reverseOrder());
+      for (String className : nameToCodeColl.get(codeType).classes){
+        if (GlobalInformation.classToPartialSize.containsKey(className)){
+
+          float curSize = 0f;
+          if (! GlobalInformation.classToPartialSize.containsKey(className)){
+            System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****");
+          }
+          else{
+            curSize = GlobalInformation.classToPartialSize.get(className);
+          }
+          
+          if (curSize != 0f){
+            sortedClasses.put(curSize, className);
+            if (curSize > maxSize){
+              maxSize = curSize;
+            }
+          }
+        }
+      }
+  
+      final PrintWriter outFile = new PrintWriter(outFileName);
+      
+      outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+      outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+      outFile.println("<html>");
+      outFile.println("<head>");
+
+      outFile.println("<style type=\"text/css\">");
+      outFile.println("body {background-color: #728FCE}");
+      outFile.println("h2 {background-color: transparent}");
+      outFile.println("p {background-color: fuchsia}");
+      outFile.println("</style>");
+      
+      outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+      outFile.println("<link rel=\"stylesheet\" href=\"classLevel.css\" media=\"screen\">");
+      outFile.println("<title>Classes of type \"" + codeType + "\"</title>");
+      outFile.println("</head>");
+      outFile.println("<body>");
+      
+
+
+      outFile.println("<center>");
+      outFile.println("<h2>Classes of type \"" + codeType + "\"</h2>");
+      outFile.println("</center>");
+      outFile.println("<hr>");
+
+      outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 90px; left:70px; position:absolute; background-color:white\"");
+
+  
+      int yOffset = 0;
+      for (Float size : sortedClasses.keySet()){
+        
+        String className = sortedClasses.get(size);
+        
+        float ratio = (size / maxSize) * 85;
+        
+        if (ratio < 3){
+          ratio = 3;
+        }
+  
+        outFile.println("<div class=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 60px;\">");
+        outFile.println("<div id=\"lb\">");
+        outFile.println("<div id=\"rb\">");
+        outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+        outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+        outFile.println("<div id=\"content\">");
+        outFile.println("</div>");
+        outFile.println("</div></div></div></div>");
+        outFile.println("</div></div></div></div>");
+        outFile.println("</div>");
+        
+        int yOffsetText = yOffset+8;
+         outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+        outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">"+className+"</div>");
+        
+        yOffset = yOffset + 25;
+  
+      }
+      
+      outFile.println("</div>");
+      outFile.println("</body>");
+      outFile.println("</html>");
+      outFile.close();
+    }    
+  }
+
+
+
+  public static void makeLiteralsClassesHtmls(TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+    
+    
+    for (String literalType : nameToLitColl.keySet()){
+      
+      String outFileName = literalType + "Lits.html";
+      final PrintWriter outFile = new PrintWriter(outFileName);
+      
+      outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+      outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+      outFile.println("<html>");
+      outFile.println("<head>");
+      outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+      outFile.println("<title>Literals of type \"" + literalType + "\"</title>");
+      outFile.println("</head>");
+
+      outFile.println("<style type=\"text/css\">");
+      outFile.println("body {background-color: #728FCE}");
+      outFile.println("h2 {background-color: transparent}");
+      outFile.println("p {background-color: fuchsia}");
+      outFile.println(".tablediv {");
+      outFile.println("display:  table;");
+      outFile.println("width:100%;");
+      outFile.println("background-color:#eee;");
+      outFile.println("border:1px solid  #666666;");
+      outFile.println("border-spacing:5px;/*cellspacing:poor IE support for  this*/");
+      outFile.println("border-collapse:separate;");
+      outFile.println("}");
+      outFile.println(".celldiv {");
+      outFile.println("float:left;/*fix for  buggy browsers*/");
+      outFile.println("display:  table-cell;");
+      outFile.println("width:50%;");
+      outFile.println("font-size: 14px;");
+      outFile.println("background-color:white;");
+      outFile.println("}");
+      outFile.println(".rowdiv  {");
+      outFile.println("display:  table-row;");
+      //outFile.println("width:90%;");
+      outFile.println("}");
+      outFile.println("</style>");
+      
+      outFile.println("<body>");
+      outFile.println("<center>");
+      outFile.println("<h2>Literals of type \"" + literalType + "\"</h2>");
+      outFile.println("</center>");
+      outFile.println("<hr>");
+      
+      outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 30px; left:60px; position:relative; background-color:white\"");  
+      outFile.println("<div class=\"tablediv\">");      
+      for (String literal : nameToLitColl.get(literalType).literalToLocations.keySet()){
+  
+        if (literal.trim().compareTo("") == 0){
+          literal = "[whitespace only string]";
+        }
+        
+
+        String newLiteral = "";
+        if(literal.length() > 100){
+          int i;
+          for (i = 100; i < literal.length(); i=i+100){
+            String part1 = literal.substring(i-100, i);
+            newLiteral = newLiteral + part1 + " "; 
+          }
+          if (i-100 > 0){
+            newLiteral = newLiteral + literal.substring(i-100);
+          }
+        }
+        else{
+          newLiteral = literal;
+        }
+        
+        String escliteral = escapeXml(newLiteral);
+        outFile.println("<div class=\"rowdiv\">");   
+        outFile.println("<div class=\"celldiv\">" + escliteral + "</div>");
+
+        for (String location : nameToLitColl.get(literalType).literalToLocations.get(literal)){
+          
+          String newLocation = "";
+          if(location.length() > 100){
+            int i;
+            for (i = 100; i < location.length(); i=i+100){
+              String part1 = location.substring(i-100, i);
+              newLocation = newLocation + part1 + " "; 
+            }
+            if (i-100 > 0){
+              newLocation = newLocation + location.substring(i-100);
+            }
+          }
+          else{
+            newLocation = location;
+          }
+          
+          outFile.println("<div class=\"celldiv\">" + newLocation + "</div>");
+        }
+        outFile.println("</div>");
+      }
+      outFile.println("</div>");
+      outFile.println("</body>");
+      outFile.println("</html>");
+      outFile.close();
+     }
+  }
+
+  /**
+   * Makes html file for fragment classes. 
+   * TODO(kprobst): update this once we have SOYC updated to supply enough information
+   * @throws IOException
+   */
+  public static void makeFragmentClassesHtmls() throws IOException{
+    
+    
+    for (Integer fragmentName : GlobalInformation.fragmentToStories.keySet()){
+      HashSet<String> alreadyPrintedClasses = new HashSet<String>();
+      
+      String outFileName = "fragment" + Integer.toString(fragmentName) + "Classes.html";
+      
+      final PrintWriter outFile = new PrintWriter(outFileName);
+      
+      outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+      outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+      outFile.println("<html>");
+      outFile.println("<head>");
+      outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+      outFile.println("<title>Classes correlated with fragment " + Integer.toString(fragmentName) + " </title>");
+      outFile.println("</head>");
+
+      outFile.println("<style type=\"text/css\">");
+      outFile.println("body {background-color: #728FCE}");
+      outFile.println("h2 {background-color: transparent}");
+      outFile.println("p {background-color: fuchsia}");
+      outFile.println(".tablediv {");
+      outFile.println("display:  table;");
+      outFile.println("width:100%;");
+      outFile.println("background-color:#eee;");
+      outFile.println("border:1px solid  #666666;");
+      outFile.println("border-spacing:5px;/*cellspacing:poor IE support for  this*/");
+      outFile.println("border-collapse:separate;");
+      outFile.println("}");
+      outFile.println(".celldiv {");
+      outFile.println("float:left;/*fix for  buggy browsers*/");
+      outFile.println("display:  table-cell;");
+      outFile.println("width:49.5%;");
+      outFile.println("font-size: 14px;");
+      outFile.println("background-color:white;");
+      outFile.println("}");
+      outFile.println(".rowdiv  {");
+      outFile.println("display:  table-row;");
+      outFile.println("width:100%;");
+      outFile.println("}");
+      outFile.println("</style>");
+      
+      outFile.println("<body>");
+      outFile.println("<center>");
+      outFile.println("<h2>Classes correlated with fragment " + Integer.toString(fragmentName) + "</h2>");
+      outFile.println("</center>");
+      outFile.println("<hr>");
+      
+      outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 30px; left:60px; position:relative; background-color:white\"");  
+      outFile.println("<div  class=\"tablediv\">");      
+      
+      for (String storyName : GlobalInformation.fragmentToStories.get(fragmentName)){
+        if (GlobalInformation.storiesToCorrClasses.containsKey(storyName)){
+          for (String className : GlobalInformation.storiesToCorrClasses.get(storyName)){
+  
+            if (! alreadyPrintedClasses.contains(className)){
+              //outFile.println("<div class=\"rowdiv\">");   
+              outFile.println("<div  class=\"rowdiv\">" + className + "</div>");
+              //outFile.println("</div>");
+              alreadyPrintedClasses.add(className);
+            }
+          }
+        }
+      }
+      outFile.println("</div>");
+      outFile.println("</body>");
+      outFile.println("</html>");
+      outFile.close();
+     }
+  }
+
+  
+  public static void makeStringLiteralsClassesHtmls(TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+    
+    
+    for (String literalType : nameToLitColl.get("string").stringTypeToSize.keySet()){
+      
+      String outFileName = literalType + "Strings.html";
+      
+      final PrintWriter outFile = new PrintWriter(outFileName);
+      
+      
+      outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+      outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+      outFile.println("<html>");
+      outFile.println("<head>");
+      outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+      outFile.println("<title>Literals of type \"" + literalType + "\"</title>");
+      outFile.println("</head>");
+
+      outFile.println("<style type=\"text/css\">");
+      outFile.println("body {background-color: #728FCE}");
+      outFile.println("h2 {background-color: transparent}");
+      outFile.println("p {background-color: fuchsia}");
+      outFile.println(".tablediv {");
+      outFile.println("display:  table;");
+      outFile.println("width:100%;");
+      outFile.println("background-color:#eee;");
+      outFile.println("border:1px solid  #666666;");
+      outFile.println("border-spacing:5px;/*cellspacing:poor IE support for  this*/");
+      outFile.println("border-collapse:separate;");
+      outFile.println("}");
+      outFile.println(".celldiv {");
+      outFile.println("float:left;/*fix for  buggy browsers*/");
+      outFile.println("display:  table-cell;");
+      outFile.println("width:49.5%;");
+      outFile.println("font-size: 14px;");
+      outFile.println("background-color:white;");
+      outFile.println("}");
+      outFile.println(".rowdiv  {");
+      outFile.println("display:  table-row;");
+      outFile.println("width:100%;");
+      outFile.println("}");
+      outFile.println("</style>");
+      
+      outFile.println("<body>");
+      outFile.println("<center>");
+      outFile.println("<h2>Literals of type \"" + literalType + "\"</h2>");
+      outFile.println("</center>");
+      outFile.println("<hr>");
+      
+      outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 30px; left:60px; position:relative; background-color:white\"");  
+      outFile.println("<div  class=\"tablediv\">");      
+
+      
+      for (String literal : nameToLitColl.get("string").stringLiteralToType.keySet()){
+        
+        if (nameToLitColl.get("string").stringLiteralToType.get(literal).compareTo(literalType) == 0){
+       
+
+          if (literal.trim().compareTo("") == 0){
+            literal = "[whitespace only string]";
+          }
+          
+          String newLiteral = "";
+          if(literal.length() > 100){
+            int i;
+            for (i = 100; i < literal.length(); i=i+100){
+              String part1 = literal.substring(i-100, i);
+              newLiteral = newLiteral + part1 + " "; 
+            }
+            if (i-100 > 0){
+              newLiteral = newLiteral + literal.substring(i-100);
+            }
+          }
+          else{
+            newLiteral = literal;
+          }
+          
+          String escliteral = escapeXml(newLiteral);
+          outFile.println("<div class=\"rowdiv\">");   
+          outFile.println("<div  class=\"celldiv\">" + escliteral + "</div>");
+
+          for (String location : nameToLitColl.get("string").literalToLocations.get(literal)){
+            
+            String newLocation = "";
+            if(location.length() > 100){
+              int i;
+              for (i = 100; i < location.length(); i=i+100){
+                String part1 = location.substring(i-100, i);
+                newLocation = newLocation + part1 + " "; 
+              }
+              if (i-100 > 0){
+                newLocation = newLocation + location.substring(i-100);
+              }
+            }
+            else{
+              newLocation = location;
+            }
+            
+            outFile.println("<div  class=\"celldiv\">" + newLocation + "</div>");
+          }
+          outFile.println("</div>");
+        }
+      }
+      outFile.println("</div>");
+      outFile.println("</body>");
+      outFile.println("</html>");
+      outFile.close();
+     }
+         
+          
+
+  }
+  
+  
+
+  public static String escapeXml(String unescaped) {
+    String escaped = unescaped.replaceAll("\\&", "&amp;");
+    escaped = escaped.replaceAll("\\<", "&lt;");
+    escaped = escaped.replaceAll("\\>", "&gt;");
+    escaped = escaped.replaceAll("\\\"", "&quot;");
+    escaped = escaped.replaceAll("\\'", "&apos;");
+    return escaped;
+  }
+
+}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java b/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java
new file mode 100644
index 0000000..3333352
--- /dev/null
+++ b/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java
@@ -0,0 +1,775 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.soyc;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+import org.xml.sax.SAXException;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.TreeSet;
+import java.util.TreeMap;
+import javax.xml.parsers.*;
+
+public class SoycDashboard {
+  
+  /**
+   * @param args Input: XML file containing soyc compile output
+   * @throws IOException 
+   * @throws SAXException 
+   */
+  public static void main(String[] args) {
+    
+    if (args.length != 1){
+      System.err.println("Usage: java com/google/gwt/soyc/SoycDashboard soyc-report0.xml");
+      System.exit(1);
+    }
+    
+    String inFileName = args[0];
+    
+    // to store literals data
+    final TreeMap<String, LiteralsCollection> nameToLitColl = new TreeMap<String, LiteralsCollection>();
+    nameToLitColl.put("long",new LiteralsCollection("long"));
+    nameToLitColl.put("null",new LiteralsCollection("null"));
+    nameToLitColl.put("class",new LiteralsCollection("class"));
+    nameToLitColl.put("int",new LiteralsCollection("int"));
+    nameToLitColl.put("string",new LiteralsCollection("string"));
+    nameToLitColl.put("number",new LiteralsCollection("number"));
+    nameToLitColl.put("boolean",new LiteralsCollection("boolean"));
+    nameToLitColl.put("double",new LiteralsCollection("double"));
+    nameToLitColl.put("char",new LiteralsCollection("char"));
+    nameToLitColl.put("undefined",new LiteralsCollection("undefined"));
+    nameToLitColl.put("float",new LiteralsCollection("float"));
+    
+    // to store code data
+    final HashMap<String, CodeCollection> nameToCodeColl = new HashMap<String, CodeCollection>();
+    nameToCodeColl.put("allOther", new CodeCollection("allOther"));
+    nameToCodeColl.put("widget", new CodeCollection("widget"));
+    nameToCodeColl.put("rpcUser", new CodeCollection("rpcUser"));
+    nameToCodeColl.put("rpcGen", new CodeCollection("rpcGen"));
+    nameToCodeColl.put("rpcGwt", new CodeCollection("rpcGwt"));
+    nameToCodeColl.put("gwtLang", new CodeCollection("long"));
+    nameToCodeColl.put("jre", new CodeCollection("jre"));
+    
+    // get the number of split points (so we know what code to ignore)
+    DefaultHandler fragmentCountHandler = scanXMLDocument();
+    
+    // start parsing
+    SAXParserFactory factory = SAXParserFactory.newInstance();
+    factory.setNamespaceAware(true);
+    try {
+      SAXParser saxParser = factory.newSAXParser();
+      InputStream in = new BufferedInputStream(new FileInputStream(inFileName));
+      saxParser.parse(in,fragmentCountHandler);
+      
+      
+    } catch (ParserConfigurationException e) {
+      throw new RuntimeException("Could not parse document. ", e);
+    } catch (SAXException e) {
+      throw new RuntimeException("Could not create SAX parser. ", e);
+    } catch (FileNotFoundException e) {
+      throw new RuntimeException("Could not open file. ", e);
+    } catch (IOException e) {
+      throw new RuntimeException("Could not open file. ", e);
+    }
+    GlobalInformation.numSplitPoints = (int)((float)(GlobalInformation.numFragments - 1) / 3f);
+    
+    // make the parser handler
+    DefaultHandler handler = parseXMLDocument(nameToLitColl, nameToCodeColl);
+    
+    
+    // start parsing
+    SAXParserFactory factoryMain = SAXParserFactory.newInstance();
+    factoryMain.setNamespaceAware(true);
+    try {
+      SAXParser saxParser = factoryMain.newSAXParser();
+      InputStream in = new BufferedInputStream(new FileInputStream(inFileName));
+      saxParser.parse(in,handler);
+      
+      
+    } catch (ParserConfigurationException e) {
+      throw new RuntimeException("Could not parse document. ", e);
+    } catch (SAXException e) {
+      throw new RuntimeException("Could not create SAX parser. ", e);
+    } catch (FileNotFoundException e) {
+      throw new RuntimeException("Could not open file. ", e);
+    } catch (IOException e) {
+      throw new RuntimeException("Could not open file. ", e);
+    }
+
+    // add to "All Other Code" if none of the special categories apply
+    updateAllOtherCodeType(nameToCodeColl);
+    
+    // now we need to aggregate numbers
+    GlobalInformation.computePackageSizes();
+    GlobalInformation.computePartialPackageSizes();
+    
+    // clean up the RPC categories
+    foldInRPCHeuristic(nameToCodeColl);
+    
+    // generate all the html files
+    makeHTMLFiles(nameToLitColl, nameToCodeColl); 
+    
+    System.out.println("Finished creating reports. To see the dashboard, open SoycDashboard-index.html in your browser.");
+  }
+
+
+  private static DefaultHandler parseXMLDocument(
+      final TreeMap<String, LiteralsCollection> nameToLitColl,
+      final HashMap<String, CodeCollection> nameToCodeColl) {
+    
+    DefaultHandler handler = new DefaultHandler() {
+
+      String curStoryId;
+      String curStoryLiteralType;
+      String curLineNumber;
+      String curLocation;
+      String curStoryRef;
+      HashSet<String> curRelevantLitTypes = new HashSet<String>();
+      HashSet<String> curRelevantCodeTypes = new HashSet<String>();
+      String curClassId;
+      String curPackage;
+      Integer curFragment;
+      boolean specialCodeType = false;
+      StringBuilder valueBuilder = new StringBuilder();
+      int ct = 0;
+      
+      /**
+       * This method deals with the beginning of the XML element.
+       * It analyzes the XML node and adds its information to the relevant literal or code collection for later analysis.
+       * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
+       */
+      @Override
+      public void startElement(String nsUri, String strippedName, String tagName, Attributes attributes) {
+        
+        if ((ct % 10000) == 0){
+          System.out.println(".");
+        }
+        ct++;
+        
+        valueBuilder.delete(0,valueBuilder.length());
+        
+        if ((strippedName.compareTo("package") == 0)&&(attributes.getValue("id") != null)){
+          curPackage = attributes.getValue("id");
+          
+          if (curPackage.compareTo("") == 0){
+            curPackage = "emptyPackageName";
+          }
+          
+          if (! GlobalInformation.packageToClasses.containsKey(curPackage)){
+            TreeSet<String> insertSet = new TreeSet<String>();
+            GlobalInformation.packageToClasses.put(curPackage, insertSet);
+          }
+        }
+        
+        else if (strippedName.compareTo("class") == 0){
+          
+          parseClass(nameToCodeColl, attributes);
+        }
+        
+        //TODO(kprobst): not currently used, but will be for dependencies
+/*        else if (strippedName.compareTo("on") == 0){
+          parseDependsOn(nameToCodeColl, attributes);
+        }*/
+        
+        else if (strippedName.compareTo("of") == 0){
+          parseOverrides(nameToCodeColl, attributes);
+        }
+
+        else if (strippedName.compareTo("by") == 0){
+          parseCorrelations(nameToCodeColl, attributes);
+        }
+
+        else if (strippedName.compareTo("story") == 0){
+          parseStory(attributes);
+        }
+        
+        else if (strippedName.compareTo("origin") == 0){
+          parseOrigins(nameToLitColl, attributes);
+        }
+        
+        else if (strippedName.compareTo("js") == 0){
+          if (attributes.getValue("fragment") != null){
+            // ignore all code that is not in the first load order
+            
+            curFragment = Integer.parseInt(attributes.getValue("fragment"));
+            if(!((curFragment == 0)||(curFragment == (GlobalInformation.numSplitPoints+1))||(curFragment == (GlobalInformation.numSplitPoints+2))||
+                  ((curFragment >= 2) && (curFragment <= GlobalInformation.numSplitPoints)))){
+              curFragment = -1;
+            }
+          }
+          else{
+            curFragment = -2;
+          }
+        }
+
+        else if (strippedName.compareTo("storyref") == 0){
+          parseJs(nameToLitColl, nameToCodeColl, attributes, curFragment);
+        }
+      }
+
+      
+      /**
+       * This method collects a block of the value of the current XML node that the SAX parser parses.
+       * It simply adds to the the previous blocks, so that we can collect the entire value block.
+       */
+       @Override
+      public void characters (char ch[], int start, int length){
+         valueBuilder.append(ch, start, length);
+       }
+      
+
+     /**
+      * This method marks the end of an XML element that the SAX parser parses.
+      * It has access to the full value of the node and uses it add information to the relevant literal or code collections.
+      * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
+      */
+      @Override
+      public void endElement (String  nsUri, String strippedName, String qName){
+        String value = valueBuilder.toString();
+        
+        int numBytes = value.getBytes().length;
+          
+        if ((curStoryRef != null)&&(curFragment != -1)){
+          
+          if ((!GlobalInformation.storiesToLitType.containsKey(curStoryRef))&&(! GlobalInformation.storiesToCorrClasses.containsKey(curStoryRef))){
+             GlobalInformation.nonAttributedStories.add(curStoryRef);
+             GlobalInformation.nonAttributedBytes += numBytes;
+          }
+          
+          GlobalInformation.cumSizeAllCode += numBytes;
+          
+          if (curFragment == 0){
+            GlobalInformation.cumSizeInitialFragment += numBytes;
+          }
+          
+          // go through all the classes for this story
+          if (GlobalInformation.storiesToCorrClasses.containsKey(curStoryRef)){
+            
+
+            if ((GlobalInformation.storiesToLitType.containsKey(curStoryRef))&&(GlobalInformation.storiesToCorrClasses.get(curStoryRef).size() > 0)){
+             GlobalInformation.numBytesDoubleCounted += numBytes;
+            }
+            
+            float partialSize = (float)numBytes / (float)GlobalInformation.storiesToCorrClasses.get(curStoryRef).size();                               
+            
+            //add this size to the current fragment
+            if (!GlobalInformation.fragmentToPartialSize.containsKey(curFragment)){
+              GlobalInformation.fragmentToPartialSize.put(curFragment, partialSize);
+            }
+            else{
+              float newSize = GlobalInformation.fragmentToPartialSize.get(curFragment) + partialSize;
+              GlobalInformation.fragmentToPartialSize.put(curFragment, newSize);
+            }
+            
+            for (String className : GlobalInformation.storiesToCorrClasses.get(curStoryRef)){
+              // get the corresponding package
+              if (GlobalInformation.classToPackage.containsKey(className)){
+                String packageName = GlobalInformation.classToPackage.get(className);
+                
+                if (!GlobalInformation.packageToClasses.containsKey(packageName)){
+                  TreeSet<String> insertSet = new TreeSet<String>();
+                  insertSet.add(className);
+                  GlobalInformation.packageToClasses.put(packageName, insertSet);
+                }
+                else{
+                  GlobalInformation.packageToClasses.get(packageName).add(className);
+                }
+                
+                if (GlobalInformation.classToSize.containsKey(className)){
+                  int newSize = GlobalInformation.classToSize.get(className) + numBytes;
+                  GlobalInformation.classToSize.put(className, newSize);
+                }
+                else{
+                  GlobalInformation.classToSize.put(className, numBytes);  
+                }
+                
+                if (GlobalInformation.classToPartialSize.containsKey(className)){
+                  float newSize = GlobalInformation.classToPartialSize.get(className) + partialSize;
+                  GlobalInformation.classToPartialSize.put(className, newSize);
+                }
+                else{
+                  GlobalInformation.classToPartialSize.put(className, partialSize);  
+                }
+              }
+            }
+          }
+            
+
+/*          else{
+            System.err.println("----- NO CORR CLASSES FOUND FOR STORY " + curStoryRef + " ---------");
+          }*/
+                   
+          updateLitTypes(nameToLitColl, value, numBytes);    
+        }
+      }
+
+      
+      /*
+       * This method assigns strings to the appropriate category
+       */
+      private void updateLitTypes(
+          final TreeMap<String, LiteralsCollection> nameToLitColl,
+          String value, int numBytes) {
+        
+        int iNumCounted = 0;
+        
+        for (String relLitType : curRelevantLitTypes){
+          
+          iNumCounted++;
+          
+          //then give string literals special treatment
+          if (relLitType.compareTo("string") == 0){
+          
+           
+            
+            // note that this will double-count (i.e., it will count a string twice if it's in the output twice), as it should.
+            nameToLitColl.get("string").cumStringSize += numBytes;
+            nameToLitColl.get(relLitType).cumSize += numBytes;
+                       
+            //get the origins
+            HashSet<String> originSet = nameToLitColl.get("string").storyToLocations.get(curStoryRef);
+            
+            // find the most appropriate string literal category
+            String mostAppropriateCategory = "";
+            String mostAppropriateLocation = "";
+            String backupLocation = "";
+            for (String origin : originSet){
+              
+              if ((origin.contains("ClassLiteralHolder")) && (mostAppropriateCategory.compareTo("") == 0)){
+                mostAppropriateCategory = "compiler";
+                mostAppropriateLocation = origin;
+              }
+              else if ((origin.startsWith("transient source for"))&&(origin.contains("_TypeSerializer")) && (mostAppropriateCategory.compareTo("") == 0)){
+                mostAppropriateCategory = "transient";
+                mostAppropriateLocation = origin;
+              }
+              else if ((origin.contains("InlineResourceBundleGenerator")) && (mostAppropriateCategory.compareTo("") == 0)){
+                mostAppropriateCategory = "inlinedTextRes";
+                mostAppropriateLocation = origin;
+              }
+              if (origin.compareTo("com.google.gwt.dev.js.ast.JsProgram: Line 0") != 0){
+                backupLocation = origin;
+              }
+            }
+
+            if (backupLocation.compareTo("") == 0){
+              backupLocation = "com.google.gwt.dev.js.ast.JsProgram: Line 0";
+            }
+            if ((((value.startsWith("'")) && (value.endsWith("'"))) ||
+                ((value.startsWith("\""))&&(value.endsWith("\"")))) &&
+                (mostAppropriateCategory.compareTo("") == 0)){
+              mostAppropriateCategory = "user";
+              mostAppropriateLocation = backupLocation;
+            }
+            else if (mostAppropriateCategory.compareTo("") == 0){
+              mostAppropriateCategory = "otherStrings";
+              mostAppropriateLocation = backupLocation;
+            }
+                        
+            if (!nameToLitColl.get("string").stringLiteralToType.containsKey(value)){
+              nameToLitColl.get("string").stringLiteralToType.put(value, mostAppropriateCategory);
+              if (!nameToLitColl.get("string").stringTypeToCount.containsKey(mostAppropriateCategory)){
+                   nameToLitColl.get("string").stringTypeToCount.put(mostAppropriateCategory, 1); 
+              }
+              else{
+                int iNewCount = nameToLitColl.get("string").stringTypeToCount.get(mostAppropriateCategory) + 1; 
+                nameToLitColl.get("string").stringTypeToCount.put(mostAppropriateCategory, iNewCount); 
+              }
+
+              
+              int iNewSize = numBytes;
+              if (nameToLitColl.get("string").stringTypeToSize.containsKey(mostAppropriateCategory)){
+                iNewSize += nameToLitColl.get("string").stringTypeToSize.get(mostAppropriateCategory);
+              }
+              nameToLitColl.get("string").stringTypeToSize.put(mostAppropriateCategory, iNewSize);
+
+
+              if (nameToLitColl.get("string").storyToLocations.containsKey(curStoryRef)){
+                HashSet<String> insertSet = new HashSet<String>();
+                insertSet.add(mostAppropriateLocation);
+                nameToLitColl.get(relLitType).literalToLocations.put(value,insertSet);
+                
+              }
+            } 
+          }
+
+          
+          
+          else{
+
+            // note that this will double-count (i.e., it will count a literal twice if it's in the output twice), as it should.
+            nameToLitColl.get(relLitType).cumSize += numBytes;
+            
+            if (nameToLitColl.get(relLitType).storyToLocations.containsKey(curStoryRef)){
+              if (nameToLitColl.get(relLitType).literalToLocations.containsKey(value)){
+                nameToLitColl.get(relLitType).literalToLocations.get(value).addAll(nameToLitColl.get(relLitType).
+                      storyToLocations.get(curStoryRef));
+              }
+              else{
+                HashSet<String> insertSet = nameToLitColl.get(relLitType).storyToLocations.get(curStoryRef);
+                nameToLitColl.get(relLitType).literalToLocations.put(value,insertSet);
+              }
+              
+            }
+          }          
+        }
+        
+        //System.out.println("value: |" + value + "| in story |" + curStoryRef + "| was counted " + iNumCounted + " times.");
+        
+      }
+      
+      /* 
+       * parses the "JS" portion of the XML file
+       */
+      private void parseJs(
+          final TreeMap<String, LiteralsCollection> nameToLitColl,
+          final HashMap<String, CodeCollection> nameToCodeColl,
+          Attributes attributes, Integer curFragment) {
+        curRelevantLitTypes.clear();
+        curRelevantCodeTypes.clear();
+        
+        if (attributes.getValue("idref") != null){
+          
+          curStoryRef = attributes.getValue("idref");
+          
+          if (curFragment != -1){
+            //add this to the stories for this fragment
+            if (!GlobalInformation.fragmentToStories.containsKey(curFragment)){
+              HashSet<String> insertSet = new HashSet<String>();
+              insertSet.add(curStoryRef);
+              GlobalInformation.fragmentToStories.put(curFragment, insertSet);
+            }
+            else{
+              GlobalInformation.fragmentToStories.get(curFragment).add(curStoryRef);
+            }
+          }
+          
+          for (String litType : nameToLitColl.keySet()){
+            if (nameToLitColl.get(litType).storyToLocations.containsKey(curStoryRef)){
+              curRelevantLitTypes.add(litType);
+            }
+          }
+          
+          specialCodeType = false;
+          for (String codeType : nameToCodeColl.keySet()){
+            if (nameToCodeColl.get(codeType).stories.contains(curStoryRef)){
+              curRelevantCodeTypes.add(codeType);
+              specialCodeType = true;
+            }
+          }
+          if (specialCodeType == false){
+                      
+              nameToCodeColl.get("allOther").stories.add(curStoryRef);
+            curRelevantCodeTypes.add("allOther");
+          }
+        }
+      }
+
+      /*
+       * parses the "origins" portion of the XML file
+       */
+      private void parseOrigins(
+          final TreeMap<String, LiteralsCollection> nameToLitColl,
+          Attributes attributes) {
+        if ((curStoryLiteralType.compareTo("") != 0)&&
+            (attributes.getValue("lineNumber") != null)&&
+            (attributes.getValue("location") != null)){
+          curLineNumber = attributes.getValue("lineNumber");
+          curLocation = attributes.getValue("location");
+          String curOrigin = curLocation + ": Line " + curLineNumber;
+          
+          if (!nameToLitColl.get(curStoryLiteralType).storyToLocations.containsKey(curStoryId)){
+            HashSet<String> insertSet = new HashSet<String>();
+            insertSet.add(curOrigin);
+            nameToLitColl.get(curStoryLiteralType).storyToLocations.put(curStoryId, insertSet);
+          }
+          else{
+            nameToLitColl.get(curStoryLiteralType).storyToLocations.get(curStoryId).add(curOrigin);
+          }
+        }
+      }
+
+      /*
+       * parses the "story" portion of the XML file
+       */
+      private void parseStory(Attributes attributes) {
+        if (attributes.getValue("id") != null){
+          curStoryId = attributes.getValue("id");
+          if (attributes.getValue("literal") != null){
+            curStoryLiteralType = attributes.getValue("literal");
+            GlobalInformation.storiesToLitType.put(curStoryId, curStoryLiteralType);
+          }
+          else{
+            curStoryLiteralType = "";
+          }
+        }
+      }
+
+      /*
+       * parses the "correlations" portion of the XML file
+       */
+      private void parseCorrelations(
+          final HashMap<String, CodeCollection> nameToCodeColl,
+          Attributes attributes) {
+        
+        if (attributes.getValue("idref") != null){
+          String corrClass = attributes.getValue("idref");
+        
+
+          if (corrClass.contains(":")){
+            corrClass = corrClass.replaceAll(":.*", "");
+          }
+
+          if (GlobalInformation.classToPackage.containsKey(corrClass)){ //if we know about this class
+  
+            if (! GlobalInformation.storiesToCorrClasses.containsKey(curStoryId)){
+              HashSet<String> insertSet = new HashSet<String>();
+              insertSet.add(corrClass);
+              GlobalInformation.storiesToCorrClasses.put(curStoryId, insertSet);
+            }
+            else{
+              GlobalInformation.storiesToCorrClasses.get(curStoryId).add(corrClass);
+            }
+            
+            for (String codeType : nameToCodeColl.keySet()){
+              if (nameToCodeColl.get(codeType).classes.contains(corrClass)){
+                nameToCodeColl.get(codeType).stories.add(curStoryId);
+              }
+            }
+          }
+        }
+      }
+
+      /*
+       * parses the "overrides" portion of the XML file
+       */
+      private void parseOverrides(
+          final HashMap<String, CodeCollection> nameToCodeColl,
+          Attributes attributes) {
+        if (attributes.getValue("idref") != null){
+          String overriddenClass = attributes.getValue("idref");
+          
+
+          if (overriddenClass.contains(":")){
+            overriddenClass = overriddenClass.replaceAll(":.*", "");
+          }
+          if (overriddenClass.contains("$")){
+            overriddenClass = overriddenClass.replaceAll("\\$.*", "");
+          }
+          
+          if (overriddenClass.compareTo("com.google.gwt.user.client.ui.UIObject") == 0){
+            nameToCodeColl.get("widget").classes.add(curClassId);
+          }
+          else if (overriddenClass.contains("java.io.Serializable") || 
+                   overriddenClass.contains("IsSerializable")){
+            nameToCodeColl.get("rpcUser").classes.add(curClassId);
+          }
+          else if (overriddenClass.contains("com.google.gwt.user.client.rpc.core.java")){
+            nameToCodeColl.get("rpcGwt").classes.add(curClassId);
+          }
+        }
+      }
+
+      /*
+       * parses the "class" portion of the XML file
+       */
+      private void parseClass(
+          final HashMap<String, CodeCollection> nameToCodeColl,
+          Attributes attributes) {
+        if (attributes.getValue("id") != null){
+          curClassId = attributes.getValue("id");
+
+          GlobalInformation.classToPackage.put(curClassId, curPackage);
+
+          if (curPackage.startsWith("java")){
+            nameToCodeColl.get("jre").classes.add(curClassId);
+          }
+          else if (curPackage.startsWith("com.google.gwt.lang")){
+            nameToCodeColl.get("gwtLang").classes.add(curClassId);
+          }
+          if (curClassId.contains("_CustomFieldSerializer")){
+            nameToCodeColl.get("rpcUser").classes.add(curClassId);
+          }
+          else if (curClassId.endsWith("_FieldSerializer") || 
+                    curClassId.endsWith("_Proxy") ||
+                    curClassId.endsWith("_TypeSerializer")){
+            nameToCodeColl.get("rpcGen").classes.add(curClassId);
+          }
+        }
+      }
+      
+      /*
+       * parses the "depends on" portion of the XML file
+       */
+      //TODO(kprobst): not currently used, but will be for dependencies
+      /*private void parseDependsOn(final HashMap<String, CodeCollection> nameToCodeColl, Attributes attributes) {
+        if (attributes.getValue("idref") != null){
+          String curDepClassId = attributes.getValue("idref");
+
+          if (curDepClassId.contains(":")){
+            // strip everything after the :: (to get to class, even if it's a method)
+            curDepClassId = curDepClassId.replaceAll(":.*", "");
+          }
+          if (curDepClassId.contains("$")){
+            curDepClassId = curDepClassId.replaceAll("\\$.*", "");
+          }
+          
+          if (! GlobalInformation.classToWhatItDependsOn.containsKey(curClassId)){
+            HashSet<String> insertSet = new HashSet<String>();
+            GlobalInformation.classToWhatItDependsOn.put(curClassId, insertSet);
+          }
+          else{
+            GlobalInformation.classToWhatItDependsOn.get(curClassId).add(curDepClassId);
+          }
+        }
+      }*/
+    };
+    return handler;
+  }
+  
+  
+  
+
+  private static DefaultHandler scanXMLDocument() {
+    
+    DefaultHandler handler = new DefaultHandler() {
+      
+
+      /**
+       * This method deals with the beginning of the XML element.
+       * It analyzes the XML node and adds its information to the relevant literal or code collection for later analysis.
+       * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
+       */
+      @Override
+      public void startElement(String nsUri, String strippedName, String tagName, Attributes attributes) {
+      
+        if (strippedName.compareTo("js") == 0){
+          if (attributes.getValue("fragment") != null){
+            GlobalInformation.numFragments++;
+          }
+        }
+      }
+    };
+    
+    return handler;
+  }
+  
+
+  /*
+   * assigns code to "all other code" if none of the special categories apply
+   */
+  private static void updateAllOtherCodeType(final HashMap<String, CodeCollection> nameToCodeColl){
+    //all classes not in any of the other categories
+    for (String className : GlobalInformation.classToPackage.keySet()){
+      if ( (!nameToCodeColl.get("widget").classes.contains(className))&&
+          (!nameToCodeColl.get("rpcUser").classes.contains(className))&&
+          (!nameToCodeColl.get("rpcGwt").classes.contains(className))&&
+          (!nameToCodeColl.get("rpcGen").classes.contains(className))&&
+          (!nameToCodeColl.get("jre").classes.contains(className))&&
+          (!nameToCodeColl.get("gwtLang").classes.contains(className))){
+        nameToCodeColl.get("allOther").classes.add(className);
+      }
+    }
+  }
+
+  /*
+   * generates all the HTML files
+   */
+  private static void makeHTMLFiles(
+      final TreeMap<String, LiteralsCollection> nameToLitColl,
+      final HashMap<String, CodeCollection> nameToCodeColl) {
+
+    try {
+      MakeTopLevelHtmlForPerm.makePackageClassesHtmls();
+      MakeTopLevelHtmlForPerm.makeCodeTypeClassesHtmls(nameToCodeColl); 
+      MakeTopLevelHtmlForPerm.makeLiteralsClassesHtmls(nameToLitColl);
+      MakeTopLevelHtmlForPerm.makeStringLiteralsClassesHtmls(nameToLitColl);
+      MakeTopLevelHtmlForPerm.makeFragmentClassesHtmls();
+
+      //make the shell last so we can display aggregate information here
+      MakeTopLevelHtmlForPerm.makeHTMLShell(nameToCodeColl, nameToLitColl);
+
+    } catch (IOException e) {
+      throw new RuntimeException("Cannot open file. ", e);
+    }
+  }
+
+  
+  /*
+   * cleans up the RPC code categories
+   */
+  private static void foldInRPCHeuristic(
+      final HashMap<String, CodeCollection> nameToCodeColl) {
+    /**
+     * Heuristic: this moves all classes that override serializable from RPC to "Other Code" *if* there is no RPC generated code, i.e., if the 
+     * application really is not using RPC
+     */
+    
+
+    if (nameToCodeColl.get("rpcGen").classes.size() == 0){
+      
+      for (String className : nameToCodeColl.get("rpcUser").classes){
+        
+        if ((! nameToCodeColl.get("widget").classes.contains(className))&&
+            (! nameToCodeColl.get("jre").classes.contains(className))&&
+            (! nameToCodeColl.get("gwtLang").classes.contains(className))){
+          nameToCodeColl.get("allOther").classes.add(className);          
+        } 
+      }
+      nameToCodeColl.get("rpcUser").classes.clear();
+      
+      for (String className : nameToCodeColl.get("rpcGwt").classes){        
+        if ((! nameToCodeColl.get("widget").classes.contains(className))&&
+          (! nameToCodeColl.get("jre").classes.contains(className))&&
+          (! nameToCodeColl.get("gwtLang").classes.contains(className))){
+          nameToCodeColl.get("allOther").classes.add(className);          
+        } 
+
+      }
+      nameToCodeColl.get("rpcGwt").classes.clear();
+    }
+            
+
+  }
+  
+
+  /*
+   * unescape the JS snippets - in the XML file they are XML encoded for correct display, but this 
+   * will mess up the byte counts
+   */
+  public static String unEscapeXml(String escaped) {
+    String unescaped = escaped.replaceAll("&amp;","\\&");
+    unescaped = unescaped.replaceAll("&lt;","\\<");
+    unescaped = unescaped.replaceAll("&gt;","\\>");
+    unescaped = unescaped.replaceAll("&quot;","\\\"");
+    //escaped = escaped.replaceAll("\\n", "");
+    unescaped = unescaped.replaceAll("&apos;","\\'");
+    return unescaped;
+  }
+  
+
+  
+  
+}
+
+
+
+
+