
<!-- Antelope plugin user's guide -->
<!-- (C) 2002-2005 Dale Anson -->

<book>
<bookinfo>
    <title>Additional Ant Tasks</title>

    <authorgroup>
        <author><firstname>Dale</firstname><surname>Anson</surname></author>
    </authorgroup>

</bookinfo>

<chapter id="introduction">
@style@
<title>Introduction</title>

<para>
Many of the Antelope tasks are now part of the Ant-Contrib project, http://ant-contrib.sourceforge.net. In this version, @buildnum@, the tasks contained in the Antelope distribution are identical to those in Ant-Contrib other than the package name. The Antelope tasks will continue to be distributed as part of the Antelope distribution, but eventually, the package and code base will reside entirely with Ant-Contrib. Additionally, it is likely that the Ant-Contrib tasks that are not part of Antelope will be included in this distribution as well. The intent is to make Ant-Contrib the central location for additional Ant tasks.
</para>

<para>
Ant was not designed to be a scripting language. It was meant to replace 'make' and has done an outstanding job in doing so. However, in day to day use in building even small-scale applications, Ant is being used in ways never foreseen by its creators. Complete applications are being build using Ant as the coding language. Build files call other build files, which in turn call other build files. Regardless of the original intent, Ant has become a replacement for batch files, shell scripts, perl scripts, and make files.
</para>

<para>
Ant is also extensible. The API is nicely defined to allow any number of new tasks to be added, and each new release of Ant includes new and useful tasks. The tasks described here help developers to create more robust build files, and to assist in structuring build files more like a programming or scripting language than is possible with the standard issue tasks.
</para>

<para>
Several of the tasks described in this manual are based on Java language counterparts:
</para>
<para>
The Assert task is modeled after the Java <computeroutput>assert</computeroutput>keyword.
</para>
<para>
The If task is modeled after the Java <computeroutput>if/else</computeroutput> construct.
</para>
<para>
The Try task is modeled after the Java <computeroutput>try/catch</computeroutput> construct.
</para>
<para>
The Variable task is modeled after Java variable declaration and assignment.
</para>
<para>
These tasks have become indispensible for me in daily use. I think you will find that your Ant build files are more robust and better structured through the use of these tasks.  I've tried to incorporate real-world examples, in fact, many come from the unit tests for the tasks.  If you have a source code distribution, you can look at the unit tests for more examples.
</para>


</chapter>

<chapter id="license">
@style@
    <title>License</title>

    <para>
        These Ant tasks are licensed under the same Apache license as Ant:
    </para>

    <para>
    <programlisting>
    <![CDATA[
The Apache Software License, Version 1.1

Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in
   the documentation and/or other materials provided with the
   distribution.

3. The end-user documentation included with the redistribution, if
   any, must include the following acknowlegement:
      "This product includes software developed by the
       Apache Software Foundation (http://www.apache.org/)."
   Alternately, this acknowlegement may appear in the software itself,
   if and wherever such third-party acknowlegements normally appear.

4. The names "The Jakarta Project", "Ant", and "Apache Software
   Foundation" must not be used to endorse or promote products derived
   from this software without prior written permission. For written
   permission, please contact apache@apache.org.

5. Products derived from this software may not be called "Apache"
   nor may "Apache" appear in their names without prior written
   permission of the Apache Group.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
====================================================================

This software consists of voluntary contributions made by many
individuals on behalf of the Apache Software Foundation.  For more
information on the Apache Software Foundation, please see
<http://www.apache.org/>.
    ]]>
    </programlisting>
    </para>

</chapter>

<chapter id="installation">
@style@
    <title>Installation</title>
    <para>
        If you are running your build files from Antelope, these tasks are already installed and nothing more needs to be done. The following discusses installing the tasks by hand for use outside of Antelope.
    </para>

    <para>
        These Ant tasks are packaged as a part of Antelope, which is an application for running Ant build files. They may also be obtained as a separate package. Depending on the distribution you have on hand, copy either antelope.jar or antelope_tasks.jar into your ${ant.home}/lib directory or add it to your classpath. This is the directory where ant.jar and optional.jar are installed for your Ant distribution.
    </para>

    <para>
        Once installed, each task that you want to use in a build file must be defined in that build file. Since several of the Antelope tasks are dependent on each other, the preferred way to define them is like this:
       <programlisting>
       <![CDATA[
         <taskdef resource="ise.antelope.tasks.antelope.taskdefs
                  classpath="path/to/AntelopeTasks_@buildnum@.jar"/>
       ]]>
       </programlisting>
       This will load all Antelope tasks without further hassle, and will only load the tasks once. It is not good to load the tasks multiple times, this can cause problems with 'ant' and 'antcall' in particular.
    </para>
    <para>
        If you don't want to load all of the tasks, the documentation for each task explains in detail what you will need to add to your build file to use the individual task. For example, the Assert tasks says:
    </para>

    <para>
        <programlisting>
        To use this task in your build files, include a task definition like this:
        <![CDATA[
        <taskdef name="assert" classname="ise.antelope.tasks.Assert"/>
        <property name="ant.enable.asserts" value="true"/>
        ]]>
        </programlisting>
    </para>

    <para>
        Notice that you may name the tasks whatever you want via 'taskdef'. The names listed in the individual task descriptions are those that are set via the preferred method mentioned above.
    </para>

    <para>
        As of Antelope version 2.64, the 'AntLib' feature of Ant 1.6 is supported, which provides an alternate way of loading optional tasks. If AntelopeTasks_@buildnum@.jar is in the core classpath (in ${ant.home}/lib for example) one can use the namespace short-cut to load them:
        <programlisting>
        <![CDATA[
        <project xmlns:antelope="antlib:ise.antelope.tasks">
          <antelope:try messageproperty="failed">
            <fail>This should fail</fail>
            <echo>This will not be reached</echo>
            <antelope:catch>
              <echo>failed is ${failed}</echo>
            </antelope:catch>
          </antelope:try>
        </project>
        ]]>
        </programlisting>
        <emphasis role="italic">Thanks to Peter Reilly of the Ant development team for this pointer and example.</emphasis>
    </para>

</chapter>

<chapter id="Assert">
@style@
    <title>Assert Task</title>

<para>
The Assert task adds an assertion capability to Ant projects. This task works in a manner very similar to the Java <computeroutput>assert</computeroutput> keyword, and provides a limited "design by contract" facility to Ant. This is very useful for testing build scripts prior to putting them into production.
</para>

<para>
The Assert task verifies that a given property has a
given value and throws a BuildException if the property value is not as expected
or the property does not exist.
</para>

<para>
Also like Java's <computeroutput>assert</computeroutput> keyword, the Assert task must be 'turned on' using the property <computeroutput>ant.enable.asserts</computeroutput>. If not set, or is set to <computeroutput>false</computeroutput>, the Assert task works exactly like the Sequential task. If the <link linkend="Variable">Variable task</link> is used to define this property, then it can be turned on and off as needed throughout a build.
</para>

<para>
This task can hold other tasks including Assert.
</para>

<para>
The Assert task may contain one 'bool' element. The 'bool' element is identical to the ConditionTask, but unlike the ConditionTask, is actually a Task. The 'bool' element can contain all the conditions permitted by the ConditionTask, plus the <link linkend="conditionals">IsPropertyTrue</link>, <link linkend="conditionals">IsPropertyFalse</link>,
<link linkend="conditionals">StartsWith</link>,
<link linkend="conditionals">EndsWith</link>,
<link linkend="conditionals">IsGreaterThan</link>,
<link linkend="conditionals">IsLessThan</link>,
<link linkend="conditionals">DateTimeBefore</link>,
<link linkend="conditionals">DateTimeDifference</link>,
<link linkend="conditionals">MathEquals</link> conditions.
See the <link linkend="IfTask">If task</link> for examples of using these conditionals.
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
    <taskdef name="assert" classname="ise.antelope.tasks.Assert"/>
    <property name="ant.enable.asserts" value="true"/>
]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>Assert Task Attributes</title>
<tgroup cols="4">
<thead>

<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>
<row>
<entry>name</entry>
<entry>The name of the property to test for.</entry>
<entry>none</entry>
<entry>Yes</entry>
</row>

<row>
<entry>exists</entry>
<entry>Test for existence or non-existence of the property.</entry>
<entry>True</entry>
<entry>No</entry>
</row>

<row>
<entry>value</entry>
<entry>The value to test for, implies 'exists=true'. If the value in the project is different than this value, a BuildException will be thrown and the build will stop.</entry>
<entry>none</entry>
<entry>No</entry>
</row>

<row>
<entry>execute</entry>
<entry>Should the tasks contained in this task be executed? It may be useful to set this to false when testing build files.</entry>
<entry>True</entry>
<entry>No</entry>
</row>

<row>
<entry>failonerror</entry>
<entry>Should the build halt if the assertion fails? Setting this to false is contrary to the intented use of assertions, but may be useful in certain situations. </entry>
<entry>True</entry>
<entry>No</entry>
</row>

<row>
<entry>message</entry>
<entry>A message to include with the output in the event of this assert failing.</entry>
<entry>none</entry>
<entry>No</entry>
</row>

<row>
<entry>level</entry>
<entry>A "level" for the assert, similar to debug levels.  Valid values are 'error', 'warning', 'info', 'debug'.</entry>
<entry>error</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>

</para>

<para>
As stated above, the Assert task may contain a nested "bool" task, otherwise,
the Assert task does not support any nested
elements apart from Ant tasks. Any valid Ant task may be embedded within the
assert task.
</para>

<para>
The "level" attribute is only (so far) useful when Assert is used in conjunction with the <link linkend="testcasetask">Testcase task</link>. Setting this attribute to "warning", "info", or "debug" will force "failonerror" to false.
</para>

<para>
In the following example, the first <computeroutput>assert</computeroutput> task checks that the <computeroutput>wait</computeroutput> property exists and does not execute the <computeroutput>echo</computeroutput> and <computeroutput>sleep</computeroutput> tasks. The second <computeroutput>assert</computeroutput> task checks that the <computeroutput>wait</computeroutput> property exists, has a value of 2, and executes the <computeroutput>echo</computeroutput> task.
</para>

<para>
<programlisting>
<![CDATA[
     <property name="wait" value="2"/>
     <assert name="wait" execute="false">
        <echo>
            Waiting ${wait} seconds...
            Click the red button to stop waiting.
        </echo>
        <sleep seconds="${wait}"/>
     </assert>
     <assert name="wait" value="2" execute="true">
        <echo>done waiting!</echo>
     </assert>
]]>
</programlisting>
</para>

<para>
The next example shows Assert being used in a unit test for the "limit" task:
<programlisting>
<![CDATA[
  <property name="ant.enable.asserts" value="true"/>
  <target name="test2">
    <!-- should not stop 'sleep' task, should print out '_passed_' -->
    <stopwatch name="timer"/>
    <limit maxwait="5">
        <sleep seconds="1"/>
        <echo>_passed_</echo>
    </limit>
    <stopwatch name="timer" action="total"/>
    <assert message="Too much time.">
        <bool>
            <islessthan arg1="${timer}" arg2="2"/>
        </bool>
    </assert>
  </target>
]]>
</programlisting>
</para>

<para>
If the <computeroutput>ant.enable.asserts</computeroutput> property is set to false, then in the above example, the <computeroutput>echo</computeroutput>, <computeroutput>sleep</computeroutput>, and <computeroutput>echo</computeroutput> tasks will all execute.
</para>

</chapter>

<chapter id="IfTask">
@style@
    <title>If Task</title>

<section>
<title>If</title>
<para>
The If task provides a greatly improved "if" capability to Ant projects. This task works in a manner very similar to the Java <computeroutput>if</computeroutput> keyword. This is useful for performing certain tasks only if a property has a specific value or certain conditions are met.
</para>

<para>
This task can hold other tasks including the If task. In particular, it can also have a single "else", which gives Ant a Java-like if/else construct, and a single "bool", which can be used for the "if" boolean expression.
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
    <taskdef name="if" classname="ise.antelope.tasks.IfTask"/>
   ]]>
</programlisting>
</para>

<para>
An If task may contain only one 'bool' and one 'else' and may contain a 'break'. The 'bool' element is identical to the ConditionTask, but unlike the ConditionTask, is actually a Task. The 'bool' element can contain all the conditions permitted by the ConditionTask, plus the <link linkend="conditionals">IsPropertyTrue</link>, <link linkend="conditionals">IsPropertyFalse</link>,
<link linkend="conditionals">StartsWith</link>,
<link linkend="conditionals">EndsWith</link>,
<link linkend="conditionals">IsGreaterThan</link>,
<link linkend="conditionals">IsLessThan</link> and conditions.
</para>

<para>
Here is a general outline of the If task:
<programlisting>
<![CDATA[
<if>
    <bool>
        <some condition(s)/>
    </bool>

    some tasks...

    <!-- a break is allowed
    <break/>
    -->

    <else>
        some other tasks...

        <!-- a break is allowed
        <break/>
        -->
    </else>
</if>
]]>
</programlisting>
</para>

<para>

<table frame="all">
<title>If Task Attributes</title>
<tgroup cols="4">
<thead>

<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>name</entry>
<entry>The name of the property to test for.</entry>
<entry>none</entry>
<entry>Yes, unless nested bool is used.</entry>
</row>

<row>
<entry>exists</entry>
<entry>Test for existence or non-existence of the property.</entry>
<entry>True</entry>
<entry>No</entry>
</row>

<row>
<entry>value</entry>
<entry>The value to test for, implies 'exists=true'. If the value for the property in the project is the same as this value, embedded tasks will be executed.</entry>
<entry>none</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>

</para>

