Home | History | Annotate | Download | only in jdiff
      1 package jdiff;
      2 
      3 import java.util.*;
      4 import java.io.*;
      5 import java.text.*;
      6 
      7 /**
      8  * Emit an HTML file containing statistics about the differences.
      9  * Statistical information only appears if the -stats argument is used.
     10  *
     11  * See the file LICENSE.txt for copyright details.
     12  * @author Matthew Doar, mdoar (at) pobox.com
     13  */
     14 
     15 public class HTMLStatistics {
     16 
     17     /** Constructor. */
     18     public HTMLStatistics(HTMLReportGenerator h) {
     19         h_ = h;
     20     }
     21 
     22     /** The HTMLReportGenerator instance used to write HTML. */
     23     private HTMLReportGenerator h_ = null;
     24 
     25     /**
     26      * Emit the statistics HTML file.
     27      */
     28 
     29     public void emitStatistics(String filename, APIDiff apiDiff) {
     30         try {
     31             FileOutputStream fos = new FileOutputStream(filename);
     32             h_.reportFile = new PrintWriter(fos);
     33             // Write out the HTML header
     34             h_.writeStartHTMLHeader();
     35             String oldAPIName = "Old API";
     36             if (apiDiff.oldAPIName_ != null)
     37                 oldAPIName = apiDiff.oldAPIName_;
     38             String newAPIName = "New API";
     39             if (apiDiff.newAPIName_ != null)
     40                 newAPIName = apiDiff.newAPIName_;
     41             // Write out the title
     42             h_.writeHTMLTitle("API Change Statistics");
     43             h_.writeStyleSheetRef();
     44             h_.writeText("</HEAD>");
     45             h_.writeText("<body class=\"gc-documentation\">");
     46 
     47            // writeText("<div class=\"g-section g-tpl-180\">");
     48            // Add the nav bar for the summary page
     49 
     50 
     51             // Write a customized navigation bar for the statistics page
     52             h_.writeText("<!-- Start of nav bar -->");
     53 
     54             SimpleDateFormat formatter
     55               = new SimpleDateFormat ("yyyy.MM.dd HH:mm");
     56             Date day = new Date();
     57 
     58 	    h_.writeText("<div id=\"gc-container\" style=\"padding-left:1em;padding-right:1em;\">");
     59 	    h_.writeText("<a name=\"top\"></a>");
     60 	    h_.writeText("<div id=\"gc-header\">");
     61 	    h_.writeText("  <div id=\"logo\" style=\"padding-left:1em;\">");
     62 	    h_.writeText("    <a href=\"../../../documentation.html\" target=\"_top\"><img style=\"border: 0;\" src=\"../../../assets-google/android-logo-sm.gif\" \"/></a>");
     63 	    h_.writeText("  </div> <!-- End logo -->");
     64 
     65             h_.writeText("<div class=\"and-diff-id\">");
     66             h_.writeText("<table class=\"diffspectable\">");
     67             h_.writeText("<tr>");
     68             h_.writeText("  <td colspan=\"2\" class=\"diffspechead\">API Diff Specification</td>");
     69             h_.writeText("</tr>");
     70 	    h_.writeText("      <tr>");
     71 	    h_.writeText("        <td class=\"diffspec\">To Version:</td>");
     72 	    h_.writeText("        <td class=\"diffvaluenew\">" + newAPIName + "</td>");
     73 	    h_.writeText("      </tr>");
     74 	    h_.writeText("      <tr>");
     75 	    h_.writeText("        <td class=\"diffspec\">From Version:</td>");
     76 	    h_.writeText("        <td class=\"diffvalueold\">" + oldAPIName + "</td>");
     77 	    h_.writeText("      </tr>");
     78             h_.writeText("<tr>");
     79             h_.writeText("  <td class=\"diffspec\">Generated</td>");
     80             h_.writeText("  <td class=\"diffvalue\">" + formatter.format( day ) + "</td>");
     81             h_.writeText("</tr>");
     82             h_.writeText("</table>");
     83 	    h_.writeText("  </div> <!-- End and-diff-id -->");
     84 
     85 	    h_.writeText("  <div class=\"and-diff-id\">");
     86 	    h_.writeText("    <table class=\"diffspectable\">");
     87 	    h_.writeText("      <tr>");
     88 	    h_.writeText("        <td class=\"diffspec\" colspan=\"2\"><a href=\"../changes.html\" target=\"_top\">Top of Report</a></div>");
     89 	    h_.writeText("      </tr>");
     90  	    h_.writeText("    </table>");
     91 	    h_.writeText("  </div> <!-- End and-diff-id -->");
     92 
     93 	    h_.writeText("</div> <!-- End gc-header -->");
     94 	    h_.writeText("<div id=\"codesiteContent\" style=\"margin-top: 70px;margin-bottom:80px;\">");
     95 
     96             // Write the title in the body with some formatting
     97             h_.writeText("<div style=\"xborder:1px solid yellow;vertical-align:top;padding:1em;margin-left:0;text-align:left;\">");
     98             h_.writeText(" <H1 class=\"pagecontenth1\">API&nbsp;Change&nbsp;Statistics</H1>");
     99             h_.writeText("</div>");
    100 
    101 
    102             h_.writeText("<p>");
    103             h_.writeText("The percent change statistic reported for all elements in each API is defined recursively as follows:</p>");
    104             h_.writeText("<pre>");
    105             h_.writeText("Percentage difference = 100 * (added + removed + 2*changed)");
    106             h_.writeText("                        -----------------------------------");
    107             h_.writeText("                        sum of public elements in BOTH APIs");
    108             h_.writeText("</pre>");
    109             h_.writeText("<p>where <code>added</code> is the number of packages added, <code>removed</code> is the number of packages removed, and <code>changed</code> is the number of packages changed.");
    110             h_.writeText("This definition is applied recursively for the classes and their program elements, so the value for a changed package will be less than 1, unless every class in that package has changed.");
    111             h_.writeText("The definition ensures that if all packages are removed and all new packages are");
    112             h_.writeText("added, the change will be 100%. Values are rounded here, so a value of 0% indicates a percentage difference of less than 0.5%.</p>");
    113 
    114             h_.writeText("<p>The overall difference between the two APIs is approximately <span style=\"color:222;font-weight:bold;\">" + (int)(apiDiff.pdiff) + "%</span>.");
    115             h_.writeText("</p>");
    116 
    117             h_.writeText("<br><h2 class=\"pagecontenth2\">Contents</h2>");
    118             h_.writeText("<dl><dt><a href=\"#packages\">Changed Packages</a></dt> <dd>Sorted by percentage difference</dd>");
    119             h_.writeText("<dt><a href=\"#classes\">Changed Classes and <i>Interfaces</i></a></dt><dd>Sorted by percentage difference</dd>");
    120             h_.writeText("<dt><a href=\"#numbers\">Total of Differences</a></dt><dd>Listed by number and type</dd></dl>");
    121 
    122             h_.writeText("<br>");
    123             h_.writeText("<a name=\"packages\"></a>");
    124             h_.writeText("<h2 class=\"pagecontenth2\">Changed Packages, Sorted by Percentage Difference</h2>");
    125             emitPackagesByDiff(apiDiff);
    126 
    127             h_.writeText("<br>");
    128             h_.writeText("<a name=\"classes\"></a>");
    129             h_.writeText("<h2 class=\"pagecontenth2\">Changed Classes and <i>Interfaces</i>, Sorted by Percentage Difference</h2>");
    130             emitClassesByDiff(apiDiff);
    131 
    132             h_.writeText("<br>");
    133             h_.writeText("<a name=\"numbers\"></a>");
    134             h_.writeText("<h2 class=\"pagecontenth2\">Total of Differences, by Number and Type</h2>");
    135             h_.writeText("<p>");
    136             h_.writeText("The table below lists the numbers of program elements (packages, classes, constructors, methods, and fields) that were removed, added or changed. The table includes only the highest-level program elements &mdash; that is, if a class with two methods was added, the number of methods added does not include those two methods, but the number of classes added does include that class.");
    137             h_.writeText("</p>");
    138 
    139             emitNumbersByElement(apiDiff);
    140 
    141 	    h_.writeText("</div><!-- end codesitecontent -->");
    142             h_.writeText("<div style=\"padding-left: 10px; padding-right: 10px; margin-top: 0; padding-bottom: 15px;\">");
    143             h_.writeText("  <table style=\"width: 100%; border: none;\"><tr>");
    144             h_.writeText("    <td style=\"text-align:center;font-size: 10pt; border: none; color: ccc;\"> ");
    145             h_.writeText("      <span>&copy;2008 Google - ");
    146             h_.writeText("            <a href=\"http://code.google.com\">Code Home</a> - ");
    147             h_.writeText("            <a href=\"http://www.google.com/accounts/TOS\">Site Terms of Sservice</a> - ");
    148             h_.writeText("            <a href=\"http://www.google.com/privacy.html\">Privacy Policy</a> ");
    149             h_.writeText("      </span>");
    150             h_.writeText("      <div style=\"xborder 1px solid red;position:relative;margin-top:-2em;" );
    151             h_.writeText("        font-size:8pt;color:aaa;text-align:right;\">");
    152             h_.writeText("        <em>Generated by <a href=\"http://www.jdiff.org/\">JDiff</a></em><br><img ");
    153             h_.writeText("        align=\"right\" src=\"../../../assets/jdiff_logo.gif\">");
    154             h_.writeText("      </span>");
    155             h_.writeText("    </td>");
    156             h_.writeText(" </tr></table>");
    157             h_.writeText("</div>");
    158             h_.writeText("</div><!-- end gc-containter -->");
    159 
    160             h_.writeText("<script src=\"http://www.google-analytics.com/ga.js\" type=\"text/javascript\">");
    161             h_.writeText("</script>");
    162             h_.writeText("<script type=\"text/javascript\">");
    163             h_.writeText("  try {");
    164             h_.writeText("    var pageTracker = _gat._getTracker(\"UA-18071-1\");");
    165             h_.writeText("    pageTracker._setAllowAnchor(true);");
    166             h_.writeText("    pageTracker._initData();");
    167             h_.writeText("    pageTracker._trackPageview();");
    168             h_.writeText("  } catch(e) {}");
    169             h_.writeText("</script>");
    170 
    171             h_.writeText("</BODY></HTML>");
    172             h_.reportFile.close();
    173         } catch(IOException e) {
    174             System.out.println("IO Error while attempting to create " + filename);
    175             System.out.println("Error: " + e.getMessage());
    176             System.exit(1);
    177         }
    178     }
    179 
    180     /**
    181      * Emit all packages sorted by percentage difference, and a histogram
    182      * of the values.
    183      */
    184     public void emitPackagesByDiff(APIDiff apiDiff) {
    185 
    186         Collections.sort(apiDiff.packagesChanged, new ComparePkgPdiffs());
    187 
    188         // Write out the table start
    189         h_.writeText("<TABLE summary=\"Packages sorted by percentage difference\" BORDER=\"1\" WIDTH=\"100%\" cellspacing=\"0\" cellpadding=\"0\">");
    190         h_.writeText("<TR WIDTH=\"20%\">");
    191         h_.writeText("  <TH>Percentage<br>Difference</TH>");
    192         h_.writeText("  <TH>Package</TH>");
    193         h_.writeText("</TR>");
    194 
    195         int[] hist = new int[101];
    196         for (int i = 0; i < 101; i++) {
    197             hist[i] = 0;
    198         }
    199 
    200         Iterator iter = apiDiff.packagesChanged.iterator();
    201         while (iter.hasNext()) {
    202             PackageDiff pkg = (PackageDiff)(iter.next());
    203             int bucket = (int)(pkg.pdiff);
    204             hist[bucket]++;
    205             h_.writeText("<TR>");
    206             if (bucket != 0)
    207                 h_.writeText("  <TD ALIGN=\"center\">" + bucket + "</TD>");
    208             else
    209                 h_.writeText("  <TD ALIGN=\"center\">&lt;1</TD>");
    210             h_.writeText("  <TD><A HREF=\"pkg_" + pkg.name_ + h_.reportFileExt + "\">" + pkg.name_ + "</A></TD>");
    211             h_.writeText("</TR>");
    212         }
    213 
    214         h_.writeText("</TABLE>");
    215 
    216         /* Emit the histogram of the results
    217         h_.writeText("<hr>");
    218         h_.writeText("<p><a name=\"packages_hist\"></a>");
    219         h_.writeText("<TABLE summary=\"Histogram of the package percentage differences\" BORDER=\"1\" cellspacing=\"0\" cellpadding=\"0\">");
    220         h_.writeText("<TR>");
    221         h_.writeText("  <TD ALIGN=\"center\" bgcolor=\"#EEEEFF\"><FONT size=\"+1\"><b>Percentage<br>Difference</b></FONT></TD>");
    222         h_.writeText("  <TD ALIGN=\"center\" bgcolor=\"#EEEEFF\"><FONT size=\"+1\"><b>Frequency</b></FONT></TD>");
    223         h_.writeText("  <TD width=\"300\" ALIGN=\"center\" bgcolor=\"#EEEEFF\"><FONT size=\"+1\"><b>Percentage Frequency</b></FONT></TD>");
    224         h_.writeText("</TR>");
    225 
    226         double total = 0;
    227         for (int i = 0; i < 101; i++) {
    228             total += hist[i];
    229         }
    230         for (int i = 0; i < 101; i++) {
    231             if (hist[i] != 0) {
    232                 h_.writeText("<TR>");
    233                 h_.writeText("  <TD ALIGN=\"center\">" + i + "</TD>");
    234                 h_.writeText("  <TD>" + (hist[i]/total) + "</TD>");
    235                 h_.writeText("  <TD><img alt=\"|\" src=\"../black.gif\" height=20 width=" + (hist[i]*300/total) + "></TD>");
    236                 h_.writeText("</TR>");
    237             }
    238         }
    239         // Repeat the data in a format which is easier for spreadsheets
    240         h_.writeText("<!-- START_PACKAGE_HISTOGRAM");
    241         for (int i = 0; i < 101; i++) {
    242             if (hist[i] != 0) {
    243                 h_.writeText(i + "," + (hist[i]/total));
    244             }
    245         }
    246         h_.writeText("END_PACKAGE_HISTOGRAM -->");
    247 
    248         h_.writeText("</TABLE>");
    249 	*/
    250     }
    251 
    252     /**
    253      * Emit all classes sorted by percentage difference, and a histogram
    254      * of the values..
    255      */
    256     public void emitClassesByDiff(APIDiff apiDiff) {
    257         // Add all the changed classes to a list
    258         List allChangedClasses = new ArrayList();
    259         Iterator iter = apiDiff.packagesChanged.iterator();
    260         while (iter.hasNext()) {
    261             PackageDiff pkg = (PackageDiff)(iter.next());
    262             if (pkg.classesChanged != null) {
    263                 // Add the package name to the class name
    264                 List cc = new ArrayList(pkg.classesChanged);
    265                 Iterator iter2 = cc.iterator();
    266                 while (iter2.hasNext()) {
    267                     ClassDiff classDiff = (ClassDiff)(iter2.next());
    268                     classDiff.name_ = pkg.name_ + "." + classDiff.name_;
    269                 }
    270                 allChangedClasses.addAll(cc);
    271             }
    272         }
    273         Collections.sort(allChangedClasses, new CompareClassPdiffs());
    274 
    275         // Write out the table start
    276         h_.writeText("<TABLE summary=\"Classes sorted by percentage difference\" BORDER=\"1\" WIDTH=\"100%\" cellspacing=\"0\" cellpadding=\"0\">");
    277         h_.writeText("<TR WIDTH=\"20%\">");
    278         h_.writeText("  <TH><b>Percentage<br>Difference</b></TH>");
    279         h_.writeText("  <TH><b>Class or <i>Interface</i></b></TH>");
    280         h_.writeText("</TR>");
    281 
    282         int[] hist = new int[101];
    283         for (int i = 0; i < 101; i++) {
    284             hist[i] = 0;
    285         }
    286 
    287         iter = allChangedClasses.iterator();
    288         while (iter.hasNext()) {
    289             ClassDiff classDiff = (ClassDiff)(iter.next());
    290             int bucket = (int)(classDiff.pdiff);
    291             hist[bucket]++;
    292             h_.writeText("<TR>");
    293             if (bucket != 0)
    294                 h_.writeText("  <TD ALIGN=\"center\">" + bucket + "</TD>");
    295             else
    296                 h_.writeText("  <TD ALIGN=\"center\">&lt;1</TD>");
    297             h_.writeText("  <TD><A HREF=\"" + classDiff.name_ + h_.reportFileExt + "\">");
    298             if (classDiff.isInterface_)
    299                 h_.writeText("<i>" + classDiff.name_ + "</i></A></TD>");
    300             else
    301                 h_.writeText(classDiff.name_ + "</A></TD>");
    302             h_.writeText("</TR>");
    303         }
    304 
    305         h_.writeText("</TABLE>");
    306 
    307         /* Emit the histogram of the results
    308         h_.writeText("<hr>");
    309         h_.writeText("<p><a name=\"classes_hist\"></a>");
    310         h_.writeText("<TABLE summary=\"Histogram of the class percentage differences\" BORDER=\"1\" cellspacing=\"0\" cellpadding=\"0\">");
    311         h_.writeText("<TR>");
    312         h_.writeText("  <TD ALIGN=\"center\" bgcolor=\"#EEEEFF\"><FONT size=\"+1\"><b>Percentage<br>Difference</b></FONT></TD>");
    313         h_.writeText("  <TD ALIGN=\"center\" bgcolor=\"#EEEEFF\"><FONT size=\"+1\"><b>Frequency</b></FONT></TD>");
    314         h_.writeText("  <TD width=\"300\" ALIGN=\"center\" bgcolor=\"#EEEEFF\"><FONT size=\"+1\"><b>Percentage Frequency</b></FONT></TD>");
    315         h_.writeText("</TR>");
    316 
    317         double total = 0;
    318         for (int i = 0; i < 101; i++) {
    319             total += hist[i];
    320         }
    321         for (int i = 0; i < 101; i++) {
    322             if (hist[i] != 0) {
    323                 h_.writeText("<TR>");
    324                 h_.writeText("  <TD ALIGN=\"center\">" + i + "</TD>");
    325                 h_.writeText("  <TD>" + (hist[i]/total) + "</TD>");
    326                 h_.writeText("  <TD><img alt=\"|\" src=\"../black.gif\" height=20 width=" + (hist[i]*300/total) + "></TD>");
    327                 h_.writeText("</TR>");
    328             }
    329         }
    330         // Repeat the data in a format which is easier for spreadsheets
    331         h_.writeText("<!-- START_CLASS_HISTOGRAM");
    332         for (int i = 0; i < 101; i++) {
    333             if (hist[i] != 0) {
    334                 h_.writeText(i + "," + (hist[i]/total));
    335             }
    336         }
    337         h_.writeText("END_CLASS_HISTOGRAM -->");
    338 
    339         h_.writeText("</TABLE>");
    340 	*/
    341     }
    342 
    343     /**
    344      * Emit a table of numbers of removals, additions and changes by
    345      * package, class, constructor, method and field.
    346      */
    347     public void emitNumbersByElement(APIDiff apiDiff) {
    348 
    349         // Local variables to hold the values
    350         int numPackagesRemoved = apiDiff.packagesRemoved.size();
    351         int numPackagesAdded = apiDiff.packagesAdded.size();
    352         int numPackagesChanged = apiDiff.packagesChanged.size();
    353 
    354         int numClassesRemoved = 0;
    355         int numClassesAdded = 0;
    356         int numClassesChanged = 0;
    357 
    358         int numCtorsRemoved = 0;
    359         int numCtorsAdded = 0;
    360         int numCtorsChanged = 0;
    361 
    362         int numMethodsRemoved = 0;
    363         int numMethodsAdded = 0;
    364         int numMethodsChanged = 0;
    365 
    366         int numFieldsRemoved = 0;
    367         int numFieldsAdded = 0;
    368         int numFieldsChanged = 0;
    369 
    370         int numRemoved = 0;
    371         int numAdded = 0;
    372         int numChanged = 0;
    373 
    374         // Calculate the values
    375         Iterator iter = apiDiff.packagesChanged.iterator();
    376         while (iter.hasNext()) {
    377             PackageDiff pkg = (PackageDiff)(iter.next());
    378             numClassesRemoved += pkg.classesRemoved.size();
    379             numClassesAdded += pkg.classesAdded.size();
    380             numClassesChanged += pkg.classesChanged.size();
    381 
    382             Iterator iter2 = pkg.classesChanged.iterator();
    383             while (iter2.hasNext()) {
    384                  ClassDiff classDiff = (ClassDiff)(iter2.next());
    385                  numCtorsRemoved += classDiff.ctorsRemoved.size();
    386                  numCtorsAdded += classDiff.ctorsAdded.size();
    387                  numCtorsChanged += classDiff.ctorsChanged.size();
    388 
    389                  numMethodsRemoved += classDiff.methodsRemoved.size();
    390                  numMethodsAdded += classDiff.methodsAdded.size();
    391                  numMethodsChanged += classDiff.methodsChanged.size();
    392 
    393                  numFieldsRemoved += classDiff.fieldsRemoved.size();
    394                  numFieldsAdded += classDiff.fieldsAdded.size();
    395                  numFieldsChanged += classDiff.fieldsChanged.size();
    396             }
    397         }
    398 
    399         // Write out the table
    400         h_.writeText("<TABLE summary=\"Number of differences\" BORDER=\"1\" WIDTH=\"100%\" cellspacing=\"0\" cellpadding=\"0\">");
    401         h_.writeText("<TR>");
    402         h_.writeText("  <TH COLSPAN=5 NOWRAP>");
    403         h_.writeText("  Number of Differences</TH>");
    404         h_.writeText("</TR>");
    405         h_.writeText("<TR>");
    406         h_.writeText("  <TH>&nbsp;</TD>");
    407         h_.writeText("  <TH ALIGN=\"center\"><b>Removals</b></TH>");
    408         h_.writeText("  <TH ALIGN=\"center\"><b>Additions</b></TH>");
    409         h_.writeText("  <TH ALIGN=\"center\"><b>Changes</b></TH>");
    410         h_.writeText("  <TH ALIGN=\"center\"><b>Total</b></TH>");
    411         h_.writeText("</TR>");
    412 
    413         h_.writeText("<TR>");
    414         h_.writeText("  <TD>Packages</TD>");
    415         h_.writeText("  <TD ALIGN=\"right\">" + numPackagesRemoved + "</TD>");
    416         h_.writeText("  <TD ALIGN=\"right\">" + numPackagesAdded + "</TD>");
    417         h_.writeText("  <TD ALIGN=\"right\">" + numPackagesChanged + "</TD>");
    418         int numPackages = numPackagesRemoved + numPackagesAdded + numPackagesChanged;
    419         h_.writeText("  <TD ALIGN=\"right\">" + numPackages + "</TD>");
    420         h_.writeText("</TR>");
    421 
    422         numRemoved += numPackagesRemoved;
    423         numAdded += numPackagesAdded;
    424         numChanged += numPackagesChanged;
    425 
    426         h_.writeText("<TR>");
    427         h_.writeText("  <TD>Classes and <i>Interfaces</i></TD>");
    428         h_.writeText("  <TD ALIGN=\"right\">" + numClassesRemoved + "</TD>");
    429         h_.writeText("  <TD ALIGN=\"right\">" + numClassesAdded + "</TD>");
    430         h_.writeText("  <TD ALIGN=\"right\">" + numClassesChanged + "</TD>");
    431         int numClasses = numClassesRemoved + numClassesAdded + numClassesChanged;
    432         h_.writeText("  <TD ALIGN=\"right\">" + numClasses + "</TD>");
    433         h_.writeText("</TR>");
    434 
    435         numRemoved += numClassesRemoved;
    436         numAdded += numClassesAdded;
    437         numChanged += numClassesChanged;
    438 
    439         h_.writeText("<TR>");
    440         h_.writeText("  <TD>Constructors</TD>");
    441         h_.writeText("  <TD ALIGN=\"right\">" + numCtorsRemoved + "</TD>");
    442         h_.writeText("  <TD ALIGN=\"right\">" + numCtorsAdded + "</TD>");
    443         h_.writeText("  <TD ALIGN=\"right\">" + numCtorsChanged + "</TD>");
    444         int numCtors = numCtorsRemoved + numCtorsAdded + numCtorsChanged;
    445         h_.writeText("  <TD ALIGN=\"right\">" + numCtors + "</TD>");
    446         h_.writeText("</TR>");
    447 
    448         numRemoved += numCtorsRemoved;
    449         numAdded += numCtorsAdded;
    450         numChanged += numCtorsChanged;
    451 
    452         h_.writeText("<TR>");
    453         h_.writeText("  <TD>Methods</TD>");
    454         h_.writeText("  <TD ALIGN=\"right\">" + numMethodsRemoved + "</TD>");
    455         h_.writeText("  <TD ALIGN=\"right\">" + numMethodsAdded + "</TD>");
    456         h_.writeText("  <TD ALIGN=\"right\">" + numMethodsChanged + "</TD>");
    457         int numMethods = numMethodsRemoved + numMethodsAdded + numMethodsChanged;
    458         h_.writeText("  <TD ALIGN=\"right\">" + numMethods + "</TD>");
    459         h_.writeText("</TR>");
    460 
    461         numRemoved += numMethodsRemoved;
    462         numAdded += numMethodsAdded;
    463         numChanged += numMethodsChanged;
    464 
    465         h_.writeText("<TR>");
    466         h_.writeText("  <TD>Fields</TD>");
    467         h_.writeText("  <TD ALIGN=\"right\">" + numFieldsRemoved + "</TD>");
    468         h_.writeText("  <TD ALIGN=\"right\">" + numFieldsAdded + "</TD>");
    469         h_.writeText("  <TD ALIGN=\"right\">" + numFieldsChanged + "</TD>");
    470         int numFields = numFieldsRemoved + numFieldsAdded + numFieldsChanged;
    471         h_.writeText("  <TD ALIGN=\"right\">" + numFields + "</TD>");
    472         h_.writeText("</TR>");
    473 
    474         numRemoved += numFieldsRemoved;
    475         numAdded += numFieldsAdded;
    476         numChanged += numFieldsChanged;
    477 
    478         h_.writeText("<TR>");
    479         h_.writeText("  <TD><b>Total</b></TD>");
    480         h_.writeText("  <TD ALIGN=\"right\">" + numRemoved + "</TD>");
    481         h_.writeText("  <TD ALIGN=\"right\">" + numAdded + "</TD>");
    482         h_.writeText("  <TD ALIGN=\"right\">" + numChanged + "</TD>");
    483         int total = numRemoved + numAdded + numChanged;
    484         h_.writeText("  <TD ALIGN=\"right\">" + total + "</TD>");
    485         h_.writeText("</TR>");
    486 
    487         h_.writeText("</TABLE>");
    488     }
    489 
    490 }
    491 
    492