<!DOCTYPE html>
<html>
<head>
  <title>Annotation File Utilities</title>
</head>
<body>
<h1>Annotation File Utilities</h1>

<p>Contents:</p>
<!-- start toc.  do not edit; run html-update-toc instead -->
    <ul>
      <li><a href="#motivation">Motivation</a>
        <ul>
          <li><a href="#jaif-file">External storage of annotations</a></li>
          <li><a href="#annotation-file-utilities-description">Annotation File Utilities</a></li>
        </ul></li>
      <li><a href="#installation">Installation</a>
        <ul>
          <li><a href="#viewing-source">Building from source</a></li>
        </ul></li>
      <li><a href="#using">Using the Annotation File Utilities</a>
        <ul>
          <li><a href="#insert-annotations">Insert-annotations</a></li>
          <li><a href="#extract-annotations">Extract-annotations</a></li>
          <li><a href="#insert-annotations-to-source">Insert-annotations-to-source</a></li>
        </ul></li>
      <li><a href="#implementation">Design and Implementation Details</a>
        <ul>
          <li><a href="#asmx">Asmx</a></li>
          <li><a href="#scene-lib">Scene-lib</a>
            <ul>
              <li><a href="#bytecode-insertion">Bytecode Insertion</a></li>
              <li><a href="#bytecode-extraction">Bytecode Extraction</a></li>
            </ul></li>
          <li><a href="#source-insertion">Annotation-file-utilities</a></li>
        </ul></li>
      <li><a href="#feedback">Feedback and bug reports</a>
        <ul>
          <li><a href="#changelog">Changelog</a></li>
        </ul></li>
    </ul>
<!-- end toc -->



<hr />
<h2 id="motivation">Motivation</h2>

<p>
Java annotations are meta-data about Java program elements, as in
&ldquo;<code><mark>@Deprecated</mark> class Date
{&nbsp;...&nbsp;}</code>&rdquo; or &ldquo;<code>List&lt;<mark>@NonNull</mark> String&gt;</code>&rdquo;.
Ordinarily, Java annotations are
written in the
source code of a <code>.java</code> Java source file.  When
<code>javac</code> compiles the source code, it inserts the annotations in
the resulting <code>.class</code> file (as
&ldquo;attributes&rdquo;).
</p>

<!--
  I've moved text from here to the annotation-file-format document, but feel
  free to improve that document.
-->

<h3 id="jaif-file">External storage of annotations</h3>

<p>
Sometimes, it is convenient to specify
the annotations outside the source code or the <code>.class</code> file.
The document
&ldquo;Annotation File Format Specification&rdquo; (<a
    href="annotation-file-format.pdf">PDF</a>, <a
    href="annotation-file-format.html">HTML</a>)
defines a textual format for annotations,
and it also motivates reasons why such a file format is necessary in
addition to the <code>.java</code> and <code>.class</code> formats.  The
file format supports both the declaration annotations and type annotations.
</p>

<p>
An annotation file
conventionally has the extension <code>.jaif</code> (for Java Annotation Index
File).
The <a href="#scene-lib"><code>scene-lib</code></a> sub-project provides
API methods for building and manipulating annotation files.
</p>


<h3 id="annotation-file-utilities-description">Annotation File Utilities</h3>

<p>
Programmers need to be able to transfer annotations
between the three possible locations for annotations &mdash; source code, class files,
and annotation files.   Programmers will want to extract
annotations from source and class files to an annotation file in order to easily
read annotations, while various tools will only read annotations from
source and class files.  The Annotation File Utilities provide three tools
to read and write annotation files.
</p>

<ul>
  <li> <a href="#insert-annotations"><code>insert-annotations</code></a> reads annotations from an annotation file
       and inserts them into a class file</li>
  <li> <a href="#extract-annotations"><code>extract-annotations</code></a> reads annotations from a class file
       and writes them out to an annotation file</li>
  <li> <a href="#insert-annotations-to-source"><code>insert-annotations-to-source</code></a> reads annotations from an
       annotation file and inserts them into a Java source file</li>
</ul>

<p>
A diagram showing the interactions betweeen these tools is below.
</p>

<div>
<img src="figures/tool-relations.svg" alt="Relationships between AFU tools" />
</div>

<p>
There is no
<code>extract-annotations-from-source</code> tool:  one can
compile the source code and then use
<code>extract-annotations</code> to read the annotations from the class
file.
</p>


