]> git.donarmstrong.com Git - perltidy.git/blob - docs/tutorial.html
update changelog to 20220613-1, update remove iso8859 patch
[perltidy.git] / docs / tutorial.html
1 <?xml version="1.0" ?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml">
4 <head>
5 <title></title>
6 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
7 <link rev="made" href="mailto:root@localhost" />
8 </head>
9
10 <body>
11
12
13
14 <ul id="index">
15   <li><a href="#A-Brief-Perltidy-Tutorial">A Brief Perltidy Tutorial</a>
16     <ul>
17       <li><a href="#A-First-Test">A First Test</a></li>
18       <li><a href="#Indentation">Indentation</a></li>
19       <li><a href="#Input-Flags">Input Flags</a></li>
20       <li><a href="#Line-Length-and-Continuation-Indentation">Line Length and Continuation Indentation.</a></li>
21       <li><a href="#Tabs-or-Spaces">Tabs or Spaces?</a></li>
22       <li><a href="#Input-Output-Control">Input/Output Control</a></li>
23       <li><a href="#Style-Variations">Style Variations</a></li>
24       <li><a href="#Configuration-Files">Configuration Files</a></li>
25       <li><a href="#Error-Reporting">Error Reporting</a></li>
26       <li><a href="#The-Log-File">The Log File</a></li>
27       <li><a href="#Using-Perltidy-as-a-Filter-on-Selected-Text-from-an-Editor">Using Perltidy as a Filter on Selected Text from an Editor</a></li>
28       <li><a href="#Writing-an-HTML-File">Writing an HTML File</a></li>
29       <li><a href="#Summary">Summary</a></li>
30     </ul>
31   </li>
32 </ul>
33
34 <h1 id="A-Brief-Perltidy-Tutorial">A Brief Perltidy Tutorial</h1>
35
36 <p>Perltidy can save you a lot of tedious editing if you spend a few minutes learning to use it effectively. Perltidy is highly configurable, but for many programmers the default parameter set will be satisfactory, with perhaps a few additional parameters to account for style preferences.</p>
37
38 <p>This tutorial assumes that perltidy has been installed on your system. Installation instructions accompany the package. To follow along with this tutorial, please find a small Perl script and place a copy in a temporary directory. For example, here is a small (and silly) script:</p>
39
40 <pre><code> print &quot;Help Desk -- What Editor do you use?&quot;;
41  chomp($editor = &lt;STDIN&gt;);
42  if ($editor =~ /emacs/i) {
43    print &quot;Why aren&#39;t you using vi?\n&quot;;
44  } elsif ($editor =~ /vi/i) {
45    print &quot;Why aren&#39;t you using emacs?\n&quot;;
46  } else {
47    print &quot;I think that&#39;s the problem\n&quot;;
48  }</code></pre>
49
50 <p>It is included in the <i>docs</i> section of the distribution.</p>
51
52 <h2 id="A-First-Test">A First Test</h2>
53
54 <p>Assume that the name of your script is <i>testfile.pl</i>. You can reformat it with the default options to use the style recommended in the perlstyle man pages with the command:</p>
55
56 <pre><code> perltidy testfile.pl</code></pre>
57
58 <p>For safety, perltidy never overwrites your original file. In this case, its output will go to a file named <i>testfile.pl.tdy</i>, which you should examine now with your editor. Here is what the above file looks like with the default options:</p>
59
60 <pre><code> print &quot;Help Desk -- What Editor do you use?&quot;;
61  chomp( $editor = &lt;STDIN&gt; );
62  if ( $editor =~ /emacs/i ) {
63      print &quot;Why aren&#39;t you using vi?\n&quot;;
64  }
65  elsif ( $editor =~ /vi/i ) {
66      print &quot;Why aren&#39;t you using emacs?\n&quot;;
67  }
68  else {
69      print &quot;I think that&#39;s the problem\n&quot;;
70  }</code></pre>
71
72 <p>You&#39;ll notice an immediate style change from the &quot;cuddled-else&quot; style of the original to the default &quot;non-cuddled-else&quot; style. This is because perltidy has to make some kind of default selection of formatting options, and this default tries to follow the suggestions in the perlstyle man pages.</p>
73
74 <p>If you prefer the original &quot;cuddled-else&quot; style, don&#39;t worry, you can indicate that with a <b>-ce</b> flag. So if you rerun with that flag</p>
75
76 <pre><code> perltidy -ce testfile.pl</code></pre>
77
78 <p>you will see a return to the original &quot;cuddled-else&quot; style. There are many more parameters for controlling style, and some of the most useful of these are discussed below.</p>
79
80 <h2 id="Indentation">Indentation</h2>
81
82 <p>Another noticeable difference between the original and the reformatted file is that the indentation has been changed from 2 spaces to 4 spaces. That&#39;s because 4 spaces is the default. You may change this to be a different number with <b>-i=n</b>.</p>
83
84 <p>To get some practice, try these examples, and examine the resulting <i>testfile.pl.tdy</i> file:</p>
85
86 <pre><code> perltidy -i=8 testfile.pl</code></pre>
87
88 <p>This changes the default of 4 spaces per indentation level to be 8. Now just to emphasize the point, try this and examine the result:</p>
89
90 <pre><code> perltidy -i=0 testfile.pl</code></pre>
91
92 <p>There will be no indentation at all in this case.</p>
93
94 <h2 id="Input-Flags">Input Flags</h2>
95
96 <p>This is a good place to mention a few points regarding the input flags. First, for each option, there are two forms, a long form and a short form, and either may be used.</p>
97
98 <p>For example, if you want to change the number of columns corresponding to one indentation level to 3 (from the default of 4) you may use either</p>
99
100 <pre><code> -i=3   or  --indent-columns=3</code></pre>
101
102 <p>The short forms are convenient for entering parameters by hand, whereas the long forms, though often ridiculously long, are self-documenting and therefore useful in configuration scripts. You may use either one or two dashes ahead of the parameters. Also, the &#39;=&#39; sign is optional, and may be a single space instead. However, the value of a parameter must NOT be adjacent to the flag, like this <b>-i3</b> (WRONG). Also, flags must be input separately, never bundled together.</p>
103
104 <h2 id="Line-Length-and-Continuation-Indentation">Line Length and Continuation Indentation.</h2>
105
106 <p>If you change the indentation spaces you will probably also need to change the continuation indentation spaces with the parameter <b>-ci=n</b>. The continuation indentation is the extra indentation -- 2 spaces by default -- given to that portion of a long line which has been placed below the start of a statement. For example:</p>
107
108 <pre><code> croak &quot;Couldn&#39;t pop genome file&quot;
109    unless sysread( $impl-&gt;{file}, $element, $impl-&gt;{group} )
110    and truncate( $impl-&gt;{file}, $new_end );</code></pre>
111
112 <p>There is no fixed rule for setting the value for <b>-ci=n</b>, but it should probably not exceed one-half of the number of spaces of a full indentation level.</p>
113
114 <p>In the above snippet, the statement was broken into three lines. The actual number is governed by a parameter, the maximum line length, as well as by what perltidy considers to be good break points. The maximum line length is 80 characters by default. You can change this to be any number <b>n</b> with the <b>-l=n</b> flag. Perltidy tries to produce lines which do not exceed this length, and it does this by finding good break points. For example, the above snippet would look like this with <b>perltidy -l=40</b>:</p>
115
116 <pre><code> croak &quot;Couldn&#39;t pop genome file&quot;
117    unless
118    sysread( $impl-&gt;{file}, $element,
119      $impl-&gt;{group} )
120    and
121    truncate( $impl-&gt;{file}, $new_end );</code></pre>
122
123 <p>You may be wondering what would happen with, say, <b>-l=1</b>. Go ahead and try it.</p>
124
125 <h2 id="Tabs-or-Spaces">Tabs or Spaces?</h2>
126
127 <p>With indentation, there is always a tab issue to resolve. By default, perltidy will use leading ascii space characters instead of tabs. The reason is that this will be displayed correctly by virtually all editors, and in the long run, will avoid maintenance problems.</p>
128
129 <p>However, if you prefer, you may have perltidy entab the leading whitespace of a line with the command <b>-et=n</b>, where <b>n</b> is the number of spaces which will be represented by one tab. But note that your text will not be displayed properly unless viewed with software that is configured to display <b>n</b> spaces per tab.</p>
130
131 <h2 id="Input-Output-Control">Input/Output Control</h2>
132
133 <p>In the first example, we saw that if we pass perltidy the name of a file on the command line, it reformats it and creates a new filename by appending an extension, <i>.tdy</i>. This is the default behavior, but there are several other options.</p>
134
135 <p>On most systems, you may use wildcards to reformat a whole batch of files at once, like this for example:</p>
136
137 <pre><code> perltidy *.pl</code></pre>
138
139 <p>and in this case, each of the output files will be have a name equal to the input file with the extension <i>.tdy</i> appended. If you decide that the formatting is acceptable, you will want to backup your originals and then remove the <i>.tdy</i> extensions from the reformatted files. There is a powerful perl script called <code>rename</code> that can be used for this purpose; if you don&#39;t have it, you can find it for example in <b>The Perl Cookbook</b>.</p>
140
141 <p>If you find that the formatting done by perltidy is usually acceptable, you may want to save some effort by letting perltidy do a simple backup of the original files and then reformat them in place. You specify this with a <b>-b</b> flag. For example, the command</p>
142
143 <pre><code> perltidy -b *.pl</code></pre>
144
145 <p>will rename the original files by appending a <i>.bak</i> extension, and then create reformatted files with the same names as the originals. (If you don&#39;t like the default backup extension choice <i>.bak</i>, the manual tells how to change it). Each time you run perltidy with the <b>-b</b> option, the previous <i>.bak</i> files will be overwritten, so please make regular separate backups.</p>
146
147 <p>If there is no input filename specified on the command line, then input is assumed to come from standard input and output will go to standard output. On systems with a Unix-like interface, you can use perltidy as a filter, like this:</p>
148
149 <pre><code> perltidy &lt;somefile.pl &gt;newfile.pl</code></pre>
150
151 <p>What happens in this case is that the shell takes care of the redirected input files, &#39;&lt;somefile.pl&#39;, and so perltidy never sees the filename. Therefore, it knows to use the standard input and standard output channels.</p>
152
153 <p>If you are executing perltidy on a file and want to force the output to standard output, rather than create a <i>.tdy</i> file, you can indicate this with the flag <b>-st</b>, like this:</p>
154
155 <pre><code> perltidy somefile.pl -st &gt;otherfile.pl</code></pre>
156
157 <p>You can also control the name of the output file with the <b>-o</b> flag, like this:</p>
158
159 <pre><code> perltidy testfile.pl -o=testfile.new.pl</code></pre>
160
161 <h2 id="Style-Variations">Style Variations</h2>
162
163 <p>Perltidy has to make some kind of default selection of formatting options, and its choice is to try to follow the suggestions in the perlstyle man pages. Many programmers more or less follow these suggestions with a few exceptions. In this section we will look at just a few of the most commonly used style parameters. Later, you may want to systematically develop a set of style parameters with the help of the perltidy <b>stylekey</b> web page at http://perltidy.sourceforge.net/stylekey.html</p>
164
165 <dl>
166
167 <dt id="ce-cuddled-elses"><b>-ce</b>, cuddled elses</dt>
168 <dd>
169
170 <p>If you prefer cuddled elses, use the <b>-ce</b> flag.</p>
171
172 </dd>
173 <dt id="bl-braces-left"><b>-bl</b>, braces left</dt>
174 <dd>
175
176 <p>Here is what the <code>if</code> block in the above script looks like with <b>-bl</b>:</p>
177
178 <pre><code> if ( $editor =~ /emacs/i )
179  {
180      print &quot;Why aren&#39;t you using vi?\n&quot;;
181  }
182  elsif ( $editor =~ /vi/i )
183  {
184      print &quot;Why aren&#39;t you using emacs?\n&quot;;
185  }
186  else
187  {
188      print &quot;I think that&#39;s the problem\n&quot;;
189  }</code></pre>
190
191 </dd>
192 <dt id="lp-Lining-up-with-parentheses"><b>-lp</b>, Lining up with parentheses</dt>
193 <dd>
194
195 <p>The <b>-lp</b> parameter can enhance the readability of lists by adding extra indentation. Consider:</p>
196
197 <pre><code>        %romanNumerals = (
198             one   =&gt; &#39;I&#39;,
199             two   =&gt; &#39;II&#39;,
200             three =&gt; &#39;III&#39;,
201             four  =&gt; &#39;IV&#39;,
202             five  =&gt; &#39;V&#39;,
203             six   =&gt; &#39;VI&#39;,
204             seven =&gt; &#39;VII&#39;,
205             eight =&gt; &#39;VIII&#39;,
206             nine  =&gt; &#39;IX&#39;,
207             ten   =&gt; &#39;X&#39;
208         );</code></pre>
209
210 <p>With the <b>-lp</b> flag, this is formatted as:</p>
211
212 <pre><code>        %romanNumerals = (
213                            one   =&gt; &#39;I&#39;,
214                            two   =&gt; &#39;II&#39;,
215                            three =&gt; &#39;III&#39;,
216                            four  =&gt; &#39;IV&#39;,
217                            five  =&gt; &#39;V&#39;,
218                            six   =&gt; &#39;VI&#39;,
219                            seven =&gt; &#39;VII&#39;,
220                            eight =&gt; &#39;VIII&#39;,
221                            nine  =&gt; &#39;IX&#39;,
222                            ten   =&gt; &#39;X&#39;
223                          );</code></pre>
224
225 <p>which is preferred by some. (I&#39;ve actually used <b>-lp</b> and <b>-cti=1</b> to format this block. The <b>-cti=1</b> flag causes the closing paren to align vertically with the opening paren, which works well with the <b>-lp</b> indentation style). An advantage of <b>-lp</b> indentation are that it displays lists nicely. A disadvantage is that deeply nested lists can require a long line length.</p>
226
227 </dd>
228 <dt id="bt--pt--sbt:-Container-tightness"><b>-bt</b>,<b>-pt</b>,<b>-sbt</b>: Container tightness</dt>
229 <dd>
230
231 <p>These are parameters for controlling the amount of space within containing parentheses, braces, and square brackets. The example below shows the effect of the three possible values, 0, 1, and 2, for the case of parentheses:</p>
232
233 <pre><code> if ( ( my $len_tab = length( $tabstr ) ) &gt; 0 ) {  # -pt=0
234  if ( ( my $len_tab = length($tabstr) ) &gt; 0 ) {    # -pt=1 (default)
235  if ((my $len_tab = length($tabstr)) &gt; 0) {        # -pt=2</code></pre>
236
237 <p>A value of 0 causes all parens to be padded on the inside with a space, and a value of 2 causes this never to happen. With a value of 1, spaces will be introduced if the item within is more than a single token.</p>
238
239 </dd>
240 </dl>
241
242 <h2 id="Configuration-Files">Configuration Files</h2>
243
244 <p>While style preferences vary, most people would agree that it is important to maintain a uniform style within a script, and this is a major benefit provided by perltidy. Once you have decided on which, if any, special options you prefer, you may want to avoid having to enter them each time you run it. You can do this by creating a special file named <i>.perltidyrc</i> in either your home directory, your current directory, or certain system-dependent locations. (Note the leading &quot;.&quot; in the file name).</p>
245
246 <p>A handy command to know when you start using a configuration file is</p>
247
248 <pre><code>  perltidy -dpro</code></pre>
249
250 <p>which will dump to standard output the search that perltidy makes when looking for a configuration file, and the contents of the one that it selects, if any. This is one of a number of useful &quot;dump and die&quot; commands, in which perltidy will dump some information to standard output and then immediately exit. Others include <b>-h</b>, which dumps help information, and <b>-v</b>, which dumps the version number.</p>
251
252 <p>Another useful command when working with configuration files is</p>
253
254 <pre><code> perltidy -pro=file</code></pre>
255
256 <p>which causes the contents of <i>file</i> to be used as the configuration file instead of a <i>.perltidyrc</i> file. With this command, you can easily switch among several different candidate configuration files during testing.</p>
257
258 <p>This <i>.perltidyrc</i> file is free format. It is simply a list of parameters, just as they would be entered on a command line. Any number of lines may be used, with any number of parameters per line, although it may be easiest to read with one parameter per line. Blank lines are ignored, and text after a &#39;#&#39; is ignored to the end of a line.</p>
259
260 <p>Here is an example of a <i>.perltidyrc</i> file:</p>
261
262 <pre><code>  # This is a simple of a .perltidyrc configuration file
263   # This implements a highly spaced style
264   -bl    # braces on new lines
265   -pt=0  # parens not tight at all
266   -bt=0  # braces not tight
267   -sbt=0 # square brackets not tight</code></pre>
268
269 <p>If you experiment with this file, remember that it is in your directory, since if you are running on a Unix system, files beginning with a &quot;.&quot; are normally hidden.</p>
270
271 <p>If you have a <i>.perltidyrc</i> file, and want perltidy to ignore it, use the <b>-npro</b> flag on the command line.</p>
272
273 <h2 id="Error-Reporting">Error Reporting</h2>
274
275 <p>Let&#39;s run through a &#39;fire drill&#39; to see how perltidy reports errors. Try introducing an extra opening brace somewhere in a test file. For example, introducing an extra brace in the file listed above produces the following message on the terminal (or standard error output):</p>
276
277 <pre><code> ## Please see file testfile.pl.ERR!</code></pre>
278
279 <p>Here is what <i>testfile.pl.ERR</i> contains:</p>
280
281 <pre><code> 10:    final indentation level: 1
282  
283  Final nesting depth of &#39;{&#39;s is 1
284  The most recent un-matched &#39;{&#39; is on line 6
285  6: } elsif ($temperature &lt; 68) {{
286                                 ^</code></pre>
287
288 <p>This shows how perltidy will, by default, write error messages to a file with the extension <i>.ERR</i>, and it will write a note that it did so to the standard error device. If you would prefer to have the error messages sent to standard output, instead of to a <i>.ERR</i> file, use the <b>-se</b> flag.</p>
289
290 <p>Almost every programmer would want to see error messages of this type, but there are a number of messages which, if reported, would be annoying. To manage this problem, perltidy puts its messages into two categories: errors and warnings. The default is to just report the errors, but you can control this with input flags, as follows:</p>
291
292 <pre><code> flag  what this does
293  ----  --------------
294        default: report errors but not warnings
295  -w    report all errors and warnings
296  -q    quiet! do not report either errors or warnings</code></pre>
297
298 <p>The default is generally a good choice, but it&#39;s not a bad idea to check programs with <b>-w</b> occasionally, especially if your are looking for a bug. For example, it will ask if you really want &#39;=&#39; instead of &#39;=~&#39; in this line:</p>
299
300 <pre><code>    $line = s/^\s*//;</code></pre>
301
302 <p>This kind of error can otherwise be hard to find.</p>
303
304 <h2 id="The-Log-File">The Log File</h2>
305
306 <p>One last topic that needs to be touched upon concerns the <i>.LOG</i> file. This is where perltidy records messages that are not normally of any interest, but which just might occasionally be useful. This file is not saved, though, unless perltidy detects that it has made a mistake or you ask for it to be saved.</p>
307
308 <p>There are a couple of ways to ask perltidy to save a log file. To create a relatively sparse log file, use</p>
309
310 <pre><code> perltidy -log testfile.pl</code></pre>
311
312 <p>and for a verbose log file, use</p>
313
314 <pre><code> perltidy -g testfile.pl</code></pre>
315
316 <p>The difference is that the first form only saves detailed information at least every 50th line, while the second form saves detailed information about every line.</p>
317
318 <p>So returning to our example, lets force perltidy to save a verbose log file by issuing the following command</p>
319
320 <pre><code> perltidy -g testfile.pl</code></pre>
321
322 <p>You will find that a file named <i>testfile.pl.LOG</i> has been created in your directory.</p>
323
324 <p>If you open this file, you will see that it is a text file with a combination of warning messages and informative messages. All you need to know for now is that it exists; someday it may be useful.</p>
325
326 <h2 id="Using-Perltidy-as-a-Filter-on-Selected-Text-from-an-Editor">Using Perltidy as a Filter on Selected Text from an Editor</h2>
327
328 <p>Most programmer&#39;s editors allow a selected group of lines to be passed through an external filter. Perltidy has been designed to work well as a filter, and it is well worthwhile learning the appropriate commands to do this with your editor. This means that you can enter a few keystrokes and watch a block of text get reformatted. If you are not doing this, you are missing out of a lot of fun! You may want to supply the <b>-q</b> flag to prevent error messages regarding incorrect syntax, since errors may be obvious in the indentation of the reformatted text. This is entirely optional, but if you do not use the <b>-q</b> flag, you will need to use the undo keys in case an error message appears on the screen.</p>
329
330 <p>For example, within the <b>vim</b> editor it is only necessary to select the text by any of the text selection methods, and then issue the command !perltidy in command mode. Thus, an entire file can be formatted using</p>
331
332 <pre><code> :%!perltidy -q</code></pre>
333
334 <p>or, without the <b>-q</b> flag, just</p>
335
336 <pre><code> :%!perltidy</code></pre>
337
338 <p>It isn&#39;t necessary to format an entire file, however. Perltidy will probably work well as long as you select blocks of text whose braces, parentheses, and square brackets are properly balanced. You can even format an <code>elsif</code> block without the leading <code>if</code> block, as long as the text you select has all braces balanced.</p>
339
340 <p>For the <b>emacs</b> editor, first mark a region and then pipe it through perltidy. For example, to format an entire file, select it with <code>C-x h</code> and then pipe it with <code>M-1 M-|</code> and then <code>perltidy</code>. The numeric argument, <code>M-1</code> causes the output from perltidy to replace the marked text. See &quot;GNU Emacs Manual&quot; for more information, http://www.gnu.org/manual/emacs-20.3/html_node/emacs_toc.html</p>
341
342 <p>If you have difficulty with an editor, try the <b>-st</b> flag, which will force perltidy to send output to standard output. This might be needed, for example, if the editor passes text to perltidy as temporary filename instead of through the standard input. If this works, you might put the <b>-st</b> flag in your <i>.perltidyrc</i> file.</p>
343
344 <p>If you have some tips for making perltidy work with your editor, and are willing to share them, please email me (see below) and I&#39;ll try to incorporate them in this document or put up a link to them.</p>
345
346 <p>After you get your editor and perltidy successfully talking to each other, try formatting a snippet of code with a brace error to see what happens. (Do not use the quiet flag, <b>-q</b>, for this test). Perltidy will send one line starting with <code>##</code> to standard error output. Your editor may either display it at the top of the reformatted text or at the bottom (or even midstream!). You probably cannot control this, and perltidy can&#39;t, but you need to know where to look when an actual error is detected.</p>
347
348 <h2 id="Writing-an-HTML-File">Writing an HTML File</h2>
349
350 <p>Perltidy can switch between two different output modes. We have been discussing what might be called its &quot;beautifier&quot; mode, but it can also output in HTML. To do this, use the <b>-html</b> flag, like this:</p>
351
352 <pre><code> perltidy -html testfile.pl</code></pre>
353
354 <p>which will produce a file <i>testfile.pl.html</i>. There are many parameters available for adjusting the appearance of an HTML file, but a very easy way is to just write the HTML file with this simple command and then edit the stylesheet which is embedded at its top.</p>
355
356 <p>One important thing to know about the <b>-html</b> flag is that perltidy can either send its output to its beautifier or to its HTML writer, but (unfortunately) not both in a single run. So the situation can be represented like this:</p>
357
358 <pre><code>                  ------------
359                   |          |     ---&gt;beautifier--&gt; testfile.pl.tdy
360  testfile.pl --&gt;  | perltidy | --&gt;
361                   |          |     ---&gt;HTML -------&gt; testfile.pl.html
362                   ------------</code></pre>
363
364 <p>And in the future, there may be more output filters. So if you would like to both beautify a script and write it to HTML, you need to do it in two steps.</p>
365
366 <h2 id="Summary">Summary</h2>
367
368 <p>That&#39;s enough to get started using perltidy. When you are ready to create a <i>.perltidyrc</i> file, you may find it helpful to use the <i>stylekey</i> page as a guide at http://perltidy.sourceforge.net/stylekey.html</p>
369
370 <p>Many additional special features and capabilities can be found in the manual pages for perltidy at http://perltidy.sourceforge.net/perltidy.html</p>
371
372 <p>We hope that perltidy makes perl programming a little more fun. Please check the perltidy web site http://perltidy.sourceforge.net occasionally for updates.</p>
373
374 <p>The author may be contacted at perltidy at users.sourceforge.net.</p>
375
376
377 </body>
378
379 </html>
380
381