<para>
The If task can hold any number of Ant tasks. If the property value is correct or the "bool" element evaluates to true, these tasks will be executed.
</para>

<para>
In addition, the If task supports three special nested elements:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis role="bold">bool</emphasis> This is very similar to the standard Ant Condition task. All conditions supported by the Condition task are supported by the bool element. This is an optional element and if used, is used to decide if the "if" tasks or the "else" tasks should be executed. If the bool element is not used, then the "name" attribute must be used.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">else</emphasis> This is very similar to the standard Ant Sequential task. The "else" can hold any number of Ant tasks. These tasks are executed if the "bool" element evaluates to false.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">break</emphasis> This is very similar to the Java "break" keyword. This is only useful if the If task is nested in another task that understands "break", such as the <link linkend="switch">Switch</link> task. Like the Java "break", when this element is encountered, no subsequent tasks will be executed and control passes outside the If.
</para>
</listitem>
</itemizedlist>

<para>
In the following example, the <computeroutput>antcall</computeroutput> task will execute only if the project has a property named <computeroutput>test</computeroutput> with a value of <computeroutput>true</computeroutput>.
</para>

<para>
<programlisting>
   <![CDATA[
   <if name="test" value="true">
      <antcall target="doUnitTests"/>
   </if>
   ]]>
</programlisting>
</para>

<para>
In the next example, the <computeroutput>antcall</computeroutput> task will execute only if the project has a property named <computeroutput>test</computeroutput>. In this example, it does not matter what value is assigned to the <computeroutput>test</computeroutput> property.
</para>

<para>
<programlisting>
    <![CDATA[
   <if name="test">
      <antcall target="doUnitTests"/>
   </if>
   ]]>
</programlisting>
</para>

<para>
Of course, the same thing could have been done as follows, but the "if" is generally much cleaner.
<programlisting>
   <![CDATA[
   <antcall target="doUnitTests"/>
   <target name="doUnitTests" if="test">
      ...
   </target>
   ]]>
</programlisting>
</para>

<para>
In the next example, the <computeroutput>antcall</computeroutput> task will execute only if the project does not have a property named <computeroutput>test</computeroutput>. This is the opposite situation of the previous example.
</para>

<para>
<programlisting>
   <![CDATA[
   <if name="test" exists="false">
      <antcall target="doUnitTests"/>
   </if>
   ]]>
</programlisting>
</para>

<para>
The next example demonstrates nested 'if' tasks. This example will run the unit tests, and if it is Monday, will publish the accumulated test results.
</para>

<para>
<programlisting>
    <![CDATA[
   <tstamp>
      <format property="day" pattern="E" />
   </tstamp>
   <if name="test" value="true">
      <antcall target="doUnitTests"/>
      <if name="day" value="Mon">
         <antcall target="publishTestResults"/>
      </if>
   </if>
   ]]>
</programlisting>
</para>

<para>
The next example shows how to use If with Else. Notice that it doesn't matter where the Else is placed inside the If. All tasks in the If that are not in the Else will execute if the property value is correct, otherwise, only those tasks inside the else will execute. The "var" task is discussed <link linkend="Variable">here</link>.
</para>

<para>
<programlisting>
    <![CDATA[
    <var name="foo" value="bar"/>
    <if name="foo" value="bar">
        <echo>this will happen</echo>
        <else>
            <echo>this won't happen</echo>
        </else>
        <echo>this will happen also</echo>
    </if>

    <if name="foo" value="snarf">
        <echo>this won't happen</echo>
        <else>
            <echo>this 'else' will happen</echo>
            <echo>and so will this</echo>
        </else>
        <echo>this won't happen either</echo>
    </if>
    ]]>
</programlisting>
</para>

<para>
The next example shows the "if" and "assert" tasks working together to validate a property before use, and also shows an example of where the "assert" 'failonerror' attribute might be useful. In this example, if the e-mail address is invalid, the e-mail won't be sent and the build won't fail. The "try" task is discussed <link linkend="TryTask">here</link>.
</para>

<para>
<programlisting>
    <![CDATA[
   <if name="email_from" value="buildteam@mycompany.com">
      <property name="valid_email" value="true"/>
   </if>
   <if name="email_from" value="buildsite@mycompany.com">
      <property name="valid_email" value="true"/>
   </if>
   <assert name="valid_email" value="true" failonerror="false">
      <try>
          <mail from="${email_from}" tolist="${email_to}"
              message="New release available"/>
      </try>
   </assert>
   ]]>
</programlisting>
</para>

<para>
Here is the same thing, but using only If and Else:
</para>
<para>
<programlisting>
    <![CDATA[
   <try>
       <if name="email_from" value="buildteam@mycompany.com">
          <mail from="${email_from}" tolist="${email_to}"
              message="New release available"/>
          <else>
             <if name="email_from" value="buildsite@mycompany.com">
                 <mail from="${email_from}" tolist="${email_to}"
                      message="New release available"/>
             </if>
          </else>
       </if>
   </try>
   ]]>
</programlisting>
</para>

<para>
The next example shows how to use the "bool" element:
</para>

<para>
<programlisting>
    <![CDATA[
    <if>
        <!-- "if" evaluates this element -->
        <bool>
            <and>
                <available file="build.xml"/>
                <available file="run.xml"/>
            </and>
        </bool>

        <!-- if true, then tasks listed here will execute -->
        <echo>build.xml and run.xml are available</echo>

        <!-- if false, then tasks inside the "else" will execute -->
        <else>
            <echo>didn't find one or both of build.xml and run.xml</echo>
        </else>
    </if>
    ]]>
</programlisting>
</para>

<para>
The following example shows the "bool" element again:
</para>
<para>
<programlisting>
    <![CDATA[
    <if>
        <bool>
            <equals arg1="${download.dir}" arg2="test.dir"/>
        </bool>

        <fail message="Download and test directories cannot be
            the same! You need to reset to use the production
            property set."/>

        <else>
            <copy file="installer.zip" todir="${download.dir}"/>
        </else>
    </if>
    ]]>
</programlisting>
</para>

<para>
The following example is from the unit test for the "Limit" task. It shows the Stopwatch task, the Limit task, and the If task with boolean conditions:
</para>
<para>
<programlisting>
    <![CDATA[
  <target name="test2">
    <!-- should not stop 'sleep' task, should print out '_passed_' -->
    <stopwatch name="timer"/>
    <limit maxwait="5">
        <sleep seconds="1"/>
        <echo>_passed_</echo>
    </limit>
    <stopwatch name="timer" action="total"/>
    <if>
        <bool>
            <isgreaterthan arg1="${timer}" arg2="2"/>
        </bool>
        <fail message="Too much time"/>
    </if>
  </target>
    ]]>
</programlisting>
</para>


</section>

<section id="conditionals">
<title>More Conditions</title>

<para>
These conditions are suitable for use in the &lt;bool&gt; element. Unfortunately, they cannot be used in the &lt;condition&gt; task, although all conditions for the &lt;condition&gt; task can be used with the bool and the bool can be used anywhere that &lt;condition&gt; can be used.
</para>

<bridgehead renderas='sect3'>IfPropertyTrue</bridgehead>
<para>
Given a property name, tests whether the value for that property equals "true" (or "yes" or "on").
</para>

<para>
<table frame="all">
<title>IfPropertyTrue Attributes</title>
<tgroup cols="3">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>property</entry>
<entry>The name of a property to test the value of.</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
<programlisting>
<![CDATA[
<ispropertytrue property="myprop"/>
<ispropertytrue property="${someprop}"/>
]]>
</programlisting>
</para>



<bridgehead renderas='sect3'>IfPropertyFalse</bridgehead>
<para>
Given a property name, tests whether the value for that property equals "false" (or "no" or "off").
</para>
<para>
<table frame="all">
<title>IfPropertyFalse Attributes</title>
<tgroup cols="3">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>property</entry>
<entry>The name of a property to test the value of.</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
<programlisting>
<![CDATA[
<ispropertyfalse property="myprop"/>
<ispropertyfalse property="${someprop}"/>
]]>
</programlisting>
</para>

<bridgehead renderas='sect3'>StartsWith</bridgehead>
<para>
Given a property name, tests whether the value for that property starts with a specified string.
</para>
<para>
<table frame="all">
<title>StartsWith Attributes</title>
<tgroup cols="3">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>string</entry>
<entry>The string to test.</entry>
<entry>Yes</entry>
</row>
<row>
<entry>with</entry>
<entry>Check if 'string' starts with this value.</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
<programlisting>
<![CDATA[
<startswith string="abcdefg" with="abc"/>
<startswith string="${myprop}" with="foo"/>
]]>
</programlisting>
</para>
<bridgehead renderas='sect3'>EndsWith</bridgehead>
<para>
Given a property name, tests whether the value for that ends with with a specified string.
</para>
<para>
<table frame="all">
<title>EndsWith Attributes</title>
<tgroup cols="3">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>string</entry>
<entry>The string to test.</entry>
<entry>Yes</entry>
</row>
<row>
<entry>with</entry>
<entry>Check if 'string' ends with this value.</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
<programlisting>
<![CDATA[
<endswith string="abcdefg" with="efg"/>
<endswith string="${myprop}" with="bar"/>
]]>
</programlisting>
</para>

<bridgehead renderas='sect3'>IsGreaterThan</bridgehead>
<para>
Tests whether the first argument is greater than the second argument. Will
automatically treat the arguments as numbers if both arguments consists of only the characters 0 through 9 and optionally a decimal point. Otherwise, a String
comparison is used.
</para>
<para>
<table frame="all">
<title>IsGreaterThan Attributes</title>
<tgroup cols="3">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>arg1</entry>
<entry>The first argument.</entry>
<entry>Yes</entry>
</row>
<row>
<entry>arg2</entry>
<entry>The second argument.</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
<programlisting>
<![CDATA[
<!-- evaluates to true -->
<isgreaterthan arg1="6.02" arg2="4"/>

<!-- evaluates to false -->
<isgreaterthan arg1="bar" arg2="foo"/>
]]>
</programlisting>
</para>


<bridgehead renderas='sect3'>IsLessThan</bridgehead>
<para>
Tests whether the first argument is less than the second argument. Will
automatically treat the arguments as numbers if both arguments consists of only the characters 0 through 9 and optionally a decimal point. Otherwise, a String
comparison is used.
</para>
<para>
<table frame="all">
<title>IsLessThan Attributes</title>
<tgroup cols="3">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>arg1</entry>
<entry>The first argument.</entry>
<entry>Yes</entry>
</row>
<row>
<entry>arg2</entry>
<entry>The second argument.</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
<programlisting>
<![CDATA[
<!-- evaluates to false -->
<islessthan arg1="6.02" arg2="4"/>

<!-- evaluates to true -->
<islessthan arg1="bar" arg2="foo"/>
]]>
</programlisting>
</para>

<bridgehead renderas='sect3'>DateBefore, TimeBefore </bridgehead>
<para>
Tests whether the first date/time is before the second date/time.
</para>
<para>
<table frame="all">
<title>DateBefore, TimeBefore</title>
<tgroup cols="3">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>datetime1</entry>
<entry>The first date/time.</entry>
<entry>Yes</entry>
</row>
<row>
<entry>datetime2</entry>
<entry>The second date/time.</entry>
<entry>Yes</entry>
</row>
<row>
<entry>format</entry>
<entry>The format of the date/time stamps.</entry>
<entry>Yes</entry>
</row>
<row>
<entry>lenient</entry>
<entry>Whether the datetime parser should use lenient parsing, defaults to true.</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
<programlisting>
<![CDATA[
   <target name="test1">
      <a:assert>
         <bool>
            <not>
            <datebefore datetime1="2005-09-09 14:58:36" datetime2="2005-07-11 14:58:36" format="yyyy-MM-dd HH:mm:ss"/>
            </not>
         </bool>
      </a:assert>
   </target>

   <target name="test2">
      <a:assert>
         <bool>
            <not>
            <timebefore datetime1="22:58:36" datetime2="10:58:36" format="HH:mm:ss"/>
            </not>
         </bool>
      </a:assert>
   </target>

   <target name="test3">
      <a:assert>
         <bool>
            <timebefore datetime1="2005" datetime2="2030" format="yyyy"/>
         </bool>
      </a:assert>
   </target>

   <target name="test4">
      <a:assert>
         <bool>
            <timebefore datetime1="01:00:00" datetime2="03:00:00" format="hh:mm:ss"/>
         </bool>
      </a:assert>
   </target>
]]>
</programlisting>
</para>


