Formatting changes. Now changing the doctype to DocBook XML 4.1
[privoxy.git] / doc / source / developer-manual.sgml
1 <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN">
2 <!--
3  File        :  $Source: /cvsroot/ijbswa/current/doc/source/developer-manual.sgml,v $
4
5  Purpose     :  developer manual
6                 This file belongs into
7                 ijbswa.sourceforge.net:/home/groups/i/ij/ijbswa/htdocs/
8                 
9  $Id: developer-manual.sgml,v 1.5 2001/10/31 18:16:51 swa Exp $
10
11  Written by and Copyright (C) 2001 the SourceForge
12  IJBSWA team.  http://ijbswa.sourceforge.net
13
14  Based on the Internet Junkbuster originally written
15  by and Copyright (C) 1997 Anonymous Coders and 
16  Junkbusters Corporation.  http://www.junkbusters.com
17 -->
18
19 <article id="index">
20   <artheader>
21     <title>Junkbuster Developer Manual</title>
22
23     <pubdate>$Id: developer-manual.sgml,v 1.5 2001/10/31 18:16:51 swa Exp $</pubdate>
24
25     <authorgroup>
26       <author>
27         <affiliation>
28           <orgname>By: Junkbuster Developers</orgname>
29         </affiliation>
30       </author>
31     </authorgroup>
32
33     <abstract>
34       <para>
35     The developer manual gives the users information on how to help the developer
36 team. It provides guidance on coding, testing, documentation and other
37 issues. The Internet Junkbuster is an application
38 that provides privacy and security to the user of the world wide web.
39  </para>
40       <para>
41 You can find the latest version of the user manual at <ulink
42 url="http://ijbswa.sourceforge.net/developer-manual/">http://ijbswa.sourceforge.net/developer-manual/</ulink>.
43 Please see the Contact section in the user-manual if you want to contact the developers.
44  </para>
45
46       <para>
47   Feel free to send a note to the developers at <email>ijbswa-developers@lists.sourceforge.net</email>.
48  </para>
49     </abstract>
50   </artheader>
51
52   <!--   ~~~~~       New section      ~~~~~     -->
53   <sect1 id="introduction"><title>Introduction</title>
54     <para>To be filled.
55 </para>
56   </sect1>
57
58   <!--   ~~~~~       New section      ~~~~~     -->
59   <sect1 id="quickstart"><title>Quickstart to Junkbuster Development</title>
60     <para>To be filled.
61 </para>
62   </sect1>
63
64   <!--   ~~~~~       New section      ~~~~~     -->
65   <sect1 id="documentation"><title>Documentation Guidelines</title>
66     <para>
67         All docs are in SGML format and located in the <computeroutput>doc/source</computeroutput> directory.
68         </para>
69         <para>
70         How do you update the webserver (i.e. the pages on sourceforge)?
71         <orderedlist numeration="arabic">
72                 <listitem><para>
73         Run <computeroutput>make dok</computeroutput> (which uses the documents in <computeroutput>doc/source</computeroutput> to update all
74         text files in <computeroutput>doc/text</computeroutput> and to update
75 all web documents in <computeroutput>doc/webserver</computeroutput>.
76                 </para></listitem>
77                 <listitem><para>
78         Run <computeroutput>make webserver</computeroutput> which copies all files from
79 <computeroutput>doc/webserver</computeroutput> to the sourceforge webserver
80 via scp.
81                 </para></listitem>
82         </orderedlist>
83   </para>
84  </sect1>
85
86 <!--     <listitem><para>be consistent with the redirect script (i.e. the junkbuster program -->
87 <!--       points via the redirect URL at sf to valid end-points in the document)</para></listitem> -->
88
89   <!--   ~~~~~       New section      ~~~~~     -->
90   <sect1 id="coding"><title>Coding Guidelines</title>
91
92     <sect2 id="s1"><title>Introduction</title>
93
94     <para>This set of standards is designed to make our lives easier.
95     It is developed with the simple goal of helping us keep the
96     "new and improved Junkbusters" consistent and reliable. Thus
97     making maintenance easier and increasing chances of success of
98     the project.</para>
99
100     <para>And that of course comes back to us as individuals. If we
101     can increase our development and product efficiencies then we
102     can solve more of the request for changes/improvements and in
103     general feel good about ourselves. ;-></para>
104
105   </sect2>
106
107     <sect2 id="s2"><title>Using Comments</title>
108  
109
110     <sect3 id="s3"><title>Comment, Comment, Comment</title>
111
112     <para><emphasis>Explanation:</emphasis></para>
113
114     <para>Comment as much as possible without commenting the obvious.
115     For example do not comment "aVariable is equal to bVariable".
116     Instead explain why aVariable should be equal to the bVariable.
117     Just because a person can read code does not mean they will
118     understand why or what is being done. A reader may spend a lot
119     more time figuring out what is going on when a simple comment
120     or explanation would have prevented the extra research. Please
121     help your brother IJB'ers out!</para>
122
123     <para>The comments will also help justify the intent of the code.
124     If the comment describes something different than what the code
125     is doing then maybe a programming error is occurring.</para>
126
127     <para><emphasis>Example:</emphasis></para>
128 <programlisting>
129 /* if page size greater than 1k ... */
130 if ( PageLength() > 1024 )
131 {
132     ... "block" the page up ...
133 }
134
135 /* if page size is small, send it in blocks */
136 if ( PageLength() > 1024 )
137 {
138     ... "block" the page up ...
139 }
140
141 This demonstrates 2 cases of "what not to do".  The first is a
142 "syntax comment".  The second is a comment that does not fit what
143 is actually being done.
144 </programlisting>
145   </sect3>
146
147     
148
149     <sect3 id="s4"><title>Use blocks for comments</title>
150
151     <para><emphasis>Explanation:</emphasis></para>
152
153     <para>Comments can help or they can clutter. They help when they
154     are differentiated from the code they describe. One line
155     comments do not offer effective separation between the comment
156     and the code. Block identifiers do, by surrounding the code
157     with a clear, definable pattern.</para>
158
159     <para><emphasis>Example:</emphasis></para>
160 <programlisting>
161 /*********************************************************************
162  * This will stand out clearly in your code!
163  *********************************************************************/
164 if ( thisVariable == thatVariable )
165 {
166    DoSomethingVeryImportant();
167 }
168
169
170 /* unfortunately, this may not */
171 if ( thisVariable == thatVariable )
172 {
173    DoSomethingVeryImportant();
174 }
175
176
177 if ( thisVariable == thatVariable ) /* this may not either */
178 {
179    DoSomethingVeryImportant();
180 }</programlisting>
181
182     <para><emphasis>Exception:</emphasis></para>
183
184     <para>If you are trying to add a small logic comment and do not
185     wish to "disrubt" the flow of the code, feel free to use a 1
186     line comment which is NOT on the same line as the code.</para>
187
188     
189   </sect3>
190     
191
192     <sect3 id="s5"><title>Keep Comments on their own line</title>
193
194     <para><emphasis>Explanation:</emphasis></para>
195
196     <para>It goes back to the question of readability. If the comment
197     is on the same line as the code it will be harder to read than
198     the comment that is on its own line.</para>
199
200     <para>There are three exceptions to this rule, which should be
201     violated freely and often: during the definition of variables,
202     at the end of closing braces, when used to comment
203     parameters.</para>
204
205     <para><emphasis>Example:</emphasis></para>
206 <programlisting>
207 /*********************************************************************
208  * This will stand out clearly in your code,
209  * But the second example won't.
210  *********************************************************************/
211 if ( thisVariable == thatVariable )
212 {
213    DoSomethingVeryImportant();
214 }
215
216 if ( thisVariable == thatVariable ) /*can you see me?*/
217 {
218    DoSomethingVeryImportant(); /*not easily*/
219 }
220
221
222 /*********************************************************************
223  * But, the encouraged exceptions:
224  *********************************************************************/
225 int urls_read     = 0;     /* # of urls read + rejected */
226 int urls_rejected = 0;     /* # of urls rejected */
227
228 if ( 1 == X )
229 {
230    DoSomethingVeryImportant();
231 }
232
233
234 short DoSomethingVeryImportant(
235    short firstparam,   /* represents something */
236    short nextparam     /* represents something else */ )
237 {
238    ...code here...
239
240 }   /* -END- DoSomethingVeryImportant */
241 </programlisting>
242   </sect3>
243     
244
245     <sect3 id="s6"><title>Comment each logical step</title>
246
247     <para><emphasis>Explanation:</emphasis></para>
248
249     <para>Logical steps should be commented to help others follow the
250     intent of the written code and comments will make the code more
251     readable.</para>
252
253     <para>If you have 25 lines of code without a comment, you should
254     probably go back into it to see where you forgot to put
255     one.</para>
256
257     <para>Most "for", "while", "do", etc... loops _probably_ need a
258     comment. After all, these are usually major logic
259     containers.</para>
260
261     
262   </sect3>
263     
264
265     <sect3 id="s7"><title>Comment All Functions Thoroughly</title>
266
267     <para><emphasis>Explanation:</emphasis></para>
268
269     <para>A reader of the code should be able to look at the comments
270     just prior to the beginning of a function and discern the
271     reason for its existence and the consequences of using it. The
272     reader should not have to read through the code to determine if
273     a given function is safe for a desired use. The proper
274     information thoroughly presented at the introduction of a
275     function not only saves time for subsequent maintenance or
276     debugging, it more importantly aids in code reuse by allowing a
277     user to determine the safety and applicability of any function
278     for the problem at hand. As a result of such benefits, all
279     functions should contain the information presented in the
280     addendum section of this document.</para>
281
282     
283   </sect3>
284     
285
286     <sect3 id="s8"><title>Comment at the end of braces if the
287     content is more than one screen length</title>
288
289     <para><emphasis>Explanation:</emphasis></para>
290
291     <para>Each closing brace should be followed on the same line by a
292     comment that describes the origination of the brace if the
293     original brace is off of the screen, or otherwise far away from
294     the closing brace. This will simplify the debugging,
295     maintenance, and readability of the code.</para>
296
297     <para>As a suggestion , use the following flags to make the
298     comment and its brace more readable:</para>
299
300     <para>use following a closing brace: } /* -END- if() or while ()
301     or etc... */</para>
302
303     <para><emphasis>Example:</emphasis></para>
304 <programlisting>
305 if ( 1 == X )
306 {
307    DoSomethingVeryImportant();
308    ...some long list of commands...
309 } /* -END- if x is 1 */
310
311 or:
312
313 if ( 1 == X )
314 {
315    DoSomethingVeryImportant();
316    ...some long list of commands...
317 } /* -END- if ( 1 == X ) */
318 </programlisting>
319   </sect3>
320     
321   </sect2>
322
323     <sect2 id="s9"><title>Naming Conventions</title>
324
325     
326
327     <sect3 id="s10"><title>Variable Names</title>
328
329     <para><emphasis>Explanation:</emphasis></para>
330
331     <para>Use all lowercase, and seperate words via an underscore
332     ('_'). Do not start an identifier with an underscore. (ANSI C
333     reserves these for use by the compiler and system headers.) Do
334     not use identifiers which are reserved in ANSI C++. (E.g.
335     template, class, true, false, ...). This is in case we ever
336     decide to port JunkBuster to C++.</para>
337
338     <para><emphasis>Example:</emphasis></para>
339 <programlisting>
340 int ms_iis5_hack = 0;</programlisting>
341
342     <para><emphasis>Instead of:</emphasis></para>
343
344     <para>
345 <programlisting>
346 int msiis5hack = 0; int msIis5Hack = 0;
347 </programlisting>
348 </para>
349
350     
351
352   </sect3>    
353
354     <sect3 id="s11"><title>Function Names</title>
355
356     <para><emphasis>Explanation:</emphasis></para>
357
358     <para>Use all lowercase, and seperate words via an underscore
359     ('_'). Do not start an identifier with an underscore. (ANSI C
360     reserves these for use by the compiler and system headers.) Do
361     not use identifiers which are reserved in ANSI C++. (E.g.
362     template, class, true, false, ...). This is in case we ever
363     decide to port JunkBuster to C++.</para>
364
365     <para><emphasis>Example:</emphasis></para>
366 <programlisting>
367 int load_some_file( struct client_state *csp )</programlisting>
368
369     <para><emphasis>Instead of:</emphasis></para>
370
371     <para>
372 <programlisting>
373 int loadsomefile( struct client_state *csp )
374 int loadSomeFile( struct client_state *csp )
375 </programlisting>
376 </para>
377
378     
379   </sect3>
380     
381
382     <sect3 id="s12"><title>Header file prototypes</title>
383
384     <para><emphasis>Explanation:</emphasis></para>
385
386     <para>Use a descriptive parameter name in the function prototype
387     in header files. Use the same parameter name in the header file
388     that you use in the c file.</para>
389
390     <para><emphasis>Example:</emphasis></para>
391 <programlisting>
392 (.h) extern int load_aclfile( struct client_state *csp );
393 (.c) int load_aclfile( struct client_state *csp )</programlisting>
394
395     <para><emphasis>Instead of:</emphasis>
396 <programlisting>
397 (.h) extern int load_aclfile( struct client_state * ); or 
398 (.h) extern int load_aclfile(); 
399 (.c) int load_aclfile( struct client_state *csp )
400 </programlisting>
401 </para>
402
403     
404   </sect3>
405     
406
407     <sect3 id="s13"><title>Enumerations, and #defines</title>
408
409     <para><emphasis>Explanation:</emphasis></para>
410
411     <para>Use all capital letters, with underscores between words. Do
412     not start an identifier with an underscore. (ANSI C reserves
413     these for use by the compiler and system headers.)</para>
414
415     <para><emphasis>Example:</emphasis></para>
416 <programlisting>
417 (enumeration) : enum Boolean { FALSE, TRUE };
418 (#define) : #define DEFAULT_SIZE 100;</programlisting>
419
420     <para><emphasis>Note:</emphasis> We have a standard naming scheme for #defines
421     that toggle a feature in the preprocessor: FEATURE_>, where
422     > is a short (preferably 1 or 2 word) description.</para>
423
424     <para><emphasis>Example:</emphasis></para>
425 <programlisting>
426 #define FEATURE_FORCE 1
427
428 #ifdef FEATURE_FORCE
429 #define FORCE_PREFIX blah
430 #endif /* def FEATURE_FORCE */
431 </programlisting>
432   </sect3>
433     
434
435     <sect3 id="s14"><title>Constants</title>
436
437     <para><emphasis>Explanation:</emphasis></para>
438
439     <para>Spell common words out entirely (do not remove vowels).</para>
440
441     <para>Use only widely-known domain acronyms and abbreviations.
442     Capitalize all letters of an acronym.</para>
443
444     <para>Use underscore (_) to separate adjacent acronyms and
445     abbreviations. Never terminate a name with an underscore.</para>
446
447     <para><emphasis>Example:</emphasis></para>
448 <programlisting>
449 #define USE_IMAGE_LIST 1</programlisting>
450
451     <para><emphasis>Instead of:</emphasis></para>
452
453     <para>
454 <programlisting>
455 #define USE_IMG_LST 1 or 
456 #define _USE_IMAGE_LIST 1 or
457 #define USE_IMAGE_LIST_ 1 or 
458 #define use_image_list 1 or
459 #define UseImageList 1
460 </programlisting>
461 </para>
462
463     
464   </sect3>
465
466   </sect2>
467     
468
469     <sect2 id="s15"><title>Using Space</title>
470
471     
472
473     <sect3 id="s16"><title>Put braces on a line by themselves.</title>
474
475     <para><emphasis>Explanation:</emphasis></para>
476
477     <para>The brace needs to be on a line all by itself, not at the
478     end of the statement. Curly braces should line up with the
479     construct that they're associated with. This practice makes it
480     easier to identify the opening and closing braces for a
481     block.</para>
482
483     <para><emphasis>Example:</emphasis></para>
484 <programlisting>
485 if ( this == that )
486 {
487    ...
488 }</programlisting>
489
490     <para><emphasis>Instead of:</emphasis></para>
491
492     <para>if ( this == that ) { ... }</para>
493
494     <para>or</para>
495
496     <para>if ( this == that ) { ... }</para>
497
498     <para><emphasis>Note:</emphasis> In the special case that the if-statement is
499     inside a loop, and it is trivial, i.e. it tests for a
500     condidtion that is obvious from the purpose of the block,
501     one-liners as above may optically preserve the loop structure
502     and make it easier to read.</para>
503
504     <para><emphasis>Status:</emphasis> developer-discrection.</para>
505
506     <para><emphasis>Example exception:</emphasis></para>
507 <programlisting>
508 while ( more lines are read )
509 {
510    /* Please document what is/is not a comment line here */
511    if ( it's a comment ) continue;
512
513    do_something( line );
514 }
515 </programlisting>
516   </sect3>
517     
518
519     <sect3 id="s17"><title>ALL control statements should have a
520     block</title>
521
522     <para><emphasis>Explanation:</emphasis></para>
523
524     <para>Using braces to make a block will make your code more
525     readable and less prone to error. All control statements should
526     have a block defined.</para>
527
528     <para><emphasis>Example:</emphasis></para>
529 <programlisting>
530 if ( this == that )
531 {
532    DoSomething();
533    DoSomethingElse();
534 }</programlisting>
535
536     <para><emphasis>Instead of:</emphasis></para>
537
538     <para>if ( this == that ) DoSomething(); DoSomethingElse();</para>
539
540     <para>or</para>
541
542     <para>if ( this == that ) DoSomething();</para>
543
544     <para><emphasis>Note:</emphasis> The first example in "Instead of" will execute
545     in a manner other than that which the developer desired (per
546     indentation). Using code braces would have prevented this
547     "feature". The "explanation" and "exception" from the point
548     above also applies.</para>
549
550     
551   </sect3>
552     
553
554     <sect3 id="s18"><title>Do not belabor/blow-up boolean
555     expressions</title>
556
557     <para><emphasis>Example:</emphasis></para>
558 <programlisting>
559 structure->flag = ( condition );</programlisting>
560
561     <para><emphasis>Instead of:</emphasis></para>
562
563     <para>if ( condition ) { structure->flag = 1; } else {
564     structure->flag = 0; }</para>
565
566     <para><emphasis>Note:</emphasis> The former is readable and consice. The later
567     is wordy and inefficient. Please assume that any developer new
568     to the project has at least a "good" knowledge of C/C++. (Hope
569     I do not offend by that last comment ... 8-)</para>
570
571     
572   </sect3>
573     
574
575     <sect3 id="s19"><title>Use white space freely because it is
576     free</title>
577
578     <para><emphasis>Explanation:</emphasis></para>
579
580     <para>Make it readable. The notable exception to using white space
581     freely is listed in the next guideline.</para>
582
583     <para><emphasis>Example:</emphasis></para>
584 <programlisting>
585 int firstValue   = 0;
586 int someValue    = 0;
587 int anotherValue = 0;
588 int thisVariable = 0;
589
590 if ( thisVariable == thatVariable )
591
592 firstValue = oldValue + ( ( someValue - anotherValue ) - whatever )
593 </programlisting>
594   </sect3>
595     
596
597     <sect3 id="s20"><title>Don't use white space around structure
598     operators</title>
599
600     <para><emphasis>Explanation:</emphasis></para>
601
602     <para>- structure pointer operator ( "->" ) - member operator (
603     "." ) - functions and parentheses</para>
604
605     <para>It is a general coding practice to put pointers, references,
606     and function parentheses next to names. With spaces, the
607     connection between the object and variable/function name is not
608     as clear.</para>
609
610     <para><emphasis>Example:</emphasis></para>
611 <programlisting>
612 aStruct->aMember;
613 aStruct.aMember;
614 FunctionName();</programlisting>
615
616     <para><emphasis>Instead of:</emphasis> aStruct -> aMember; aStruct . aMember;
617     FunctionName ();</para>
618
619     
620   </sect3>
621     
622
623     <sect3 id="s21"><title>Make the last brace of a function stand
624     out</title>
625
626     <para><emphasis>Example:</emphasis></para>
627 <programlisting>
628 int function1( ... )
629 {
630    ...code...
631    return( retCode );
632
633 }   /* -END- function1 */
634
635
636 int function2( ... )
637 {
638 }   /* -END- function2 */
639 </programlisting>
640
641     <para><emphasis>Instead of:</emphasis></para>
642
643     <para>int function1( ... ) { ...code... return( retCode ); } int
644     function2( ... ) { }</para>
645
646     <para><emphasis>Note:</emphasis> Use 1 blank line before the closing brace and 2
647     lines afterwards. This makes the end of function standout to
648     the most casual viewer. Although function comments help
649     seperate functions, this is still a good coding practice. In
650     fact, I follow these rules when using blocks in "for", "while",
651     "do" loops, and long if {} statements too. After all whitespace
652     is free!</para>
653
654     <para><emphasis>Status:</emphasis> developer-discrection on the number of blank
655     lines. Enforced is the end of function comments.</para>
656
657     
658   </sect3>
659     
660
661     <sect3 id="s22"><title>Use 3 character indentions</title>
662
663     <para><emphasis>Explanation:</emphasis></para>
664
665     <para>If some use 8 character TABs and some use 3 character TABs,
666     the code can look *very* ragged. So use 3 character indentions
667     only. If you like to use TABs, pass your code through a filter
668     such as "expand -t3" before checking in your code.</para>
669
670     <para><emphasis>Example:</emphasis></para>
671 <programlisting>
672 static const char * const url_code_map[256] =
673 {
674    NULL, ...
675 };
676
677
678 int function1( ... )
679 {
680    if ( 1 )
681    {
682       return( ALWAYS_TRUE );
683    }
684    else
685    {
686       return( HOW_DID_YOU_GET_HERE );
687    }
688
689    return( NEVER_GETS_HERE );
690
691 }
692 </programlisting>
693   </sect3>
694
695   </sect2>
696     
697
698     <sect2 id="s23"><title>Initializing</title>
699
700     
701
702     <sect3 id="s24"><title>Initialize all variables</title>
703
704     <para><emphasis>Explanation:</emphasis></para>
705
706     <para>Do not assume that the variables declared will not be used
707     until after they have been assigned a value somewhere else in
708     the code. Remove the chance of accidentally using an unassigned
709     variable.</para>
710
711     <para><emphasis>Example:</emphasis></para>
712 <programlisting>
713 short anShort = 0;
714 float aFloat  = 0;
715 struct *ptr = NULL;</programlisting>
716
717     <para><emphasis>Note:</emphasis> It is much easier to debug a SIGSEGV if the
718     message says you are trying to access memory address 00000000
719     and not 129FA012; or arrayPtr[20] causes a SIGSEV vs.
720     arrayPtr[0].</para>
721
722     <para><emphasis>Status:</emphasis> developer-discrection if and only if the
723     variable is assigned a value "shortly after" declaration.</para>
724
725   </sect3>
726   </sect2>
727     
728
729     <sect2 id="s25"><title>Functions</title>
730
731     
732
733     <sect3 id="s26"><title>Name functions that return a boolean as a
734     question.</title>
735
736     <para><emphasis>Explanation:</emphasis></para>
737
738     <para>Value should be phrased as a question that would logically
739     be answered as a true or false statement</para>
740
741     <para><emphasis>Example:</emphasis></para>
742 <programlisting>
743 ShouldWeBlockThis();
744 ContainsAnImage();
745 IsWebPageBlank();
746 </programlisting>
747   </sect3>
748     
749
750     <sect3 id="s27"><title>Always specify a return type for a
751     function.</title>
752
753     <para><emphasis>Explanation:</emphasis></para>
754
755     <para>The default return for a function is an int. To avoid
756     ambiguity, create a return for a function when the return has a
757     purpose, and create a void return type if the function does not
758     need to return anything.</para>
759
760     
761   </sect3>
762     
763
764     <sect3 id="s28"><title>Minimize function calls when iterating by
765     using variables</title>
766
767     <para><emphasis>Explanation:</emphasis></para>
768
769     <para>It is easy to write the following code, and a clear argument
770     can be made that the code is easy to understand:</para>
771
772     <para><emphasis>Example:</emphasis></para>
773 <programlisting>
774 for ( size_t cnt = 0; cnt &lt; blockListLength(); cnt ++ )
775 {
776    ....
777 }</programlisting>
778
779     <para><emphasis>Note:</emphasis> Unfortunately, this makes a function call for
780     each and every iteration. This increases the overhead in the
781     program, because the compiler has to look up the function each
782     time, call it, and return a value. Depending on what occurs in
783     the blockListLength() call, it might even be creating and
784     destroying structures with each iteration, even though in each
785     case it is comparing "cnt" to the same value, over and over.
786     Remember too - even a call to blockListLength() is a function
787     call, with the same overhead.</para>
788
789     <para>Instead of using a function call during the iterations,
790     assign the value to a variable, and evaluate using the
791     variable.</para>
792
793     <para><emphasis>Example:</emphasis></para>
794 <programlisting>
795 size_t len = blockListLength();
796
797 for ( size_t cnt = 0; cnt &lt; len; cnt ++ )
798 {
799    ....
800 }</programlisting>
801
802     <para><emphasis>Exceptions:</emphasis> if the value of blockListLength() *may*
803     change or could *potentially* change, then you must code the
804     function call in the for/while loop.</para>
805
806     
807   </sect3>
808     
809
810     <sect3 id="s29"><title>Pass and Return by Const Reference</title>
811
812     <para><emphasis>Explanation:</emphasis></para>
813
814     <para>This allows a developer to define a const pointer and call
815     your function. If your function does not have the const
816     keyword, we may not be able to use your function. Consider
817     strcmp, if it were defined as: extern int strcmp( char *s1,
818     char *s2 );</para>
819
820     <para>I could then not use it to compare argv's in main: int main(
821     int argc, const char *argv[] ) { strcmp( argv[0], "junkbusters"
822     ); }</para>
823
824     <para>Both these pointers are *const*! If the c runtime library
825     maintainers do it, we should too.</para>
826
827     
828   </sect3>
829     
830
831     <sect3 id="s30"><title>Pass and Return by Value</title>
832
833     <para><emphasis>Explanation:</emphasis></para>
834
835     <para>Most structures cannot fit onto a normal stack entry (i.e.
836     they are not 4 bytes or less). Aka, a function declaration
837     like: int load_aclfile( struct client_state csp )</para>
838
839     <para>would not work. So, to be consistent, we should declare all
840     prototypes with "pass by value": int load_aclfile( struct
841     client_state *csp )</para>
842
843     
844   </sect3>
845     
846
847     <sect3 id="s31"><title>Names of include files</title>
848
849     <para><emphasis>Explanation:</emphasis></para>
850
851     <para>Your include statements should contain the file name without
852     a path. The path should be listed in the Makefile, using -I as
853     processor directive to search the indicated paths. An exception
854     to this would be for some proprietary software that utilizes a
855     partial path to distinguish their header files from system or
856     other header files.</para>
857
858     <para><emphasis>Example:</emphasis></para>
859 <programlisting>
860 #include &lt;iostream.h&gt;     /* This is not a local include */
861 #include "config.h"       /* This IS a local include */
862 </programlisting>
863
864     <para><emphasis>Exception:</emphasis></para>
865
866     <para>
867 <programlisting>
868 /* This is not a local include, but requires a path element. */ 
869 #include &lt;sys/fileName.h&gt;
870 </programlisting>
871 </para>
872
873     <para><emphasis>Note:</emphasis> Please! do not add "-I." to the Makefile
874     without a _very_ good reason. This duplicates the #include
875     "file.h" behaviour.</para>
876
877     
878   </sect3>
879     
880
881     <sect3 id="s32"><title>Provide multiple inclusion
882     protection</title>
883
884     <para><emphasis>Explanation:</emphasis></para>
885
886     <para>Prevents compiler and linker errors resulting from
887     redefinition of items.</para>
888
889     <para>Wrap each header file with the following syntax to prevent
890     multiple inclusions of the file. Of course, replace PROJECT_H
891     with your file name, with "." Changed to "_", and make it
892     uppercase.</para>
893
894     <para><emphasis>Example:</emphasis></para>
895 <programlisting>
896 #ifndef PROJECT_H_INCLUDED
897 #define PROJECT_H_INCLUDED
898  ...
899 #endif /* ndef PROJECT_H_INCLUDED */
900 </programlisting>
901   </sect3>
902     
903
904     <sect3 id="s33"><title>Use `extern "C"` when appropriate</title>
905
906     <para><emphasis>Explanation:</emphasis></para>
907
908     <para>If our headers are included from C++, they must declare our
909     functions as `extern "C"`. This has no cost in C, but increases
910     the potential re-usability of our code.</para>
911
912     <para><emphasis>Example:</emphasis></para>
913 <programlisting>
914 #ifdef __cplusplus
915 extern "C"
916 {
917 #endif /* def __cplusplus */
918
919 ... function definitions here ...
920
921 #ifdef __cplusplus
922 }
923 #endif /* def __cplusplus */
924 </programlisting>
925   </sect3>
926     
927
928     <sect3 id="s34"><title>Where Possible, Use Forward Struct
929     Declaration Instead of Includes</title>
930
931     <para><emphasis>Explanation:</emphasis></para>
932
933     <para>Useful in headers that include pointers to other struct's.
934     Modifications to excess header files may cause needless
935     compiles.</para>
936
937     <para><emphasis>Example:</emphasis></para>
938 <programlisting>
939 /*********************************************************************
940  * We're avoiding an include statement here!
941  *********************************************************************/
942 struct file_list;
943 extern file_list *xyz;</programlisting>
944
945     <para><emphasis>Note:</emphasis> If you declare "file_list xyz;" (without the
946     pointer), then including the proper header file is necessary.
947     If you only want to prototype a pointer, however, the header
948     file is unneccessary.</para>
949
950     <para><emphasis>Status:</emphasis> Use with discrection.</para>
951
952     
953   </sect3>
954   </sect2>
955
956     <sect2 id="s35"><title>General Coding Practices</title>
957
958     
959
960     <sect3 id="s36"><title>Turn on warnings</title>
961
962     <para><emphasis>Explanation</emphasis></para>
963
964     <para>Compiler warnings are meant to help you find bugs. You
965     should turn on as many as possible. With GCC, the switch is
966     "-Wall". Try and fix as many warnings as possible.</para>
967
968     
969   </sect3>
970     
971
972     <sect3 id="s37"><title>Provide a default case for all switch
973     statements</title>
974
975     <para><emphasis>Explanation:</emphasis></para>
976
977     <para>What you think is guaranteed is never really guaranteed. The
978     value that you don't think you need to check is the one that
979     someday will be passed. So, to protect yourself from the
980     unknown, always have a default step in a switch statement.</para>
981
982     <para><emphasis>Example:</emphasis></para>
983 <programlisting>
984 switch( hash_string( cmd ) )
985 {
986    case hash_actions_file :
987       ... code ...
988       break;
989
990    case hash_confdir :
991       ... code ...
992       break;
993
994    default :
995       log_error( ... );
996       ... anomly code goes here ...
997       continue; / break; / exit( 1 ); / etc ...
998
999 } /* end switch( hash_string( cmd ) ) */</programlisting>
1000
1001     <para><emphasis>Note:</emphasis> If you already have a default condition, you
1002     are obviously exempt from this point. Of note, most of the
1003     WIN32 code calls `DefWindowProc' after the switch statement.
1004     This API call *should* be included in a default statement.</para>
1005
1006     <para><emphasis>Another Note:</emphasis> This is not so much a readability issue
1007     as a robust programming issue. The "anomly code goes here" may
1008     be no more than a print to the STDERR stream (as in
1009     load_config). Or it may really be an ABEND condition.</para>
1010
1011     <para><emphasis>Status:</emphasis> Programmer discretion is advised.</para>
1012
1013     
1014   </sect3>
1015     
1016
1017     <sect3 id="s38"><title>Try to avoid falling through cases in a
1018     switch statement.</title>
1019
1020     <para><emphasis>Explanation:</emphasis></para>
1021
1022     <para>In general, you will want to have a 'break' statement within
1023     each 'case' of a switch statement. This allows for the code to
1024     be more readable and understandable, and furthermore can
1025     prevent unwanted surprises if someone else later gets creative
1026     and moves the code around.</para>
1027
1028     <para>The language allows you to plan the fall through from one
1029     case statement to another simply by omitting the break
1030     statement within the case statement. This feature does have
1031     benefits, but should only be used in rare cases. In general,
1032     use a break statement for each case statement.</para>
1033
1034     <para>If you choose to allow fall through, you should comment both
1035     the fact of the fall through and reason why you felt it was
1036     necessary.</para>
1037
1038     
1039   </sect3>
1040     
1041
1042     <sect3 id="s39"><title>Use 'long' or 'short' Instead of
1043     'int'</title>
1044
1045     <para><emphasis>Explanation:</emphasis></para>
1046
1047     <para>On 32-bit platforms, int usually has the range of long. On
1048     16-bit platforms, int has the range of short.</para>
1049
1050     <para><emphasis>Status:</emphasis> open-to-debate. In the case of most FSF
1051     projects (including X/GNU-Emacs), there are typedefs to int4,
1052     int8, int16, (or equivalence ... I forget the exact typedefs
1053     now). Should we add these to IJB now that we have a "configure"
1054     script?</para>
1055
1056     
1057   </sect3>
1058     
1059
1060     <sect3 id="s40"><title>Don't mix size_t and other types</title>
1061
1062     <para><emphasis>Explanation:</emphasis></para>
1063
1064     <para>The type of size_t varies across platforms. Do not make
1065     assumptions about whether it is signed or unsigned, or about
1066     how long it is. Do not compare a size_t against another
1067     variable of a different type (or even against a constant)
1068     without casting one of the values. Try to avoid using size_t if
1069     you can.</para>
1070
1071     
1072   </sect3>
1073     
1074
1075     <sect3 id="s41"><title>Declare each variable and struct on its
1076     own line.</title>
1077
1078     <para><emphasis>Explanation:</emphasis></para>
1079
1080     <para>It can be tempting to declare a series of variables all on
1081     one line. Don't.</para>
1082
1083     <para><emphasis>Example:</emphasis></para>
1084 <programlisting>
1085 long a = 0;
1086 long b = 0;
1087 long c = 0;</programlisting>
1088
1089     <para><emphasis>Instead of:</emphasis></para>
1090
1091     <para>long a, b, c;</para>
1092
1093     <para><emphasis>Explanation:</emphasis> - there is more room for comments on the
1094     individual variables - easier to add new variables without
1095     messing up the original ones - when searching on a variable to
1096     find its type, there is less clutter to "visually"
1097     eliminate</para>
1098
1099     <para><emphasis>Exceptions:</emphasis> when you want to declare a bunch of loop
1100     variables or other trivial variables; feel free to declare them
1101     on 1 line. You should, although, provide a good comment on
1102     their functions.</para>
1103
1104     <para><emphasis>Status:</emphasis> developer-discrection.</para>
1105
1106     
1107   </sect3>
1108     
1109
1110     <sect3 id="s42"><title>Use malloc/zalloc sparingly</title>
1111
1112     <para><emphasis>Explanation:</emphasis></para>
1113
1114     <para>Create a local stuct (on the stack) if the variable will
1115     live and die within the context of one function call.</para>
1116
1117     <para>Only "malloc" a struct (on the heap) if the variable's life
1118     will extend beyond the context of one function call.</para>
1119
1120     <para><emphasis>Example:</emphasis></para>
1121 <programlisting>
1122 If a function creates a struct and stores a pointer to it in a
1123 list, then it should definately be allocated via `malloc'.
1124 </programlisting>
1125   </sect3>
1126     
1127
1128     <sect3 id="s43"><title>The Programmer Who Uses 'malloc' is
1129     Responsible for Ensuring 'free'</title>
1130
1131     <para><emphasis>Explanation:</emphasis></para>
1132
1133     <para>If you have to "malloc" an instance, you are responsible for
1134     insuring that the instance is `free'd, even if the deallocation
1135     event falls within some other programmer's code. You are also
1136     responsible for ensuring that deletion is timely (i.e. not too
1137     soon, not too late). This is known as "low-coupling" and is a
1138     "good thing (tm)". You may need to offer a
1139     free/unload/destuctor type function to accomodate this.</para>
1140
1141     <para><emphasis>Example:</emphasis></para>
1142 <programlisting>
1143 int load_re_filterfile( struct client_state *csp ) { ... }
1144 static void unload_re_filterfile( void *f ) { ... }</programlisting>
1145
1146     <para><emphasis>Exceptions:</emphasis></para>
1147
1148     <para>The developer cannot be expected to provide `free'ing
1149     functions for C run-time library functions ... such as
1150     `strdup'.</para>
1151
1152     <para><emphasis>Status:</emphasis> developer-discrection. The "main" use of this
1153     standard is for allocating and freeing data structures (complex
1154     or nested).</para>
1155
1156     
1157   </sect3>
1158     
1159
1160     <sect3 id="s44"><title>Add loaders to the `file_list' structure
1161     and in order</title>
1162
1163     <para><emphasis>Explanation:</emphasis></para>
1164
1165     <para>I have ordered all of the "blocker" file code to be in alpha
1166     order. It is easier to add/read new blockers when you expect a
1167     certain order.</para>
1168
1169     <para><emphasis>Note:</emphasis> It may appear that the alpha order is broken in
1170     places by POPUP tests coming before PCRS tests. But since
1171     POPUPs can also be referred to as KILLPOPUPs, it is clear that
1172     it should come first.</para>
1173
1174     
1175   </sect3>
1176     
1177
1178     <sect3 id="s45"><title>"Uncertain" new code and/or changes to
1179     exitinst code, use FIXME</title>
1180
1181     <para><emphasis>Explanation:</emphasis></para>
1182
1183     <para>If you have enough confidence in new code or confidence in
1184     your changes, but are not *quite* sure of the reprocussions,
1185     add this:</para>
1186
1187     <para>/* FIXME: this code has a logic error on platform XYZ, *
1188     attempthing to fix */ #ifdef PLATFORM ...changed code here...
1189     #endif</para>
1190
1191     <para>or:</para>
1192
1193     <para>/* FIXME: I think the original author really meant this...
1194     */ ...changed code here...</para>
1195
1196     <para>or:</para>
1197
1198     <para>/* FIXME: new code that *may* break something else... */
1199     ...new code here...</para>
1200
1201     <para><emphasis>Note:</emphasis> If you make it clear that this may or may not
1202     be a "good thing (tm)", it will be easier to identify and
1203     include in the project (or conversly exclude from the
1204     project).</para>
1205
1206     
1207   </sect3>
1208
1209   </sect2>
1210
1211     <sect2 id="s46"><title>Addendum: Template for files and function
1212     comment blocks:</title>
1213
1214     <para><emphasis>Example for file comments:</emphasis></para>
1215 <programlisting>
1216 const char FILENAME_rcs[] = "$Id: developer-manual.sgml,v 1.5 2001/10/31 18:16:51 swa Exp $";
1217 /*********************************************************************
1218  *
1219  * File        :  $S<!-- Break CVS Substitution -->ource$
1220  *
1221  * Purpose     :  (Fill me in with a good description!)
1222  *
1223  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
1224  *                IJBSWA team.  http://ijbswa.sourceforge.net
1225  *
1226  *                Based on the Internet Junkbuster originally written
1227  *                by and Copyright (C) 1997 Anonymous Coders and
1228  *                Junkbusters Corporation.  http://www.junkbusters.com
1229  *
1230  *                This program is free software; you can redistribute it
1231  *                and/or modify it under the terms of the GNU General
1232  *                Public License as published by the Free Software
1233  *                Foundation; either version 2 of the License, or (at
1234  *                your option) any later version.
1235  *
1236  *                This program is distributed in the hope that it will
1237  *                be useful, but WITHOUT ANY WARRANTY; without even the
1238  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
1239  *                PARTICULAR PURPOSE.  See the GNU General Public
1240  *                License for more details.
1241  *
1242  *                The GNU General Public License should be included with
1243  *                this file.  If not, you can view it at
1244  *                http://www.gnu.org/copyleft/gpl.html
1245  *                or write to the Free Software Foundation, Inc., 59
1246  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
1247  *
1248  * Revisions   :
1249  *    $L<!-- Break CVS Substitution -->og$
1250  *
1251  *********************************************************************/
1252
1253
1254 #include "config.h"
1255
1256    ...necessary include files for us to do our work...
1257
1258 const char FILENAME_h_rcs[] = FILENAME_H_VERSION;
1259 </programlisting>
1260
1261     <para><emphasis>Note:</emphasis> This declares the rcs variables that should be
1262     added to the "show-proxy-args" page. If this is a brand new
1263     creation by you, you are free to change the "Copyright" section
1264     to represent the rights you wish to maintain.</para>
1265
1266     <para><emphasis>Note:</emphasis> The formfeed character that is present right
1267     after the comment flower box is handy for (X|GNU)Emacs users to
1268     skip the verbige and get to the heart of the code (via
1269     `forward-page' and `backward-page'). Please include it if you
1270     can.</para>
1271
1272     <para><emphasis>Example for file header comments:</emphasis></para>
1273 <programlisting>
1274 #ifndef _FILENAME_H
1275 #define _FILENAME_H
1276 #define FILENAME_H_VERSION "$Id: developer-manual.sgml,v 1.5 2001/10/31 18:16:51 swa Exp $"
1277 /*********************************************************************
1278  *
1279  * File        :  $S<!-- Break CVS Substitution -->ource$
1280  *
1281  * Purpose     :  (Fill me in with a good description!)
1282  *
1283  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
1284  *                IJBSWA team.  http://ijbswa.sourceforge.net
1285  *
1286  *                Based on the Internet Junkbuster originally written
1287  *                by and Copyright (C) 1997 Anonymous Coders and
1288  *                Junkbusters Corporation.  http://www.junkbusters.com
1289  *
1290  *                This program is free software; you can redistribute it
1291  *                and/or modify it under the terms of the GNU General
1292  *                Public License as published by the Free Software
1293  *                Foundation; either version 2 of the License, or (at
1294  *                your option) any later version.
1295  *
1296  *                This program is distributed in the hope that it will
1297  *                be useful, but WITHOUT ANY WARRANTY; without even the
1298  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
1299  *                PARTICULAR PURPOSE.  See the GNU General Public
1300  *                License for more details.
1301  *
1302  *                The GNU General Public License should be included with
1303  *                this file.  If not, you can view it at
1304  *                http://www.gnu.org/copyleft/gpl.html
1305  *                or write to the Free Software Foundation, Inc., 59
1306  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
1307  *
1308  * Revisions   :
1309  *    $L<!-- Break CVS Substitution -->og$
1310  *
1311  *********************************************************************/
1312
1313
1314 #include "project.h"
1315
1316 #ifdef __cplusplus
1317 extern "C" {
1318 #endif
1319
1320    ... function headers here ...
1321
1322
1323 /* Revision control strings from this header and associated .c file */
1324 extern const char FILENAME_rcs[];
1325 extern const char FILENAME_h_rcs[];
1326
1327
1328 #ifdef __cplusplus
1329 } /* extern "C" */
1330 #endif
1331
1332 #endif /* ndef _FILENAME_H */
1333
1334 /*
1335   Local Variables:
1336   tab-width: 3
1337   end:
1338 */
1339 </programlisting>
1340
1341     <para><emphasis>Example for function comments:</emphasis></para>
1342 <programlisting>
1343 /*********************************************************************
1344  *
1345  * Function    :  FUNCTION_NAME
1346  *
1347  * Description :  (Fill me in with a good description!)
1348  *
1349  * parameters  :
1350  *          1  :  param1 = pointer to an important thing
1351  *          2  :  x      = pointer to something else
1352  *
1353  * Returns     :  0 => Ok, everything else is an error.
1354  *
1355  *********************************************************************/
1356 int FUNCTION_NAME( void *param1, const char *x )
1357 {
1358    ...
1359    return( 0 );
1360
1361 }
1362 </programlisting>
1363
1364     <para><emphasis>Note:</emphasis> If we all follow this practice, we should be
1365     able to parse our code to create a "self-documenting" web
1366     page.</para>
1367
1368   </sect2>
1369
1370   </sect1>
1371
1372   <!--   ~~~~~       New section      ~~~~~     -->
1373   <sect1 id="cvs"><title>Version Control Guidelines</title>
1374     <para>To be filled. note on cvs comments. don't comment what you did, comment
1375 why you did it.
1376 </para>
1377   </sect1>
1378
1379   <!--   ~~~~~       New section      ~~~~~     -->
1380   <sect1 id="testing"><title>Testing Guidelines</title>
1381     <para>To be filled.
1382 </para>
1383
1384     <!--   ~~~~~       New section      ~~~~~     -->
1385     <sect2 id="testing-plan"><title>Testplan for releases</title>
1386       <para>
1387 Explain release numbers. major, minor. developer releases. etc.
1388
1389 <orderedlist numeration="arabic">
1390           <listitem><para>
1391 Remove any existing rpm with rpm -e
1392 </para></listitem>
1393           <listitem><para>
1394 Remove any file that was left over. This includes (but is not limited to)
1395       <itemizedlist>
1396                 <listitem><para>/var/log/junkbuster</para></listitem>
1397                 <listitem><para>/etc/junkbuster</para></listitem>
1398                 <listitem><para>/usr/sbin/junkbuster</para></listitem>
1399                 <listitem><para>/etc/init.d/junkbuster</para></listitem>
1400                 <listitem><para>/usr/doc/junkbuster*</para></listitem>
1401               </itemizedlist>
1402 </para></listitem>
1403           <listitem><para>
1404 Install the rpm. Any error messages?
1405 </para></listitem>
1406           <listitem><para>start,stop,status junkbuster with the specific script
1407       (e.g. /etc/rc.d/init/junkbuster stop). Reboot your machine. Does
1408       autostart work?</para></listitem>
1409           <listitem><para>Start browsing. Does the junkbuster work? Logfile written?</para></listitem>
1410           <listitem><para>Remove the rpm. Any error messages? All files removed?</para></listitem>
1411         </orderedlist>
1412 </para>
1413     </sect2>
1414
1415     <!--   ~~~~~       New section      ~~~~~     -->
1416     <sect2 id="testing-report"><title>Test reports</title>
1417       <para>
1418 Please submit test reports only with the <ulink url="http://sourceforge.net/tracker/?func=add&amp;group_id=11118&amp;atid=395005">test form</ulink>
1419 at sourceforge. Three simple steps:
1420         <itemizedlist>
1421           
1422           <listitem><para>Select category: the distribution you test on.</para></listitem>
1423           <listitem><para>Select group: the version of Junkbuster that we are about to release.</para></listitem>
1424           <listitem><para>Fill the Summary and Detailed Description with something
1425               intelligent (keep it short and precise).</para>
1426           </listitem>
1427         </itemizedlist>
1428         Do not mail to the mailinglist (we cannot keep track on issues there).
1429       </para>
1430     </sect2>
1431     
1432   </sect1>
1433   
1434   <!--   ~~~~~       New section      ~~~~~     -->
1435   <sect1 id="contact"><title>Contact the developers</title>
1436     <para>Please see the user manual for information on how to contact the developers.
1437     </para>
1438   </sect1>
1439   
1440   <!--   ~~~~~       New section      ~~~~~     -->
1441   <sect1 id="copyright"><title>Copyright and History</title>
1442     <para>Please see the user manual for information on Copyright and History.
1443     </para>
1444   </sect1>
1445   
1446   <!--   ~~~~~       New section      ~~~~~     -->
1447   <sect1 id="seealso"><title>See also</title>
1448     <para>Please see the user manual for information on references.
1449     </para>
1450   </sect1>
1451
1452   <!--
1453
1454   This program is free software; you can redistribute it 
1455   and/or modify it under the terms of the GNU General
1456   Public License as published by the Free Software
1457   Foundation; either version 2 of the License, or (at
1458   your option) any later version.
1459
1460   This program is distributed in the hope that it will
1461   be useful, but WITHOUT ANY WARRANTY; without even the
1462   implied warranty of MERCHANTABILITY or FITNESS FOR A
1463   PARTICULAR PURPOSE.  See the GNU General Public
1464   License for more details.
1465
1466   The GNU General Public License should be included with
1467   this file.  If not, you can view it at
1468   http://www.gnu.org/copyleft/gpl.html
1469   or write to the Free Software Foundation, Inc., 59
1470   Temple Place - Suite 330, Boston, MA  02111-1307, USA.
1471
1472   $Log: developer-manual.sgml,v $
1473   Revision 1.5  2001/10/31 18:16:51  swa
1474   documentation added: howto generate docs in text and html
1475   format, howto move stuff to the webserver.
1476
1477   Revision 1.4  2001/09/23 10:13:48  swa
1478   upload process established. run make webserver and
1479   the documentation is moved to the webserver. documents
1480   are now linked correctly.
1481
1482   Revision 1.3  2001/09/13 15:27:40  swa
1483   cosmetics
1484
1485   Revision 1.2  2001/09/13 15:20:17  swa
1486   merged standards into developer manual
1487
1488   Revision 1.1  2001/09/12 15:36:41  swa
1489   source files for junkbuster documentation
1490
1491   Revision 1.3  2001/09/10 17:43:59  swa
1492   first proposal of a structure.
1493
1494   Revision 1.2  2001/06/13 14:28:31  swa
1495   docs should have an author.
1496
1497   Revision 1.1  2001/06/13 14:20:37  swa
1498   first import of project's documentation for the webserver.
1499
1500   -->
1501
1502 </article>