View Javadoc

1   /*
2    * This file is part of hyphenType. hyphenType is free software: you can
3    * redistribute it and/or modify it under the terms of the GNU General Public
4    * License as published by the Free Software Foundation, either version 3 of the
5    * License, or (at your option) any later version. hyphenType is distributed in
6    * the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
7    * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
8    * the GNU General Public License for more details. You should have received a
9    * copy of the GNU General Public License along with hyphenType. If not, see
10   * <http://www.gnu.org/licenses/>.
11   */
12  package org.hyphenType.documentation.lib;
13  
14  import java.io.PrintStream;
15  import java.lang.annotation.ElementType;
16  import java.lang.annotation.Retention;
17  import java.lang.annotation.RetentionPolicy;
18  import java.lang.annotation.Target;
19  
20  import org.hyphenType.datastructure.Options;
21  import org.hyphenType.datastructure.parser.option.StructureOption;
22  import org.hyphenType.datastructure.parser.option.StructureOptionArgument;
23  import org.hyphenType.datastructure.parser.simple.StructureSimpleArgument;
24  import org.hyphenType.documentation.DocumentationFormatterEngine;
25  import org.hyphenType.exit.StatusCode;
26  import org.hyphenType.lexerparser.LexerParser;
27  import org.hyphenType.util.soc.StringParsingError;
28  
29  /**
30   * A documentation formatter that generates HTML code as output. Although there
31   * is no specific method in this formatter to redirect the output to a file,
32   * saving the output of this formatter
33   * 
34   * @author Aurelio Akira M. Matsui
35   * @param <T>
36   */
37  public class HTMLFormatterEngine<T extends Options<?>> extends DocumentationFormatterEngine<T, HTMLFormatterEngine.HTMLFormatter> {
38  
39      /**
40       * @author Aurelio Akira M. Matsui
41       */
42      @Retention(RetentionPolicy.RUNTIME)
43      @Target(ElementType.TYPE)
44      public @interface HTMLFormatter {
45          /**
46           * 
47           */
48          boolean bodyOnly() default false;
49  
50          /**
51           *
52           */
53          boolean addW3CLogo() default false;
54  
55          /**
56           *
57           */
58          boolean addHyphenTypeLogo() default false;
59  
60          /**
61           *
62           */
63          String colorA() default "#DDDDDD";
64  
65          /**
66           * 
67           */
68          String colorB() default "#FFFFDD";
69  
70          /**
71           *
72           */
73          String usage() default "usage";
74  
75          /**
76           * 
77           */
78          String options() default "options";
79  
80          /**
81           * 
82           */
83          String option() default "option";
84  
85          /**
86           * 
87           */
88          String statusCode() default "status code";
89  
90          /**
91           * 
92           */
93          String meaning() default "Meaning";
94      }
95  
96      @SuppressWarnings("unchecked")
97      @Override
98      public final void printDocumentation(final PrintStream pw, final LexerParser<T> lexPar, final HTMLFormatter annotation) {
99  
100         try {
101 
102             if (!annotation.bodyOnly()) {
103                 pw.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
104                 pw.println("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">");
105                 pw.println("\t<head>");
106                 pw.println("\t\t<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />");
107                 pw.println("\t\t<title>Command line documentation</title>");
108                 pw.println("\t\t<style type=\"text/css\">");
109                 pw.println("\t\t\tbody {font-family:Verdana;}");
110                 pw.println("\t\t\ttr.r0 {");
111                 pw.println("\t\t\t\tbackground-color: " + annotation.colorA() + ";");
112                 pw.println("\t\t\t}");
113                 pw.println("\t\t\ttr.r1 {");
114                 pw.println("\t\t\t\tbackground-color: " + annotation.colorB() + ";");
115                 pw.println("\t\t\t}");
116                 pw.println("\t\t\timg {border: none}");
117                 pw.println("\t\t</style>");
118                 pw.println("\t</head>");
119                 pw.println("\t<body>");
120             }
121 
122             pw.println("\t\t<p>" + annotation.usage() + ": program [" + annotation.options() + "] ");
123 
124             pw.print("\t\t");
125 
126             for (StructureSimpleArgument simpleArgument : lexPar.getSimpleArguments()) {
127                 if (!simpleArgument.isMandatory()) {
128                     pw.print("\t\t[");
129                 }
130                 pw.print(getOptionsInterfaceValue(simpleArgument.getName(), simpleArgument.getName()));
131                 if (simpleArgument.method.getReturnType().isArray()) {
132                     pw.print("...");
133                 }
134                 if (!simpleArgument.isMandatory()) {
135                     pw.print("]");
136                 }
137                 pw.print(" ");
138             }
139 
140             pw.println("<br/>");
141             pw.println("\t\t\t<br/>");
142             pw.println("\t\t\t" + getOptionsInterfaceValue("", lexPar.getArgsObject().description()));
143             pw.println("\t\t\t<br/>");
144             pw.println("\t\t\t<br/>");
145             pw.println("\t\t</p>");
146             pw.println("\t\t<table cellspacing=\"0\" rules=\"rows\" frame=\"hsides\">");
147             pw.println("\t\t\t<tr>");
148             pw.println("\t\t\t\t<td>");
149             pw.println("\t\t\t\t\t<strong>" + annotation.option() + "</strong>");
150             pw.println("\t\t\t\t</td>");
151             pw.println("\t\t\t\t<td>");
152             pw.println("\t\t\t\t\t&nbsp;&nbsp;&nbsp;&nbsp;");
153             pw.println("\t\t\t\t</td>");
154             pw.println("\t\t\t\t<td>");
155             pw.println("\t\t\t\t\t<strong>" + annotation.meaning() + "</strong>");
156             pw.println("\t\t\t\t</td>");
157             pw.println("\t\t\t</tr>");
158 
159             int x = 0;
160 
161             for (StructureOption parsedOption : lexPar.getParsedOptions()) {
162 
163                 x = (x + 1) % 2;
164 
165                 pw.println("\t\t\t<tr class=\"r" + x + "\">");
166                 pw.println("\t\t\t\t<td>");
167 
168                 String entry = "  ";
169                 for (String alternative : parsedOption.alternatives) {
170                     if (entry.contains(lexPar.getArgsObject().singleHyphen())) {
171                         entry += ", ";
172                     }
173                     if (lexPar.getArgsObject().doubleHyphenInLongOptions() && alternative.length() > 1) {
174                         entry += lexPar.getArgsObject().doubleHyphen();
175                     } else {
176                         entry += lexPar.getArgsObject().singleHyphen();
177                     }
178                     entry += alternative;
179                     if (parsedOption.value != null) {
180                         if (!parsedOption.value.mandatory) {
181                             entry += "[";
182                         }
183                         entry += lexPar.getArgsObject().equals() + parsedOption.value.name;
184                         if (!parsedOption.value.mandatory) {
185                             entry += "]";
186                         }
187                     }
188                 }
189 
190                 for (StructureOptionArgument argument : parsedOption.arguments) {
191                     entry += " ";
192                     if (!argument.isMandatory()) {
193                         entry += "[";
194                     } else {
195                         entry += "&lt;";
196                     }
197                     entry += argument.getName();
198                     if (argument.method.getReturnType().isArray()) {
199                         entry += "...";
200                     }
201                     if (!argument.isMandatory()) {
202                         entry += "]";
203                     } else {
204                         entry += "&gt;";
205                     }
206                 }
207 
208                 pw.println("\t\t\t\t\t<code>" + entry + "</code>");
209                 pw.println("\t\t\t\t</td>");
210                 pw.println("\t\t\t\t<td>");
211                 pw.println("\t\t\t\t\t&nbsp;&nbsp;");
212                 pw.println("\t\t\t\t</td>");
213                 pw.println("\t\t\t\t<td>");
214 
215                 String optionDocumentation = getOptionsInterfaceValue(parsedOption.method.getName(), parsedOption.description);
216                 pw.println("\t\t\t\t\t" + optionDocumentation);
217                 pw.println("\t\t\t\t</td>");
218                 pw.println("\t\t\t</tr>");
219             }
220 
221             pw.println("\t\t</table>");
222 
223             if (lexPar.getArgsObject().documentStatusCodes()) {
224 
225                 pw.println("\t\t<p><br/><br/></p>");
226                 pw.println("\t\t<table cellspacing=\"0\" rules=\"rows\" frame=\"hsides\">");
227                 pw.println("\t\t\t<tr>");
228                 pw.println("\t\t\t\t<td>");
229                 pw.println("\t\t\t\t\t<strong>" + annotation.statusCode() + "</strong>");
230                 pw.println("\t\t\t\t</td>");
231                 pw.println("\t\t\t\t<td>");
232                 pw.println("\t\t\t\t\t&nbsp;&nbsp;&nbsp;&nbsp;");
233                 pw.println("\t\t\t\t</td>");
234                 pw.println("\t\t\t\t<td>");
235                 pw.println("\t\t\t\t\t<strong>" + annotation.meaning() + "</strong>");
236                 pw.println("\t\t\t\t</td>");
237                 pw.println("\t\t\t</tr>");
238                 pw.println();
239 
240                 for (StatusCode statusCode : lexPar.getArgsObject().statusCodeEnum().getEnumConstants()) {
241                     Enum<?> enumConstant = Enum.valueOf((Class<? extends Enum>) lexPar.getArgsObject().statusCodeEnum(), statusCode.toString());
242 
243                     x = (x + 1) % 2;
244 
245                     pw.println("\t\t\t<tr class=\"r" + x + "\">");
246                     pw.println("\t\t\t\t<td align=\"right\">");
247                     pw.println("\t\t\t\t\t" + enumConstant.ordinal());
248                     pw.println("\t\t\t\t</td>");
249                     pw.println("\t\t\t\t<td>");
250                     pw.println("\t\t\t\t\t&nbsp;&nbsp;");
251                     pw.println("\t\t\t\t</td>");
252                     pw.println("\t\t\t\t<td>");
253                     pw.println("\t\t\t\t\t" + getStatusCodeUserDescription(enumConstant));
254                     pw.println("\t\t\t\t</td>");
255                     pw.println("\t\t\t</tr>");
256                 }
257                 pw.println("\t\t</table>");
258             }
259 
260             pw.println("\t\t<p>");
261 
262             if (annotation.addW3CLogo()) {
263                 pw.println("\t\t\t<a href=\"http://validator.w3.org/check?uri=referer\"><img src=\"data:image/png;base64," + "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAABUFvrSAAADAFBMVEUBAAAIBgMMCQQLCwsSDgYXEgkaFQoUFBQcHB" + "wlHQ4rIhEwJhM2KxU7Lxc9MBgjIyMoKCg0MzI7OztBNBpOPh5OSz9TQiFeSyVkUChqVCpuWCx1Rzl0XC5+ZDFOTk5S" + "T0tWUk1VVVVcXFxqXUplZWVra2twcHB7e3sAWpwIX58JYJ8OY6ERZaIVaKQaa6Yebaghb6klcqopdawxea82fbE4fr" + "I+grRFhrZMi7pVkb1alL9dlsBkm8NoncRtocZ0pcl8qsyWBAOZAACcCASIIBmdNiegDge3PB6mPiqBZzODaDSKbjaO" + "cTiUdjuXeDyaez26QiG/TCaAeWihclPATifBUCjIXy/QbzfWej3Yfj+KgWWjgkGui0WxjUa0gVi3kkm6lEq+mEyjkm" + "uzn2e7pnLFnU7eikXOpFHRp1PVqlXarlfesVjjlUrmm03poFDtqVTitFrmuFzqu13ywWD7xWL+y2WDg4OXl5eYmJip" + "pZ61rZisrKy0tLS/v7+Crs6FsNCLtNKQt9SWu9aYvNebvtifwdqjw9uox92ryd6yzeG20OPCwsLMzMzU1NTA1ufG2u" + "jN3+zT4+7d6fL/7Mbn5+fs7Ozl7vXp8fbu9Pj09PTy9/r1+Pv+/v7MzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
264                         + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADn" + "4rtgAAAAnnRSTlP///////////////////////////////////////////////////////////////////////////" + "//////////////////////////////////////////////////////////////////////////////////////////" + "////////////////////////////////////////////AD6H4/gAAAABYktHRP+lB/LFAAAACXBIWXMAAABIAAAASA" + "BGyWs+AAADSUlEQVRIx+2WaU8TURSGzyCLQEUxiFYtCEo8Da3sYglQbDUaluISV6pYFdsyop1Or8ElSgg2RSjgArSZ" + "63/13JkOXRBZgn7yTXpmyzwz857lFhb3XW9/CsEi317f2c71/OnZ/+C9gSdDKmNySI2GorQNxiaDpFA4FgrS+WgoxF" + "hwck/gMTjBwmCJ+WCYMQso5SBUoQCcZKwGgClg2QSOt7jp7pnWGQFJ2e0tpFYX5+k3TUn+QTOsqAV/hRRmJngiYAVr" + "YILAkipT+C34GzqJ+AW7BDiBhga4VgdwIFmdNMBKMcAQI3Ctz1cOCmPD4hEKVBX5TpdYfg/m7bhC0YHrFHvQtbY2h8"
265                         + "40fw9Hzh8tO7CaSZ6V3k2AdWXBNdaKosGtwG78SLED4xSd+I1rbWK37ii5cO58pirCUglYBXhIjVlywWGQoluBl7CT" + "83VE8nUZ28lu3ZUycUlLZ8CVUrgGnpgeR7JgZrUxHVzh9/tjAuzxbFRFM7nwGbGZ8wF083UHLlPqDuZWxSAZrBSXqm" + "byGBuBEQNM0sFCUQJf8QiyAXbRp7uwA5fI7iXei9ifotzlgiMy3R+NqKpMRiv6gUwVzfTAlAiLyUJkxVWPUAYcR5fW" + "fCGB7jV00GOciJ0an95T5133GDLAKXTMY1/K3j6HPeJ42YEJvrAX8M0M1+y8LvJhnnejURmc92HvH2aFGtuWa4I/Id" + "o1qgbElH48j235YNkiwbhxc6QKpJN56NiN18bOnQ2uCV5BvCRaEC8aqAS2rBp76bSRPFutCT4No8chkMu95vG+ynIv" + "e3KHUAvO6i04w2d7dCu6Fwxy00LGCpsJrixlQbAVfL/35Qb3VN5068M1vQW/UrG5U3EHxrXGH4IrJTfAxluqUMWicC" + "jLva/zvC8Mf72388fmfIeIS61UIU60o2jFxbKGxsMwzQvfuKScyTREcxz2ZOV9XDCPtY/6ZoB+X1/udzl6Rw2RDWfV" + "7ngceonFxXIqMgj83eXey3Fe7HfRh0bAlondZQJKgXM2rsrsmd2rXK4j6ZHx8PMAmhM/y2CO1oH7vmdx9X0wfZLj7v" + "0q/8Orcv7D8T039s/8VH7bVu2c718NbJrhuBzq2leo3nTlTX62DfwGZkKiGotSUXQAAAABJRU5ErkJggg==\" " + "alt=\"Valid XHTML 1.0 Strict\" height=\"31\" width=\"88\" /></a>");
266             }
267 
268             if (annotation.addHyphenTypeLogo()) {
269                 pw.println("\t\t\t<a href=\"http://hyphenType.org\"><img alt=\"hyphenType\" src=\"data:image/png;base64," + "iVBORw0KGgoAAAANSUhEUgAAAFQAAAAkCAYAAAAXSR0AAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAEnQAABJ0BfD" + "RroQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAA15SURBVGiB7Zp5UBdXtsc/v/6xaNgk4rDK" + "T0UT/ImIigsOyUDUjHF5SHADgxj35cUk46QkMS9xcFIPLevlaWb8GTNJZUajMWJiKUoIgkkUpBRHVBR3ERUkrggosp" + "33R0NDsyeaMpN536pbt/ts9/bt0+ee2/caVqxYIf7+/gAYaAQRPb32vk1ac7ot0dqgN6QZGrXXGr1FWuM+t9Nee2TT" + "tm3DkJSUJGazmYyMjCbCv1Z0ys/H8cqVR2av64QJdH32WaKHD8cKICMjg8jIyEfWwC8d8cCSR2hv/717dH32WRRFQX" + "mEdn+RiIqKIjU1tWUBNzfIy1Prh4TRaPz1D6i9vT1eXl4tCxiNYDKBldVDt9XEQ21sbDAajRgMBnr27Ennzp2bVXR2" + "dsZsNmNjY6Ojd+jQAYOhfhqxtrZGUeqbsLKywtraWqfj6OiIn58fdnZ2Orq1tTVWDR6yoV0Ak8lEz549dfYbtmM2m/" + "Hw8Gi2/y3CxgbMZrC1bdgRtTQnazTqSIrBAElJSbJ582YBJCsrS7Zu3Sp5eXlSVVUlIiLLly8XQADp2LGjbNiwQURE" + "7t69K6WlpRIdHS2AKIoiN2/elAkTJmjyJ0+elLi4OO3+888/l5UrVwogHTp0kI8++kiqq6slLy9PKioqZMmSJTrZDz"
270                         + "/8UFatWiXXr1+Xc+fOCSD9+/eXU6dOye3bt+X27dty9uxZ6devn6YXEhIiRUVFUlFRIaWlpVJYWCinT5/W+IDEq/Oy" + "Wjw9RURE/vIXkXv3RKqqRIqLRZ57TuUvWCBy6ZKI0Viv4+YmUlEhMnCgCMi+mTNFRGTuuHHS5PV6eHgQFhaGvb09r7" + "76Km+//TYDBgwAYMmSJQwbNowhQ4bg4uLC4sWL+eSTTzCbzdTU1LB3716Cg4MB8PX1xWQyMXHiRM12UFAQaWlpAMTG" + "xtK/f398fHzo1q0bISEhvPfee9SlcAAxMTFUVlYSERHBSy+9hK2tLdu2bWPTpk24u7vj7u5OSkoKFosFUL19y5YtfP" + "XVV5hMJhwcHFi/fn37vFMEevVSP//kZPj4YzUMbNgAzs4wZky97OzZcPiwWhp6qKLA1408dOHChbq3ee3aNVm6dKkA" + "cv78eYmPj9fx8/PzNS+eP3++HDp0SAB56623JD4+XgoLC8XPz088PDykoqJC7OzsBJArV67I0qVLJSAgQCu5ubmyaN" + "EizUNXr16ta2v06NFSXFwsgwcP1nSioqKkpqZGOnbsKFOnTpXKykpxcnLSdObMmdM+D/XyqqcNGqTS/PzU+7VrRZKS" + "1GsrK5ErV0SiojT5Og/9z/BwaTMS5+Tk4OrqCoC3tzfp6ek6fnp6Ot7e3gCkpqayZs0a7OzsePHFF5k9ezb29vZMmD" + "CBY8eOcfDgQcrKyujQoQOenp6Eh4czcuRIzVZRURFlZWXafU1Nja6tnj17YjAYWLlypY7+/fff4+DggK+vL9nZ2RQX" + "F7f1WK3jxAm1dnWFnBxYuxaOHoUePaB/f9VzExKaqClGI60OqKIoBAQEkJiYCMD169cxm83s3LlTk+nTpw/ffPMNAG"
271                         + "fOnKGwsJBJkybRqVMnjhw5whdffIHFYsHOzk773MvLyykuLmbZsmWa7fagqKiI0tJSQkJCmuXfvXuXrl27tttei+jX" + "T60vXlTrnBxIT4e5cyEwENavh4qKJmrG5vLQulnYYDAQHR2No6Mju3btAiAlJYXw8HDs7e0BCAgIoG/fvqSkpGj6aW" + "lpLF++nITaN7h//36cnZ2JjIzUBhRg9+7dxMbG6mZ3b29vzGZzi89Z54nz58/X0UeNGgWoCxRXV1dGjBihPcvgwYNb" + "tKdDXRZhZQVTp8LJk/UDCvDXv8K8efDMM7BuXQsmDE1jaHl5uWRmZsq5c+eksrJSXnnlFS32eHp6yokTJ+TWrVuSnJ" + "ws1dXVYrFYdPEpOjpaREQCAwM12gcffCD3798XW1tbjebm5iaZmZly7do1SUxM1NoODw/XYuj777+vsw3IpEmT5M6d" + "O3L48GFJTEyUvLw8KSoq0vh1WUh2drYUFhZKdnZ2+2JoYaHIzp0iBQUit2+LBAfXy4CItbVIUZHIli16eoMY+kZUlB" + "i+TkqS23fuEBkZSVZWFhs3biQ3N5fOnTtz4MABLjZ8S6i5ZmhoKO7u7hw9epTDjWY6e3t7Bg4cyHfffafRXF1d8fb2" + "5tChQzpZRVEYOnQoPj4+lJWVkZWVRX5+PgBms5kHDx5w/vz5Jp7g4uLC4MGD6dKlC1euXCE9PZ3y8nLNS4YPH46Xlx" + "cZGRmUlJTQtWtXDh48qOnrlp42NjBsGJw/DyEhUFMDqalw7Zq+UWdnuHwZXngB9u3TsfbPnEnw3/5GbHR027P8r7Ho" + "PLS9ZckSkezsZnl1HvrmtGn6PLSkpIQHDx408Yh/exiNEB0Nq1e3LqYo6ixvMpmYPHky62qD7eTJk3/+Tj5GPJGfz4"
272                         + "GrV3+c0ujRal2bIjaEQ+1iRFEUrBAhKCiIoKCgh+3nvz2UOg8tLIYjlx93dx4OfW7lYHoS8PN7bH3QEvsjl+GNBOjW" + "WU3HLt74eRp8wgb6eMDhS1Ajj9b2p3kJmLrxeAe0zkPrEBMEtlbw1vafp0HvJ+HT6TDgz/Cg6tHb37NnD3/c3nLnZ8" + "yYwaJFix59w7UwGo1YNdkY+xeGr68vsbWrpEuXLhEbG8u6detwcnICaHUV9ihgMBiaX8v36AIje8Pd+7DzGJQ+AKMC" + "EQPguzNQdLdettdv1LI7B3zdwN0Jzv6g6tt3gG9OwulGObKNFYz1B49OkHwCzhTp+d1d4LmnodMTcPwqpOSibUK+4A" + "enrqntDOoGOVfh2zMqz8vLiylTpgCQnZ1NbGwsYWFhuLm5UVBQwM6dO+ndu7fuJ3dqaiqKohAaGkpycjKdOnVCURR2" + "796Nra0t06ZN0/2oLi8v57PPPiM3NxdPT0+mTZum/Yhvdi0/tAdYosDUGcIC4OtXwcoI1TUw2g9eHqaX/+Pz4OepXg" + "f3hPfGw9+ng9kdxvjBppnqgDfEltnwvBm8OsEXc2B033re756CzbPUWCsCsaPgDyPq+QtD4MOX4I3nwcVe5a9uR5bn" + "7OzMm2++yZdffqnRKioqiIqK4sYNddKwWCxEREQQGRnJ2bNnWblyJUOGDNFy8+LiYgIDA7FYLDg4OLB9+3b8/f2prK" + "wEmomhAPm3YN5nUF6peuXeP8AgExy4AJsPwZ/Gwf+mqnwvZwjqAX/eXa9/oxSmfgwl5ar+x9Mg5GnVa+uwOAFyC9Xr" + "q3fg+d6w+7gq/84YWJUCCbUr2uST8MEU+J899V6alAPv71Gve/1GfSnH29gd69ixIy+//DIWi0XLs7du3Yq1tTXh4e"
273                         + "GaXHBwMBs3bsTKyorS0lK8vb3JyMggNDSU+Ph4XF1dtU2/d999l759+/Ltt98ycuTI5jfpCu6ogwWqV+bfAnOtx6ee" + "Unlja3+qTwqE9PNw+Va9/q0ydTDr9A/mwdDu+jYuXK+/vnij3r73k+DmpHp37Ci1jPNXPdHsrtfRbN1QQ0jHZrZ9Gm" + "PevHns27eP3NxcANauXcvcuXN1e1fdunXT7u3t7RkyZIg2gHv37kVEeO2117QCsGPHDqBBYt8aqmrqT1xUVUPCPyFq" + "EOw4Ci/2h9gvW1WntFwdpJZQ3cC+8xNqfaJApdfhnR2q57ek31706tWLESNGYLFYmDFjBllZWboQ0BycnJy4fFlN0m" + "/cuEFoaCgBAQEaPyAggO7dVY8xNPfJt4Wth2HOM7Dk9+qkld70Z5AOQT56j2wNeTfV+nSROtn8HFiwYAExMTHcvHmT" + "iRMnarsRzUFESE1NZfHixQA89dRT2NraMn369Gblm42hbaHoLuw9DVMGwYqvaeLgro4Q0BWK70NYPxjSHWb9o322b5" + "Wpnv/f4+FPiWrc9X4S/qMf/CNTH1p+KsaOHYujoyObNm3iwIEDTfjHjh3j+PHjlJeXs2bNGqqrq5k1axYAixcvZtSo" + "UfTu3ZuIiAhKSkpIS0ujqqqKhQsXqnloQ2N37oONfquZG6Vq2tQQKbnwWx/4Krtph22t4L/GqJPF5dtqSPin+ouTym" + "o1Rjd8B/cq9WlY3C5Y8DtYNQG6OKgvJvOC+jUA/FAC9xrtPhTcafpibWxsMJlMGBvtnRuNRsLCwsjMzGTo0KFN+l9Q" + "UMC4ceO4evUqgYGBpKam4uLiAsDw4cNJSEjgnXfe4fXXX0dRFPz9/YmLiwNUDzUk79olVd6jeaPpnlOLWD0ZbpZBXK"
274                         + "PtoFnBauo0/VN1CdtGeG4T1kb1JbQHn+YtY1A3YNmyVuWqqqrw8fEhLi6OmJgYHW/8+PH4+voSHx+PiDQ5XNHYjqIo" + "uoMWn8TF/fijOF7OEPo0bDrYutzDDia0fzB/DLZt28a9e/e0BUBLaG0wQT2d0vjUyk+KoV7OsCYNzv3QlJdT0PRz/K" + "WhtLSUNWvWYNvwuE0txo0b1+ok1Ra0T77vb0f//++7R4CNK1aoP0fcndTyr43HN5B1UBQFQ8zkyTXHTp40tPdodENa" + "c0esm6MrBoPaWG2tGAwYDAaMjWgNa4PBoLtuTlZHry2t2vuJbbdop3ZSqqPduXCB/wPneX1TjWdPrAAAAABJRU5Erk" + "Jggg==\" /></a>");
275             }
276             pw.println("\t\t</p>");
277 
278             if (!annotation.bodyOnly()) {
279                 pw.println("\t</body>");
280                 pw.println("</html>");
281             }
282 
283         } catch (StringParsingError e) {
284             e.printStackTrace();
285         }
286     }
287 }