<bridgehead renderas='sect3'>DateDifference, TimeDifference </bridgehead>
<para>
Tests that the difference between two dates or times is a certain value.
</para>
<para>
<table frame="all">
<title>DateDifference, TimeDifference</title>
<tgroup cols="3">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>datetime1</entry>
<entry>The first date/time.</entry>
<entry>Yes</entry>
</row>
<row>
<entry>datetime2</entry>
<entry>The second date/time.</entry>
<entry>Yes</entry>
</row>
<row>
<entry>format</entry>
<entry>The format of the date/time stamps.</entry>
<entry>Yes</entry>
</row>
<row>
<entry>lenient</entry>
<entry>Whether the datetime parser should use lenient parsing, defaults to true.</entry>
<entry>No</entry>
</row>
<row>
<entry>value</entry>
<entry>The expected difference between the 2 datetimes.</entry>
<entry>No, default is 0</entry>
</row>
<row>
<entry>unit</entry>
<entry>Sets the unit for the difference between the 2 datetimes.  For example,
if value is 12 and unit is "hours", then this
condition checks that the difference between the 2 datetimes is 12 hours.
Valid values are "millisecond", "second", "minute", "hour", "day", "week", "month", "year".</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
<programlisting>
<![CDATA[
   <target name="test1">
      <a:assert message="Difference between dates is not 60 days.">
         <bool>
            <datedifference datetime1="2005-09-09 14:58:36" datetime2="2005-07-11 14:58:36" format="yyyy-MM-dd HH:mm:ss" value="60" unit="day"/>
         </bool>
      </a:assert>
   </target>

   <target name="test2">
      <a:assert message="Difference between hours is not 12.">
         <bool>
            <timedifference datetime1="22:58:36" datetime2="10:58:36" format="HH:mm:ss" value="12" unit="hour"/>
         </bool>
      </a:assert>
   </target>

   <target name="test3">
      <a:assert message="Difference between years is not 25.">
         <bool>
            <timedifference datetime1="2005" datetime2="2030" format="yyyy" value="25" unit="year"/>
         </bool>
      </a:assert>
   </target>

   <target name="test4">
      <a:assert message="Difference between minutes is not 120.">
         <bool>
            <timedifference datetime1="01:00:00" datetime2="03:00:00" format="hh:mm:ss" value="120" unit="minute"/>
         </bool>
      </a:assert>
   </target>

   <target name="test5">
      <a:assert message="Difference between seconds is not 7200.">
         <bool>
            <timedifference datetime1="01:00:00" datetime2="03:00:00" format="hh:mm:ss" value="7200" unit="second"/>
         </bool>
      </a:assert>
   </target>
]]>
</programlisting>
</para>


</section>

</chapter>

<chapter id="switch">
@style@
    <title>SwitchTask</title>
<para>
The "Switch" task works much like the Java "switch" construct. It supports nested "case" elements, which in turn, support nested "break" elements. There is also a "default" case element, so this should be very natural for Java developers to use.
</para>

<para>
<table frame="all">
<title>Switch Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>name</entry>
<entry>The name of a property whose value will be used for the switch.</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>
<para>
<table frame="all">
<title>"case" and "default" Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>value</entry>
<entry>The value of of the property used for the switch. If this value equals the property value, then all tasks in this 'case' will be executed.</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
<programlisting>
<![CDATA[
<property name="foo" value="bar"/>
<switch name="foo">
    <case value="baz">
        <echo>Executing case baz</echo>
        <break/>
    </case>
    <case value="bar">
        <echo>Executing case bar</echo>
        <if name="foo" value="bar">
            <echo>breaking from the if</echo>
            <break/>
        </if>
        <echo>Falling through to case "bat"</echo>
    </case>
    <case value="bat">
        <echo>Executing case bat</echo>
        <break/>
    </case>
    <default>
        <echo>Executing default case</echo>
        <break/>
    </default>
</switch>
]]>
</programlisting>
</para>

</chapter>

<chapter id="TryTask">
@style@
    <title>Try Task</title>

<para>
The "Try" task works similarly to the try/catch/finally construct in Java. This task is useful when a particular task might fail, but the build should not fail if it does. An example is the "mail" task will fail if the mail server is not available, but the build should not fail if the mail message cannot be delivered.
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
<taskdef name="try" classname="ise.antelope.tasks.TryTask"/>
]]>
</programlisting>
</para>

<para>
A quick example is probably all that is necessary:
<programlisting>
<![CDATA[
 <tempfile property="temp.file" destdir="${java.io.tmpdir}"
     prefix="delete" suffix=".tmp"/>
 <try>
     <!-- use 'get' task to post to the unit test status servlet. It
         would be better to use a post for this, but this shows a good
         use of 'finally'. -->
     <get
         src="http://mycompany.com/servlet/junit?testnum=${test.num}&status="${status}"
         dest="${temp.file}"/>

     <catch>
         <echo>Unit test servlet update failed.</echo>
     </catch>

     <finally>
         <delete file="${temp.file}"/>
     </finally>
 </try>
]]>
</programlisting>
</para>

<para>
Unlike the Java "try", neither the "catch" block nor the "finally" block are required. Also, the order does not matter, the "catch" block may be listed first, followed by the "finally", followed by the tasks that may fail.
</para>

<para>
<table frame="all">
<title>Try Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>break</entry>
<entry>If true and a nested task fails, no other nested tasks will execute. If false, all nested tasks will execute regardless of whether a previous task failed. Note that for each failed task, the 'catch' block (if defined) will execute.</entry>
<entry>true</entry>
<entry>No</entry>
</row>

<row>
<entry>printstacktrace</entry>
<entry>If true, the exception stack trace from a failed task will be logged. </entry>
<entry>false</entry>
<entry>No</entry>
</row>

<row>
<entry>stacktraceproperty</entry>
<entry>Specify a property to store the stack trace of any exception. </entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>printmessage</entry>
<entry>If true, the exception message from a failed task will be logged. If printstacktrace is set to true, this attribute is ignored as the exception message is printed as part of the stack trace.</entry>
<entry>true</entry>
<entry>No</entry>
</row>

<row>
<entry>messageproperty</entry>
<entry>Specify a property to store the message line of any exception.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
The next example shows the "break" attribute set to "no". In this case, the second echo task will execute.
</para>

<para>
<programlisting>
<![CDATA[
    <target name="test" description="This exercises the Try task.">
        <try break="no">
            <echo>I am trying...</echo>
            <fail message=" and I failed..."/>
            <echo> but I did not die!</echo> <!-- this WILL print -->
        </try>
    </target>
   ]]>
</programlisting>
</para>

<para>
This slightly more practical example uses the <link linkend="Variable">Variable</link> task coupled with "try" to run a series of tests. All tests will run even if a preceding test fails. The "catch" block logs a message of each failed test.
</para>

<para>
<programlisting>
<![CDATA[
    <target name="runTests" messageproperty="msg">
        <try catch="testFailed" break="no">
            <var name="testname" value="fileUtilTests"/>
            <antcall target="runFileUtilTests"/>
            <var name="testname" value="imageUtilTests"/>
            <antcall target="runImageUtilTests"/>
            <var name="testname" value="imageConversionTests"/>
            <antcall target="runImageConversionTests"/>

            <catch>
              <!-- log a test failure -->
              <echo file="test.log" append="yes">
                  Test suite ${testname} failed: ${msg}
              </echo>
            </catch>
        </try>
    </target>
    </target>
   ]]>
</programlisting>
</para>

<para>
The following example uses a nested Finally to clean up resources:
<programlisting>
<![CDATA[
    <tempfile property="temp.file" destdir="${java.io.tmpdir}"
        prefix="delete" suffix=".tmp"/>
    <try>
        <!-- use 'get' task to post to the unit test status servlet. It
            would be better use use a post for this, but this shows a good
            use of 'finally'. -->
        <get
            src="http://mycompany.com/servlet/junit?testnum=${test.num}&status="${status}"
            dest="${temp.file}"/>

        <catch>
            <echo>Unit test servlet update failed.</echo>
        </catch>

        <finally>
            <delete file="${temp.file}"/>
        </finally>
    </try>
]]>
</programlisting>
See the <link linkend="post">post</link> task for a better way to do a post.
</para>

</chapter>

<chapter id="Unset">
@style@
    <title>Unset Task</title>

<para>
The Unset task provides easier access to one of the most used use cases of <link linkend="Variable">Variable</link>, the ability to unset a property.  By design, Ant properties are immutable, but sometimes it is handy to set a property to a new value.
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
    <taskdef name="unset" classname="ise.antelope.tasks.Unset"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>Unset Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>name</entry>
<entry>The name of the property to unset.</entry>
<entry>None</entry>
<entry>Yes, unless 'file' is used.</entry>
</row>

<row>
<entry>file</entry>
<entry>The name of a property file.  All properties references in the file will be unset.  This means you can load a bunch of properties from a file, then unset them all with a single line.</entry>
<entry>None</entry>
<entry>Yes, unless 'name' is used.</entry>
</row>

</tbody>
</tgroup>
</table>
</para>
<para>
Example:
<programlisting>
<![CDATA[
<project name="unset_example" basedir=".">
    <taskdef resource="ise/antelope/tasks/antlib.xml"/>
    <property name="x" value="6"/>
    <echo>original value = ${x}</echo>
    <unset name="x"/>
    <echo>unset: ${x}</echo>
    <property name="x" value="hello"/>
    <echo>new value = ${x}</echo>
</project>

$ ant -f unset_example.xml
Buildfile: unset_example.xml
     [echo] original value = 6
     [echo] unset: ${x}
     [echo] new value = hello

BUILD SUCCESSFUL
Total time: 0 seconds
]]>
</programlisting>
</para>
</chapter>

<chapter id="Variable">
@style@
    <title>Variable Task</title>

<para>
The Variable task provides a mutable property to Ant and works much like variable assignment in Java. This task is similar to the standard Ant Property task, except that THESE PROPERTIES ARE MUTABLE. While this goes against the standard Ant use of properties, occasionally it is useful to be able to change a property value within the build. <emphasis role="bold">In general, use of this task is DISCOURAGED, and the standard Ant Property should be used if possible.</emphasis> Having said that, in real life I use this a lot.
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
    <taskdef name="var" classname="ise.antelope.tasks.Variable"/>
   ]]>
</programlisting>
</para>

<para>
Variables can be set individually or loaded from a standard properties file. A 'feature' of variables is that they can override properties, but properties cannot override variables. So if an already established property exists, its value can be reassigned by use of this task.
</para>

<para>
<table frame="all">
<title>Variable Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>name</entry>
<entry>The name of the property to set.</entry>
<entry>None</entry>
<entry>Yes, unless 'file' is used.</entry>
</row>

<row>
<entry>value</entry>
<entry>The value of the property.</entry>
<entry>""</entry>
<entry>No</entry>
</row>

<row>
<entry>file</entry>
<entry>The name of a standard properties file to load variables from.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
In the following example, the property <computeroutput>x</computeroutput> is first set to "6", then evaluated by the <computeroutput>if</computeroutput>, and reassigned the value "12". The <computeroutput>echo</computeroutput> task will print out 12.
</para>

<para>
<programlisting>
<![CDATA[
    <var name="x" value="6"/>
    <if name="x" value="6">
        <var name="x" value="12"/>
    </if>
    <echo>${x}</echo>   <!-- will print 12 -->
]]>
</programlisting>
</para>

<para>
The following shows some more uses of the Variable task. It is especially handy for property appending. Notice a couple of things: the property task can't override a var value, however, if the var value is set to "", then it can as in the case of the format example.
</para>