<hr />
<h2 id="installation">Installation</h2>

<p>
The following instructions assume either a Linux or Windows system using a command-line environment.
</p>

<p>
The current release is Annotation File Utilities version
<!-- afu-version -->3.6.44, 03 Aug 2017<!-- /afu-version -->.
</p>

<ol>
<li>
  Download
  <a href="annotation-tools-3.6.44.zip"><!-- annotation-tools-zip-version -->annotation-tools-3.6.44.zip<!-- /annotation-tools-zip-version --></a>.
</li>

<li>
  Creade a directory named
  <code>annotation-tools</code> by
  unpacking the distribution zipfile (a standard place to do this is in a
  directory <code>~/jsr308/</code>):

  <pre><code>unzip annotation-tools-3.6.44.zip</code></pre>

  The <code>annotation-tools</code> directory must be a sibling of the <code>jsr308-langtools</code>
  directory (available at <a href="https://checkerframework.org/jsr308/">https://checkerframework.org/jsr308/</a>).
  Alternatively, Unix (including Linux and MacOS) users may set the <code>LANGTOOLS</code> environment variable to
  the location of the <code>jsr308-langtools</code> directory:

  <pre><code>export LANGTOOLS=<em>/path/to</em>/jsr308-langtools</code></pre>
</li>

<li>
Add the <code>annotation-file-utilities</code> directory to your path.

<ul>
<li>
For <b>Unix</b> (including Linux and MacOS), add the directory to your PATH
environment variable.  If your shell is sh or bash, add to your
<code>~/.bashrc</code> or <code>~/.bash_profile</code> file:
<pre><code>export PATH=${PATH}:<em>/path/to</em>/annotation-tools/annotation-file-utilities/scripts</code></pre>
<!-- Omitted to save space and simplify instructions
For csh/tcsh, add to ~/.tcshrc or ~/.cshrc or ~/.login:
<pre><code>setenv PATH=${PATH}:/path/to/annotation-file-utilities/</code></pre>
-->
</li>
<li>
For <b>Windows</b>, add the directory to your
<code>PATH</code> system
variable by going to

<pre><code> Control Panel -> System -> Advanced -> Environment Variables </code></pre>

From there, find the <code>PATH</code> variable under &ldquo;System variables&rdquo;
and append to it the directory <code><em>path\to</em>\annotatation-tools\annotation-file-utilities\scripts</code>.
</li>
</ul>
</li>
</ol>


<!-- I think this is obvious, so I have commented it out -MDE. -->
<!--
<p>
To update the annotation file utilities, simply download the most recent <code>annotation-tools.zip</code> file from this website and replace the existing <code>annotation-tools.zip</code>, then extract the file just as when you first installed it.  As long as you followed the above instructions, no further work needs to be done.
</p>
-->

<h3 id="viewing-source">Building from source</h3>

<p>
The annotation file utilities are pre-compiled (a jar file is included in
the distribution), so most users do not need to compile it themselves.
</p>

<p>
There are two ways to obtain the source code.
Source code is provided in the
<a href="https://github.com/typetools/annotation-tools/releases">distribution</a>.
Alternately, see the source code repository at
<a href="https://github.com/typetools/annotation-tools">https://github.com/typetools/annotation-tools</a>.
</p>

<p>
To compile, run
<code>ant jarfile</code> from the <code>annotation-file-utilities</code>
subdirectory.  If the <code>javac</code> and <code>java</code> programs are
not on your execution path, see the notes near the top of
<code>annotation-file-utilities/tests/Makefile</code>.
</p>


<hr />
<h2 id="using">Using the Annotation File Utilities</h2>

<p>
To use the tools, simply run them from the command-line with the
appropriate arguments.  The following instructions are for running the
tools on a Linux/Unix/MacOS machine.
The tools work identically on Windows, except
the extension <code>.bat</code> needs to be appended to the tool name (for
example, Windows users would execute <code>insert-annotations.bat</code>
instead of <code>insert-annotations</code>).
</p>

<p>
For all the tools, arguments starting with a single
&lsquo;<code>@</code>&rsquo; are recognized as argument files
(<code>argfiles</code>), the contents of which get expanded into the
command line.  (Initial <code>@@</code> represents a literal
<code>@</code> in the argument text.)  For additional details of argfile
processing, refer to Oracle's
<a href="https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html"><code>javac</code></a>
documentation.
</p>

<h3 id="insert-annotations"> Insert-annotations </h3>

<p>
To insert annotations specified by an annotation file into a class file, use the
insert-annotations tool.  Running:
</p>

<pre><code>insert-annotations mypackage.MyClass indexFile.jaif</code></pre>

<p>
will read in all the annotations from the annotation file
<code>indexFile.jaif</code> and insert those annotations pertaining to
<code>mypackage.myClass</code> into the class file for
<code>mypackage.MyClass</code>, outputting the final class file to
<code>mypackage.MyClass.class</code> in the present working directory.
Note that the class file for <code>mypackage.MyClass</code> must be located
on your classpath.
</p>

<p>
Multiple pairs of class and index files (in that order) can be specified
on a single command line; if the program exits normally, the results
are the same as if the program were run once for each pair of arguments
in sequence.
Run:
</p>

<pre><code>insert-annotations --help</code></pre>

<p>
for full usage information.
</p>


<h3 id="extract-annotations"> Extract-annotations </h3>

<p>
To extract annotations from a class file and write them to an annotation file,
use the extract-annotations tool.  Running:
</p>

<pre><code>extract-annotations mypackage.MyClass</code></pre>

<p>
will locate the class file for <code>mypackage.MyClass</code>, read all
annotations from it, and write the results in annotation file format to
<code>mypackage.MyClass.jaif</code> in the present working directory.  Note
that <code>mypackage.MyClass</code> must be located on your classpath.
</p>

<p>
Multiple classes can be specified on a single command line; if the
program exits normally, the results are the same as if the program were
run once for each class in sequence.
Run:
</p>

<pre><code>extract-annotations --help</code></pre>

<p>
for full usage information.
</p>


<h3 id="insert-annotations-to-source">Insert-annotations-to-source </h3>

<p>
To insert annotations specified by an annotation file into a Java source file,
use the insert-annotations-to-source tool.  Running:
</p>

<pre><code>insert-annotations-to-source index1.jaif index2.jaif mypackage/MyClass.java yourpackage/YourClass.java</code></pre>

<p>
will read all the annotations from <code>index1.jaif</code> and
<code>index2.jaif</code>, insert them (when applicable) into their
appropriate locations in <code>mypackage/MyClass.java</code> and
<code>yourpackage/YourClass.java</code>, and write the results to
<code>annotated/mypackage/MyClass.java</code> and
<code>annotated/mypackage/MyClass.java</code>, respectively.
</p>

<p>
Index and source files can be specified in any order, mixing the two
file types freely; if the source files have no overlapping definitions
and the program exits normally, the results are the same as if the
program were run once for each source file, with <em>all</em> JAIFs
given for each run.
Run:
</p>

<pre><code>insert-annotations-to-source --help</code></pre>

<p>
for full usage information.
</p>

<p>
If you wish to insert annotations into method bodies, you must have the
associated class <code>mypackage.MyClass.class</code> on your classpath.
You can insert annotations on class/field/method declarations and
signatures without the class on your classpath.
</p>

<p>
In general (but see below for exceptions), your source code needs to
contain the locations that your
<code>.jaif</code> file references.  In particular, if the
<code>.jaif</code> file contains annotations for a type parameter, but the
source code uses a raw type, then you will get an error such as
</p>
<pre>
Found class Edge, but unable to insert @checkers.nullness.quals.Nullable:
  @checkers.nullness.quals.Nullable (nl=true) @ [GenericArrayLocationCriterion at ( [TYPE_ARGUMENT(0)] ), ...
</pre>
<p>
In this case, you should add type arguments, such as changing
</p>
<pre>  public void pushNonezeroRing(Stack stack, Hashtable seen) {</pre>
<p>to</p>
<pre>  public void pushNonezeroRing(Stack&lt;Edge&gt; stack, Hashtable&lt;Edge, ?&gt; seen) {</pre>
<p>
In a few cases, insert-annotations-to-source will generate "default"
code to provide a location for an annotation.  These include
</p>
<ul>
<li>method and constructor <a href="http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.1-220">receivers;</a></li>
<li>type parameter bounds (<code>extends Object</code>);</li>
<li>type casts for expressions</li>
<li>nullary constructor definitions; and</li>
<li>explicit constructor invocations for literal arrays (e.g., <code>{"a", "b"}</code> becomes <code>new String[] {"a", "b"}</code>).</li>
</ul>

<p>
The command-line options are as follows:
</p>

<!-- start options doc (DO NOT EDIT BY HAND) -->
<ul>
  <li id="optiongroup:General-options">General options
    <ul>
      <li id="option:outdir"><b>-d</b> <b>--outdir=</b><i>directory</i>. Directory in which output files are written. [default annotated/]</li>
      <li id="option:in-place"><b>-i</b> <b>--in-place=</b><i>boolean</i>. If true, overwrite original source files (making a backup first).
 Furthermore, if the backup files already exist, they are used instead
 of the .java files.  This behavior permits a user to tweak the .jaif
 file and re-run the annotator.
 <p>

 Note that if the user runs the annotator with --in-place, makes edits,
 and then re-runs the annotator with this --in-place option, those
 edits are lost.  Similarly, if the user runs the annotator twice in a
 row with --in-place, only the last set of annotations will appear in
 the codebase at the end.
 <p>

 To preserve changes when using the --in-place option, first remove the
 backup files.  Or, use the <code>-d .</code> option, which makes (and
 reads) no backup, instead of --in-place. [default false]</li>
      <li id="option:abbreviate"><b>-a</b> <b>--abbreviate=</b><i>boolean</i>. Abbreviate annotation names [default true]</li>
      <li id="option:comments"><b>-c</b> <b>--comments=</b><i>boolean</i>. Insert annotations in comments [default false]</li>
      <li id="option:omit-annotation"><b>-o</b> <b>--omit-annotation=</b><i>string</i>. Omit given annotation</li>
      <li id="option:nowarn"><b>--nowarn=</b><i>boolean</i>. Suppress warnings about disallowed insertions [default false]</li>
      <li id="option:convert-jaifs"><b>--convert-jaifs=</b><i>boolean</i>. Convert JAIFs to new format [default false]</li>
      <li id="option:help"><b>-h</b> <b>--help=</b><i>boolean</i>. Print usage information and exit [default false]</li>
    </ul>
  </li>
  <li id="optiongroup:Debugging-options">Debugging options
    <ul>
      <li id="option:verbose"><b>-v</b> <b>--verbose=</b><i>boolean</i>. Verbose (print progress information) [default false]</li>
      <li id="option:debug"><b>--debug=</b><i>boolean</i>. Debug (print debug information) [default false]</li>
      <li id="option:print-error-stack"><b>--print-error-stack=</b><i>boolean</i>. Print error stack [default false]</li>
    </ul>
  </li>
</ul>
<!-- end options doc -->


<hr />
<h2 id="implementation">Design and Implementation Details</h2>

<p>This section describes some high level-design and implementation
details of the Annotation File Utilities, including the different
components of the Annotation File Utilities and how they fit together.
It is intended for someone who is beginning work on the Annotation File
Utilities or is curious about how the Annotation File Utilities work.</p>

<p>The Annotation File Utilities is composed of three sub-projects:
<code>asmx</code>, <code>scene-lib</code>, and
<code>annotation-file-utilities</code>.  The <code>asmx</code>
sub-project provides methods for reading and writing class files.  The
<code>scene-lib</code> sub-project represents a <code>.jaif</code> file
and inserts and extracts annotations to/from bytecode.  The
<code>annotation-file-utilities</code> sub-project inserts annotations
into source code.</p>

<h3 id="asmx" class="subsection">Asmx</h3>

<p>The <code>asmx</code> sub-project provides methods for reading and
writing class files.  <code>asmx</code> is based on an old version
(2.2.2) of the <a href="http://asm.ow2.org/">ASM Framework</a>. It has been modified to
allow it to read and write <a href="https://checkerframework.org/jsr308/specification/java-annotation-design.html">JSR 308</a>
annotations in bytecode.  However, it is far behind the current ASM
version (5.0), which provides support for type annotations. We should
discard the custom <code>asmx</code> in the Annotation File Utilities
and adapt the Annotation File Utilities to use the official, supported
version of ASM.</p>

<h3 id="scene-lib" class="subsection">Scene-lib</h3>

<p><code>scene-lib</code> is an interface to a <code>.jaif</code> file.
It reads in and writes out <code>.jaif</code> files and provides an
internal representation of a <code>.jaif</code> file to access and
manipulate.</p>

<p>Internally, a <code>.jaif</code> file is represented by the
<code>scene-lib/src/annotations/el/AScene.java</code> class. The
<code>AScene</code> class (or &ldquo;annotated scene&rdquo;) roughly
parallels the root of an abstract syntax tree. An <code>AScene</code>
has a number of classes (<code>AClass</code>) as children. Each class
has a number of methods (<code>AMethod</code>), fields
(<code>AElement</code>), etc. as children. All of these classes are
related in the type hierarchy shown below.</p>

<div>
<img src="figures/scene-lib-type-hierarchy.svg" alt="scene-lib type hierarchy">
</div>

<p>Each class in the type hierarchy has one or more fields to hold
annotations for the different components of the class. For example, the
<code>AMethod</code> class has the following fields: bounds, return
type, receiver parameters, and throws clause. Each of these fields
holds the annotations stored on that part of the method. For details on
the remainder of the classes in the type hierarchy, and their
respective fields, see the documentation for each file in
<code>scene-lib/src/annotations/el/</code>.</p>

<p>An <code>AScene</code> instance can be created in two ways. An empty
<code>AScene</code> can be created by calling the <code>AScene</code>
constructor, or an <code>AScene</code> can be created by parsing an
existing <code>.jaif</code> file. Once an <code>AScene</code> is
created, annotations can be added to it by adding them to the correct
fields of the children. An <code>AScene</code> can also be output to
create a new <code>.jaif</code> file.</p>

<h4 id="bytecode-insertion" class="subsubsection">Bytecode Insertion</h4>

<p>Annotations can be inserted into bytecode by executing the
<code>annotation-file-utilities/scripts/insert-annotations</code>
script. This script takes one or more &langle;class name,
<code>.jaif</code> file&rangle; pairs as arguments. The annotations
specified in the <code>.jaif</code> file are inserted into the
classfile directly before the <code>.jaif</code> file in the argument
list.</p><p>First, each <code>.jaif</code> file is parsed into an
<code>AScene</code> (as described in
<a href="#scene-lib">Scene-lib</a>). Then,
<code>asmx/src/org/objectweb/asm/ClassReader.java</code> parses the
classfile.  As it is parsing the classfile, it passes the parsed
bytecode off to the
<code>scene-lib/src/annotations/io/classfile/ClassAnnotationSceneWriter.java</code>
class. This class has a reference to the <code>AScene</code> parsed
from the <code>.jaif</code> file. As this class receives the parsed
bytecode it inserts the relevant annotations from the
<code>AScene</code> in the bytecode and then writes the bytecode back
out.</p>

<h4 id="bytecode-extraction" class="subsubsection">Bytecode Extraction</h4>

<p>Annotations can be extracted from bytecode by executing the
<code>annotation-file-utilities/scripts/extract-annotations</code>
script. This script takes one or more class names as arguments and
outputs the annotations found in those classes to <code>.jaif</code>
files.</p><p>First, an empty <code>AScene</code> is constructed to store
the annotations.
<code>asmx/src/org/objectweb/asm/ClassReader.java</code> parses the
classfile and passes the parsed bytecode off to the
<code>scene-lib/src/annotations/io/classfile/ClassAnnotationSceneReader.java</code>
class. This class filters out the annotations in the bytecode and adds
them to the correct part of the <code>AScene</code>. After this, the
<code>AScene</code> is output to a <code>.jaif</code> file.</p>

<h3 id="source-insertion" class="subsection">Annotation-file-utilities</h3>

<p>The <code>annotation-file-utilities</code> sub-project inserts annotations into source
code. It can be run by executing the
<code>annotation-file-utilities/scripts/insert-annotations-to-source</code>
script.  The script takes one or more <code>.jaif</code> files, followed by one or more <code>.java</code> source files as arguments. The annotations in the <code>.jaif</code> files are inserted into the <code>.java</code> source files.</p><p>First, an instance of
<code>annotation-file-utilities/src/annotator/specification/IndexFileSpecification.java</code>
is created. Its <code>parse</code> method parses the <code>.jaif</code>
file into an <code>AScene</code> (as described in
<a href="#scene-lib">Scene-lib</a>).  The <code>parse</code> method
calls the <code>parseScene</code> method, which traverses through the
<code>AScene</code> and creates an
<code>annotation-file-utilities/src/annotator/specification/CriterionList.java.</code>
A <code>CriterionList</code> identifies a unique AST node that is the
location of an insertion. It contains objects that implement the
<code>annotation-file-utilities/src/annotator/find/Criterion.java</code>
interface.
Each <code>Criterion</code> has an <code>isSatisifiedBy</code> method —
a predicate that takes an AST node and returns <code>true</code> if the
AST node satisfies the <code>Criterion</code> and <code>false</code>
otherwise. To determine if a given node matches a
<code>CriterionList</code>, the node is passed to all of the
<code>Criterion</code>s in the <code>CriteriaList</code>. If every
<code>Criterion</code> returns <code>true</code> then it is match. If
one or more <code>Criterion</code>s return <code>false</code> then it is
not a match.  The various <code>Criterion</code> classes are in the
<code>annotation-file-utilities/src/annotator/find/</code> directory.
For example, take the following source code:</p>

<pre class="verbatim">package afu.example;

public class Test {
    public void m(boolean b, int i) {
      // ...
    }
}
</pre>

<p>The <code>CriterionList</code> to specify the location of the
<code>i</code> parameter contains the following
<code>Criterion</code>s:</p>

<ul class="itemize"><li class="li-itemize">
<code>InPackageCriterion("afu.example")</code>
</li><li class="li-itemize"><code>InClassCriterion("Test")</code>
</li><li class="li-itemize"><code>InMethodCriterion("m(ZI)V")</code>
</li><li class="li-itemize"><code>ParamCriterion(1)</code>
</li></ul>

<p>After this <code>CriterionList</code> is built up an
<code>annotation-file-utilities/src/annotator/find/Insertion.java</code>
is created.  An <code>Insertion</code> stores an
<code>annotation-file-utilities/src/annotator/find/Criteria.java</code>
(which is created from a <code>CriterionList</code>) and the text to be
inserted. All of these <code>Insertion</code>s are then added to a
list. The Java compiler then is called to parse the Java source into an
abstract syntax tree. This is followed by a call to the
<code>getPositions</code> method of
<code>annotation-file-utilities/src/annotator/find/TreeFinder.java</code>,
which scans through each node of the abstract syntax trees. For each node,
it runs through the <code>Criteria</code> for each un-matched
<code>Insertion</code>. If at least one of the <code>Criteria</code>
does not match, then this is not the correct place for the
<code>Insertion</code> and the <code>Insertion</code> will be checked
at the remaining nodes of the tree. If all of the <code>Criteria</code>
match, then this node is the correct place for the
<code>Insertion</code>. It is removed from the list of un-matched
<code>Insertion</code>s and the position where to insert the
<code>Insertion</code> is determined. This position is the integer
index in the file where the <code>Insertion</code> should be inserted.
After the positions are found for all of the <code>Insertion</code>s,
the <code>Insertion</code> text is inserted into the file. This happens
backwards, with <code>Insertion</code>s at the end of the file (i.e.
with higher positions) being inserted first. If <code>Insertion</code>s
were instead inserted from the beginning of the file then a single
<code>Insertion</code> would invalidate all of the positions for the
following <code>Insertion</code>s.</p>

<p>If there are remaining <code>Insertion</code>s that were not matched
to a node in the abstract syntax tree then an error message is
displayed.</p>


<hr />
<h2 id="feedback"> Feedback and bug reports </h2>

<p>
To submit a bug report or request a new feature, use the
<a href="https://github.com/typetools/annotation-tools/issues">issue
  tracker</a>.  When reporting a bug, please include exact instructions in
how to reproduce it, and please also attach relevant input files.  This
will let us resolve the issue quickly.
</p>

<p>
You can also reach the developers at
<a href="mailto:annotation-tools-dev@googlegroups.com">annotation-tools-dev@googlegroups.com</a>.
But please use the
  <a href="https://github.com/typetools/annotation-tools/issues">issue
  tracker</a> for bug reports and feature requests.
</p>


<h3 id="changelog">Changelog</h3>

<p>
The <a href="changelog.html">changelog</a> describes what is new in each release.
</p>


<hr/>

</body>
</html>

<!--  LocalWords:  utils bashrc tcsh tcshrc cshrc classpath
 -->