<para>
<programlisting>
<![CDATA[
    <var name="x" value="6"/>
    <echo>x = ${x}</echo>   <!-- print: 6 -->

    <var name="x" value="12"/>
    <echo>x = ${x}</echo>   <!-- print: 12 -->

    <var name="x" value="6 + ${x}"/>
    <echo>x = ${x}</echo>   <!-- print: 6 + 12 -->

    <var name="str" value="I "/>
    <var name="str" value="${str} am "/>
    <var name="str" value="${str} a "/>
    <var name="str" value="${str} string."/>
    <echo>${str}</echo>     <!-- print: I am a string. -->

    <var name="x" value="6"/>
    <echo>x = ${x}</echo>   <!-- print: 6 -->

    <property name="x" value="12"/>
    <echo>x = ${x}</echo>   <!-- print: 6 (property can't override) -->

    <var name="x" value="blue"/>
    <tstamp>
        <format property="x" pattern="EEEE"/>
    </tstamp>
    <echo>Today is ${x}.</echo> <!-- print: Today is blue. -->

    <var name="x" value=""/>
    <tstamp>
        <format property="x" pattern="EEEE"/>
    </tstamp>
    <echo>Today is ${x}.</echo> <!-- print: Today is Friday. -->

]]>
</programlisting>
</para>

<para>
The next example shows Variable, If, Assert, and Try working together to make sure e-mail is sent from the right address and that if the mail fails to be sent for any reason, the build will not fail.
</para>
<para>
<programlisting>
    <![CDATA[
   <var name="valid_email" value="false"/>
   <if name="email_from" value="buildteam@mycompany.com">
      <var name="valid_email" value="true"/>
   </if>
   <if name="email_from" value="buildsite@mycompany.com">
      <var name="valid_email" value="true"/>
   </if>
   <assert name="valid_email" value="true" failonerror="false">
      <try>
         <mail from="${email_from}" tolist="${email_to}"
            message="New release available"/>
      </try>
   </assert>
   ]]>
</programlisting>
</para>
</chapter>

<chapter id="stopwatch">
@style@
    <title>Stopwatch</title>
<para>
The Stopwatch task makes it easy to add performance timing to Ant targets. Stopwatches are named so that multiple watches can run simultaneously.
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
    <taskdef name="stopwatch" classname="ise.antelope.tasks.StopWatchTask"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>Stopwatch Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>name</entry>
<entry>The name for the stopwatch. The elapsed time or total time will be stored as an Ant property with this name.</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>

<row>
<entry>action</entry>
<entry>Valid values are "start", "stop", "elapsed", and "total".</entry>
<entry>"start"</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
The stopwatch is started with the "start" action. When the action is "elapsed" or "total", the running time of the stopwatch is printed out. Both "stop" and "total" stop the stopwatch and reset it to zero. "elapsed" prints out the current running time of the stopwatch without stopping it.
</para>

<para>
Example:
<programlisting>
<![CDATA[
<stopwatch name="timer1"/>
<!-- do some tasks here... -->
<stopwatch name="timer1" action="elapsed"/> <!-- print the elapsed time -->
<!-- do some more tasks here... -->
<stopwatch name="timer1" action="total"/> <!-- print out the total time -->
]]>
</programlisting>
</para>

</chapter>


<chapter id="Limit">
@style@
   <title>Limit</title>

<para>
The Limit task is a task container (that is, it holds other tasks) and sets a time limit on how long the nested tasks are allowed to run. This is useful for unit tests that go awry, hung socket connections, or other potentially long running tasks that need to be shut off without stopping the build.
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
    <taskdef name="limit" classname="ise.antelope.tasks.Limit"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>Limit Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>maxwait</entry>
<entry>How long to wait for nested tasks to finish, this is in seconds.</entry>
<entry>180 seconds (3 minutes)</entry>
<entry>No</entry>
</row>

<row>
<entry>failonerror</entry>
<entry>Should the build fail if the time limit has been exceeded?</entry>
<entry>false</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
Examples:
</para>

<para>
Neither the echo nor the fail will happen in this example. The build will continue once the time has expired.
<programlisting>
<![CDATA[
<limit maxwait="3">
   <sleep seconds="10"/>
   <echo>This won't happen...</echo>
   <fail>This won't happen either...</fail>
</limit>
]]>
</programlisting>
</para>

<para>
Neither the echo nor the fail will happen in this example. The build will not continue once the time has expired.
<programlisting>
<![CDATA[
<limit maxwait="3" failonerror="true">
   <sleep seconds="10"/>
   <echo>This won't happen...</echo>
   <fail>This won't happen either...</fail>
</limit>
]]>
</programlisting>
</para>
</chapter>


<chapter id="FileUtils">
@style@
   <title>FileUtils</title>

<para>
The FileUtils task provides a number of useful file information functions, such as readability, writability, length, etc.  <emphasis role="bold">Caution: this task does not follow the standard Ant convention of property immutability.</emphasis>
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
    <taskdef name="fileutil" classname="ise.antelope.tasks.FileUtilTask"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>FileUtil Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>file</entry>
<entry>The file or directory in question.</entry>
<entry>None</entry>
<entry>No, but does nothing without a file.</entry>
</row>

<row>
<entry>property</entry>
<entry>Where to store the answer. Caution: this task will overwrite any existing property with this name.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
Operations as nested elements:
</para>

<para>
<emphasis role="bold">listfiles</emphasis> Create a list of files and/or directories.
<table frame="all">
<title>listfiles</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>what</entry>
<entry>What to list, valid values are "files", "dirs", or "all".</entry>
<entry>files</entry>
<entry>No</entry>
</row>

<row>
<entry>separator</entry>
<entry>The separator to use between individual items in the list of files.</entry>
<entry>, (comma)</entry>
<entry>No</entry>
</row>

<row>
<entry>includepath</entry>
<entry>If true, include the path with the names in the list.  If false, include only the names.</entry>
<entry>true</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
<emphasis role="bold">lastmodified</emphasis> Get the "last modified" date/timestamp of a file.

<table frame="all">
<title>lastmodified</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>format</entry>
<entry>A format for the last modified timestamp.  Must comply with the standards listed in java.text.SimpleDateFormat.</entry>
<entry></entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>

</para>

<para>
These operations have no attributes:
<itemizedlist>
<listitem>
<para>
<emphasis role="bold">canread</emphasis> Is the file readable?
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">canwrite</emphasis> Is the file writable?
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">length</emphasis> Finds the length of the file.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">filecount</emphasis> Find the number of files in the directory.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">isdirectory</emphasis> Is the file a directory?
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">isfile</emphasis> Is the file a file?
</para>
</listitem>
</itemizedlist>

</para>

<para>
Only one of the operations can be used at once.
</para>

<para>
Examples: See the <link linkend="Split">Split</link> for several examples.
</para>



</chapter>

<chapter id="StringUtils">
@style@
   <title>StringUtils</title>

<para>
The StringUtils task provides a number of useful string manipulation functions, such as converting a string to upper or lower case, trimming white space, finding a substring, etc. <emphasis role="bold">Caution: this task does not follow the standard Ant convention of property immutability.</emphasis>
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
    <taskdef name="stringutil" classname="ise.antelope.tasks.StringUtilTask"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>StringUtil Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>string</entry>
<entry>The string to manipulate.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>property</entry>
<entry>Where to store the manipulated string. Caution: this task will overwrite any existing property with this name.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
Operations as nested elements:
</para>

<para>
<table frame="all">
<title>indexof, lastindexof: Find the index of or the last index of a substring.</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>string</entry>
<entry>The string to find the index of.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>fromindex</entry>
<entry>Where to start looking.</entry>
<entry>0</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>


<table frame="all">
<title>substring: Get a substring from the string.</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>beginindex</entry>
<entry>Start of substring.</entry>
<entry>0</entry>
<entry>No</entry>
</row>

<row>
<entry>endindex</entry>
<entry>End of substring.</entry>
<entry>End of string.</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>


<table frame="all">
<title>replace: Replace parts of the string.</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>regex</entry>
<entry>Pattern to replace.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>replacement</entry>
<entry>What to replace with.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>

<table frame="all">
<title>sort: Sort items in a string.</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>separator</entry>
<entry>The character separating individual items in the string.</entry>
<entry>Any of tab, new line, carriage return, line feed, or space.</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
This is useful for sorting a comma separated list or a property value that spans several lines.

</para>

<para>
<table frame="all">
<title>messagebox: Put the string in a box for nice display.</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>title</entry>
<entry>Title for the message box.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>width</entry>
<entry>
Maximum width in characters for the message box. Lines
will be wrapped to fit inside the box.  The box will not
stretch to this width if the message is less than
width - 4 characters wide.
</entry>
<entry>60</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>


<para>
These operations have no attributes:
<itemizedlist>
<listitem>
<para>
<emphasis role="bold">lowercase</emphasis> Converts the string to lowercase.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">uppercase</emphasis> Converts the string to uppercase.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">length</emphasis> Finds the length of the string.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">trim</emphasis> Removes white space from boths ends of the string.
</para>
</listitem>
</itemizedlist>

</para>

<para>
More than one of the operations can be used at once, that is, you can convert a string to lowercase and trim it at the same time.  See below for examples.
</para>

<para>
Examples:
</para>

<para>
Convert a string to lower case:
<programlisting>
<![CDATA[
   <target name="test1">
      <property name="prop1" value="ABCDE"/>
      <echo>prop1 before = ${prop1}</echo>
      <a:stringutil string="${prop1}" property="prop1">
         <a:lowercase/>
      </a:stringutil>
      <echo>prop1 after = ${prop1}</echo>
      <a:assert message="prop1, expected abcde, got ${prop1}">
         <bool>
            <equals arg1="abcde" arg2="${prop1}"/>
         </bool>
      </a:assert>
   </target>
]]>
</programlisting>
</para>

<para>
Convert a string to upper case:
<programlisting>
<![CDATA[
   <target name="test2">
      <property name="prop2" value="abcdefgh"/>
      <echo>prop2 before = ${prop2}</echo>
      <a:stringutil string="${prop2}" property="prop2">
         <a:uppercase/>
      </a:stringutil>
      <echo>prop2 after = ${prop2}</echo>
      <a:assert message="prop2, expected ABCDEFGH, got ${prop2}">
         <bool>
            <equals arg1="ABCDEFGH" arg2="${prop2}"/>
         </bool>
      </a:assert>
   </target>
]]>
</programlisting>
</para>

<para>
Convert a string to upper case and trim white space:
<programlisting>
<![CDATA[
   <target name="test3">
      <property name="prop3" value=" abcdefgh "/>
      <echo>prop3 before = ${prop3}</echo>
      <a:stringutil string="${prop3}" property="prop3">
         <a:uppercase/>
         <a:trim/>
      </a:stringutil>
      <echo>prop3 after = ${prop3}</echo>
      <a:assert message="prop3, expected ABCDEFGH, got ${prop3}">
         <bool>
            <equals arg1="ABCDEFGH" arg2="${prop3}"/>
         </bool>
      </a:assert>
   </target>
]]>
</programlisting>
</para>

<para>
Convert a string to upper case, trim white space, and find a substring:
<programlisting>
<![CDATA[
   <target name="test4">
      <property name="prop4" value=" abcdefgh "/>
      <echo>prop4 before = ${prop4}</echo>
      <a:stringutil string="${prop4}" property="prop4">
         <a:uppercase/>
         <a:trim/>
         <a:substring beginindex="3"/>
      </a:stringutil>
      <echo>prop4 after = ${prop4}</echo>
      <a:assert message="prop4, expected DEFGH, got ${prop4}">
         <bool>
            <equals arg1="DEFGH" arg2="${prop4}"/>
         </bool>
      </a:assert>
   </target>
]]>
</programlisting>
</para>

<para>
Get the length of a string:
<programlisting>
<![CDATA[
   <target name="test7">
      <property name="prop7" value="abcdefgh"/>
      <echo>prop7 before = ${prop7}</echo>
      <a:stringutil string="${prop7}" property="prop7">
         <a:length/>
      </a:stringutil>
      <echo>prop7 length = ${prop7}</echo>
      <a:assert message="prop7, expected 8, got ${prop7}">
         <bool>
            <mathequals arg1="8" arg2="${prop7}"/>
         </bool>
      </a:assert>
   </target>
]]>
</programlisting>
</para>

<para>
Sort a list:
<programlisting>
<![CDATA[
   <target name="test12">
      <property name="prop12" value="a,b,c,d,e,f,g,h,a,b,c,d,e,f,g,h"/>
      <echo>prop12 before = ${prop12}</echo>
      <a:stringutil string="${prop12}" property="prop12">
         <a:sort separator=","/>
      </a:stringutil>
      <echo>prop12 sorted = ${prop12}</echo>
      <a:assert message="prop12, expected 'a,a,b,b,c,c,d,d,e,e,f,f,g,g,h,h', got ${prop12}">
         <bool>
            <equals arg1="a,a,b,b,c,c,d,d,e,e,f,f,g,g,h,h" arg2="${prop12}"/>
         </bool>
      </a:assert>
   </target>
]]>
</programlisting>
</para>

<para>
Message boxes:
<programlisting>
<![CDATA[
   <target name="test13">
      <property name="prop13" value="Character boundary analysis allows users to interact with characters as they expect to, for example, when moving the cursor around through a text string. Character boundary analysis provides correct navigation of through character strings, regardless of how the character is stored. For example, an accented character might be stored as a base character and a diacritical mark. What users consider to be a character can differ between languages."/>
      <echo>prop13 before = ${prop13}</echo>
      <a:stringutil string="${prop13}" property="prop13">
         <a:messagebox/>
      </a:stringutil>
      <echo>prop13 in messagebox:${line.separator}${prop13}</echo>

      <property name="prop13a" value="Character boundary analysis allows users to interact with characters as they expect to, for example, when moving the cursor around through a text string. Character boundary analysis provides correct navigation of through character strings, regardless of how the character is stored. For example, an accented character might be stored as a base character and a diacritical mark. What users consider to be a character can differ between languages."/>
      <a:stringutil string="${prop13a}" property="prop13a">
         <a:messagebox title="About Character Boundaries"/>
      </a:stringutil>
      <echo>prop13a in messagebox with title:${line.separator}${prop13a}</echo>

   </target>

test13:
     [echo] prop13 before = Character boundary analysis allows users to interact with characters as they expect to, for
example, when moving the cursor around through a text string. Character boundary analysis provides correct navigation of
 through character strings, regardless of how the character is stored. For example, an accented character might be store
d as a base character and a diacritical mark. What users consider to be a character can differ between languages.
     [echo] prop13 in messagebox:
     [echo]
     [echo] +----------------------------------------------------------------------+
     [echo] | Character boundary analysis allows users to interact with characters |
     [echo] | as they expect to, for example, when moving the cursor around        |
     [echo] | through a text string. Character boundary analysis provides correct  |
     [echo] | navigation of through character strings, regardless of how the       |
     [echo] | character is stored. For example, an accented character might        |
     [echo] | be stored as a base character and a diacritical mark. What users     |
     [echo] | consider to be a character can differ between languages.             |
     [echo] +----------------------------------------------------------------------+
     [echo] prop13a in messagebox with title:
     [echo]
     [echo] +----------------------------------------------------------------------+
     [echo] | About Character Boundaries                                           |
     [echo] +----------------------------------------------------------------------+
     [echo] | Character boundary analysis allows users to interact with characters |
     [echo] | as they expect to, for example, when moving the cursor around        |
     [echo] | through a text string. Character boundary analysis provides correct  |
     [echo] | navigation of through character strings, regardless of how the       |
     [echo] | character is stored. For example, an accented character might        |
     [echo] | be stored as a base character and a diacritical mark. What users     |
     [echo] | consider to be a character can differ between languages.             |
     [echo] +----------------------------------------------------------------------+
[antlib:ise.antelope.tasks:testcase] test13 passed.
]]>
</programlisting>
</para>


</chapter>




<chapter id="UID">
@style@
   <title>UID</title>

<para>
The UID task generates a unique ID.  This ID may be either a unique string or integer.
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
    <taskdef name="uid" classname="ise.antelope.tasks.UIDTask"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>UID Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>name</entry>
<entry>Name of a property to store the unique ID.</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>

<row>
<entry>int</entry>
<entry>If true, generate a unique integer.</entry>
<entry>false</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
Examples:
</para>

<para>
<programlisting>
<![CDATA[
<uid name="uid_1"/>
<echo>uid_1 = ${uid_1}</echo>
<uid name="uid_2" int="yes"/>
<echo>uid_2 = ${uid_2}</echo>


     [echo] uid_1 = -4a1a8b86:10728498757:-7fff
     [echo] uid_2 = 2
]]>
</programlisting>
</para>

</chapter>





<chapter id="math">
@style@
    <title>Math</title>

<para>
The Math task provides support for all the basic mathematical operations
provided by the java.lang.Math and java.lang.StrictMath classed. It supports int, long, float and double data types. Nesting of operations is supported to allow computation of formulas like (6 + (7.25 * 3.9))/(2 * 3 * 3) or calculating the area of a circle given a radius (I'm sure this comes up often in builds controlled by Ant!).
</para>

<para>
In addition to the operations provided by the java.lang.Math and java.lang.StrictMath classes, the Math task provides several additional operations: "add", "subtract", "multiply", "divide", and "mod", which duplicate the basic Java mathematical operations "+", "-", "*", "/", and "%", respectively. In fact, either notation can be used, that is, the operation can be set to "add" or "+", depending only on which you feel is more convenient.
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
    <taskdef name="math" classname="ise.antelope.tasks.MathTask"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>Math Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>result</entry>
<entry>The name of the property to hold the result of the operation.</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>

<row>
<entry>datatype</entry>
<entry>Sets the datatype of the calculation. Allowed values are
"int", "long", "float", or "double". Optional, if
used, will be applied to all numbers in this math operation.</entry>
<entry>double</entry>
<entry>No</entry>
</row>

<row>
<entry>strict</entry>
<entry>If true, use the methods in the java.lang.StrictMath class.</entry>
<entry>false</entry>
<entry>No</entry>
</row>

<row>
<entry>operation</entry>
<entry>If used, any nested Ops will be ignored. This is for convenience for simple calculations.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>operand1</entry>
<entry>A number to use with the operation specified in the 'operation' attribute.</entry>
<entry>None</entry>
<entry>Depends on the specific operation.</entry>
</row>

<row>
<entry>operand2</entry>
<entry>A number to use with the operation specified in the 'operation' attribute.</entry>
<entry>None</entry>
<entry>Depends on the specific operation.</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
The 'result' property is reusable.
</para>

The Math task supports nested "Op" elements. An Op element represents single mathematical operation, such as "min" or "add".

<para>
<table frame="all">
<title>Op Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>op</entry>
<entry>Set the name of this operation. Allowed values are
one of the method names from java.lang.Math or java.lang.StrictMath, or one of "add", "subtract", "multiply", "divide", or "mod" (or "+", "-", "*", "/", or "%", respectively)</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>

<row>
<entry>datatype</entry>
<entry>Sets the datatype of this calculation. Allowed values are
"int", "long", "float", or "double". Optional, default
is "double". If the parent Math task has a datatype set, this value will be ignored and the datatype specifed in the task will be used.</entry>
<entry>"int"</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
The Op element supports nested "Op" elements and nested "Num" elements. A Num represents a number. When an Op is nested in another Op, the nested Op is treated as a Num. The nested elements can be any combination of Op or Num as appropriate for the formula being calculated. Most of the operations provided by java.lang.Math and java.lang.StrictMath operate on one or two numbers. The "+", "-", "*", "/", and "%" operations can task any number of nested numbers.
</para>

<para>
<table frame="all">
<title>Num Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>value</entry>
<entry>Set the value for this number. Must be able to parse to the datatype set by the parent element or the default datatype set by the task. Two special numbers, pi and e, can be represented by PI and E respectively. ("PI" is the ratio of the diameter of a circle to its radius, "E" is Euler's e, the base for natural logrithms.)</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>

<row>
<entry>datatype</entry>
<entry>Sets the datatype of this number. Allowed values are
"int", "long", "float", or "double". Optional, default
is "double". If the parent Math task has a datatype set, this value will be ignored and the datatype specifed in the task will be used.</entry>
<entry>double</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
Some examples:
</para>

<para>
<programlisting>
<![CDATA[
    <var name="op1" value="12"/>
    <var name="op2" value="6"/>
    <var name="op" value="+"/>

    <!-- demo plus -->
    <math result="result" operand1="${op1}" operation="${op}" operand2="${op2}" datatype="int"/>
    <echo>${op1} ${op} ${op2} = ${result}</echo>
    <assert name="result" value="18"/>

    <!-- demo reusing result -->
    <math result="result" operand1="${result}" operation="${op}" operand2="${op2}" datatype="int"/>
    <echo>${op1} ${op} ${op2} = ${result}</echo>
    <assert name="result" value="24"/>

    <!-- demo minus -->
    <var name="op" value="-"/>
    <math result="result" operand1="${op1}" operation="${op}" operand2="${op2}" datatype="int"/>
    <echo>${op1} ${op} ${op2} = ${result}</echo>
    <assert name="result" value="6"/>

    <!-- demo multiply -->
    <var name="op" value="*"/>
    <math result="result" operand1="${op1}" operation="${op}" operand2="${op2}" datatype="int"/>
    <echo>${op1} ${op} ${op2} = ${result}</echo>
    <assert name="result" value="72"/>

    <!-- demo divide -->
    <var name="op" value="/"/>
    <math result="result" operand1="${op1}" operation="${op}" operand2="${op2}" datatype="int"/>
    <echo>${op1} ${op} ${op2} = ${result}</echo>
    <assert name="result" value="2"/>

    <!-- demo modulo -->
    <var name="op" value="%"/>
    <math result="result" operand1="${op1}" operation="${op}" operand2="${op2}" datatype="int"/>
    <echo>${op1} ${op} ${op2} = ${result}</echo>
    <assert name="result" value="0"/>

    <!-- demo calculating the area of a circle -->
    <!-- first, calculate the radius -->
    <math result="radius">  <!-- defaults to double datatype -->
        <op type="*">
            <num value="1"/>
            <num value="2"/>
            <num value="3"/>
            <num value="4"/>
            <num value="5"/>
        </op>
    </math>
    <echo> 1 * 2 * 3 * 4 * 5 = ${radius}</echo>

    <!-- now calculate the area -->
    <math result="area" precision="float">
        <op type="*">
            <num value="PI"/>
            <op type="pow">
                <num value="${radius}"/>
                <num value="2"/>
            </op>
        </op>
    </math>
    <echo>area = PI * radius ^ 2 = ${area}</echo>

    <!-- demo calculating a random number between 0 and 100 -->
    <math result="result">
        <op op="rint">
            <op op="*">
                <num value="100"/>
                <op op="random"/>
            </op>
        </op>
    </math>
    <echo>a random number between 0 and 100: ${result}</echo>

    <!-- demo another multiplication -->
    <math result="result" operation="multiply" operand1="17" operand2="13"/>
    <echo>${result}</echo>
]]>
</programlisting>
</para>

</chapter>


<chapter id="hostname">
@style@
    <title>Hostname</title>

<para>
This task shows the hostname or IP address of the local machine.
</para>

<para>
To use this task in your build files, include a task definition like this:
<programlisting>
<![CDATA[
    <taskdef name="hostname" classname="ise.antelope.tasks.HostnameTask"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>Hostname Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>property</entry>
<entry>Name of the property to store the hostname or IP</entry>
<entry>hostname</entry>
<entry>No</entry>
</row>

<row>
<entry>showip</entry>
<entry>If true, get the IP address of the local machine.</entry>
<entry>false</entry>
<entry>No</entry>
</row>

<row>
<entry>nic</entry>
<entry>The specific name of an interface to get the hostname or IP address of.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>showall</entry>
<entry>Get all names or IP addresses for all network interfaces on the local machine.</entry>
<entry>false</entry>
<entry>No</entry>
</row>

<row>
<entry>failonerror</entry>
<entry>Should the build fail if this task fails?</entry>
<entry>false</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
Examples:
</para>

<para>
<programlisting>
<![CDATA[
   <description>
      Unit tests for hostname task, not really good as hostname is machine
      dependent, so writing a portable test is hard.
   </description>

   <target name="test1">
      <a:unset name="hostname"/>
      <a:hostname/>
      <echo>hostname: ${hostname}</echo>
      <a:assert name="hostname" exists="true" message="test 1 failed."/>
   </target>

   <target name="test2">
      <a:unset name="localhost"/>
      <a:hostname property="localhost"/>
      <echo>localhost: ${localhost}</echo>
      <a:assert name="localhost" exists="true" message="test 2 failed."/>
   </target>

   <target name="test3">
      <a:unset name="localhost"/>
      <a:hostname property="localhost" showall="yes"/>
      <echo>all interfaces: ${localhost}</echo>
      <a:assert name="localhost" exists="true" message="test 3 failed."/>
   </target>

   <target name="test4">
      <a:unset name="localhost"/>
      <a:hostname property="localhost" showall="yes" showip="yes"/>
      <echo>all interfaces by IP: ${localhost}</echo>
      <a:assert name="localhost" exists="true" message="test 4 failed."/>
   </target>

   <target name="test5">
      <a:unset name="localhost"/>
      <a:hostname property="localhost" nic="lo" showip="yes"/>
      <echo>nic lo: ${localhost}</echo>
      <a:assert name="localhost" value="lo:127.0.0.1" message="test 5 failed."/>
   </target>

Output:

test1:
     [echo] hostname: blackdog

test2:
     [echo] localhost: blackdog

test3:
     [echo] all interfaces: lo:127.0.0.1, eth0:, eth1:blackdog.somewhere.com, eth2:blackdog.wireless.somewhere.com

test4:
     [echo] all interfaces by IP: lo:127.0.0.1, eth0:, eth1:192.168.1.3, eth2:192.168.44.12

test5:
     [echo] nic lo: lo:127.0.0.1
]]>
</programlisting>
</para>

</chapter>



<chapter id="post">
@style@
    <title>HTTP Post</title>

<para>
The Post task is a companion to the standard Ant "Get" task. This task does a post and does not necessarily expect anything in return. Almost always, there will be some sort of returned data, this can be logged or written to a file if needed.
</para>

<para>
To use this task in your build files, include a task definition like this:
<programlisting>
<![CDATA[
    <taskdef name="post" classname="ise.antelope.tasks.PostTask"/>
   ]]>
</programlisting>
</para>

<para>
Basically, an HTTP POST sends name/value pairs to a web server. A very common usage is for html forms for submitting data. A typical use of this task is to send data to a servlet for updating a web page with the status of a build.
</para>

<para>
This Post task handles cookies and remembers them across calls.  This means that you can post to a login form, receive authentication cookies, then subsequent posts will automatically pass the correct cookies.  The cookies are stored in memory only, they are not written to disk and will cease to exist upon completion of the build.
</para>

<para>
The Post task has three ways of specifying the data to be posted. Nested "prop" elements can be used. A "prop" element represents a single name/value pair. The second way is to specify a property file as an attribute to the Post. All properties from the file will be sent as part of the Post data. The third way is to just type in some defined Ant properties. Is it allowed to use all three ways at once, that is, read some properties from a file, specify others via "prop" elements, and just type in some Ant properties.
</para>

<para>
<table frame="all">
<title>Post Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>to</entry>
<entry>The URL of the remote server to send the post.</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>

<row>
<entry>encoding</entry>
<entry>Character encoding for the name/value pairs.</entry>
<entry>UTF-8</entry>
<entry>No</entry>
</row>

<row>
<entry>logfile</entry>
<entry>The name of a file to write any response to. Ignored if wantresponse is set to false.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>append</entry>
<entry>Should an existing log file be appended to or overwritten?</entry>
<entry>True, append to an existing file.</entry>
<entry>No</entry>
</row>

<row>
<entry>file</entry>
<entry>A file to read POST data from. All Ant properties contained in this file will be resolved (that is, ${} syntax will be expanded to their values) prior to sending the file contents.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>maxwait</entry>
<entry>The maximum amount of time in seconds to wait for the data to be sent or for a response from the remote server. Setting this to zero means wait forever.</entry>
<entry>180 (3 minutes)</entry>
<entry>No</entry>
</row>

<row>
<entry>wantresponse</entry>
<entry>Whether to wait for a response from the remote server or not. In many cases this can greatly improve the performance of the build script as the server response may be large and useless to the script. Use this with caution - while the response from the server may not be required for the client, the server may require that the client accept the response prior to processing the post data.</entry>
<entry>true</entry>
<entry>No</entry>
</row>

<row>
<entry>property</entry>
<entry>If set and wantresponse, put the response from the remote server into this property.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>failonerror</entry>
<entry>Whether the build should fail if the post fails.</entry>
<entry>false</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
Post supports nested "prop" elements. As an HTTP POST basically sends a list of names and values, the "prop" element represents one name/value pair. A Post may contain any number of "prop" elements.
</para>

<para>
<table frame="all">
<title>Prop Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>name</entry>
<entry>The name of a property to post.</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>

<row>
<entry>value</entry>
<entry>The value associated with the name.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
The "value" attribute is not strictly required. This provides a short-cut method in cases where the property data is an already-defined Ant property. Suppose the build file has this property defined:
</para>

<para>
<programlisting>
<![CDATA[
    <property name="src.dir" value="/home/user/project/src"/>
]]>
</programlisting>
</para>

<para>
Then the following are equivalent:
</para>

<para>
<programlisting>
<![CDATA[
    <prop name="src.dir"/>
    <prop name="src.dir" value="${src.dir}"/>
    <prop name="src.dir" value="/home/user/project/src"/>
]]>
</programlisting>
</para>

<para>
Defined Ant properties can be entered directly into the post element. Again, suppose the build file has this property defined:
</para>

<para>
<programlisting>
<![CDATA[
    <property name="src.dir" value="/home/user/project/src"/>
]]>
</programlisting>
</para>

<para>
Then the following are equivalent:
</para>

<para>
<programlisting>
<![CDATA[
    ${src.dir}
    <prop name="src.dir"/>
    <prop name="src.dir" value="${src.dir}"/>
    <prop name="src.dir" value="/home/user/project/src"/>
]]>
</programlisting>
</para>


<para>
I googled for the URL in the following example.
</para>
<para>
<programlisting>
<![CDATA[
    <property name="test.val" value="here's my test value"/>
    <property name="test.val2" value="second test value"/>
    <post to="http://wwwj.cs.unc.edu:8888/tang/servlet/tangGetPostServlet"
        verbose="true">
        <prop name="prop1" value="val1 ${test.val}"/>
        <prop name="prop2" value="val1 value 2"/>
        <prop name="prop3" value="val got some spaces %funky ^$* chars"/>
        <prop name="prop4" value="&amp; do an ampersand like this &amp;amp; or
        Ant will whine"/>
        <prop name="thanks" value="dude, thanks for the echo server!"/>
        <prop name="test.val"/>
        ${test.val2}
    </post>
]]>
</programlisting>
</para>

<para>
Also see the <link linkend="greptask">Grep task</link> for additional examples.
</para>
</chapter>


<chapter id="ssh">
@style@

<title>SSH and SCP</title>

<para>
The ssh and scp tasks are no longer included in the main Antelope distribution as they are scheduled to be released as part of Ant 1.6.
</para>
</chapter>

<chapter id="antfetch">
@style@
    <title>AntFetch</title>

<para>
AntFetch is identical to the standard 'Ant' task, except that it allows properties from the new project to be set in the original project.
</para>

<para>
To use this task in your build files, include a task definition like this:
<programlisting>
<![CDATA[
    <taskdef name="antfetch" classname="ise.antelope.tasks.AntFetch"/>
   ]]>
</programlisting>
</para>


<para>
Some background may be in order: When the &lt;ant&gt; task is used, in actuality, a new Ant project is created, and depending on the inheritAll property, it is populated with properties from the original project. Then the target in this new project is executed. Any properties set in the new project remain with that project, they do not get "passed back" to the original project. So, for example, if the target in the new project sets a property named "image.directory", there is no reference to that property in the original. Here's an example of what I mean:
</para>

<para>
Suppose that the "fillImageDirectory" target sets a property named "image.directory" and I call the following:
<programlisting>
<![CDATA[
    <ant dir="${image.project} target="fillImageDirectory"/>
    <echo>${image.directory}</echo>
]]>
</programlisting>
The output of the echo task will be ${image.directory}, not whatever was set in the "fillImageDirectory" target.
</para>

<para>
The AntFetch task allows that image.directory property to be set in the original project. The attributes for AntFetch are identical to the 'Ant' task, with one additional, optional attibute. This attribute is named "return" and can be either a single property name or a comma separated list of property names.
</para>

<para>
Assuming that "fillImageDirectory" actually sets a property named "image.directory", the following example will print out the directory name:
<programlisting>
<![CDATA[
    <antfetch dir="${image.project} target="fillImageDirectory" return="image.directory"/>
    <echo>${image.directory}</echo>
]]>
</programlisting>
</para>

<para>
And this one will also print out the thumbnail directory:
<programlisting>
<![CDATA[
    <antfetch dir="${image.project} target="fillImageDirectory" return="image.directory, thumbnail.directory"/>
    <echo>${image.directory}</echo>
    <echo>${thumbnail.directory}</echo>
]]>
</programlisting>
</para>

<para>
The attributes for AntFetch are identical to the 'ant' task, with one additional, optional attibute. This attribute is named "return" and can be either a single property name or a comma separated list of property names.
<table frame="all">
<title>AntFetch Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>return</entry>
<entry>A comma separated list of property names. Whitespace is allowed, so either "a,b" or "a, b" are acceptable.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>
<para>
For other attribute and nested element information and more examples, see the documentation for the "ant" task in the Ant documentation.
</para>


</chapter>


<chapter id="antcallback">
@style@
    <title>AntCallBack</title>

<para>
AntCallBack is identical to the standard 'antcall' task, except that it allows properties set in the called target to be available in the calling target.
</para>

<para>
To use this task in your build files, include a task definition like this:
<programlisting>
<![CDATA[
    <taskdef name="antcallback" classname="ise.antelope.tasks.AntCallBack"/>
   ]]>
</programlisting>
</para>


<para>
Some background may be in order: When the &lt;antcall&gt; task is used, in actuality, a new Ant project is created, and depending on the inheritAll property, it is populated with properties from the original project. Then the requested target in this new project is executed. Any properties set in the new project remain with that project, they do not get "passed back" to the original project. So, for example, if the target in the new project sets a property named "image.directory", there is no reference to that property in the original. Here's an example of what I mean:
</para>

<para>
<programlisting>
<![CDATA[
    <target name="testCallback" description="Test CallBack">
        <taskdef name="antcallback" classname="ise.antelope.tasks.AntCallBack" classpath="${antelope.home}/build" />
        <antcallback target="-testcb" return="a, b"/>
        <echo>a = ${a}</echo>
        <echo>b = ${b}</echo>
    </target>

    <target name="-testcb">
        <property name="a" value="A"/>
        <property name="b" value="B"/>
    </target>
]]>
</programlisting>
The output from executing "testCallback" looks like this:
<programlisting>
a = A
b = B
</programlisting>
Contrast with this output from "antcall":
<programlisting>
a = ${a}
b = ${b}
</programlisting>
</para>

<para>
This is an often requested feature for Ant, at least judging from the Ant mailing lists. I assume this is because it allows a more functional programming style than Ant natively supports. The proper Ant way of doing the above is like this:
<programlisting>
<![CDATA[
    <target name="testCallback" description="Test CallBack" depends="-testcb">
        <echo>a = ${a}</echo>
        <echo>b = ${b}</echo>
    </target>

    <target name="-testcb">
        <property name="a" value="A"/>
        <property name="b" value="B"/>
    </target>
]]>
</programlisting>
This is actually looks cleaner in this situation, and is faster, too. There is significant overhead in using both "antcall" and "antcallback" in that they both require a lot of object instantiation and property copying. That said, many people prefer to use "antcall" and "antcallback" as it better fits their logic and style.
</para>

<para>
The attributes for AntCallBack are identical to the 'antcall' task, with one additional, optional attibute. This attribute is named "return" and can be either a single property name or a comma separated list of property names.
<table frame="all">
<title>AntCallBack Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>return</entry>
<entry>A comma separated list of property names. Whitespace is allowed, so either "a,b" or "a, b" are acceptable.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>


<para>
For other attribute and nested element information and more examples, see the documentation for the "antcall" task in the Ant documentation.
</para>

</chapter>

<chapter id="calltask">
@style@
    <title>Call Task</title>
<para>
This is the simplest and possibly the most obvious of the "call" type of tasks. It simply calls a target in the current build file and provides exactly the functionality expected by many users of "antcall".
</para>
<para>
To use this task in your build files, include a task definition like this:
<programlisting>
<![CDATA[
    <taskdef name="call" classname="ise.antelope.tasks.Call"/>
   ]]>
</programlisting>
</para>

<para>
There is only one attribute, that is the name of the target to call.

<table frame="all">
<title>Call Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>target</entry>
<entry>The name of a target to execute.</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
There is none of the weird property manipulation done by "ant", "antcall", "antfetch", or "antcallback", and none of the overhead. When you call a target, any properties set in that target are immediately available in the calling target. A simple example should be all that is necessary:
<programlisting>
<![CDATA[
 <target name="test" description="Test Call">
     <call target="called"/>
     <echo>a = ${a}</echo>
     <echo>b = ${b}</echo>
 </target>

 <target name="called">
     <property name="a" value="A"/>
     <property name="b" value="B"/>
 </target>
]]>
</programlisting>
</para>
</chapter>

<chapter id="greptask">
@style@
    <title>Grep Task</title>
<para>
This task uses a regular expression to do pattern matching against a string and store the match in a property.  This is useful for extracting a substring, or checking that an html form contains a particular value.</para>
<para>
To use this task in your build files, include a task definition like this:
<programlisting>
<![CDATA[
    <taskdef name="grep" classname="ise.antelope.tasks.Find"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>Grep Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>in</entry>
<entry>The string to perform the regular expression matching on</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>
<row>
<entry>regex</entry>
<entry>The regular expression.  See the Java API documentation for java.util.regex.Pattern for the details of the syntax for this expression.</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>
<row>
<entry>group</entry>
<entry>The regular expression group to return in the property.</entry>
<entry>0</entry>
<entry>No</entry>
</row>
<row>
<entry>property</entry>
<entry>The name of a property in which to put the matched value.</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>
<row>
<entry>allmatches</entry>
<entry>A regex may find multiple matches in the input string.  If this attribute is set to true, then the property set after the grep will contain all matches.  The individual matches can be separated by using the 'separator' attribute (see below). The default is 'false', that is, only return the first match.</entry>
<entry>false</entry>
<entry>No</entry>
</row>
<row>
<entry>separator</entry>
<entry>When 'allmatches' is set to true and there are multiple matches, this value will be used to separate the individual matches.</entry>
<entry>${line.separator}</entry>
<entry>No</entry>
</row>

<row>
<entry>caseinsensitive</entry>
<entry>Enables case-insensitive matching.</entry>
<entry>false</entry>
<entry>No</entry>
</row>
<row>
<entry>comments</entry>
<entry>Permits whitespace and comments in pattern.</entry>
<entry>false</entry>
<entry>No</entry>
</row>
<row>
<entry>dotall</entry>
<entry>Enables dotall mode.</entry>
<entry>false</entry>
<entry>No</entry>
</row>
<row>
<entry>multiline</entry>
<entry>Enables multiline mode.</entry>
<entry>false</entry>
<entry>No</entry>
</row>
<row>
<entry>unicodecase</entry>
<entry>Enables Unicode-aware case folding.</entry>
<entry>false</entry>
<entry>No</entry>
</row>
<row>
<entry>canoneq</entry>
<entry>Enables canonical equivalence.</entry>
<entry>false</entry>
<entry>No</entry>
</row>
<row>
<entry>unixlines</entry>
<entry>Enables Unix lines mode.</entry>
<entry>false</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
Examples:
</para>
<para>
<programlisting>
<![CDATA[
 <target name="test" description="Test grep">
      <grep in="${response}" regex="(account id=)([0-9]+)" group="2" property="AccountId"/>
      <echo>Account Id: ${AccountId} received for ${user}</echo>
 </target>
]]>
</programlisting>
</para>
<para>
This example uses the 'unset' and 'post' tasks along with 'grep' to list the download url's for Ant:
<programlisting>
<![CDATA[

    <target name="test">
      <unset name="ant_download_page"/>
      <post to="http://ant.apache.org/bindownload.cgi"
            verbose="no"
            property="ant_download_page"/>
      <grep in="${ant_download_page}"
            regex="select name=&quot;Preferred.*?&lt;/select"
            dotall="yes"
            property="options"/>

      <unset name="urls"/>
      <grep in="${options}"
         regex="&lt;option.*?&gt;(.*?)&lt;/option&gt;"
         group="1"
         allmatches="yes"
         separator="${line.separator}"
         property="urls"/>
      <echo>${urls}</echo>
    </target>

     [echo] http://apache.gr-linux.com
     [echo] http://www.reverse.net/pub/apache
     [echo] http://government-grants.org/mirrors/apache.org
     [echo] http://apache.mirrors.hoobly.com
     [echo] http://apache.mirrormax.net
     [echo] http://www.ibiblio.org/pub/mirrors/apache
     [echo] http://www.mirrormonster.com/apache.org
     [echo] http://apache.towardex.com
     [echo] http://www.axint.net/apache
     [echo] http://apache.tradebit.com/pub
     [echo] http://www.eng.lsu.edu/mirrors/apache
     [echo] http://mirrors.isc.org/pub/apache
     [echo] http://www.theshell.com/pub/apache
     [echo] http://apache.mirrors.redwire.net
     [echo] http://apache.cs.utah.edu
     [echo] http://www.tux.org/pub/net/apache/dist
     [echo] http://linux.cs.lewisu.edu/apache
     [echo] http://apache.roweboat.net
     [echo] http://apache.secsup.org/dist
     [echo] http://www.signal42.com/mirrors/apache
     [echo] http://apache.mirror99.com
     [echo] http://mirrors.xtria.com/apache
     [echo] http://apache.downlod.in
     [echo] http://apache.mirrors.pair.com
     [echo] http://apache.seekmeup.com
     [echo] http://mirrors.combose.com/apache
     [echo] http://www.wmwweb.com/apache
     [echo] http://apache.intissite.com
     [echo] http://apache.oregonstate.edu
     [echo] http://apache.bestwebcover.com
     [echo] http://ftp.wayne.edu/apache
     [echo] http://mirrors.ccs.neu.edu/Apache/dist
     [echo] http://www.ip97.com/apache.org
     [echo] http://apache.mirrors.versehost.com
     [echo] http://mirrors.playboy.com/apache
     [echo] ftp://ftp.ccs.neu.edu/net/mirrors/Apache/dist
     [echo] ftp://apache.mirrors.pair.com
     [echo] ftp://apache.cs.utah.edu/pub/apache.org
     [echo] ftp://apache.mirrors.redwire.net/pub/apache
     [echo] ftp://ftp.oregonstate.edu/pub/apache
     [echo] ftp://ftp.wayne.edu/apache
     [echo] ftp://mirror.sg.depaul.edu/pub/apache
     [echo] ftp://www.ibiblio.org/pub/mirrors/apache
     [echo] ftp://ftp.tux.org/pub/net/apache/dist
     [echo] ftp://www.reverse.net/pub/apache
     [echo] ftp://apache.secsup.org/pub/apache/dist
     [echo] http://www.eu.apache.org/dist (backup)
     [echo] http://www.apache.org/dist (backup)
]]>
</programlisting>
</para>

</chapter>


<chapter id="Split">
@style@
    <title>Split Task</title>

<para>
This task splits a property or file into pieces.  This is similar to the "split" utility found on most Unix and Linux distributions.
</para>

<para>
To use this task in your build files, include a task definition like this:
</para>

<para>
<programlisting>
<![CDATA[
    <taskdef name="split" classname="ise.antelope.tasks.SplitTask"/>
   ]]>
</programlisting>
</para>

<para>
Once a file has been split into smaller pieces, it can be rejoined with the "concat" task that is part of the standard Ant core tasks.
</para>

<para>
<table frame="all">
<title>Split Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>prefix</entry>
<entry>The start of the filename(s) to write the parts to.</entry>
<entry>x</entry>
<entry>No</entry>
</row>

<row>
<entry>bytes</entry>
<entry>How big, in bytes, to make the individual pieces. In general, use lines for text files, bytes or size for binary files.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>size</entry>
<entry>How big to make the individual pieces. Like the Unix/Linux split utility, this attribute allows modifiers: b for 512, k for 1K, m for 1 Meg, so 100k is the same as passing 102400 in the bytes attribute.  In general, use lines for text files, bytes or size for binary files.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>lines</entry>
<entry>How big to make the individual pieces in lines.  In general, use lines for text files, bytes or size for binary files.</entry>
<entry>1000</entry>
<entry>No</entry>
</row>

<row>
<entry>property</entry>
<entry>Split the value of the property into several files.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>string</entry>
<entry>Split this string into several files.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>file</entry>
<entry>Split this file into several files.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>outputdir</entry>
<entry>Destination for the output files.</entry>
<entry>None</entry>
<entry>Maybe.  If file is given and output dir is not, will write to the same directory as file, otherwise, this is a required attribute.</entry>
</row>

<row>
<entry>failonerror</entry>
<entry>Should the build stop if this task fails?</entry>
<entry>Yes</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
Examples
</para>

<para>
Split the value of a property into several files:
<programlisting>
<![CDATA[
   <target name="test1" depends="clean">
      <property name="prop1" value="ABCDE"/>
      <a:split property="prop1" bytes="1" outputdir="${out_dir}"/>
      <a:fileutil file="${out_dir}" property="file_count">
         <a:filecount/>
      </a:fileutil>
      <a:assert message="Expected 5 files, got ${file_count}">
         <bool>
            <a:mathequals arg1="5" arg2="${file_count}"/>
         </bool>
      </a:assert>
   </target>
]]>
</programlisting>
This will result in 5 files named x.0, x.1, x.2, x.3, and x.4, each containing a single character.
</para>

<para>
This more involved example shows how to split ant.jar into several files each 100000 bytes in size.  The files will be names ant.jar.0, ant.jar.1, ..., ant.jar.10.  Then the parts are put back together with concat.
<programlisting>
<![CDATA[
   <target name="test2" depends="clean">
      <!-- make sure ant.jar is available -->
      <property name="ant.jar" value="${ant.library.dir}/ant.jar"/>
      <available property="ant.jar.available" file="${ant.jar}"/>

      <a:if name="ant.jar.available" value="true">
         <!-- ant.jar generally runs around 1MB in size, so split into 100000 byte pieces -->
         <a:unset name="piece_size"/>
         <property name="piece_size" value="100000"/>
         <a:split file="${ant.jar}" bytes="${piece_size}" outputdir="${out_dir}" prefix="ant.jar"/>

         <!-- count the parts -->
         <a:fileutil file="${out_dir}" property="file_count">
            <a:filecount/>
         </a:fileutil>

         <!-- calculate how many parts there should be -->
         <a:fileutil file="${ant.jar}" property="ant_size">
            <a:filelength/>
         </a:fileutil>
         <a:math result="split_size">
            <a:op op="ceil">
               <a:op op="/">
                  <a:num value="${ant_size}"/>
                  <a:num value="${piece_size}"/>
               </a:op>
            </a:op>
         </a:math>

         <!-- make sure there are the right number of parts -->
         <a:assert message="Expected ${split_size} files, got ${file_count}">
            <bool>
               <a:mathequals arg1="${split_size}" arg2="${file_count}"/>
            </bool>
         </a:assert>

         <!-- sort the filenames of the parts so concat puts them together in
         the right order-->
         <a:fileutil file="${out_dir}" property="file_list">
            <a:listfiles includepath="no"/>
         </a:fileutil>
         <a:stringutil string="${file_list}" property="file_list">
            <a:sort/>
         </a:stringutil>

         <!-- put them back together -->
         <concat destfile="${out_dir}/ant.jar" binary="true">
            <filelist dir="${out_dir}" files="${file_list}"/>
         </concat>

         <!-- make sure the new file is the identical to the original -->
         <a:assert message="concat did not produce identical file">
            <bool>
               <filesmatch file1="${ant.jar}" file2="${out_dir}/ant.jar"/>
            </bool>
         </a:assert>
      </a:if>
   </target>
]]>
</programlisting>
</para>

</chapter>



<chapter id="Repeat">
@style@
    <title>Repeat Task</title>
<para>
The Repeat task performs the same subtasks over and over a certain number of times or until a condition is met.  Since most tasks are configured when the build file is first loaded and never again, this task may not do what you want.
</para>
<para>
To use this task in your build files, include a task definition like this:
<programlisting>
<![CDATA[
    <taskdef name="call" classname="ise.antelope.tasks.Repeat"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>Repeat Task Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>count</entry>
<entry>The number of times to repeat execution of the nested tasks.</entry>
<entry>1</entry>
<entry>No</entry>
</row>

<row>
<entry>interval</entry>
<entry>How long to wait between repetitions.  If set to 0, only 1 repetition will be performed, this is to avoid a tight loop.</entry>
<entry>0</entry>
<entry>No</entry>
</row>

<row>
<entry>unit</entry>
<entry>The units for interval, allowed values are "milliseconds", "seconds", "minutes", "days", and "weeks"</entry>
<entry>seconds</entry>
<entry>No</entry>
</row>

<row>
<entry>property</entry>
<entry>The name of a property to set upon completion.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

<row>
<entry>value</entry>
<entry>The value to set for the property to be set upon completion.</entry>
<entry>None</entry>
<entry>No</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
Here are a number of examples taken from the unit tests for this task:
<programlisting>
<![CDATA[
   <target name="test1a">
      <!-- no count set, verify performs tasks once -->
      <a:var name="count" value="0"/>
      <a:repeat>
         <a:math result="count" operand1="${count}" operand2="1" operation="+"/>
      </a:repeat>
      <a:assert>
         <bool>
            <mathequals arg1="${count}" arg2="1"/>
         </bool>
      </a:assert>
   </target>

   <target name="test1b">
      <!-- count > 1, verify performs tasks correct number of times -->
      <a:var name="count" value="0"/>
      <a:repeat count="3" interval="1">
         <a:math result="count" operand1="${count}" operand2="1" operation="+"/>
      </a:repeat>
      <a:assert message="Expected 3, got ${count}">
         <bool>
            <mathequals arg1="${count}" arg2="3"/>
         </bool>
      </a:assert>
   </target>

   <target name="test1c">
      <!-- count = -1, verify performs tasks indefinitely -->
      <a:var name="count" value="0"/>
      <a:limit maxwait="10">
         <a:repeat count="-1" interval="1">
            <a:math result="count" operand1="${count}" operand2="1" operation="+"/>
         </a:repeat>
      </a:limit>
      <a:assert>
         <bool>
            <and>
               <a:isgreaterthan arg1="${count}" arg2="8"/>
               <a:islessthan arg1="${count}" arg2="12"/>
            </and>
         </bool>
      </a:assert>
   </target>

   <target name="test2a">
      <!-- no interval set, verify performs tasks 10 seconds apart -->
      <a:var name="count" value="0"/>
      <a:stopwatch name="test2a_stopwatch" action="start"/>
      <a:repeat count="2">
         <a:math result="count" operand1="${count}" operand2="1" operation="+"/>
      </a:repeat>
      <a:stopwatch name="test2a_stopwatch" action="total"/>
      <a:assert message="Got ${count}, expected 2">
         <bool>
            <and>
               <a:mathequals arg1="${count}" arg2="2"/>
               <a:islessthan arg1="${test2a_stopwatch}" arg2="11"/>
            </and>
         </bool>
      </a:assert>
   </target>


   <target name="test2b">
      <!-- interval set to other than 10 seconds, verify tasks performed correct
           time apart. -->
      <a:var name="count" value="0"/>
      <a:stopwatch name="test2b_stopwatch" action="start"/>
      <a:repeat count="2" interval="5">
         <a:math result="count" operand1="${count}" operand2="1" operation="+"/>
      </a:repeat>
      <a:stopwatch name="test2b_stopwatch" action="total"/>
      <a:assert>
         <bool>
            <and>
               <a:mathequals arg1="${count}" arg2="2"/>
               <a:islessthan arg1="${test2b_stopwatch}" arg2="6"/>
            </and>
         </bool>
      </a:assert>
   </target>

   <target name="test2c">
      <!-- interval = 0, verify tasks performed just once -->
      <a:var name="count" value="0"/>
      <a:stopwatch name="test2c_stopwatch" action="start"/>
      <a:repeat count="5" interval="0">
         <a:math result="count" operand1="${count}" operand2="1" operation="+" datatype="int"/>
      </a:repeat>
      <a:stopwatch name="test2c_stopwatch" action="total"/>
      <a:assert>
         <bool>
            <and>
               <a:mathequals arg1="${count}" arg2="1"/>
               <a:islessthan arg1="${test2c_stopwatch}" arg2="1"/>
            </and>
         </bool>
      </a:assert>
   </target>

   <target name="test3a">
      <!-- failOnError not set, verify continues to execute tasks even if one fails -->
      <a:var name="count" value="0"/>
      <a:repeat count="3" interval="1">
         <a:math result="count" operand1="${count}" operand2="1" operation="+"/>
         <fail/>
      </a:repeat>
      <a:assert>
         <bool>
            <a:mathequals arg1="${count}" arg2="3"/>
         </bool>
      </a:assert>
   </target>

   <target name="test3b">
      <!-- failOnError set to false, same as 3a -->
      <a:var name="count" value="0"/>
      <a:repeat count="3" interval="1" failonerror="no">
         <a:math result="count" operand1="${count}" operand2="1" operation="+"/>
         <fail/>
      </a:repeat>
      <a:assert>
         <bool>
            <a:mathequals arg1="${count}" arg2="3"/>
         </bool>
      </a:assert>
   </target>

   <target name="test3c">
      <!-- failOnError set to true, verify build fails if subtask fails -->
      <a:var name="count" value="0"/>
      <a:try>
         <a:repeat count="3" interval="1" failonerror="yes">
            <a:math result="count" operand1="${count}" operand2="1" operation="+"/>
            <fail/>
         </a:repeat>
      </a:try>
      <a:assert>
         <bool>
            <a:mathequals arg1="${count}" arg2="1"/>
         </bool>
      </a:assert>
   </target>

   <target name="test4a">
      <!-- property name set, value not set, verify property is set to true when task
           is complete -->
      <a:var name="count" value="0"/>
      <a:repeat count="1" interval="1" property="test4a_property">
         <a:math result="count" operand1="${count}" operand2="1" operation="+"/>
         <fail/>
      </a:repeat>
      <a:assert>
         <bool>
            <istrue value="${test4a_property}"/>
         </bool>
      </a:assert>
   </target>

   <target name="test4b">
      <!-- property ame set, value set to a specific value, verify property is set to
           specific value when task is complete -->
      <a:var name="count" value="0"/>
      <a:repeat count="1" interval="1" property="test4b_property" value="good">
         <a:math result="count" operand1="${count}" operand2="1" operation="+"/>
         <fail/>
      </a:repeat>
      <a:assert name="test4b_property" value="good"/>
   </target>

   <target name="test5">
      <property name="call_count" value="0"/>
      <a:limit seconds="5" failonerror="true">
         <a:repeat count="-1" interval="1">
            <a:until>
               <a:contains property="log_contents" substring="All tests passed 4 times." />
            </a:until>

            <echo>read log</echo>
            <a:new>
               <a:call target="readLog"/>
            </a:new>
            <echo>${call_count} - ${log_contents}</echo>

         </a:repeat>
      </a:limit>
   </target>

   <target name="readLog">
      <a:unset name="log_contents"/>
      <a:new>
         <a:math result="call_count" operand1="${call_count}" operand2="1" operation="+" datatype="int"/>
         <property name="log_contents" value="All tests passed ${call_count} times."/>
      </a:new>
   </target>
]]>
</programlisting>
</para>
</chapter>

<chapter id="suitetask">
@style@
    <title>Suite Task</title>
<para>
 Modeled after the TestSuite provided by jUnit, this class is an Ant task that
 looks through the build file that contains this task, calls a 'setUp' target
 (if it exists), then executes all nested tasks, and last calls
 a target named 'tearDown' (if it exists).  Both 'setUp' and 'tearDown' are
 optional targets in the build file.  A build file may contain multiple suite tasks, note that each invocation will call 'setUp' and 'tearDown', so you may want to use some conditionals to only have them execute once.
</para>
<para>
<emphasis role="bold">While this task and the associated 'testcase' task work very well, a similar test framework has been created by the Ant development team.  You may want to check out that framework as it is likely to be the "standard" Ant test framework.  Look for "AntUnit" at http://ant.apache.org.</emphasis>
</para>
<para>
 Typically, the nested tasks are TestCases, although they can be any task as appropriate to your testing.  The nested tasks may also be Suites, so you can group your tests easily.  Nested tasks are executed in order.
</para>
<para>
 Suite may also hold FileSets.  Each file in the FileSet will be treated as a file suitable for use by a TestCase and will be executed as such.  This makes it easy to run an entire directory of tests without having to specify a TestCase for each one individually.
</para>
<para>
To use this task in your build files, include a task definition like this:
<programlisting>
<![CDATA[
    <taskdef name="suite" classname="ise.antelope.tasks.Suite"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>Suite Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>enabled</entry>
<entry>Determines if this suite should be ran.  By using a property for this attribute, it is easy to turn off/on multiple tests.</entry>
<entry>On</entry>
<entry>No</entry>
</row>
<row>
<entry>assertenabled</entry>
<entry>Generally tests will use the Assert task.  This attribute sets whether asserts should be enabled.</entry>
<entry>Yes</entry>
<entry>No</entry>
</row>
<row>
<entry>showoutput</entry>
<entry>If true, show intermediate test results</entry>
<entry>Yes</entry>
<entry>No</entry>
</row>
<row>
<entry>showsummary</entry>
<entry>If true, show a summary of test results at the end of the test run.</entry>
<entry>Yes</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
In the example below, the "suite" tasks is a top-level task, so will execute automatically.  This example does not use 'setUp' or 'tearDown' targets.
</para>
<para>
<programlisting>
<![CDATA[
<project name="mathtest" basedir="." xmlns:a="antlib:ise.antelope.tasks">
   <description>
     Build file to run unit tests for the Math task
   </description>

   <a:suite>
      <a:testcase file="math_basic_tests.xml"/>
      <a:testcase file="math_rules_tests.xml"/>
      <a:testcase file="math_precision_tests.xml"/>
   </a:suite>

   <!-- alternatively, a fileset could be used:
   <a:suite>
      <fileset dir="${basedir}">
         <include name="math_*.xml"/>
      </fileset>
   </a:suite>
   -->
</project>

$ ant -f mathtest2.xml
Buildfile: mathtest2.xml
 [testcase] +-------------------------------------------+
 [testcase] + mathtest
 [testcase] +-------------------------------------------+

test6:
 [testcase] ERROR: test6 failed: string or property must be set.

test5:
 [testcase] test5 passed.

test4:
 [testcase] test4 passed.

test3:
 [testcase] test3 passed.

test2:
 [testcase] test2 passed.

test1:
 [testcase] test1 passed.
 [testcase] +-------------------------------------------+
 [testcase] + mathtest
 [testcase] +-------------------------------------------+
 [testcase]
 [testcase] ---- Errors ---------------------------------
 [testcase] ERROR: test6 failed: string or property must be set.
 [testcase] ---- Results --------------------------------
 [testcase] Ran 6 out of 6 tests.
 [testcase] Passed: 5
 [testcase] Warning: 0
 [testcase] Failed: 1
 [testcase] +-------------------------------------------+
 [testcase] +-------------------------------------------+
 [testcase] + math_precision_tests
 [testcase] +-------------------------------------------+

test11:
     [echo] Division by zero test
    [a:try] Task 'a:math' in target 'test11' failed, error message is: java.lang.ArithmeticException
 [testcase] ERROR: test11 failed: java.lang.ArithmeticException: / by zero

test10:
     [echo] Circle area test
 [testcase] ERROR: test10 failed: string or property must be set.
 [testcase] +-------------------------------------------+
 [testcase] + math_precision_tests
 [testcase] +-------------------------------------------+
 [testcase]
 [testcase] ---- Errors ---------------------------------
 [testcase] ERROR: test11 failed: java.lang.ArithmeticException: / by zero
 [testcase] ERROR: test10 failed: string or property must be set.
 [testcase] ---- Results --------------------------------
 [testcase] Ran 2 out of 2 tests.
 [testcase] Passed: 0
 [testcase] Warning: 0
 [testcase] Failed: 2
 [testcase] +-------------------------------------------+
 [testcase] +-------------------------------------------+
 [testcase] + math_rules_tests
 [testcase] +-------------------------------------------+

test7.2:
 [testcase] test7.2 passed.

test7.1:
 [testcase] test7.1 passed.

test7.0:
 [testcase] test7.0 passed.

test8.3:
 [testcase] test8.3 passed.

test8.2:
 [testcase] test8.2 passed.

test9:
 [testcase] test9 passed.

test8.1:
 [testcase] test8.1 passed.

test8.0:
 [testcase] test8.0 passed.
 [testcase] +-------------------------------------------+
 [testcase] + math_rules_tests
 [testcase] +-------------------------------------------+
 [testcase] ---- Results --------------------------------
 [testcase] Ran 8 out of 8 tests.
 [testcase] Passed: 8
 [testcase] Warning: 0
 [testcase] Failed: 0
 [testcase] +-------------------------------------------+
    [suite] ++-- Totals -------------------------------++
    [suite] ++ Total Ran 16 out of 16 tests.
    [suite] ++ Total Passed: 13
    [suite] ++ Total Warnings: 0
    [suite] ++ Total Failed: 3
    [suite] ++-----------------------------------------++

BUILD SUCCESSFUL
Total time: 1 second
]]>
</programlisting>
</para>
</chapter>

<chapter id="testcasetask">
@style@
    <title>TestCase Task</title>
<para>
 Modeled after the TestCase provided by jUnit, this class is an Ant task that
 looks through the build file that contains this task, calls a 'setUp' target
 (if it exists), then all targets whose names start with 'test', and last calls
 a target named 'tearDown' (if it exists).  Both 'setUp' and 'tearDown' are
 optional targets in the build file.
</para>
<para>
 Ant stores targets in a hashtable, so there is no guaranteed order in which
 the 'test*' targets will be called.  If order is important, use the 'depends'
 attribue of a target to enforce order, and do not name dependent targets with
 a name starting with 'test'.
</para>
<para>
 Most unit tests will make use of Assert.  As the Assert task requires that the property "ant.enable.asserts" be set to true before it will do anything, this task automatically sets this property to true. The Assert task has a "level" attribute.  By default, the level is set to "error", so if the Assert fails, the TestCase fails.  If the level is set to "warning", the test case will be marked as a warning rather than a failure.  If the level is set to "info" or "debug" and the Assert fails, any message associated with the Assert will be written out, but otherwise will be ignored by TestCase.
</para>
<para>
To use this task in your build files, include a task definition like this:
<programlisting>
<![CDATA[
    <taskdef name="testcase" classname="ise.antelope.tasks.TestCase"/>
   ]]>
</programlisting>
</para>

<para>
<table frame="all">
<title>TestCase Attributes</title>
<tgroup cols="4">

<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>

<tbody>

<row>
<entry>file</entry>
<entry>The file containing tests.</entry>
<entry>None</entry>
<entry>Yes</entry>
</row>
<row>
<entry>enabled</entry>
<entry>Determines if this test should be ran.  By using a property for this attribute, it is easy to turn off/on multiple tests.</entry>
<entry>On</entry>
<entry>No</entry>
</row>
<row>
<entry>assertenabled</entry>
<entry>Generally tests will use the Assert task.  This attribute sets whether asserts should be enabled.</entry>
<entry>Yes</entry>
<entry>No</entry>
</row>
<row>
<entry>failonerror</entry>
<entry>If true, cause the build to fail. By default, a failed test does not cause the build to fail, so all tests may have the opportunity to run.</entry>
<entry>No</entry>
<entry>No</entry>
</row>
<row>
<entry>showoutput</entry>
<entry>If true, show intermediate test results</entry>
<entry>Yes</entry>
<entry>No</entry>
</row>
<row>
<entry>showsummary</entry>
<entry>If true, show a summary of test results at the end of the test run.</entry>
<entry>Yes</entry>
<entry>Yes</entry>
</row>

</tbody>
</tgroup>
</table>
</para>

<para>
TestCase is most often used in conjunction with the Suite task.
</para>
<para>
<programlisting>
<![CDATA[
<project name="mathtest" basedir="." default="suite"
   xmlns:a="antlib:ise.antelope.tasks">

   <description>
     Build file to run unit tests for the Math task
   </description>

   <a:suite>
      <a:testcase file="math_basic_tests.xml"/>
      <a:testcase file="math_rules_tests.xml"/>
      <a:testcase file="math_precision_tests.xml"/>
   </a:suite>

</project>
]]>
</programlisting>
</para>

<para>
Here is an example build file containing actual tests.  The 'setUp' target will execute first, then the two test targets.
</para>
<para>
<programlisting>
<![CDATA[
<project name="math_precision_tests" basedir="." default="suite"
   xmlns:a="antlib:ise.antelope.tasks">

   <target name="setUp">
      <echo>Running math precision tests.</echo>
   </target>

   <target name="test10">
      <echo>Circle area test</echo>
      <a:math result="pi">
         <a:op op="*">
            <a:num value="PI"/>
            <a:op op="pow">
               <a:num value="1"/>
               <a:num value="2"/>
            </a:op>
         </a:op>
      </a:math>
      <a:assert message="failed circle area test">
         <a:bool>
            <a:startswith string="${pi}" with="3.141592653589793"/>
         </a:bool>
      </a:assert>
   </target>

   <target name="test11">
      <echo>Division by zero test</echo>
      <!-- division by zero -->
      <a:try>
         <a:math result="x">
            <a:op op="/">
               <a:num value="PI"/>
               <a:num value="0"/>
            </a:op>
         </a:math>
         <fail>Division by 0 succeeded: ${x}</fail>
         <catch>
            <assert/>
         </catch>
      </a:try>
   </target>

</project>
]]>
</programlisting>
</para>

</chapter>

<chapter id="performance">
@style@
    <title>Performance Monitoring</title>

<para>
In addition to the tasks described in this manual, Antelope also ships with a special Ant listener than can keep track of the amount of time that each target and task takes to execute. At the end of the build, these times will be sorted from fastest to slowest and displayed following the build output. This can be useful to pinpoint slow and/or inefficient spots in the build process and identify those areas that could benefit from optimization.
</para>

<para>
The performance listener can be used outside of Antelope by passing a parameter to the command line for Ant:
</para>

<para>
<programlisting>
<![CDATA[
    ant -listener ise.antelope.common.AntPerformanceListener target
]]>
</programlisting>
</para>

<para>
Following is an example of the results from using the listener. The result format is projectname.targetname for targets and projectname.targetname.taskname for tasks. All times are shown to the nearest millisecond.
<programlisting>
<![CDATA[
[danson@blackdog antelope]$ ant -listener ise.antelope.common.AntPerformanceListener dist
Buildfile: build.xml

init:

clean:
   [delete] Deleting 170 files from /home/danson/apps/antelope/build

compile:
    [javac] Compiling 61 source files to /home/danson/apps/antelope/build

all:

-build_number:

prep_files:
   [delete] Deleting 3 files from /home/danson/apps/antelope/config
     [copy] Copying 3 files to /home/danson/apps/antelope/config

combined:
     [echo] basedir = /home/danson/apps/antelope
      [jar] Building jar: /home/danson/apps/antelope/Antelope_1.208.jar

dist:
   [delete] Deleting 4 files from /home/danson/apps/antelope/dist
      [zip] Building zip: /home/danson/apps/antelope/dist/Antelope_1.208.zip
     [echo] Created zip file.

-zip_docs:
      [zip] Building zip: /home/danson/apps/antelope/dist/Antelope_docs_1.208.zip
     [echo] Zipped docs to Antelope_docs_1.208.zip.

-zip_tasks:
      [jar] Building jar: /tmp/Antelope_tasks_1.208.jar
      [zip] Building zip: /home/danson/apps/antelope/dist/Antelope_tasks_1.208.zip
   [delete] Deleting: /tmp/Antelope_tasks_1.208.jar
     [echo] Zipped tasks to Antelope_tasks_1.208.zip.
     [copy] Copying 1 file to /home/danson/apps/antelope/dist

BUILD SUCCESSFUL
Total time: 8 seconds

-------------- Target Results -----------------------
Antelope.all: 0.000 sec
Antelope.init: 0.011 sec
Antelope.-build_number: 0.014 sec
Antelope.clean: 0.233 sec
Antelope.-zip_tasks: 0.297 sec
Antelope.prep_files: 0.311 sec
Antelope.-zip_docs: 0.546 sec
Antelope.combined: 1.290 sec
Antelope.compile: 1.724 sec
Antelope.dist: 2.162 sec

-------------- Task Results -----------------------
Antelope.init.mkdir: 0.000 sec
Antelope.init.mkdir: 0.001 sec
Antelope.dist.echo: 0.002 sec
Antelope.prep_files.delete: 0.004 sec
Antelope.combined.echo: 0.005 sec
Antelope.dist.delete: 0.006 sec
Antelope.-zip_tasks.echo: 0.007 sec
Antelope.dist.copy: 0.011 sec
Antelope.-build_number.buildnumber: 0.014 sec
Antelope.compile.copy: 0.016 sec
Antelope.prep_files.copy: 0.020 sec
Antelope.prep_files.replace: 0.071 sec
Antelope.-zip_tasks.zip: 0.122 sec
Antelope.-zip_tasks.jar: 0.161 sec
Antelope.prep_files.replace: 0.216 sec
Antelope.clean.delete: 0.233 sec
Antelope.dist.antcall: 0.421 sec
Antelope.-zip_docs.zip: 0.540 sec
Antelope.dist.antcall: 0.685 sec
Antelope.dist.zip: 1.036 sec
Antelope.combined.jar: 1.284 sec
Antelope.compile.javac: 1.708 sec

-------------- Totals -----------------------
Start time: Thu, 5 Dec 2002 17:18:30
Stop time: Thu, 5 Dec 2002 17:18:39
Total time: 8.476 sec
]]>
</programlisting>
</para>

</chapter>

<chapter id="feedback">
@style@
    <title>Feedback</title>

<para>
The preferred way to send bug reports is to use the
Issue Tracker at
<ulink url="http://antelope.tigris.org">
http://antelope.tigris.org
</ulink>.
</para>

<para>You can also write to me directly at:</para>
<itemizedlist>
    <listitem>
    <para>
        Dale Anson <email>danson@germane-software.com</email>
    </para>
    </listitem>
</itemizedlist>
</chapter>


</book>
